open-webui/src/lib/components/chat/Messages.svelte

259 lines
7.1 KiB
Svelte
Raw Normal View History

2023-11-20 01:47:07 +00:00
<script lang="ts">
import { v4 as uuidv4 } from 'uuid';
2023-12-26 20:50:52 +00:00
import { chats, config, db, modelfiles, settings, user } from '$lib/stores';
2023-11-20 01:47:07 +00:00
import { tick } from 'svelte';
import toast from 'svelte-french-toast';
2023-12-26 20:50:52 +00:00
import { getChatList, updateChatById } from '$lib/apis/chats';
2023-11-20 01:47:07 +00:00
2023-12-30 07:03:48 +00:00
import UserMessage from './Messages/UserMessage.svelte';
import ResponseMessage from './Messages/ResponseMessage.svelte';
import Placeholder from './Messages/Placeholder.svelte';
2023-12-26 11:28:30 +00:00
export let chatId = '';
2023-11-20 01:47:07 +00:00
export let sendPrompt: Function;
export let regenerateResponse: Function;
2023-12-14 00:21:50 +00:00
export let bottomPadding = false;
2023-11-20 01:47:07 +00:00
export let autoScroll;
export let selectedModels;
2023-11-20 01:47:07 +00:00
export let history = {};
export let messages = [];
2023-12-30 07:03:48 +00:00
export let selectedModelfiles = [];
2023-11-20 01:47:07 +00:00
2023-12-14 00:21:50 +00:00
$: if (autoScroll && bottomPadding) {
(async () => {
await tick();
window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
})();
}
2023-11-20 01:47:07 +00:00
const copyToClipboard = (text) => {
if (!navigator.clipboard) {
var textArea = document.createElement('textarea');
textArea.value = text;
// Avoid scrolling to bottom
textArea.style.top = '0';
textArea.style.left = '0';
textArea.style.position = 'fixed';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
console.log('Fallback: Copying text command was ' + msg);
} catch (err) {
console.error('Fallback: Oops, unable to copy', err);
}
document.body.removeChild(textArea);
return;
}
navigator.clipboard.writeText(text).then(
function () {
console.log('Async: Copying to clipboard was successful!');
toast.success('Copying to clipboard was successful!');
},
function (err) {
console.error('Async: Could not copy text: ', err);
}
);
};
2023-12-30 07:03:48 +00:00
const confirmEditMessage = async (messageId, content) => {
let userPrompt = content;
2023-11-20 01:47:07 +00:00
let userMessageId = uuidv4();
let userMessage = {
id: userMessageId,
parentId: history.messages[messageId].parentId,
childrenIds: [],
role: 'user',
2023-12-14 00:21:50 +00:00
content: userPrompt,
...(history.messages[messageId].files && { files: history.messages[messageId].files })
2023-11-20 01:47:07 +00:00
};
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();
2023-12-26 11:28:30 +00:00
await sendPrompt(userPrompt, userMessageId, chatId);
2023-11-20 01:47:07 +00:00
};
2023-12-30 07:03:48 +00:00
const confirmEditResponseMessage = async (messageId, content) => {
2023-12-30 07:25:40 +00:00
history.messages[messageId].originalContent = history.messages[messageId].content;
2023-12-30 07:03:48 +00:00
history.messages[messageId].content = content;
2023-12-30 07:25:40 +00:00
await tick();
await updateChatById(localStorage.token, chatId, {
messages: messages,
history: history
});
await chats.set(await getChatList(localStorage.token));
2023-12-11 06:47:16 +00:00
};
2023-12-30 07:03:48 +00:00
const rateMessage = async (messageId, rating) => {
history.messages[messageId].rating = rating;
await tick();
2023-12-26 20:50:52 +00:00
await updateChatById(localStorage.token, chatId, {
2023-11-20 01:47:07 +00:00
messages: messages,
history: history
});
2023-12-26 20:50:52 +00:00
await chats.set(await getChatList(localStorage.token));
2023-11-20 01:47:07 +00:00
};
const showPreviousMessage = async (message) => {
if (message.parentId !== null) {
let messageId =
history.messages[message.parentId].childrenIds[
Math.max(history.messages[message.parentId].childrenIds.indexOf(message.id) - 1, 0)
];
if (message.id !== messageId) {
let messageChildrenIds = history.messages[messageId].childrenIds;
while (messageChildrenIds.length !== 0) {
messageId = messageChildrenIds.at(-1);
messageChildrenIds = history.messages[messageId].childrenIds;
}
history.currentId = messageId;
}
} else {
let childrenIds = Object.values(history.messages)
.filter((message) => message.parentId === null)
.map((message) => message.id);
let messageId = childrenIds[Math.max(childrenIds.indexOf(message.id) - 1, 0)];
if (message.id !== messageId) {
let messageChildrenIds = history.messages[messageId].childrenIds;
while (messageChildrenIds.length !== 0) {
messageId = messageChildrenIds.at(-1);
messageChildrenIds = history.messages[messageId].childrenIds;
}
history.currentId = messageId;
}
}
await tick();
autoScroll = window.innerHeight + window.scrollY >= document.body.offsetHeight - 40;
setTimeout(() => {
window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
}, 100);
};
const showNextMessage = async (message) => {
if (message.parentId !== null) {
let messageId =
history.messages[message.parentId].childrenIds[
Math.min(
history.messages[message.parentId].childrenIds.indexOf(message.id) + 1,
history.messages[message.parentId].childrenIds.length - 1
)
];
if (message.id !== messageId) {
let messageChildrenIds = history.messages[messageId].childrenIds;
while (messageChildrenIds.length !== 0) {
messageId = messageChildrenIds.at(-1);
messageChildrenIds = history.messages[messageId].childrenIds;
}
history.currentId = messageId;
}
} else {
let childrenIds = Object.values(history.messages)
.filter((message) => message.parentId === null)
.map((message) => message.id);
let messageId =
childrenIds[Math.min(childrenIds.indexOf(message.id) + 1, childrenIds.length - 1)];
if (message.id !== messageId) {
let messageChildrenIds = history.messages[messageId].childrenIds;
while (messageChildrenIds.length !== 0) {
messageId = messageChildrenIds.at(-1);
messageChildrenIds = history.messages[messageId].childrenIds;
}
history.currentId = messageId;
}
}
await tick();
autoScroll = window.innerHeight + window.scrollY >= document.body.offsetHeight - 40;
setTimeout(() => {
window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
}, 100);
};
</script>
{#if messages.length == 0}
2023-12-30 07:03:48 +00:00
<Placeholder models={selectedModels} modelfiles={selectedModelfiles} />
2023-11-20 01:47:07 +00:00
{:else}
2024-01-01 21:01:42 +00:00
{#key chatId}
{#each messages as message, messageIdx}
<div class=" w-full">
<div class="flex justify-between px-5 mb-3 max-w-3xl mx-auto rounded-lg group">
{#if message.role === 'user'}
<UserMessage
user={$user}
{message}
siblings={message.parentId !== null
? history.messages[message.parentId]?.childrenIds ?? []
: Object.values(history.messages)
.filter((message) => message.parentId === null)
.map((message) => message.id) ?? []}
{confirmEditMessage}
{showPreviousMessage}
{showNextMessage}
{copyToClipboard}
/>
{:else}
<ResponseMessage
{message}
modelfiles={selectedModelfiles}
siblings={history.messages[message.parentId]?.childrenIds ?? []}
isLastMessage={messageIdx + 1 === messages.length}
{confirmEditResponseMessage}
{showPreviousMessage}
{showNextMessage}
{rateMessage}
{copyToClipboard}
{regenerateResponse}
/>
{/if}
</div>
2023-11-20 01:47:07 +00:00
</div>
2024-01-01 21:01:42 +00:00
{/each}
2023-12-14 00:21:50 +00:00
2024-01-01 21:01:42 +00:00
{#if bottomPadding}
<div class=" mb-10" />
{/if}
{/key}
2023-11-20 01:47:07 +00:00
{/if}