From 4eecdbadd30d4528cd358781b37b953d651da5ce Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Wed, 17 Jul 2024 11:39:37 +0200 Subject: [PATCH] enh: files chat control --- src/lib/components/chat/Chat.svelte | 60 +++---- src/lib/components/chat/ChatControls.svelte | 5 +- .../components/chat/Controls/Controls.svelte | 29 +++- src/lib/components/chat/MessageInput.svelte | 151 ++++-------------- .../chat/Messages/UserMessage.svelte | 102 +----------- src/lib/components/common/FileItem.svelte | 130 +++++++++++++++ 6 files changed, 216 insertions(+), 261 deletions(-) create mode 100644 src/lib/components/common/FileItem.svelte diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 043e18d38..b7b8dedea 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -98,6 +98,8 @@ let title = ''; let prompt = ''; + + let chatFiles = []; let files = []; let messages = []; let history = { @@ -333,6 +335,7 @@ } params = chatContent?.params ?? {}; + chatFiles = chatContent?.files ?? {}; autoScroll = true; await tick(); @@ -408,7 +411,8 @@ models: selectedModels, messages: messages, history: history, - params: params + params: params, + files: chatFiles }); await chats.set(await getChatList(localStorage.token)); } @@ -453,7 +457,8 @@ models: selectedModels, messages: messages, history: history, - params: params + params: params, + files: chatFiles }); await chats.set(await getChatList(localStorage.token)); } @@ -514,6 +519,13 @@ } const _files = JSON.parse(JSON.stringify(files)); + chatFiles.push(..._files.filter((item) => ['doc', 'file', 'collection'].includes(item.type))); + chatFiles = chatFiles.filter( + // Remove duplicates + (item, index, array) => + array.findIndex((i) => JSON.stringify(i) === JSON.stringify(item)) === index + ); + files = []; prompt = ''; @@ -754,25 +766,10 @@ } }); - let files = []; + let files = JSON.parse(JSON.stringify(chatFiles)); if (model?.info?.meta?.knowledge ?? false) { - files = model.info.meta.knowledge; + files.push(...model.info.meta.knowledge); } - const lastUserMessage = messages.filter((message) => message.role === 'user').at(-1); - - files = [ - ...files, - ...(lastUserMessage?.files?.filter((item) => - ['doc', 'file', 'collection', 'web_search_results'].includes(item.type) - ) ?? []), - ...(responseMessage?.files?.filter((item) => - ['doc', 'file', 'collection', 'web_search_results'].includes(item.type) - ) ?? []) - ].filter( - // Remove duplicates - (item, index, array) => - array.findIndex((i) => JSON.stringify(i) === JSON.stringify(item)) === index - ); eventTarget.dispatchEvent( new CustomEvent('chat:start', { @@ -936,7 +933,8 @@ messages: messages, history: history, models: selectedModels, - params: params + params: params, + files: chatFiles }); await chats.set(await getChatList(localStorage.token)); } @@ -1003,24 +1001,10 @@ let _response = null; const responseMessage = history.messages[responseMessageId]; - let files = []; + let files = JSON.parse(JSON.stringify(chatFiles)); if (model?.info?.meta?.knowledge ?? false) { - files = model.info.meta.knowledge; + files.push(...model.info.meta.knowledge); } - const lastUserMessage = messages.filter((message) => message.role === 'user').at(-1); - files = [ - ...files, - ...(lastUserMessage?.files?.filter((item) => - ['doc', 'file', 'collection', 'web_search_results'].includes(item.type) - ) ?? []), - ...(responseMessage?.files?.filter((item) => - ['doc', 'file', 'collection', 'web_search_results'].includes(item.type) - ) ?? []) - ].filter( - // Remove duplicates - (item, index, array) => - array.findIndex((i) => JSON.stringify(i) === JSON.stringify(item)) === index - ); scrollToBottom(); @@ -1214,7 +1198,8 @@ models: selectedModels, messages: messages, history: history, - params: params + params: params, + files: chatFiles }); await chats.set(await getChatList(localStorage.token)); } @@ -1632,6 +1617,7 @@ return a; }, [])} bind:show={showControls} + bind:chatFiles bind:params bind:valves /> diff --git a/src/lib/components/chat/ChatControls.svelte b/src/lib/components/chat/ChatControls.svelte index 72c083e99..f67e6d6ef 100644 --- a/src/lib/components/chat/ChatControls.svelte +++ b/src/lib/components/chat/ChatControls.svelte @@ -9,8 +9,9 @@ export let models = []; export let chatId = null; - export let valves = {}; + export let chatFiles = []; + export let valves = {}; export let params = {}; let largeScreen = false; @@ -48,6 +49,7 @@ show = false; }} {models} + bind:chatFiles bind:valves bind:params /> @@ -63,6 +65,7 @@ show = false; }} {models} + bind:chatFiles bind:valves bind:params /> diff --git a/src/lib/components/chat/Controls/Controls.svelte b/src/lib/components/chat/Controls/Controls.svelte index 3852b2fbf..fe2036286 100644 --- a/src/lib/components/chat/Controls/Controls.svelte +++ b/src/lib/components/chat/Controls/Controls.svelte @@ -6,8 +6,11 @@ import XMark from '$lib/components/icons/XMark.svelte'; import AdvancedParams from '../Settings/Advanced/AdvancedParams.svelte'; import Valves from '$lib/components/common/Valves.svelte'; + import FileItem from '$lib/components/common/FileItem.svelte'; export let models = []; + + export let chatFiles = []; export let valves = {}; export let params = {}; @@ -26,9 +29,33 @@
+ {#if chatFiles.length > 0} +
+
{$i18n.t('Files')}
+ +
+ {#each chatFiles as file} + { + // Remove the file from the chatFiles array + chatFiles = chatFiles.filter((f) => f.id !== file.id); + }} + /> + {/each} +
+
+ +
+ {/if} + {#if models.length === 1 && models[0]?.pipe?.valves_spec}
-
Valves
+
{$i18n.t('Valves')}
diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index 4816d6375..a9bed21a2 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -40,6 +40,7 @@ import Headphone from '../icons/Headphone.svelte'; import VoiceRecording from './MessageInput/VoiceRecording.svelte'; import { transcribeAudio } from '$lib/apis/audio'; + import FileItem from '../common/FileItem.svelte'; const i18n = getContext('i18n'); @@ -502,8 +503,8 @@ {#if files.length > 0}
{#each files as file, fileIdx} -
- {#if file.type === 'image'} + {#if file.type === 'image'} +
{/if}
- {:else if ['doc', 'file'].includes(file.type)} -
-
- {#if file.status === 'processed'} - - - - - {:else} - - {/if} -
- -
-
- {file.name} -
- -
{$i18n.t('Document')}
-
-
- {:else if file.type === 'collection'} -
-
+
+
- -
-
- {file?.title ?? `#${file.name}`} -
- -
{$i18n.t('Collection')}
-
+
- {/if} - -
-
-
+ {:else} + { + files.splice(fileIdx, 1); + files = files; + }} + /> + {/if} {/each}
{/if} diff --git a/src/lib/components/chat/Messages/UserMessage.svelte b/src/lib/components/chat/Messages/UserMessage.svelte index 7ac18e714..5aa06ffe0 100644 --- a/src/lib/components/chat/Messages/UserMessage.svelte +++ b/src/lib/components/chat/Messages/UserMessage.svelte @@ -9,6 +9,7 @@ import { user as _user } from '$lib/stores'; import { getFileContentById } from '$lib/apis/files'; + import FileItem from '$lib/components/common/FileItem.svelte'; const i18n = getContext('i18n'); @@ -99,106 +100,11 @@ {#if file.type === 'image'} input {:else if file.type === 'file'} - + {:else if file.type === 'doc'} - + {:else if file.type === 'collection'} - + {/if}
{/each} diff --git a/src/lib/components/common/FileItem.svelte b/src/lib/components/common/FileItem.svelte new file mode 100644 index 000000000..91f27e417 --- /dev/null +++ b/src/lib/components/common/FileItem.svelte @@ -0,0 +1,130 @@ + + +
+ + + {#if dismissible} +
+ +
+ {/if} +