From 5978e7c9a6bedf8f888cbdec672f017b68fa44e6 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Mon, 23 Sep 2024 01:36:46 +0200 Subject: [PATCH] refac: wip --- src/lib/components/chat/Chat.svelte | 102 +++++----- src/lib/components/chat/Messages.svelte | 186 +++++++++--------- .../components/chat/Messages/Message.svelte | 87 ++++---- .../Messages/MultiResponseMessages.svelte | 4 +- .../chat/Messages/ResponseMessage.svelte | 32 +-- .../chat/Messages/UserMessage.svelte | 35 ++-- src/routes/s/[id]/+page.svelte | 2 +- 7 files changed, 244 insertions(+), 204 deletions(-) diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index f9e23ca2f..25928ddd7 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -1520,8 +1520,8 @@ } }; - const continueGeneration = async () => { - console.log('continueGeneration'); + const continueResponse = async () => { + console.log('continueResponse'); const _chatId = JSON.parse(JSON.stringify($chatId)); if (history.currentId && history.messages[history.currentId].done == true) { @@ -1552,6 +1552,53 @@ } }; + const mergeResponses = async (messageId, responses, _chatId) => { + console.log('mergeResponses', messageId, responses); + const message = history.messages[messageId]; + const mergedResponse = { + status: true, + content: '' + }; + message.merged = mergedResponse; + history.messages[messageId] = message; + + try { + const [res, controller] = await generateMoACompletion( + localStorage.token, + message.model, + history.messages[message.parentId].content, + responses + ); + + if (res && res.ok && res.body) { + const textStream = await createOpenAITextStream(res.body, $settings.splitLargeChunks); + for await (const update of textStream) { + const { value, done, citations, error, usage } = update; + if (error || done) { + break; + } + + if (mergedResponse.content == '' && value == '\n') { + continue; + } else { + mergedResponse.content += value; + history.messages[messageId] = message; + } + + if (autoScroll) { + scrollToBottom(); + } + } + + await saveChatHandler(_chatId); + } else { + console.error(res); + } + } catch (e) { + console.error(e); + } + }; + const generateChatTitle = async (userPrompt) => { if ($settings?.title?.auto ?? true) { const title = await generateTitle( @@ -1684,52 +1731,6 @@ } } }; - const mergeResponses = async (messageId, responses, _chatId) => { - console.log('mergeResponses', messageId, responses); - const message = history.messages[messageId]; - const mergedResponse = { - status: true, - content: '' - }; - message.merged = mergedResponse; - history.messages[messageId] = message; - - try { - const [res, controller] = await generateMoACompletion( - localStorage.token, - message.model, - history.messages[message.parentId].content, - responses - ); - - if (res && res.ok && res.body) { - const textStream = await createOpenAITextStream(res.body, $settings.splitLargeChunks); - for await (const update of textStream) { - const { value, done, citations, error, usage } = update; - if (error || done) { - break; - } - - if (mergedResponse.content == '' && value == '\n') { - continue; - } else { - mergedResponse.content += value; - history.messages[messageId] = message; - } - - if (autoScroll) { - scrollToBottom(); - } - } - - await saveChatHandler(_chatId); - } else { - console.error(res); - } - } catch (e) { - console.error(e); - } - }; @@ -1827,13 +1828,12 @@ bind:autoScroll bind:prompt {selectedModels} - {processing} {sendPrompt} - {continueGeneration} + {showMessage} + {continueResponse} {regenerateResponse} {mergeResponses} {chatActionHandler} - {showMessage} bottomPadding={files.length > 0} /> diff --git a/src/lib/components/chat/Messages.svelte b/src/lib/components/chat/Messages.svelte index 7ea3a3d69..596458578 100644 --- a/src/lib/components/chat/Messages.svelte +++ b/src/lib/components/chat/Messages.svelte @@ -15,7 +15,7 @@ export let chatId = ''; export let readOnly = false; export let sendPrompt: Function; - export let continueGeneration: Function; + export let continueResponse: Function; export let regenerateResponse: Function; export let mergeResponses: Function; export let chatActionHandler: Function; @@ -23,7 +23,6 @@ export let user = $_user; export let prompt; - export let processing = ''; export let bottomPadding = false; export let autoScroll; export let history = {}; @@ -43,7 +42,7 @@ element.scrollTop = element.scrollHeight; }; - const updateChatMessages = async () => { + const updateChatHistory = async () => { await tick(); await updateChatById(localStorage.token, chatId, { history: history @@ -53,87 +52,6 @@ await chats.set(await getChatList(localStorage.token, $currentChatPage)); }; - const confirmEditMessage = async (messageId, content, submit = true) => { - if (submit) { - let userPrompt = content; - let userMessageId = uuidv4(); - - let userMessage = { - id: userMessageId, - parentId: history.messages[messageId].parentId, - childrenIds: [], - role: 'user', - content: userPrompt, - ...(history.messages[messageId].files && { files: history.messages[messageId].files }), - models: selectedModels - }; - - let messageParentId = history.messages[messageId].parentId; - - if (messageParentId !== null) { - history.messages[messageParentId].childrenIds = [ - ...history.messages[messageParentId].childrenIds, - userMessageId - ]; - } - - history.messages[userMessageId] = userMessage; - history.currentId = userMessageId; - - await tick(); - await sendPrompt(userPrompt, userMessageId); - } else { - history.messages[messageId].content = content; - await tick(); - await updateChatById(localStorage.token, chatId, { - history: history - }); - } - }; - - const confirmEditResponseMessage = async (messageId, content) => { - history.messages[messageId].originalContent = history.messages[messageId].content; - history.messages[messageId].content = content; - - await updateChatMessages(); - }; - - const saveNewResponseMessage = async (message, content) => { - const responseMessageId = uuidv4(); - const parentId = message.parentId; - - const responseMessage = { - ...message, - id: responseMessageId, - parentId: parentId, - childrenIds: [], - content: content, - timestamp: Math.floor(Date.now() / 1000) // Unix epoch - }; - - history.messages[responseMessageId] = responseMessage; - history.currentId = responseMessageId; - - // Append messageId to childrenIds of parent message - if (parentId !== null) { - history.messages[parentId].childrenIds = [ - ...history.messages[parentId].childrenIds, - responseMessageId - ]; - } - - await updateChatMessages(); - }; - - const rateMessage = async (messageId, rating) => { - history.messages[messageId].annotation = { - ...history.messages[messageId].annotation, - rating: rating - }; - - await updateChatMessages(); - }; - const showPreviousMessage = async (message) => { if (message.parentId !== null) { let messageId = @@ -232,6 +150,87 @@ } }; + const rateMessage = async (messageId, rating) => { + history.messages[messageId].annotation = { + ...history.messages[messageId].annotation, + rating: rating + }; + + await updateChatHistory(); + }; + + const editMessage = async (messageId, content, submit = true) => { + if (history.messages[messageId].role === 'user') { + if (submit) { + // New user message + let userPrompt = content; + let userMessageId = uuidv4(); + + let userMessage = { + id: userMessageId, + parentId: history.messages[messageId].parentId, + childrenIds: [], + role: 'user', + content: userPrompt, + ...(history.messages[messageId].files && { files: history.messages[messageId].files }), + models: selectedModels + }; + + let messageParentId = history.messages[messageId].parentId; + + if (messageParentId !== null) { + history.messages[messageParentId].childrenIds = [ + ...history.messages[messageParentId].childrenIds, + userMessageId + ]; + } + + history.messages[userMessageId] = userMessage; + history.currentId = userMessageId; + + await tick(); + await sendPrompt(userPrompt, userMessageId); + } else { + // Edit user message + history.messages[messageId].content = content; + await updateChatHistory(); + } + } else { + if (submit) { + // New response message + const responseMessageId = uuidv4(); + const parentId = message.parentId; + + const responseMessage = { + ...message, + id: responseMessageId, + parentId: parentId, + childrenIds: [], + content: content, + timestamp: Math.floor(Date.now() / 1000) // Unix epoch + }; + + history.messages[responseMessageId] = responseMessage; + history.currentId = responseMessageId; + + // Append messageId to childrenIds of parent message + if (parentId !== null) { + history.messages[parentId].childrenIds = [ + ...history.messages[parentId].childrenIds, + responseMessageId + ]; + } + + await updateChatHistory(); + } else { + // Edit response message + history.messages[messageId].originalContent = history.messages[messageId].content; + history.messages[messageId].content = content; + await updateChatHistory(); + } + } + }; + const deleteMessage = async (messageId) => { const messageToDelete = history.messages[messageId]; const parentMessageId = messageToDelete.parentId; @@ -267,9 +266,7 @@ showMessage({ id: parentMessageId }); // Update the chat - await updateChatById(localStorage.token, chatId, { - history: history - }); + await updateChatHistory(); }; @@ -315,8 +312,19 @@ {:else}
{#key chatId} - {JSON.stringify(history)} - + +
+ +
{#if bottomPadding}
diff --git a/src/lib/components/chat/Messages/Message.svelte b/src/lib/components/chat/Messages/Message.svelte index 1629a765e..9a328e0d7 100644 --- a/src/lib/components/chat/Messages/Message.svelte +++ b/src/lib/components/chat/Messages/Message.svelte @@ -10,6 +10,10 @@ import MultiResponseMessages from './MultiResponseMessages.svelte'; import ResponseMessage from './ResponseMessage.svelte'; import UserMessage from './UserMessage.svelte'; + import { updateChatById } from '$lib/apis/chats'; + + // h here refers to the height of the message graph + export let h; export let chatId; @@ -21,19 +25,15 @@ export let scrollToBottom; export let chatActionHandler; - export let confirmEditMessage; - export let confirmEditResponseMessage; - export let showPreviousMessage; export let showNextMessage; - export let rateMessage; + export let editMessage; export let deleteMessage; - - export let saveNewResponseMessage; + export let rateMessage; export let regenerateResponse; - export let continueGeneration; + export let continueResponse; // MultiResponseMessages export let mergeResponses; @@ -48,44 +48,39 @@ }; -
-
- {#if history.messages[messageId].role === 'user'} - {@const message = history.messages[messageId]} +
+ {#if history.messages[messageId]} + {@const message = history.messages[messageId]} + {#if message.role === 'user'} message.parentId === null) .map((message) => message.id) ?? [])} - {confirmEditMessage} {showPreviousMessage} {showNextMessage} - copyToClipboard={copyToClipboardWithToast} - isFirstMessage={messageIdx === 0} + {editMessage} on:delete={() => deleteMessage(message.id)} {readOnly} /> {:else if (history.messages[message.parentId]?.models?.length ?? 1) === 1} { console.log('action', e); @@ -96,6 +91,10 @@ await chatActionHandler(chatId, id, message.model, message.id, event); } }} + on:update={async (e) => { + console.log('update', e); + // call updateChatHistory + }} on:save={async (e) => { console.log('save', e); @@ -111,6 +110,7 @@ }); } }} + {readOnly} /> {:else} { console.log('action', e); if (typeof e.detail === 'string') { @@ -152,5 +150,26 @@ }} /> {/if} -
+ {/if}
+ +{#if history.messages[messageId]?.parentId !== null} + +{/if} diff --git a/src/lib/components/chat/Messages/MultiResponseMessages.svelte b/src/lib/components/chat/Messages/MultiResponseMessages.svelte index c35ab9412..6b116a396 100644 --- a/src/lib/components/chat/Messages/MultiResponseMessages.svelte +++ b/src/lib/components/chat/Messages/MultiResponseMessages.svelte @@ -34,7 +34,7 @@ export let rateMessage: Function; export let copyToClipboard: Function; - export let continueGeneration: Function; + export let continueResponse: Function; export let mergeResponses: Function; export let regenerateResponse: Function; export let saveNewResponseMessage: Function; @@ -193,7 +193,7 @@ {readOnly} {rateMessage} {copyToClipboard} - {continueGeneration} + {continueResponse} regenerateResponse={async (message) => { regenerateResponse(message); await tick(); diff --git a/src/lib/components/chat/Messages/ResponseMessage.svelte b/src/lib/components/chat/Messages/ResponseMessage.svelte index af892bcfa..f0a0660e2 100644 --- a/src/lib/components/chat/Messages/ResponseMessage.svelte +++ b/src/lib/components/chat/Messages/ResponseMessage.svelte @@ -13,6 +13,7 @@ import { synthesizeOpenAISpeech } from '$lib/apis/audio'; import { imageGenerations } from '$lib/apis/images'; import { + copyToClipboard as _copyToClipboard, approximateToHumanReadable, extractParagraphsForAudio, extractSentencesForAudio, @@ -83,16 +84,15 @@ export let readOnly = false; - export let updateChatMessages: Function; - export let confirmEditResponseMessage: Function; export let saveNewResponseMessage: Function = () => {}; export let showPreviousMessage: Function; export let showNextMessage: Function; + + export let editMessage: Function; export let rateMessage: Function; - export let copyToClipboard: Function; - export let continueGeneration: Function; + export let continueResponse: Function; export let regenerateResponse: Function; let model = null; @@ -111,6 +111,13 @@ let showRateComment = false; + const copyToClipboard = async (text) => { + const res = await _copyToClipboard(text); + if (res) { + toast.success($i18n.t('Copying to clipboard was successful!')); + } + }; + const playAudio = (idx: number) => { return new Promise((res) => { speakingIdx = idx; @@ -260,11 +267,7 @@ }; const editMessageConfirmHandler = async () => { - if (editedContent === '') { - editedContent = ' '; - } - - confirmEditResponseMessage(message.id, editedContent); + editMessage(message.id, editedContent ? editedContent : '', false); edit = false; editedContent = ''; @@ -272,8 +275,8 @@ await tick(); }; - const saveNewMessageHandler = async () => { - saveNewResponseMessage(message, editedContent); + const saveAsCopyHandler = async () => { + editMessage(message.id, editedContent ? editedContent : ''); edit = false; editedContent = ''; @@ -424,7 +427,7 @@ id="save-new-message-button" class=" px-4 py-2 bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 border dark:border-gray-700 text-gray-700 dark:text-gray-200 transition rounded-3xl" on:click={() => { - saveNewMessageHandler(); + saveAsCopyHandler(); }} > {$i18n.t('Save As Copy')} @@ -909,7 +912,7 @@ ? 'visible' : 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition regenerate-response-button" on:click={() => { - continueGeneration(); + continueResponse(); (model?.actions ?? []) .filter((action) => action?.__webui__ ?? false) @@ -1028,8 +1031,7 @@ bind:show={showRateComment} bind:message on:submit={(e) => { - updateChatMessages(); - + dispatch('update'); (model?.actions ?? []) .filter((action) => action?.__webui__ ?? false) .forEach((action) => { diff --git a/src/lib/components/chat/Messages/UserMessage.svelte b/src/lib/components/chat/Messages/UserMessage.svelte index 351e3c0da..532f85de2 100644 --- a/src/lib/components/chat/Messages/UserMessage.svelte +++ b/src/lib/components/chat/Messages/UserMessage.svelte @@ -1,18 +1,20 @@