Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
chenpangpang
open-webui
Commits
3c10c3b9
Unverified
Commit
3c10c3b9
authored
Feb 25, 2024
by
Timothy Jaeryang Baek
Committed by
GitHub
Feb 25, 2024
Browse files
Merge pull request #910 from open-webui/dev
0.1.104
parents
02fb517b
1d937ec2
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
210 additions
and
66 deletions
+210
-66
CHANGELOG.md
CHANGELOG.md
+11
-0
backend/apps/web/models/tags.py
backend/apps/web/models/tags.py
+21
-0
backend/apps/web/routers/chats.py
backend/apps/web/routers/chats.py
+5
-2
backend/constants.py
backend/constants.py
+1
-0
backend/main.py
backend/main.py
+21
-1
package.json
package.json
+1
-1
src/lib/apis/index.ts
src/lib/apis/index.ts
+34
-0
src/lib/components/chat/MessageInput.svelte
src/lib/components/chat/MessageInput.svelte
+12
-14
src/lib/components/chat/MessageInput/Suggestions.svelte
src/lib/components/chat/MessageInput/Suggestions.svelte
+40
-38
src/lib/components/chat/Messages/Placeholder.svelte
src/lib/components/chat/Messages/Placeholder.svelte
+4
-1
src/lib/components/chat/Settings/About.svelte
src/lib/components/chat/Settings/About.svelte
+48
-2
src/lib/components/layout/Sidebar.svelte
src/lib/components/layout/Sidebar.svelte
+8
-2
src/lib/utils/index.ts
src/lib/utils/index.ts
+2
-3
src/routes/(app)/+layout.svelte
src/routes/(app)/+layout.svelte
+2
-2
No files found.
CHANGELOG.md
View file @
3c10c3b9
...
...
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on
[
Keep a Changelog
](
https://keepachangelog.com/en/1.1.0/
)
,
and this project adheres to
[
Semantic Versioning
](
https://semver.org/spec/v2.0.0.html
)
.
## [0.1.104] - 2024-02-25
### Added
-
**🔄 Check for Updates**
: Keep your system current by checking for updates conveniently located in Settings > About.
-
**🗑️ Automatic Tag Deletion**
: Unused tags on the sidebar will now be deleted automatically with just a click.
### Changed
-
**🎨 Modernized Styling**
: Enjoy a refreshed look with updated styling for a more contemporary experience.
## [0.1.103] - 2024-02-25
### Added
...
...
backend/apps/web/models/tags.py
View file @
3c10c3b9
...
...
@@ -167,6 +167,27 @@ class TagTable:
.
count
()
)
def
delete_tag_by_tag_name_and_user_id
(
self
,
tag_name
:
str
,
user_id
:
str
)
->
bool
:
try
:
query
=
ChatIdTag
.
delete
().
where
(
(
ChatIdTag
.
tag_name
==
tag_name
)
&
(
ChatIdTag
.
user_id
==
user_id
)
)
res
=
query
.
execute
()
# Remove the rows, return number of rows removed.
print
(
res
)
tag_count
=
self
.
count_chat_ids_by_tag_name_and_user_id
(
tag_name
,
user_id
)
if
tag_count
==
0
:
# Remove tag item from Tag col as well
query
=
Tag
.
delete
().
where
(
(
Tag
.
name
==
tag_name
)
&
(
Tag
.
user_id
==
user_id
)
)
query
.
execute
()
# Remove the rows, return number of rows removed.
return
True
except
Exception
as
e
:
print
(
"delete_tag"
,
e
)
return
False
def
delete_tag_by_tag_name_and_chat_id_and_user_id
(
self
,
tag_name
:
str
,
chat_id
:
str
,
user_id
:
str
)
->
bool
:
...
...
backend/apps/web/routers/chats.py
View file @
3c10c3b9
...
...
@@ -115,9 +115,12 @@ async def get_user_chats_by_tag_name(
for
chat_id_tag
in
Tags
.
get_chat_ids_by_tag_name_and_user_id
(
tag_name
,
user
.
id
)
]
print
(
chat_ids
)
chats
=
Chats
.
get_chat_lists_by_chat_ids
(
chat_ids
,
skip
,
limit
)
return
Chats
.
get_chat_lists_by_chat_ids
(
chat_ids
,
skip
,
limit
)
if
len
(
chats
)
==
0
:
Tags
.
delete_tag_by_tag_name_and_user_id
(
tag_name
,
user
.
id
)
return
chats
############################
...
...
backend/constants.py
View file @
3c10c3b9
...
...
@@ -47,3 +47,4 @@ class ERROR_MESSAGES(str, Enum):
INCORRECT_FORMAT
=
(
lambda
err
=
""
:
f
"Invalid format. Please use the correct format
{
err
if
err
else
''
}
"
)
RATE_LIMIT_EXCEEDED
=
"API rate limit exceeded"
backend/main.py
View file @
3c10c3b9
...
...
@@ -4,8 +4,9 @@ import markdown
import
time
import
os
import
sys
import
requests
from
fastapi
import
FastAPI
,
Request
,
Depends
from
fastapi
import
FastAPI
,
Request
,
Depends
,
status
from
fastapi.staticfiles
import
StaticFiles
from
fastapi
import
HTTPException
from
fastapi.responses
import
JSONResponse
...
...
@@ -26,6 +27,8 @@ from apps.web.main import app as webui_app
from
config
import
WEBUI_NAME
,
ENV
,
VERSION
,
CHANGELOG
,
FRONTEND_BUILD_DIR
from
constants
import
ERROR_MESSAGES
from
utils.utils
import
get_http_authorization_cred
,
get_current_user
...
...
@@ -127,6 +130,23 @@ async def get_app_changelog():
return
CHANGELOG
@
app
.
get
(
"/api/version/updates"
)
async
def
get_app_latest_release_version
():
try
:
response
=
requests
.
get
(
f
"https://api.github.com/repos/open-webui/open-webui/releases/latest"
)
response
.
raise_for_status
()
latest_version
=
response
.
json
()[
"tag_name"
]
return
{
"current"
:
VERSION
,
"latest"
:
latest_version
[
1
:]}
except
Exception
as
e
:
raise
HTTPException
(
status_code
=
status
.
HTTP_503_SERVICE_UNAVAILABLE
,
detail
=
ERROR_MESSAGES
.
RATE_LIMIT_EXCEEDED
,
)
app
.
mount
(
"/static"
,
StaticFiles
(
directory
=
"static"
),
name
=
"static"
)
...
...
package.json
View file @
3c10c3b9
{
"name"
:
"open-webui"
,
"version"
:
"0.1.10
3
"
,
"version"
:
"0.1.10
4
"
,
"private"
:
true
,
"scripts"
:
{
"dev"
:
"vite dev --host"
,
...
...
src/lib/apis/index.ts
View file @
3c10c3b9
...
...
@@ -19,6 +19,10 @@ export const getBackendConfig = async () => {
return
null
;
});
if
(
error
)
{
throw
error
;
}
return
res
;
};
...
...
@@ -41,5 +45,35 @@ export const getChangelog = async () => {
return
null
;
});
if
(
error
)
{
throw
error
;
}
return
res
;
};
export
const
getVersionUpdates
=
async
()
=>
{
let
error
=
null
;
const
res
=
await
fetch
(
`
${
WEBUI_BASE_URL
}
/api/version/updates`
,
{
method
:
'
GET
'
,
headers
:
{
'
Content-Type
'
:
'
application/json
'
}
})
.
then
(
async
(
res
)
=>
{
if
(
!
res
.
ok
)
throw
await
res
.
json
();
return
res
.
json
();
})
.
catch
((
err
)
=>
{
console
.
log
(
err
);
error
=
err
;
return
null
;
});
if
(
error
)
{
throw
error
;
}
return
res
;
};
src/lib/components/chat/MessageInput.svelte
View file @
3c10c3b9
...
...
@@ -490,7 +490,7 @@
}}
/>
<form
class=" flex flex-col relative w-full rounded-xl
border
dark:border-gray-
70
0 bg-white dark:bg-gray-900 dark:text-gray-100"
class=" flex flex-col relative w-full rounded-
3
xl
px-1.5 border border-gray-100
dark:border-gray-
85
0 bg-white dark:bg-gray-900 dark:text-gray-100"
on:submit|preventDefault={() => {
submitPrompt(prompt, user);
}}
...
...
@@ -633,9 +633,9 @@
<div class=" flex">
{#if fileUploadEnabled}
<div class=" self-end mb-2 ml-1
.5
">
<div class=" self-end mb-2 ml-1">
<button
class="
text-gray-
6
00 dark:
text
-gray-
2
00 transition rounded-
lg p-1 ml-1
"
class="
bg-gray-50 hover:bg-gray-100
text-gray-
8
00 dark:
bg-gray-850 dark:text-white dark:hover:bg
-gray-
8
00 transition rounded-
full p-1.5
"
type="button"
on:click={() => {
filesInputElement.click();
...
...
@@ -643,14 +643,12 @@
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0
20 20
"
viewBox="0 0
16 16
"
fill="currentColor"
class="w-
5 h-5
"
class="w-
[1.2rem] h-[1.2rem]
"
>
<path
fill-rule="evenodd"
d="M15.621 4.379a3 3 0 00-4.242 0l-7 7a3 3 0 004.241 4.243h.001l.497-.5a.75.75 0 011.064 1.057l-.498.501-.002.002a4.5 4.5 0 01-6.364-6.364l7-7a4.5 4.5 0 016.368 6.36l-3.455 3.553A2.625 2.625 0 119.52 9.52l3.45-3.451a.75.75 0 111.061 1.06l-3.45 3.451a1.125 1.125 0 001.587 1.595l3.454-3.553a3 3 0 000-4.242z"
clip-rule="evenodd"
d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z"
/>
</svg>
</button>
...
...
@@ -659,7 +657,7 @@
<textarea
id="chat-textarea"
class=" dark:bg-gray-900 dark:text-gray-100 outline-none w-full py-3 px-
2
{fileUploadEnabled
class=" dark:bg-gray-900 dark:text-gray-100 outline-none w-full py-3 px-
3
{fileUploadEnabled
? ''
: ' pl-4'} rounded-xl resize-none h-[48px]"
placeholder={chatInputPlaceholder !== ''
...
...
@@ -803,12 +801,12 @@
}}
/>
<div class="self-end mb-2 flex space-x-
0.5
mr-
2
">
<div class="self-end mb-2 flex space-x-
1
mr-
1
">
{#if messages.length == 0 || messages.at(-1).done == true}
{#if speechRecognitionEnabled}
<button
id="voice-input-button"
class=" text-gray-600 dark:text-gray-300 transition rounded-l
g
p-1.5 mr-0.5 self-center"
class=" text-gray-600 dark:text-gray-300
hover:bg-gray-50 dark:hover:bg-gray-850
transition rounded-
ful
l p-1.5 mr-0.5 self-center"
type="button"
on:click={() => {
speechRecognitionHandler();
...
...
@@ -869,7 +867,7 @@
<button
class="{prompt !== ''
? 'bg-black text-white hover:bg-gray-900 dark:bg-white dark:text-black dark:hover:bg-gray-100 '
: 'text-white bg-gray-100 dark:text-gray-900 dark:bg-gray-800 disabled'} transition rounded-
lg p-1 mr-0.5 w-7 h-7
self-center"
: 'text-white bg-gray-100 dark:text-gray-900 dark:bg-gray-800 disabled'} transition rounded-
full p-1.5
self-center"
type="submit"
disabled={prompt === ''}
>
...
...
@@ -877,7 +875,7 @@
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-
4.
5 h-
4.5 mx-auto
"
class="w-5 h-
5
"
>
<path
fill-rule="evenodd"
...
...
@@ -888,7 +886,7 @@
</button>
{:else}
<button
class="bg-white hover:bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-800 transition rounded-l
g
p-1.5"
class="bg-white hover:bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-800 transition rounded-
ful
l p-1.5"
on:click={stopResponse}
>
<svg
...
...
src/lib/components/chat/MessageInput/Suggestions.svelte
View file @
3c10c3b9
...
...
@@ -10,45 +10,47 @@
: suggestionPrompts.sort(() => Math.random() - 0.5).slice(0, 4);
</script>
<div class=" flex flex-wrap-reverse mb-3 md:p-1 text-left w-full">
{#each prompts as prompt, promptIdx}
<div
class="{promptIdx > 1 ? 'hidden sm:inline-flex' : ''} basis-full sm:basis-1/2 p-[5px] px-2"
>
<button
class=" flex-1 flex justify-between w-full h-full px-4 py-2.5 bg-white hover:bg-gray-50 dark:bg-gray-900 dark:hover:bg-gray-700 outline outline-1 outline-gray-200 dark:outline-gray-800 rounded-lg transition group"
on:click={() => {
submitPrompt(prompt.content);
}}
<div class=" mb-3 md:p-1 text-left w-full">
<div class=" flex flex-wrap-reverse px-2 text-left">
{#each prompts as prompt, promptIdx}
<div
class="{promptIdx > 1 ? 'hidden sm:inline-flex' : ''} basis-full sm:basis-1/2 p-[5px] px-1"
>
<div class="flex flex-col text-left self-center">
{#if prompt.title && prompt.title[0] !== ''}
<div class="text-sm font-medium dark:text-gray-300">{prompt.title[0]}</div>
<div class="text-sm text-gray-500 line-clamp-1">{prompt.title[1]}</div>
{:else}
<div class=" self-center text-sm font-medium dark:text-gray-300 line-clamp-2">
{prompt.content}
</div>
{/if}
</div>
<div
class="self-center p-1 rounded-lg text-white group-hover:bg-gray-100 group-hover:text-gray-800 dark:group-hover:bg-gray-800 dark:group-hover:text-gray-100 dark:text-gray-900 transition"
<button
class=" flex-1 flex justify-between w-full h-full px-4 py-2.5 bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 rounded-2xl transition group"
on:click={() => {
submitPrompt(prompt.content);
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-4 h-4"
<div class="flex flex-col text-left self-center">
{#if prompt.title && prompt.title[0] !== ''}
<div class="text-sm font-medium dark:text-gray-300">{prompt.title[0]}</div>
<div class="text-sm text-gray-500 line-clamp-1">{prompt.title[1]}</div>
{:else}
<div class=" self-center text-sm font-medium dark:text-gray-300 line-clamp-2">
{prompt.content}
</div>
{/if}
</div>
<div
class="self-center p-1 rounded-lg text-gray-50 group-hover:text-gray-800 dark:text-gray-850 dark:group-hover:text-gray-100 transition"
>
<path
fill-rule="evenodd"
d="M8 14a.75.75 0 0 1-.75-.75V4.56L4.03 7.78a.75.75 0 0 1-1.06-1.06l4.5-4.5a.75.75 0 0 1 1.06 0l4.5 4.5a.75.75 0 0 1-1.06 1.06L8.75 4.56v8.69A.75.75 0 0 1 8 14Z"
clip-rule="evenodd"
/>
</svg>
</div>
</button>
</div>
{/each}
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-4 h-4"
>
<path
fill-rule="evenodd"
d="M8 14a.75.75 0 0 1-.75-.75V4.56L4.03 7.78a.75.75 0 0 1-1.06-1.06l4.5-4.5a.75.75 0 0 1 1.06 0l4.5 4.5a.75.75 0 0 1-1.06 1.06L8.75 4.56v8.69A.75.75 0 0 1 8 14Z"
clip-rule="evenodd"
/>
</svg>
</div>
</button>
</div>
{/each}
</div>
</div>
src/lib/components/chat/Messages/Placeholder.svelte
View file @
3c10c3b9
<script lang="ts">
import { WEBUI_BASE_URL } from '$lib/constants';
import { user } from '$lib/stores';
import { onMount } from 'svelte';
export let models = [];
...
...
@@ -63,7 +64,9 @@
</div>
{/if}
{:else}
How can I help you today?
<div class=" line-clamp-1">Hello, {$user.name}</div>
<div>How can I help you today?</div>
{/if}
</div>
</div>
...
...
src/lib/components/chat/Settings/About.svelte
View file @
3c10c3b9
<script lang="ts">
import { getVersionUpdates } from '$lib/apis';
import { getOllamaVersion } from '$lib/apis/ollama';
import { WEBUI_VERSION } from '$lib/constants';
import { WEBUI_NAME, config, showChangelog } from '$lib/stores';
import { compareVersion } from '$lib/utils';
import { onMount } from 'svelte';
let ollamaVersion = '';
let updateAvailable = null;
let version = {
current: '',
latest: ''
};
const checkForVersionUpdates = async () => {
updateAvailable = null;
version = await getVersionUpdates(localStorage.token).catch((error) => {
return {
current: WEBUI_VERSION,
latest: WEBUI_VERSION
};
});
console.log(version);
updateAvailable = compareVersion(version.latest, version.current);
console.log(updateAvailable);
};
onMount(async () => {
ollamaVersion = await getOllamaVersion(localStorage.token).catch((error) => {
return '';
});
checkForVersionUpdates();
});
</script>
...
...
@@ -20,10 +46,21 @@
{$WEBUI_NAME} Version
</div>
</div>
<div class="flex w-full">
<div class="flex
-1
text-xs text-gray-700 dark:text-gray-200
flex space-x-1.5 items-center
">
<div class="flex w-full
justify-between items-center
">
<div class="flex
flex-col
text-xs text-gray-700 dark:text-gray-200">
<div>
v{WEBUI_VERSION}
<a
href="https://github.com/open-webui/open-webui/releases/tag/v{version.latest}"
target="_blank"
>
{updateAvailable === null
? 'Checking for updates...'
: updateAvailable
? `(v${version.latest} available!)`
: '(latest)'}
</a>
</div>
<button
...
...
@@ -35,6 +72,15 @@
<div>See what's new</div>
</button>
</div>
<button
class=" text-xs px-3 py-1.5 bg-gray-100 hover:bg-gray-200 dark:bg-gray-850 dark:hover:bg-gray-800 transition rounded-lg font-medium"
on:click={() => {
checkForVersionUpdates();
}}
>
Check for updates
</button>
</div>
</div>
...
...
src/lib/components/layout/Sidebar.svelte
View file @
3c10c3b9
...
...
@@ -13,7 +13,8 @@
getChatList,
getChatById,
getChatListByTagName,
updateChatById
updateChatById,
getAllChatTags
} from '$lib/apis/chats';
import toast from 'svelte-french-toast';
import { slide } from 'svelte/transition';
...
...
@@ -330,7 +331,12 @@
<button
class="px-2.5 text-xs font-medium bg-gray-900 hover:bg-gray-800 transition rounded-full"
on:click={async () => {
await chats.set(await getChatListByTagName(localStorage.token, tag.name));
let chatIds = await getChatListByTagName(localStorage.token, tag.name);
if (chatIds.length === 0) {
await tags.set(await getAllChatTags(localStorage.token));
chatIds = await getChatList(localStorage.token);
}
await chats.set(chatIds);
}}
>
{tag.name}
...
...
src/lib/utils/index.ts
View file @
3c10c3b9
...
...
@@ -101,11 +101,10 @@ export const copyToClipboard = (text) => {
);
};
export
const
checkVersion
=
(
required
,
current
)
=>
{
// Returns true when current version is below required
export
const
compareVersion
=
(
latest
,
current
)
=>
{
return
current
===
'
0.0.0
'
?
false
:
current
.
localeCompare
(
required
,
undefined
,
{
:
current
.
localeCompare
(
latest
,
undefined
,
{
numeric
:
true
,
sensitivity
:
'
case
'
,
caseFirst
:
'
upper
'
...
...
src/routes/(app)/+layout.svelte
View file @
3c10c3b9
...
...
@@ -28,7 +28,7 @@
config
} from '$lib/stores';
import { REQUIRED_OLLAMA_VERSION, WEBUI_API_BASE_URL } from '$lib/constants';
import { c
heck
Version } from '$lib/utils';
import { c
ompare
Version } from '$lib/utils';
import SettingsModal from '$lib/components/chat/SettingsModal.svelte';
import Sidebar from '$lib/components/layout/Sidebar.svelte';
...
...
@@ -79,7 +79,7 @@
ollamaVersion = version;
console.log(ollamaVersion);
if (c
heck
Version(REQUIRED_OLLAMA_VERSION, ollamaVersion)) {
if (c
ompare
Version(REQUIRED_OLLAMA_VERSION, ollamaVersion)) {
toast.error(`Ollama Version: ${ollamaVersion !== '' ? ollamaVersion : 'Not Detected'}`);
}
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment