2023-11-20 01:47:07 +00:00
|
|
|
<script lang="ts">
|
|
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
|
|
|
2024-01-02 00:05:05 +00:00
|
|
|
import { chats, config, modelfiles, settings, user } from '$lib/stores';
|
2023-11-20 01:47:07 +00:00
|
|
|
import { tick } from 'svelte';
|
|
|
|
|
2024-03-01 09:18:07 +00:00
|
|
|
import { toast } from 'svelte-sonner';
|
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';
|
2024-01-07 11:19:34 +00:00
|
|
|
import Spinner from '../common/Spinner.svelte';
|
2024-02-22 02:36:40 +00:00
|
|
|
import { imageGenerations } from '$lib/apis/images';
|
2023-12-30 07:03:48 +00:00
|
|
|
|
2023-12-26 11:28:30 +00:00
|
|
|
export let chatId = '';
|
2023-11-20 01:47:07 +00:00
|
|
|
export let sendPrompt: Function;
|
2024-02-15 09:23:02 +00:00
|
|
|
export let continueGeneration: Function;
|
2023-11-20 01:47:07 +00:00
|
|
|
export let regenerateResponse: Function;
|
|
|
|
|
2024-01-07 11:19:34 +00:00
|
|
|
export let processing = '';
|
2023-12-14 00:21:50 +00:00
|
|
|
export let bottomPadding = false;
|
2023-11-20 01:47:07 +00:00
|
|
|
export let autoScroll;
|
2023-12-03 19:54:11 +00:00
|
|
|
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();
|
2024-02-16 00:20:46 +00:00
|
|
|
scrollToBottom();
|
2023-12-14 00:21:50 +00:00
|
|
|
})();
|
|
|
|
}
|
|
|
|
|
2024-02-16 00:20:46 +00:00
|
|
|
const scrollToBottom = () => {
|
|
|
|
const element = document.getElementById('messages-container');
|
|
|
|
element.scrollTop = element.scrollHeight;
|
|
|
|
};
|
|
|
|
|
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();
|
|
|
|
|
2024-02-16 00:20:46 +00:00
|
|
|
const element = document.getElementById('messages-container');
|
2024-02-16 04:10:48 +00:00
|
|
|
autoScroll = element.scrollHeight - element.scrollTop <= element.clientHeight + 50;
|
2023-11-20 01:47:07 +00:00
|
|
|
|
|
|
|
setTimeout(() => {
|
2024-02-16 00:20:46 +00:00
|
|
|
scrollToBottom();
|
2023-11-20 01:47:07 +00:00
|
|
|
}, 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();
|
|
|
|
|
2024-02-16 00:20:46 +00:00
|
|
|
const element = document.getElementById('messages-container');
|
2024-02-16 04:10:48 +00:00
|
|
|
autoScroll = element.scrollHeight - element.scrollTop <= element.clientHeight + 50;
|
2024-02-16 00:20:46 +00:00
|
|
|
|
2023-11-20 01:47:07 +00:00
|
|
|
setTimeout(() => {
|
2024-02-16 00:20:46 +00:00
|
|
|
scrollToBottom();
|
2023-11-20 01:47:07 +00:00
|
|
|
}, 100);
|
|
|
|
};
|
2024-02-20 23:12:06 +00:00
|
|
|
|
2024-02-23 01:53:58 +00:00
|
|
|
const messageDeleteHandler = async (messageId) => {
|
2024-03-03 07:23:49 +00:00
|
|
|
const messageParentId = history.messages[messageId]?.parentId;
|
2024-02-20 23:12:06 +00:00
|
|
|
|
2024-03-03 07:23:49 +00:00
|
|
|
if (messageParentId !== null) {
|
|
|
|
history.messages[messageParentId].childrenIds = []
|
2024-02-21 00:35:44 +00:00
|
|
|
}
|
2024-03-03 07:23:49 +00:00
|
|
|
|
|
|
|
history.currentId = messageParentId;
|
|
|
|
|
|
|
|
await tick();
|
|
|
|
|
|
|
|
await updateChatById(localStorage.token, chatId, {
|
|
|
|
messages: messages,
|
|
|
|
history: history
|
|
|
|
});
|
2024-02-20 21:24:22 +00:00
|
|
|
};
|
2023-11-20 01:47:07 +00:00
|
|
|
</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-02-16 00:20:46 +00:00
|
|
|
<div class=" pb-10">
|
|
|
|
{#key chatId}
|
|
|
|
{#each messages as message, messageIdx}
|
2024-03-03 07:23:49 +00:00
|
|
|
<div class=" w-full">
|
|
|
|
<div
|
|
|
|
class="flex flex-col justify-between px-5 mb-3 {$settings?.fullScreenMode ?? null
|
|
|
|
? 'max-w-full'
|
|
|
|
: 'max-w-3xl'} mx-auto rounded-lg group"
|
|
|
|
>
|
|
|
|
{#if message.role === 'user'}
|
|
|
|
<UserMessage
|
|
|
|
on:delete={() => messageDeleteHandler(message.id)}
|
|
|
|
user={$user}
|
|
|
|
{message}
|
|
|
|
isFirstMessage={messageIdx === 0}
|
|
|
|
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}
|
|
|
|
{continueGeneration}
|
|
|
|
{regenerateResponse}
|
|
|
|
on:save={async (e) => {
|
|
|
|
console.log('save', e);
|
|
|
|
|
|
|
|
const message = e.detail;
|
|
|
|
history.messages[message.id] = message;
|
|
|
|
await updateChatById(localStorage.token, chatId, {
|
|
|
|
messages: messages,
|
|
|
|
history: history
|
|
|
|
});
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
{/if}
|
2024-02-16 00:20:46 +00:00
|
|
|
</div>
|
2024-03-03 07:23:49 +00:00
|
|
|
</div>
|
2024-02-16 00:20:46 +00:00
|
|
|
{/each}
|
2023-12-14 00:21:50 +00:00
|
|
|
|
2024-02-16 00:20:46 +00:00
|
|
|
{#if bottomPadding}
|
|
|
|
<div class=" mb-10" />
|
|
|
|
{/if}
|
|
|
|
{/key}
|
|
|
|
</div>
|
2023-11-20 01:47:07 +00:00
|
|
|
{/if}
|