From 5a6ece9513be3e5a92b52ca70b9088cc9b8e844d Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Thu, 15 Aug 2024 00:08:15 +0200 Subject: [PATCH 01/10] refac: enhanced response content sanitisation '<' and '>' can be correctly displayed now --- package-lock.json | 7 +-- package.json | 1 + .../components/chat/Messages/CodeBlock.svelte | 2 +- .../chat/Messages/MarkdownInlineTokens.svelte | 8 ++- .../chat/Messages/MarkdownTokens.svelte | 8 ++- .../chat/Messages/ResponseMessage.svelte | 5 +- src/lib/utils/index.ts | 51 +++++++------------ 7 files changed, 39 insertions(+), 43 deletions(-) diff --git a/package-lock.json b/package-lock.json index 52c5f89335..aa813a4dbb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "codemirror": "^6.0.1", "crc-32": "^1.2.2", "dayjs": "^1.11.10", + "dompurify": "^3.1.6", "eventsource-parser": "^1.1.2", "file-saver": "^2.0.5", "fuse.js": "^7.0.0", @@ -3918,9 +3919,9 @@ } }, "node_modules/dompurify": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.5.tgz", - "integrity": "sha512-lwG+n5h8QNpxtyrJW/gJWckL+1/DQiYMX8f7t8Z2AZTPw1esVrqjI63i7Zc2Gz0aKzLVMYC1V1PL/ky+aY/NgA==" + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz", + "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==" }, "node_modules/domutils": { "version": "3.1.0", diff --git a/package.json b/package.json index 2d32422d1b..fef2cbaef6 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "codemirror": "^6.0.1", "crc-32": "^1.2.2", "dayjs": "^1.11.10", + "dompurify": "^3.1.6", "eventsource-parser": "^1.1.2", "file-saver": "^2.0.5", "fuse.js": "^7.0.0", diff --git a/src/lib/components/chat/Messages/CodeBlock.svelte b/src/lib/components/chat/Messages/CodeBlock.svelte index bb10af4096..f368c84591 100644 --- a/src/lib/components/chat/Messages/CodeBlock.svelte +++ b/src/lib/components/chat/Messages/CodeBlock.svelte @@ -261,7 +261,7 @@ __builtins__.input = input`);
-
{@html lang}
+
{lang}
{#if lang.toLowerCase() === 'python' || lang.toLowerCase() === 'py' || (lang === '' && checkPythonCode(code))} diff --git a/src/lib/components/chat/Messages/MarkdownInlineTokens.svelte b/src/lib/components/chat/Messages/MarkdownInlineTokens.svelte index 4567cf5079..8ca6fa37d6 100644 --- a/src/lib/components/chat/Messages/MarkdownInlineTokens.svelte +++ b/src/lib/components/chat/Messages/MarkdownInlineTokens.svelte @@ -1,4 +1,5 @@ @@ -234,84 +265,98 @@
- {#if func?.meta?.manifest?.funding_url ?? false} - + {#if shiftKey} + + + + {:else} + {#if func?.meta?.manifest?.funding_url ?? false} + + + + {/if} + + - {/if} - - - - - { - goto(`/workspace/functions/edit?id=${encodeURIComponent(func.id)}`); - }} - shareHandler={() => { - shareHandler(func); - }} - cloneHandler={() => { - cloneHandler(func); - }} - exportHandler={() => { - exportHandler(func); - }} - deleteHandler={async () => { - selectedFunction = func; - showDeleteConfirm = true; - }} - toggleGlobalHandler={() => { - if (['filter', 'action'].includes(func.type)) { - toggleGlobalHandler(func); - } - }} - onClose={() => {}} - > - - + + + + {/if}
diff --git a/src/lib/components/workspace/Tools.svelte b/src/lib/components/workspace/Tools.svelte index 8ea5ec582e..fbbaa8878f 100644 --- a/src/lib/components/workspace/Tools.svelte +++ b/src/lib/components/workspace/Tools.svelte @@ -24,9 +24,12 @@ import ManifestModal from './common/ManifestModal.svelte'; import Heart from '../icons/Heart.svelte'; import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte'; + import GarbageBin from '../icons/GarbageBin.svelte'; const i18n = getContext('i18n'); + let shiftKey = false; + let toolsImportInputElement: HTMLInputElement; let importFiles; @@ -107,6 +110,34 @@ tools.set(await getTools(localStorage.token)); } }; + + onMount(() => { + const onKeyDown = (event) => { + if (event.key === 'Shift') { + shiftKey = true; + } + }; + + const onKeyUp = (event) => { + if (event.key === 'Shift') { + shiftKey = false; + } + }; + + const onBlur = () => { + shiftKey = false; + }; + + window.addEventListener('keydown', onKeyDown); + window.addEventListener('keyup', onKeyUp); + window.addEventListener('blur', onBlur); + + return () => { + window.removeEventListener('keydown', onKeyDown); + window.removeEventListener('keyup', onKeyUp); + window.removeEventListener('blur', onBlur); + }; + }); @@ -206,78 +237,92 @@
- {#if tool?.meta?.manifest?.funding_url ?? false} - + {#if shiftKey} + + + + {:else} + {#if tool?.meta?.manifest?.funding_url ?? false} + + + + {/if} + + - {/if} - - - - - { - goto(`/workspace/tools/edit?id=${encodeURIComponent(tool.id)}`); - }} - shareHandler={() => { - shareHandler(tool); - }} - cloneHandler={() => { - cloneHandler(tool); - }} - exportHandler={() => { - exportHandler(tool); - }} - deleteHandler={async () => { - selectedTool = tool; - showDeleteConfirm = true; - }} - onClose={() => {}} - > - - + + + + {/if}
{/each} From afe1f13c5b45219582f695513d344b1c10204432 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 15 Aug 2024 00:42:36 +0200 Subject: [PATCH 03/10] Make PWA icon maskable --- backend/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/main.py b/backend/main.py index d8ce5f5d78..0201b43324 100644 --- a/backend/main.py +++ b/backend/main.py @@ -2264,7 +2264,7 @@ async def get_manifest_json(): "display": "standalone", "background_color": "#343541", "orientation": "portrait-primary", - "icons": [{"src": "/static/logo.png", "type": "image/png", "sizes": "500x500"}], + "icons": [{"src": "/static/logo.png", "type": "image/png", "sizes": "500x500", "purpose": "any maskable"}], } From f73a60d96c0018d9cb57e3e2382ca52a5316eb71 Mon Sep 17 00:00:00 2001 From: Juraj Onuska Date: Thu, 15 Aug 2024 13:15:12 +0200 Subject: [PATCH 04/10] fix: set content-type header in ollama backend --- backend/apps/ollama/main.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/backend/apps/ollama/main.py b/backend/apps/ollama/main.py index 03a8e198ee..810a05999e 100644 --- a/backend/apps/ollama/main.py +++ b/backend/apps/ollama/main.py @@ -147,13 +147,17 @@ async def cleanup_response( await session.close() -async def post_streaming_url(url: str, payload: str, stream: bool = True): +async def post_streaming_url(url: str, payload: Union[str, bytes], stream: bool = True): r = None try: session = aiohttp.ClientSession( trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT) ) - r = await session.post(url, data=payload) + r = await session.post( + url, + data=payload, + headers={"Content-Type": "application/json"}, + ) r.raise_for_status() if stream: @@ -422,6 +426,7 @@ async def copy_model( r = requests.request( method="POST", url=f"{url}/api/copy", + headers={"Content-Type": "application/json"}, data=form_data.model_dump_json(exclude_none=True).encode(), ) @@ -470,6 +475,7 @@ async def delete_model( r = requests.request( method="DELETE", url=f"{url}/api/delete", + headers={"Content-Type": "application/json"}, data=form_data.model_dump_json(exclude_none=True).encode(), ) try: @@ -510,6 +516,7 @@ async def show_model_info(form_data: ModelNameForm, user=Depends(get_verified_us r = requests.request( method="POST", url=f"{url}/api/show", + headers={"Content-Type": "application/json"}, data=form_data.model_dump_json(exclude_none=True).encode(), ) try: @@ -567,6 +574,7 @@ async def generate_embeddings( r = requests.request( method="POST", url=f"{url}/api/embeddings", + headers={"Content-Type": "application/json"}, data=form_data.model_dump_json(exclude_none=True).encode(), ) try: @@ -616,6 +624,7 @@ def generate_ollama_embeddings( r = requests.request( method="POST", url=f"{url}/api/embeddings", + headers={"Content-Type": "application/json"}, data=form_data.model_dump_json(exclude_none=True).encode(), ) try: From ba370438b2b3743be9240958fb400b2244651dfd Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Thu, 15 Aug 2024 13:24:47 +0200 Subject: [PATCH 05/10] refac: "any maskable" is discouraged --- backend/main.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/backend/main.py b/backend/main.py index 0201b43324..c7bdb62842 100644 --- a/backend/main.py +++ b/backend/main.py @@ -2264,7 +2264,20 @@ async def get_manifest_json(): "display": "standalone", "background_color": "#343541", "orientation": "portrait-primary", - "icons": [{"src": "/static/logo.png", "type": "image/png", "sizes": "500x500", "purpose": "any maskable"}], + "icons": [ + { + "src": "/static/logo.png", + "type": "image/png", + "sizes": "500x500", + "purpose": "any", + }, + { + "src": "/static/logo.png", + "type": "image/png", + "sizes": "500x500", + "purpose": "maskable", + }, + ], } From dbd5b4c9f19c999d42e23cd239f3c1b1dc663ae6 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Thu, 15 Aug 2024 15:41:02 +0200 Subject: [PATCH 06/10] enh: render markdown user message --- .../chat/Messages/UserMessage.svelte | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/lib/components/chat/Messages/UserMessage.svelte b/src/lib/components/chat/Messages/UserMessage.svelte index 1dea97f11a..59f9af4c9c 100644 --- a/src/lib/components/chat/Messages/UserMessage.svelte +++ b/src/lib/components/chat/Messages/UserMessage.svelte @@ -10,6 +10,9 @@ import { user as _user } from '$lib/stores'; import { getFileContentById } from '$lib/apis/files'; import FileItem from '$lib/components/common/FileItem.svelte'; + import { marked } from 'marked'; + import { processResponseContent, replaceTokens } from '$lib/utils'; + import MarkdownTokens from './MarkdownTokens.svelte'; const i18n = getContext('i18n'); @@ -91,7 +94,7 @@ {/if}
{#if message.files}
@@ -162,15 +165,24 @@
{:else}
-
+
-
{message.content}
+ {#if message.content} +
+ {#key message.id} + + {/key} +
+ {/if}
From 439cb66672aac1490a8e16ed5a99159dddcefd85 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Thu, 15 Aug 2024 15:44:38 +0200 Subject: [PATCH 07/10] refac: fuzzy search threshold --- src/lib/components/chat/ModelSelector/Selector.svelte | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/components/chat/ModelSelector/Selector.svelte b/src/lib/components/chat/ModelSelector/Selector.svelte index 3471d344a3..b710bce252 100644 --- a/src/lib/components/chat/ModelSelector/Selector.svelte +++ b/src/lib/components/chat/ModelSelector/Selector.svelte @@ -59,7 +59,8 @@ return _item; }), { - keys: ['value', 'label', 'tags', 'desc', 'modelName'] + keys: ['value', 'tags', 'modelName'], + threshold: 0.3 } ); From dc6ca61548927924ddbe82ce8dbf4fac41c5d7cb Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Thu, 15 Aug 2024 16:54:16 +0200 Subject: [PATCH 08/10] enh: temp chat deprecates chat history setting and introduces temp chat from model selector --- src/lib/components/chat/Chat.svelte | 17 +- .../chat/Messages/Placeholder.svelte | 15 +- src/lib/components/chat/ModelSelector.svelte | 1 + .../chat/ModelSelector/Selector.svelte | 30 +- src/lib/components/chat/Settings/Chats.svelte | 74 +---- .../documents/Settings/ChunkParams.svelte | 126 -------- .../documents/Settings/QueryParams.svelte | 119 -------- .../documents/Settings/WebParams.svelte | 285 ------------------ .../components/documents/SettingsModal.svelte | 187 ------------ .../components/icons/ChatBubbleOval.svelte | 19 ++ src/lib/components/icons/EyeSlash.svelte | 19 ++ src/lib/components/layout/Sidebar.svelte | 48 +-- src/lib/stores/index.ts | 2 +- 13 files changed, 99 insertions(+), 843 deletions(-) delete mode 100644 src/lib/components/documents/Settings/ChunkParams.svelte delete mode 100644 src/lib/components/documents/Settings/QueryParams.svelte delete mode 100644 src/lib/components/documents/Settings/WebParams.svelte delete mode 100644 src/lib/components/documents/SettingsModal.svelte create mode 100644 src/lib/components/icons/ChatBubbleOval.svelte create mode 100644 src/lib/components/icons/EyeSlash.svelte diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 64b51be96c..b81315ced5 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -26,7 +26,8 @@ socket, showCallOverlay, tools, - currentChatPage + currentChatPage, + temporaryChatEnabled } from '$lib/stores'; import { convertMessagesToHistory, @@ -238,7 +239,7 @@ } }); } else { - if (!($settings.saveChatHistory ?? true)) { + if ($temporaryChatEnabled) { await goto('/'); } } @@ -414,7 +415,7 @@ } if ($chatId == chatId) { - if ($settings.saveChatHistory ?? true) { + if (!$temporaryChatEnabled) { chat = await updateChatById(localStorage.token, chatId, { models: selectedModels, messages: messages, @@ -462,7 +463,7 @@ } if ($chatId == chatId) { - if ($settings.saveChatHistory ?? true) { + if (!$temporaryChatEnabled) { chat = await updateChatById(localStorage.token, chatId, { models: selectedModels, messages: messages, @@ -620,7 +621,7 @@ // Create new chat if only one message in messages if (newChat && messages.length == 2) { - if ($settings.saveChatHistory ?? true) { + if (!$temporaryChatEnabled) { chat = await createNewChat(localStorage.token, { id: $chatId, title: $i18n.t('New Chat'), @@ -954,7 +955,7 @@ } if ($chatId == _chatId) { - if ($settings.saveChatHistory ?? true) { + if (!$temporaryChatEnabled) { chat = await updateChatById(localStorage.token, _chatId, { messages: messages, history: history, @@ -1227,7 +1228,7 @@ } if ($chatId == _chatId) { - if ($settings.saveChatHistory ?? true) { + if (!$temporaryChatEnabled) { chat = await updateChatById(localStorage.token, _chatId, { models: selectedModels, messages: messages, @@ -1400,7 +1401,7 @@ title = _title; } - if ($settings.saveChatHistory ?? true) { + if (!$temporaryChatEnabled) { chat = await updateChatById(localStorage.token, _chatId, { title: _title }); currentChatPage.set(1); diff --git a/src/lib/components/chat/Messages/Placeholder.svelte b/src/lib/components/chat/Messages/Placeholder.svelte index 34038a6083..6b4c41744a 100644 --- a/src/lib/components/chat/Messages/Placeholder.svelte +++ b/src/lib/components/chat/Messages/Placeholder.svelte @@ -2,7 +2,7 @@ import { WEBUI_BASE_URL } from '$lib/constants'; import { marked } from 'marked'; - import { config, user, models as _models } from '$lib/stores'; + import { config, user, models as _models, temporaryChatEnabled } from '$lib/stores'; import { onMount, getContext } from 'svelte'; import { blur, fade } from 'svelte/transition'; @@ -10,6 +10,7 @@ import Suggestions from '../MessageInput/Suggestions.svelte'; import { sanitizeResponseContent } from '$lib/utils'; import Tooltip from '$lib/components/common/Tooltip.svelte'; + import EyeSlash from '$lib/components/icons/EyeSlash.svelte'; const i18n = getContext('i18n'); @@ -64,6 +65,18 @@
+ {#if $temporaryChatEnabled} + +
+ Temporary Chat +
+
+ {/if} +
diff --git a/src/lib/components/chat/ModelSelector.svelte b/src/lib/components/chat/ModelSelector.svelte index c045d138e5..eb4be9d81e 100644 --- a/src/lib/components/chat/ModelSelector.svelte +++ b/src/lib/components/chat/ModelSelector.svelte @@ -46,6 +46,7 @@ label: model.name, model: model }))} + showTemporaryChatControl={true} bind:value={selectedModel} />
diff --git a/src/lib/components/chat/ModelSelector/Selector.svelte b/src/lib/components/chat/ModelSelector/Selector.svelte index b710bce252..5b312848ce 100644 --- a/src/lib/components/chat/ModelSelector/Selector.svelte +++ b/src/lib/components/chat/ModelSelector/Selector.svelte @@ -12,12 +12,14 @@ import { deleteModel, getOllamaVersion, pullModel } from '$lib/apis/ollama'; - import { user, MODEL_DOWNLOAD_POOL, models, mobile } from '$lib/stores'; + import { user, MODEL_DOWNLOAD_POOL, models, mobile, temporaryChatEnabled } from '$lib/stores'; import { toast } from 'svelte-sonner'; import { capitalizeFirstLetter, sanitizeResponseContent, splitStream } from '$lib/utils'; import { getModels } from '$lib/apis'; import Tooltip from '$lib/components/common/Tooltip.svelte'; + import Switch from '$lib/components/common/Switch.svelte'; + import ChatBubbleOval from '$lib/components/icons/ChatBubbleOval.svelte'; const i18n = getContext('i18n'); const dispatch = createEventDispatcher(); @@ -27,6 +29,8 @@ export let searchEnabled = true; export let searchPlaceholder = $i18n.t('Search a model'); + export let showTemporaryChatControl = false; + export let items: { label: string; value: string; @@ -514,6 +518,30 @@ {/each}
+ {#if showTemporaryChatControl} +
+ +
+ +
+ {/if} +