Timothy Jaeryang Baek 3 месяцев назад
Родитель
Сommit
7f61d01fde

+ 26 - 1
src/lib/components/playground/Chat.svelte

@@ -33,6 +33,7 @@
 	let loading = false;
 	let stopResponseFlag = false;
 
+	let systemTextareaElement: HTMLTextAreaElement;
 	let messagesContainerElement: HTMLDivElement;
 
 	let showSystem = false;
@@ -58,8 +59,29 @@
 		console.log('stopResponse');
 	};
 
+	const resizeSystemTextarea = async () => {
+		await tick();
+		if (systemTextareaElement) {
+			systemTextareaElement.style.height = '';
+			systemTextareaElement.style.height = Math.min(systemTextareaElement.scrollHeight, 555) + 'px';
+		}
+	};
+
+	$: if (showSystem) {
+		resizeSystemTextarea();
+	}
+
 	const chatCompletionHandler = async () => {
+		if (selectedModelId === '') {
+			toast.error($i18n.t('Please select a model.'));
+			return;
+		}
+
 		const model = $models.find((model) => model.id === selectedModelId);
+		if (!model) {
+			selectedModelId = '';
+			return;
+		}
 
 		const [res, controller] = await chatCompletion(
 			localStorage.token,
@@ -258,10 +280,13 @@
 					<div slot="content">
 						<div class="pt-1 px-1.5">
 							<textarea
-								id="system-textarea"
+								bind:this={systemTextareaElement}
 								class="w-full h-full bg-transparent resize-none outline-none text-sm"
 								bind:value={system}
 								placeholder={$i18n.t("You're a helpful assistant.")}
+								on:input={() => {
+									resizeSystemTextarea();
+								}}
 								rows="4"
 							/>
 						</div>

+ 76 - 0
src/lib/components/playground/Chat/Message.svelte

@@ -0,0 +1,76 @@
+<script lang="ts">
+	import { onMount, getContext } from 'svelte';
+
+	const i18n = getContext('i18n');
+
+	export let message;
+	export let idx;
+
+	export let onDelete;
+
+	let textAreaElement: HTMLTextAreaElement;
+
+	onMount(() => {
+		textAreaElement.style.height = '';
+		textAreaElement.style.height = textAreaElement.scrollHeight + 'px';
+	});
+</script>
+
+<div class="flex gap-2 group">
+	<div class="flex items-start pt-1">
+		<div
+			class="px-2 py-1 text-sm font-semibold uppercase min-w-[6rem] text-left rounded-lg transition"
+		>
+			{$i18n.t(message.role)}
+		</div>
+	</div>
+
+	<div class="flex-1">
+		<!-- $i18n.t('a user') -->
+		<!-- $i18n.t('an assistant') -->
+		<textarea
+			id="{message.role}-{idx}-textarea"
+			bind:this={textAreaElement}
+			class="w-full bg-transparent outline-none rounded-lg p-2 text-sm resize-none overflow-hidden"
+			placeholder={$i18n.t(`Enter {{role}} message here`, {
+				role: message.role === 'user' ? $i18n.t('a user') : $i18n.t('an assistant')
+			})}
+			rows="1"
+			on:input={(e) => {
+				textAreaElement.style.height = '';
+				textAreaElement.style.height = textAreaElement.scrollHeight + 'px';
+			}}
+			on:focus={(e) => {
+				textAreaElement.style.height = '';
+				textAreaElement.style.height = textAreaElement.scrollHeight + 'px';
+
+				// e.target.style.height = Math.min(e.target.scrollHeight, 200) + 'px';
+			}}
+			bind:value={message.content}
+		/>
+	</div>
+
+	<div class=" pt-1">
+		<button
+			class=" group-hover:text-gray-500 dark:text-gray-900 dark:hover:text-gray-300 transition"
+			on:click={() => {
+				onDelete();
+			}}
+		>
+			<svg
+				xmlns="http://www.w3.org/2000/svg"
+				fill="none"
+				viewBox="0 0 24 24"
+				stroke-width="2"
+				stroke="currentColor"
+				class="w-5 h-5"
+			>
+				<path
+					stroke-linecap="round"
+					stroke-linejoin="round"
+					d="M15 12H9m12 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
+				/>
+			</svg>
+		</button>
+	</div>
+</div>

+ 8 - 65
src/lib/components/playground/Chat/Messages.svelte

@@ -1,77 +1,20 @@
 <script lang="ts">
 	import { onMount, getContext } from 'svelte';
+	import Message from './Message.svelte';
 
 	const i18n = getContext('i18n');
 
 	export let messages = [];
-	let textAreaElement: HTMLTextAreaElement;
-	onMount(() => {
-		messages.forEach((message, idx) => {
-			textAreaElement.style.height = '';
-			textAreaElement.style.height = textAreaElement.scrollHeight + 'px';
-		});
-	});
 </script>
 
 <div class="py-3 space-y-3">
 	{#each messages as message, idx}
-		<div class="flex gap-2 group">
-			<div class="flex items-start pt-1">
-				<div
-					class="px-2 py-1 text-sm font-semibold uppercase min-w-[6rem] text-left rounded-lg transition"
-				>
-					{$i18n.t(message.role)}
-				</div>
-			</div>
-
-			<div class="flex-1">
-				<!-- $i18n.t('a user') -->
-				<!-- $i18n.t('an assistant') -->
-				<textarea
-					id="{message.role}-{idx}-textarea"
-					bind:this={textAreaElement}
-					class="w-full bg-transparent outline-none rounded-lg p-2 text-sm resize-none overflow-hidden"
-					placeholder={$i18n.t(`Enter {{role}} message here`, {
-						role: message.role === 'user' ? $i18n.t('a user') : $i18n.t('an assistant')
-					})}
-					rows="1"
-					on:input={(e) => {
-						textAreaElement.style.height = '';
-						textAreaElement.style.height = textAreaElement.scrollHeight + 'px';
-					}}
-					on:focus={(e) => {
-						textAreaElement.style.height = '';
-						textAreaElement.style.height = textAreaElement.scrollHeight + 'px';
-
-						// e.target.style.height = Math.min(e.target.scrollHeight, 200) + 'px';
-					}}
-					bind:value={message.content}
-				/>
-			</div>
-
-			<div class=" pt-1">
-				<button
-					class=" group-hover:text-gray-500 dark:text-gray-900 dark:hover:text-gray-300 transition"
-					on:click={() => {
-						messages = messages.filter((message, messageIdx) => messageIdx !== idx);
-					}}
-				>
-					<svg
-						xmlns="http://www.w3.org/2000/svg"
-						fill="none"
-						viewBox="0 0 24 24"
-						stroke-width="2"
-						stroke="currentColor"
-						class="w-5 h-5"
-					>
-						<path
-							stroke-linecap="round"
-							stroke-linejoin="round"
-							d="M15 12H9m12 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
-						/>
-					</svg>
-				</button>
-			</div>
-		</div>
+		<Message
+			{message}
+			{idx}
+			onDelete={() => {
+				messages = messages.filter((message, messageIdx) => messageIdx !== idx);
+			}}
+		/>
 	{/each}
 </div>