File size: 3,286 Bytes
502cb81 b924465 4b8b411 b2170a7 4b8b411 b2170a7 60216ec 502cb81 0ffe6c3 0bcf467 1cd3833 502cb81 25a5986 502cb81 5c869f5 de2ec19 5c869f5 de2ec19 cd2e1ea de2ec19 cd2e1ea de2ec19 502cb81 25a5986 502cb81 5213b80 f2e5687 de2ec19 25a5986 502cb81 25a5986 5c869f5 b2170a7 502cb81 5213b80 60c7941 502cb81 73b6f4f 92f7aa1 d5e14b5 5213b80 25a5986 502cb81 5213b80 f2e5687 5213b80 b2170a7 25a5986 de2ec19 b2170a7 b34b73b 5213b80 502cb81 eeca96c b2170a7 5213b80 502cb81 8c5a2cf 64cfbce b2170a7 5213b80 502cb81 5213b80 25c63d0 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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
<script lang="ts">
import type { Conversation } from "$lib/types";
import { tick } from "svelte";
import IconPlus from "~icons/carbon/add";
import CodeSnippets from "./InferencePlaygroundCodeSnippets.svelte";
import Message from "./InferencePlaygroundMessage.svelte";
export let conversation: Conversation;
export let loading: boolean;
export let viewCode: boolean;
export let compareActive: boolean;
let shouldScrollToBottom = true;
let isProgrammaticScroll = true;
let conversationLength = conversation.messages.length;
let messageContainer: HTMLDivElement | null = null;
async function resizeMessageTextAreas() {
// ideally we would use CSS "field-sizing:content". However, it is currently only supported on Chrome.
await tick();
if (messageContainer) {
const containerScrollTop = messageContainer.scrollTop;
const textareaEls = messageContainer.querySelectorAll("textarea");
for (const textarea of textareaEls) {
textarea.style.height = "0px";
textarea.style.height = textarea.scrollHeight + "px";
}
messageContainer.scrollTop = containerScrollTop;
}
}
function scrollToBottom() {
if (messageContainer) {
isProgrammaticScroll = true;
messageContainer.scrollTop = messageContainer.scrollHeight;
}
}
$: {
if (conversation.messages.at(-1)) {
resizeMessageTextAreas();
if (shouldScrollToBottom) {
scrollToBottom();
}
}
}
$: if (conversation.messages.length !== conversationLength) {
// enable automatic scrolling when new message was added
conversationLength = conversation.messages.length;
shouldScrollToBottom = true;
}
$: viewCode, resizeMessageTextAreas();
function addMessage() {
const msgs = conversation.messages.slice();
conversation.messages = [
...msgs,
{
role: msgs.at(-1)?.role === "user" ? "assistant" : "user",
content: "",
},
];
conversation = conversation;
}
function deleteMessage(idx: number) {
conversation.messages.splice(idx, 1);
conversation = conversation;
}
</script>
<svelte:window on:resize={resizeMessageTextAreas} />
<div
class="@container flex flex-col overflow-x-hidden overflow-y-auto {compareActive
? 'max-h-[calc(100dvh-5.8rem-2.5rem-75px)] md:max-h-[calc(100dvh-5.8rem-2.5rem)]'
: 'max-h-[calc(100dvh-5.8rem-2.5rem-75px)] md:max-h-[calc(100dvh-5.8rem)]'}"
class:animate-pulse={loading && !conversation.streaming}
bind:this={messageContainer}
on:scroll={() => {
// disable automatic scrolling is user initiates scroll
if (!isProgrammaticScroll) {
shouldScrollToBottom = false;
}
isProgrammaticScroll = false;
}}
>
{#if !viewCode}
{#each conversation.messages as message, messageIdx}
<Message
class="border-b"
bind:message
{loading}
on:input={resizeMessageTextAreas}
on:delete={() => deleteMessage(messageIdx)}
autofocus={!loading && messageIdx === conversation.messages.length - 1}
/>
{/each}
<button
class="flex px-3.5 py-6 hover:bg-gray-50 md:px-6 dark:hover:bg-gray-800/50"
on:click={addMessage}
disabled={loading}
>
<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} on:closeCode />
{/if}
</div>
|