Spaces:
Runtime error
Runtime error
File size: 2,530 Bytes
502cb81 0ce274f 1778c9e 0ce274f b2170a7 b1426d3 f48efbb 502cb81 5851d63 1778c9e 5851d63 1778c9e 5851d63 502cb81 1778c9e 5851d63 2dd779d 5851d63 0ce274f 5c869f5 2dd779d 1778c9e 2dd779d 0ce274f 2dd779d 0ce274f 5851d63 2dd779d b2170a7 1778c9e b2170a7 f36471e 1778c9e f36471e 1778c9e f36471e 1778c9e f36471e 1778c9e f36471e 502cb81 5213b80 502cb81 28faefd 1778c9e 5213b80 502cb81 5213b80 1778c9e f48efbb 1778c9e 899d9c6 1778c9e f48efbb 5213b80 502cb81 eeca96c 5851d63 1778c9e 502cb81 8c5a2cf 64cfbce b2170a7 5213b80 502cb81 5213b80 1778c9e 5213b80 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
<script lang="ts">
import { ScrollState } from "$lib/spells/scroll-state.svelte";
import { type ConversationClass } from "$lib/state/conversations.svelte";
import { watch } from "runed";
import { tick } from "svelte";
import IconPlus from "~icons/carbon/add";
import CodeSnippets from "./code-snippets.svelte";
import Message from "./message.svelte";
interface Props {
conversation: ConversationClass;
viewCode: boolean;
onCloseCode: () => void;
}
const { conversation, viewCode, onCloseCode }: Props = $props();
let messageContainer: HTMLDivElement | null = $state(null);
const scrollState = new ScrollState({
element: () => messageContainer,
offset: { bottom: 100 },
});
const atBottom = $derived(scrollState.arrived.bottom);
watch(
() => conversation.data.messages.at(-1)?.content,
() => {
const shouldScroll = atBottom && !scrollState.isScrolling;
if (!shouldScroll) return;
try {
tick().then(() => {
scrollState.scrollToBottom();
});
} catch {
// noop
}
}
);
function addMessage() {
const msgs = conversation.data.messages.slice();
conversation.update({
...conversation.data,
messages: [
...msgs,
{
role: msgs.at(-1)?.role === "user" ? "assistant" : "user",
content: "",
},
],
});
}
async function regenMessage(idx: number) {
// TODO: migrate to new logic
const msg = conversation.data.messages[idx];
if (!msg) return;
if (msg.role === "user") {
await conversation.deleteMessages(idx + 1);
} else {
await conversation.deleteMessages(idx);
}
conversation.stopGenerating();
conversation.genNextMessage();
}
</script>
<div
class="@container flex flex-col overflow-x-hidden overflow-y-auto"
class:animate-pulse={conversation.generating && !conversation.data.streaming}
bind:this={messageContainer}
>
{#if !viewCode}
{#each conversation.data.messages as message, index}
<Message
{message}
{index}
{conversation}
autofocus={index === conversation.data.messages.length - 1}
onDelete={() => conversation.deleteMessage(index)}
onRegen={() => regenMessage(index)}
/>
{/each}
<button
class="flex px-3.5 py-6 hover:bg-gray-50 md:px-6 dark:hover:bg-gray-800/50"
onclick={addMessage}
disabled={conversation.generating}
>
<div class="flex items-center gap-2 p-0! text-sm font-semibold">
<div class="text-lg">
<IconPlus />
</div>
Add message
</div>
</button>
{:else}
<CodeSnippets {conversation} {onCloseCode} />
{/if}
</div>
|