diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index f3d8241846..9d9bbfbc3a 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -1484,14 +1484,23 @@ saveSessionSelectedModels(); - await sendPrompt(history, userPrompt, userMessageId, { newChat: true }); + await sendMessage(history, userMessageId, { newChat: true }); }; - const sendPrompt = async ( + const sendMessage = async ( _history, - prompt: string, parentId: string, - { modelId = null, modelIdx = null, newChat = false } = {} + { + messages = null, + modelId = null, + modelIdx = null, + newChat = false + }: { + messages?: any[] | null; + modelId?: string | null; + modelIdx?: number | null; + newChat?: boolean; + } = {} ) => { if (autoScroll) { scrollToBottom(); @@ -1561,9 +1570,8 @@ const model = $models.filter((m) => m.id === modelId).at(0); if (model) { - const messages = createMessagesList(_history, parentId); // If there are image files, check if model is vision capable - const hasImages = messages.some((message) => + const hasImages = createMessagesList(_history, parentId).some((message) => message.files?.some((file) => file.type === 'image') ); @@ -1580,7 +1588,15 @@ const chatEventEmitter = await getChatEventEmitter(model.id, _chatId); scrollToBottom(); - await sendPromptSocket(_history, model, responseMessageId, _chatId); + await sendMessageSocket( + model, + messages && messages.length > 0 + ? messages + : createMessagesList(_history, responseMessageId), + _history, + responseMessageId, + _chatId + ); if (chatEventEmitter) clearInterval(chatEventEmitter); } else { @@ -1593,12 +1609,11 @@ chats.set(await getChatList(localStorage.token, $currentChatPage)); }; - const sendPromptSocket = async (_history, model, responseMessageId, _chatId) => { - const chatMessages = createMessagesList(history, history.currentId); + const sendMessageSocket = async (model, _messages, _history, responseMessageId, _chatId) => { const responseMessage = _history.messages[responseMessageId]; const userMessage = _history.messages[responseMessage.parentId]; - const chatMessageFiles = chatMessages + const chatMessageFiles = _messages .filter((message) => message.files) .flatMap((message) => message.files); @@ -1652,7 +1667,7 @@ )}` } : undefined, - ...createMessagesList(_history, responseMessageId).map((message) => ({ + ..._messages.map((message) => ({ ...message, content: processDetails(message.content) })) @@ -1900,31 +1915,39 @@ scrollToBottom(); } - await sendPrompt(history, userPrompt, userMessageId); + await sendMessage(history, userMessageId); }; - const regenerateResponse = async (message) => { + const regenerateResponse = async (message, suggestionPrompt = null) => { console.log('regenerateResponse'); if (history.currentId) { let userMessage = history.messages[message.parentId]; - let userPrompt = userMessage.content; if (autoScroll) { scrollToBottom(); } - if ((userMessage?.models ?? [...selectedModels]).length == 1) { - // If user message has only one model selected, sendPrompt automatically selects it for regeneration - await sendPrompt(history, userPrompt, userMessage.id); - } else { - // If there are multiple models selected, use the model of the response message for regeneration - // e.g. many model chat - await sendPrompt(history, userPrompt, userMessage.id, { - modelId: message.model, - modelIdx: message.modelIdx - }); - } + await sendMessage(history, userMessage.id, { + ...(suggestionPrompt + ? { + messages: [ + ...createMessagesList(history, message.id), + { + role: 'user', + content: suggestionPrompt + } + ] + } + : {}), + ...((userMessage?.models ?? [...selectedModels]).length > 1 + ? { + // If multiple models are selected, use the model from the message + modelId: message.model, + modelIdx: message.modelIdx + } + : {}) + }); } }; @@ -1942,7 +1965,13 @@ .at(0); if (model) { - await sendPromptSocket(history, model, responseMessage.id, _chatId); + await sendMessageSocket( + model, + createMessagesList(history, responseMessage.id), + history, + responseMessage.id, + _chatId + ); } } }; @@ -2171,7 +2200,7 @@ }} {selectedModels} {atSelectedModel} - {sendPrompt} + {sendMessage} {showMessage} {submitMessage} {continueResponse} diff --git a/src/lib/components/chat/Messages.svelte b/src/lib/components/chat/Messages.svelte index eb4c71bf2b..566e32cbbc 100644 --- a/src/lib/components/chat/Messages.svelte +++ b/src/lib/components/chat/Messages.svelte @@ -38,7 +38,7 @@ export let setInputText: Function = () => {}; - export let sendPrompt: Function; + export let sendMessage: Function; export let continueResponse: Function; export let regenerateResponse: Function; export let mergeResponses: Function; @@ -294,7 +294,7 @@ history.currentId = userMessageId; await tick(); - await sendPrompt(history, userPrompt, userMessageId); + await sendMessage(history, userMessageId); } else { // Edit user message history.messages[messageId].content = content; diff --git a/src/lib/components/chat/Messages/MultiResponseMessages.svelte b/src/lib/components/chat/Messages/MultiResponseMessages.svelte index 8197b8747b..e6e190b7c1 100644 --- a/src/lib/components/chat/Messages/MultiResponseMessages.svelte +++ b/src/lib/components/chat/Messages/MultiResponseMessages.svelte @@ -313,8 +313,8 @@ {actionMessage} {submitMessage} {continueResponse} - regenerateResponse={async (message) => { - regenerateResponse(message); + regenerateResponse={async (message, prompt = null) => { + regenerateResponse(message, prompt); await tick(); groupedMessageIdsIdx[selectedModelIdx] = groupedMessageIds[selectedModelIdx].messageIds.length - 1; @@ -368,8 +368,8 @@ {actionMessage} {submitMessage} {continueResponse} - regenerateResponse={async (message) => { - regenerateResponse(message); + regenerateResponse={async (message, prompt = null) => { + regenerateResponse(message, prompt); await tick(); groupedMessageIdsIdx[modelIdx] = groupedMessageIds[modelIdx].messageIds.length - 1; @@ -428,7 +428,7 @@ id="merge-response-button" class="{true ? 'visible' - : 'invisible group-hover:visible'} p-1 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition regenerate-response-button" + : 'invisible group-hover:visible'} p-1 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition" on:click={() => { mergeResponsesHandler(); }} diff --git a/src/lib/components/chat/Messages/ResponseMessage.svelte b/src/lib/components/chat/Messages/ResponseMessage.svelte index 33a36520be..736b12711d 100644 --- a/src/lib/components/chat/Messages/ResponseMessage.svelte +++ b/src/lib/components/chat/Messages/ResponseMessage.svelte @@ -51,6 +51,7 @@ import FollowUps from './ResponseMessage/FollowUps.svelte'; import { fade } from 'svelte/transition'; import { flyAndScale } from '$lib/utils/transitions'; + import RegenerateMenu from './ResponseMessage/RegenerateMenu.svelte'; interface MessageType { id: string; @@ -1316,7 +1317,7 @@ id="continue-response-button" class="{isLastMessage ? '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" + : '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" on:click={() => { continueResponse(); }} @@ -1345,47 +1346,70 @@ {/if} - - - + + + + {#if siblings.length > 1} @@ -1395,7 +1419,7 @@ id="delete-response-button" class="{isLastMessage ? '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" + : '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" on:click={() => { showDeleteConfirm = true; }} diff --git a/src/lib/components/chat/Messages/ResponseMessage/RegenerateMenu.svelte b/src/lib/components/chat/Messages/ResponseMessage/RegenerateMenu.svelte new file mode 100644 index 0000000000..31e7a64952 --- /dev/null +++ b/src/lib/components/chat/Messages/ResponseMessage/RegenerateMenu.svelte @@ -0,0 +1,126 @@ + + + { + if (e.detail === false) { + onClose(); + } + }} + align="end" +> + + +
+ +
+ { + if (e.key === 'Enter') { + onRegenerate(inputValue); + show = false; + } + }} + /> + +
+ +
+
+
+ { + onRegenerate(); + show = false; + }} + > + +
{$i18n.t('Try Again')}
+
+ + { + onRegenerate($i18n.t('Add Details')); + }} + > + +
{$i18n.t('Add Details')}
+
+ + { + onRegenerate($i18n.t('More Concise')); + }} + > + +
{$i18n.t('More Concise')}
+
+
+
+
diff --git a/src/lib/components/icons/LineSpace.svelte b/src/lib/components/icons/LineSpace.svelte new file mode 100644 index 0000000000..c8a62274b6 --- /dev/null +++ b/src/lib/components/icons/LineSpace.svelte @@ -0,0 +1,22 @@ + + + diff --git a/src/lib/components/icons/LineSpaceSmaller.svelte b/src/lib/components/icons/LineSpaceSmaller.svelte new file mode 100644 index 0000000000..b371d22570 --- /dev/null +++ b/src/lib/components/icons/LineSpaceSmaller.svelte @@ -0,0 +1,24 @@ + + + + + + diff --git a/src/lib/components/layout/SearchModal.svelte b/src/lib/components/layout/SearchModal.svelte index 274846bb49..6543746361 100644 --- a/src/lib/components/layout/SearchModal.svelte +++ b/src/lib/components/layout/SearchModal.svelte @@ -352,7 +352,7 @@ bind:history bind:messages autoScroll={true} - sendPrompt={() => {}} + sendMessage={() => {}} continueResponse={() => {}} regenerateResponse={() => {}} /> diff --git a/src/routes/s/[id]/+page.svelte b/src/routes/s/[id]/+page.svelte index 9768638ce7..7d9a8a8a96 100644 --- a/src/routes/s/[id]/+page.svelte +++ b/src/routes/s/[id]/+page.svelte @@ -186,7 +186,7 @@ bind:messages bind:autoScroll bottomPadding={files.length > 0} - sendPrompt={() => {}} + sendMessage={() => {}} continueResponse={() => {}} regenerateResponse={() => {}} />