refac
Some checks are pending
Deploy to HuggingFace Spaces / check-secret (push) Waiting to run
Deploy to HuggingFace Spaces / deploy (push) Blocked by required conditions
Create and publish Docker images with specific build args / build-main-image (linux/amd64) (push) Waiting to run
Create and publish Docker images with specific build args / build-main-image (linux/arm64) (push) Waiting to run
Create and publish Docker images with specific build args / build-cuda-image (linux/amd64) (push) Waiting to run
Create and publish Docker images with specific build args / build-cuda-image (linux/arm64) (push) Waiting to run
Create and publish Docker images with specific build args / build-ollama-image (linux/amd64) (push) Waiting to run
Create and publish Docker images with specific build args / build-ollama-image (linux/arm64) (push) Waiting to run
Create and publish Docker images with specific build args / merge-main-images (push) Blocked by required conditions
Create and publish Docker images with specific build args / merge-cuda-images (push) Blocked by required conditions
Create and publish Docker images with specific build args / merge-ollama-images (push) Blocked by required conditions
Python CI / Format Backend (3.11) (push) Waiting to run
Frontend Build / Format & Build Frontend (push) Waiting to run
Frontend Build / Frontend Unit Tests (push) Waiting to run
Integration Test / Run Cypress Integration Tests (push) Waiting to run
Integration Test / Run Migration Tests (push) Waiting to run

This commit is contained in:
Timothy J. Baek 2024-11-06 02:58:44 -08:00
parent ccbf5a08f3
commit 02269a21a9
6 changed files with 163 additions and 252 deletions

View File

@ -1794,6 +1794,33 @@
console.log('stopResponse');
};
const submitMessage = async (parentId, prompt) => {
let userPrompt = prompt;
let userMessageId = uuidv4();
let userMessage = {
id: userMessageId,
parentId: parentId,
childrenIds: [],
role: 'user',
content: userPrompt,
models: selectedModels
};
if (parentId !== null) {
history.messages[parentId].childrenIds = [
...history.messages[parentId].childrenIds,
userMessageId
];
}
history.messages[userMessageId] = userMessage;
history.currentId = userMessageId;
await tick();
await sendPrompt(userPrompt, userMessageId);
};
const regenerateResponse = async (message) => {
console.log('regenerateResponse');
@ -2204,42 +2231,12 @@
{selectedModels}
{sendPrompt}
{showMessage}
{submitMessage}
{continueResponse}
{regenerateResponse}
{mergeResponses}
{chatActionHandler}
bottomPadding={files.length > 0}
on:submit={async (e) => {
if (e.detail) {
// New user message
let userPrompt = e.detail.prompt;
let userMessageId = uuidv4();
let userMessage = {
id: userMessageId,
parentId: e.detail.parentId,
childrenIds: [],
role: 'user',
content: userPrompt,
models: selectedModels
};
let messageParentId = e.detail.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);
}
}}
/>
</div>
</div>

View File

@ -29,8 +29,10 @@
export let continueResponse: Function;
export let regenerateResponse: Function;
export let mergeResponses: Function;
export let chatActionHandler: Function;
export let showMessage: Function = () => {};
export let submitMessage: Function = () => {};
export let readOnly = false;
@ -79,9 +81,9 @@
element.scrollTop = element.scrollHeight;
};
const updateChatHistory = async () => {
await tick();
const updateChat = async () => {
history = history;
await tick();
await updateChatById(localStorage.token, chatId, {
history: history,
messages: messages
@ -195,7 +197,7 @@
rating: rating
};
await updateChatHistory();
await updateChat();
};
const editMessage = async (messageId, content, submit = true) => {
@ -232,7 +234,7 @@
} else {
// Edit user message
history.messages[messageId].content = content;
await updateChatHistory();
await updateChat();
}
} else {
if (submit) {
@ -261,16 +263,25 @@
];
}
await updateChatHistory();
await updateChat();
} else {
// Edit response message
history.messages[messageId].originalContent = history.messages[messageId].content;
history.messages[messageId].content = content;
await updateChatHistory();
await updateChat();
}
}
};
const actionMessage = async (actionId, event = null) => {
await chatActionHandler(chatId, actionId, message.model, message.id, event);
};
const saveMessage = async (messageId, message) => {
history.messages[messageId] = message;
await updateChat();
};
const deleteMessage = async (messageId) => {
const messageToDelete = history.messages[messageId];
const parentMessageId = messageToDelete.parentId;
@ -306,7 +317,17 @@
showMessage({ id: parentMessageId });
// Update the chat
await updateChatHistory();
await updateChat();
};
const triggerScroll = () => {
if (autoScroll) {
const element = document.getElementById('messages-container');
autoScroll = element.scrollHeight - element.scrollTop <= element.clientHeight + 50;
setTimeout(() => {
scrollToBottom();
}, 100);
}
};
</script>
@ -372,37 +393,18 @@
{user}
{showPreviousMessage}
{showNextMessage}
{updateChat}
{editMessage}
{deleteMessage}
{rateMessage}
{actionMessage}
{saveMessage}
{submitMessage}
{regenerateResponse}
{continueResponse}
{mergeResponses}
{triggerScroll}
{readOnly}
on:submit={async (e) => {
dispatch('submit', e.detail);
}}
on:action={async (e) => {
if (typeof e.detail === 'string') {
await chatActionHandler(chatId, e.detail, message.model, message.id);
} else {
const { id, event } = e.detail;
await chatActionHandler(chatId, id, message.model, message.id, event);
}
}}
on:update={() => {
updateChatHistory();
}}
on:scroll={() => {
if (autoScroll) {
const element = document.getElementById('messages-container');
autoScroll =
element.scrollHeight - element.scrollTop <= element.clientHeight + 50;
setTimeout(() => {
scrollToBottom();
}, 100);
}
}}
/>
{/each}
</div>

View File

@ -22,23 +22,21 @@
export let showPreviousMessage;
export let showNextMessage;
export let updateChat;
export let editMessage;
export let saveMessage;
export let deleteMessage;
export let rateMessage;
export let actionMessage;
export let submitMessage;
export let regenerateResponse;
export let continueResponse;
// MultiResponseMessages
export let mergeResponses;
export let autoScroll = false;
export let triggerScroll;
export let readOnly = false;
onMount(() => {
// console.log('message', idx);
});
</script>
<div
@ -61,7 +59,7 @@
{showPreviousMessage}
{showNextMessage}
{editMessage}
on:delete={() => deleteMessage(messageId)}
{deleteMessage}
{readOnly}
/>
{:else if (history.messages[history.messages[messageId].parentId]?.models?.length ?? 1) === 1}
@ -73,30 +71,14 @@
siblings={history.messages[history.messages[messageId].parentId]?.childrenIds ?? []}
{showPreviousMessage}
{showNextMessage}
{updateChat}
{editMessage}
{saveMessage}
{rateMessage}
{actionMessage}
{submitMessage}
{continueResponse}
{regenerateResponse}
on:submit={async (e) => {
dispatch('submit', e.detail);
}}
on:action={async (e) => {
dispatch('action', e.detail);
}}
on:update={async (e) => {
dispatch('update');
}}
on:save={async (e) => {
console.log('save', e);
const message = e.detail;
if (message) {
history.messages[message.id] = message;
dispatch('update');
} else {
dispatch('update');
}
}}
{readOnly}
/>
{:else}
@ -105,35 +87,16 @@
{chatId}
{messageId}
isLastMessage={messageId === history?.currentId}
{rateMessage}
{updateChat}
{editMessage}
{saveMessage}
{rateMessage}
{actionMessage}
{submitMessage}
{continueResponse}
{regenerateResponse}
{mergeResponses}
on:submit={async (e) => {
dispatch('submit', e.detail);
}}
on:action={async (e) => {
dispatch('action', e.detail);
}}
on:update={async (e) => {
dispatch('update');
}}
on:save={async (e) => {
console.log('save', e);
const message = e.detail;
if (message) {
history.messages[message.id] = message;
dispatch('update');
} else {
dispatch('update');
}
}}
on:change={async () => {
await tick();
dispatch('update');
dispatch('scroll');
}}
{triggerScroll}
{readOnly}
/>
{/if}

View File

@ -25,13 +25,19 @@
export let isLastMessage;
export let readOnly = false;
export let updateChat: Function;
export let editMessage: Function;
export let saveMessage: Function;
export let rateMessage: Function;
export let actionMessage: Function;
export let submitMessage: Function;
export let continueResponse: Function;
export let regenerateResponse: Function;
export let mergeResponses: Function;
export let triggerScroll: Function;
const dispatch = createEventDispatcher();
let currentMessageId;
@ -46,7 +52,7 @@
}
}
const showPreviousMessage = (modelIdx) => {
const showPreviousMessage = async (modelIdx) => {
groupedMessageIdsIdx[modelIdx] = Math.max(0, groupedMessageIdsIdx[modelIdx] - 1);
let messageId = groupedMessageIds[modelIdx].messageIds[groupedMessageIdsIdx[modelIdx]];
@ -60,10 +66,13 @@
}
history.currentId = messageId;
dispatch('change');
await tick();
await updateChat();
triggerScroll();
};
const showNextMessage = (modelIdx) => {
const showNextMessage = async (modelIdx) => {
groupedMessageIdsIdx[modelIdx] = Math.min(
groupedMessageIds[modelIdx].messageIds.length - 1,
groupedMessageIdsIdx[modelIdx] + 1
@ -80,7 +89,10 @@
}
history.currentId = messageId;
dispatch('change');
await tick();
await updateChat();
triggerScroll();
};
const initHandler = async () => {
@ -182,7 +194,7 @@
: `border-gray-50 dark:border-gray-850 border-dashed ${
$mobile ? 'min-w-full' : 'min-w-80'
}`} transition-all p-5 rounded-2xl"
on:click={() => {
on:click={async () => {
if (messageId != _messageId) {
let currentMessageId = _messageId;
let messageChildrenIds = history.messages[currentMessageId].childrenIds;
@ -191,7 +203,10 @@
messageChildrenIds = history.messages[currentMessageId].childrenIds;
}
history.currentId = currentMessageId;
dispatch('change');
await tick();
await updateChat();
triggerScroll();
}
}}
>
@ -205,8 +220,12 @@
siblings={groupedMessageIds[modelIdx].messageIds}
showPreviousMessage={() => showPreviousMessage(modelIdx)}
showNextMessage={() => showNextMessage(modelIdx)}
{rateMessage}
{updateChat}
{editMessage}
{saveMessage}
{rateMessage}
{actionMessage}
{submitMessage}
{continueResponse}
regenerateResponse={async (message) => {
regenerateResponse(message);
@ -214,18 +233,6 @@
groupedMessageIdsIdx[modelIdx] =
groupedMessageIds[modelIdx].messageIds.length - 1;
}}
on:submit={async (e) => {
dispatch('submit', e.detail);
}}
on:action={async (e) => {
dispatch('action', e.detail);
}}
on:update={async (e) => {
dispatch('update', e.detail);
}}
on:save={async (e) => {
dispatch('save', e.detail);
}}
{readOnly}
/>
{/if}

View File

@ -15,9 +15,6 @@
import {
copyToClipboard as _copyToClipboard,
approximateToHumanReadable,
extractParagraphsForAudio,
extractSentencesForAudio,
cleanText,
getMessageContentParts,
sanitizeResponseContent,
createMessagesList
@ -33,7 +30,6 @@
import Spinner from '$lib/components/common/Spinner.svelte';
import WebSearchResults from './ResponseMessage/WebSearchResults.svelte';
import Sparkles from '$lib/components/icons/Sparkles.svelte';
import Markdown from './Markdown.svelte';
import Error from './Error.svelte';
import Citations from './Citations.svelte';
import CodeExecutions from './CodeExecutions.svelte';
@ -112,9 +108,13 @@
export let showPreviousMessage: Function;
export let showNextMessage: Function;
export let updateChat: Function;
export let editMessage: Function;
export let saveMessage: Function;
export let rateMessage: Function;
export let actionMessage: Function;
export let submitMessage: Function;
export let continueResponse: Function;
export let regenerateResponse: Function;
@ -329,7 +329,10 @@
url: `${image.url}`
}));
dispatch('save', { ...message, files: files });
saveMessage(message.id, {
...message,
files: files
});
}
generatingImage = false;
@ -422,7 +425,7 @@
}
console.log(updatedMessage);
dispatch('save', updatedMessage);
saveMessage(message.id, updatedMessage);
await tick();
@ -443,7 +446,7 @@
updatedMessage.annotation.tags = tags;
feedbackItem.data.tags = tags;
dispatch('save', updatedMessage);
saveMessage(message.id, updatedMessage);
await updateFeedbackById(
localStorage.token,
updatedMessage.feedbackId,
@ -631,22 +634,19 @@
message.id
].content.replace(raw, raw.replace(oldContent, newContent));
dispatch('update');
updateChat();
}}
on:select={(e) => {
const { type, content } = e.detail;
if (type === 'explain') {
dispatch('submit', {
parentId: message.id,
prompt: `Explain this section to me in more detail\n\n\`\`\`\n${content}\n\`\`\``
});
submitMessage(
message.id,
`Explain this section to me in more detail\n\n\`\`\`\n${content}\n\`\`\``
);
} else if (type === 'ask') {
const input = e.detail?.input ?? '';
dispatch('submit', {
parentId: message.id,
prompt: `\`\`\`\n${content}\n\`\`\`\n${input}`
});
submitMessage(message.id, `\`\`\`\n${content}\n\`\`\`\n${input}`);
}
}}
/>
@ -1019,21 +1019,6 @@
disabled={feedbackLoading}
on:click={async () => {
await feedbackHandler(1);
(model?.actions ?? [])
.filter((action) => action?.__webui__ ?? false)
.forEach((action) => {
dispatch('action', {
id: action.id,
event: {
id: 'good-response',
data: {
messageId: message.id
}
}
});
});
window.setTimeout(() => {
document
.getElementById(`message-feedback-${message.id}`)
@ -1070,21 +1055,6 @@
disabled={feedbackLoading}
on:click={async () => {
await feedbackHandler(-1);
(model?.actions ?? [])
.filter((action) => action?.__webui__ ?? false)
.forEach((action) => {
dispatch('action', {
id: action.id,
event: {
id: 'bad-response',
data: {
messageId: message.id
}
}
});
});
window.setTimeout(() => {
document
.getElementById(`message-feedback-${message.id}`)
@ -1120,20 +1090,6 @@
: '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={() => {
continueResponse();
(model?.actions ?? [])
.filter((action) => action?.__webui__ ?? false)
.forEach((action) => {
dispatch('action', {
id: action.id,
event: {
id: 'continue-response',
data: {
messageId: message.id
}
}
});
});
}}
>
<svg
@ -1157,50 +1113,52 @@
</svg>
</button>
</Tooltip>
{/if}
<Tooltip content={$i18n.t('Regenerate')} placement="bottom">
<button
type="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"
on:click={() => {
showRateComment = false;
regenerateResponse(message);
<Tooltip content={$i18n.t('Regenerate')} placement="bottom">
<button
type="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"
on:click={() => {
showRateComment = false;
regenerateResponse(message);
(model?.actions ?? [])
.filter((action) => action?.__webui__ ?? false)
.forEach((action) => {
dispatch('action', {
id: action.id,
event: {
id: 'regenerate-response',
data: {
messageId: message.id
}
(model?.actions ?? [])
.filter((action) => action?.__webui__ ?? false)
.forEach((action) => {
dispatch('action', {
id: action.id,
event: {
id: 'regenerate-response',
data: {
messageId: message.id
}
});
}
});
}}
});
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="2.3"
stroke="currentColor"
class="w-4 h-4"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="2.3"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99"
/>
</svg>
</button>
</Tooltip>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99"
/>
</svg>
</button>
</Tooltip>
{#each (model?.actions ?? []).filter((action) => !(action?.__webui__ ?? false)) as action}
{#if isLastMessage}
{#each model?.actions ?? [] as action}
<Tooltip content={action.name} placement="bottom">
<button
type="button"
@ -1208,7 +1166,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={() => {
dispatch('action', action.id);
actionMessage(action.id);
}}
>
{#if action.icon_url}
@ -1242,22 +1200,6 @@
comment: e.detail.comment,
reason: e.detail.reason
});
(model?.actions ?? [])
.filter((action) => action?.__webui__ ?? false)
.forEach((action) => {
dispatch('action', {
id: action.id,
event: {
id: 'rate-comment',
data: {
messageId: message.id,
comment: e.detail.comment,
reason: e.detail.reason
}
}
});
});
}}
/>
{/if}

View File

@ -1,7 +1,7 @@
<script lang="ts">
import dayjs from 'dayjs';
import { toast } from 'svelte-sonner';
import { tick, createEventDispatcher, getContext, onMount } from 'svelte';
import { tick, getContext, onMount } from 'svelte';
import { models, settings } from '$lib/stores';
import { user as _user } from '$lib/stores';
@ -19,7 +19,6 @@
const i18n = getContext('i18n');
const dispatch = createEventDispatcher();
export let user;
export let history;
@ -31,6 +30,7 @@
export let showNextMessage: Function;
export let editMessage: Function;
export let deleteMessage: Function;
export let isFirstMessage: boolean;
export let readOnly: boolean;
@ -78,7 +78,7 @@
};
const deleteMessageHandler = async () => {
dispatch('delete', message.id);
deleteMessage(message.id);
};
onMount(() => {