ソースを参照

refac: message status history

Timothy J. Baek 10 ヶ月 前
コミット
a75b68c19c

+ 23 - 18
src/lib/components/chat/Chat.svelte

@@ -515,11 +515,13 @@
 	const getWebSearchResults = async (model: string, parentId: string, responseId: string) => {
 		const responseMessage = history.messages[responseId];
 
-		responseMessage.status = {
-			done: false,
-			action: 'web_search',
-			description: $i18n.t('Generating search query')
-		};
+		responseMessage.statusHistory = [
+			{
+				done: false,
+				action: 'web_search',
+				description: $i18n.t('Generating search query')
+			}
+		];
 		messages = messages;
 
 		const prompt = history.messages[parentId].content;
@@ -532,19 +534,21 @@
 
 		if (!searchQuery) {
 			toast.warning($i18n.t('No search query generated'));
-			responseMessage.status = {
-				...responseMessage.status,
+			responseMessage.statusHistory.push({
 				done: true,
 				error: true,
+				action: 'web_search',
 				description: 'No search query generated'
-			};
+			});
+
 			messages = messages;
 		}
 
-		responseMessage.status = {
-			...responseMessage.status,
-			description: $i18n.t("Searching the web for '{{searchQuery}}'", { searchQuery })
-		};
+		responseMessage.statusHistory.push({
+			done: false,
+			action: 'web_search',
+			description: $i18n.t(`Searching "{{searchQuery}}"`, { searchQuery })
+		});
 		messages = messages;
 
 		const results = await runWebSearch(localStorage.token, searchQuery).catch((error) => {
@@ -555,12 +559,13 @@
 		});
 
 		if (results) {
-			responseMessage.status = {
-				...responseMessage.status,
+			responseMessage.statusHistory.push({
 				done: true,
+				action: 'web_search',
 				description: $i18n.t('Searched {{count}} sites', { count: results.filenames.length }),
+				query: searchQuery,
 				urls: results.filenames
-			};
+			});
 
 			if (responseMessage?.files ?? undefined === undefined) {
 				responseMessage.files = [];
@@ -575,12 +580,12 @@
 
 			messages = messages;
 		} else {
-			responseMessage.status = {
-				...responseMessage.status,
+			responseMessage.statusHistory.push({
 				done: true,
 				error: true,
+				action: 'web_search',
 				description: 'No search results found'
-			};
+			});
 			messages = messages;
 		}
 	};

+ 9 - 6
src/lib/components/chat/Messages/ResponseMessage.svelte

@@ -420,26 +420,29 @@
 				class="prose chat-{message.role} w-full max-w-full dark:prose-invert prose-headings:my-0 prose-headings:-mb-4 prose-p:m-0 prose-p:-mb-6 prose-pre:my-0 prose-table:my-0 prose-blockquote:my-0 prose-img:my-0 prose-ul:-my-4 prose-ol:-my-4 prose-li:-my-3 prose-ul:-mb-6 prose-ol:-mb-8 prose-ol:p-0 prose-li:-mb-4 whitespace-pre-line"
 			>
 				<div>
-					{#if message?.status}
+					{#if (message?.statusHistory ?? [...(message?.status ? [message?.status] : [])]).length > 0}
+						{@const status = (
+							message?.statusHistory ?? [...(message?.status ? [message?.status] : [])]
+						).at(-1)}
 						<div class="flex items-center gap-2 pt-1 pb-1">
-							{#if message?.status?.done === false}
+							{#if status.done === false}
 								<div class="">
 									<Spinner className="size-4" />
 								</div>
 							{/if}
 
-							{#if message?.status?.action === 'web_search' && message?.status?.urls}
-								<WebSearchResults urls={message?.status?.urls}>
+							{#if status?.action === 'web_search' && status?.urls}
+								<WebSearchResults {status}>
 									<div class="flex flex-col justify-center -space-y-0.5">
 										<div class="text-base line-clamp-1 text-wrap">
-											{message.status.description}
+											{status?.description}
 										</div>
 									</div>
 								</WebSearchResults>
 							{:else}
 								<div class="flex flex-col justify-center -space-y-0.5">
 									<div class=" text-gray-500 dark:text-gray-500 text-base line-clamp-1 text-wrap">
-										{message.status.description}
+										{status?.description}
 									</div>
 								</div>
 							{/if}

+ 38 - 3
src/lib/components/chat/Messages/ResponseMessage/WebSearchResults.svelte

@@ -1,10 +1,11 @@
 <script lang="ts">
 	import ChevronDown from '$lib/components/icons/ChevronDown.svelte';
 	import ChevronUp from '$lib/components/icons/ChevronUp.svelte';
+	import MagnifyingGlass from '$lib/components/icons/MagnifyingGlass.svelte';
 	import { Collapsible } from 'bits-ui';
 	import { slide } from 'svelte/transition';
 
-	export let urls = [];
+	export let status = { urls: [], query: '' };
 	let state = false;
 </script>
 
@@ -27,11 +28,45 @@
 		class=" text-sm border border-gray-300/30 dark:border-gray-700/50 rounded-xl"
 		transition={slide}
 	>
-		{#each urls as url, urlIdx}
+		{#if status?.query}
+			<a
+				href="https://www.google.com/search?q={status.query}"
+				target="_blank"
+				class="flex w-full items-center p-3 px-4 border-b border-gray-300/30 dark:border-gray-700/50 group/item justify-between font-normal text-gray-800 dark:text-gray-300 no-underline"
+			>
+				<div class="flex gap-2 items-center">
+					<MagnifyingGlass />
+
+					<div class=" line-clamp-1">
+						{status.query}
+					</div>
+				</div>
+
+				<div
+					class=" ml-1 text-white dark:text-gray-900 group-hover/item:text-gray-600 dark:group-hover/item:text-white transition"
+				>
+					<!--  -->
+					<svg
+						xmlns="http://www.w3.org/2000/svg"
+						viewBox="0 0 16 16"
+						fill="currentColor"
+						class="size-4"
+					>
+						<path
+							fill-rule="evenodd"
+							d="M4.22 11.78a.75.75 0 0 1 0-1.06L9.44 5.5H5.75a.75.75 0 0 1 0-1.5h5.5a.75.75 0 0 1 .75.75v5.5a.75.75 0 0 1-1.5 0V6.56l-5.22 5.22a.75.75 0 0 1-1.06 0Z"
+							clip-rule="evenodd"
+						/>
+					</svg>
+				</div>
+			</a>
+		{/if}
+
+		{#each status.urls as url, urlIdx}
 			<a
 				href={url}
 				target="_blank"
-				class="flex w-full items-center p-3 px-4 {urlIdx === urls.length - 1
+				class="flex w-full items-center p-3 px-4 {urlIdx === status.urls.length - 1
 					? ''
 					: 'border-b border-gray-300/30 dark:border-gray-700/50'} group/item justify-between font-normal text-gray-800 dark:text-gray-300"
 			>

+ 19 - 0
src/lib/components/icons/MagnifyingGlass.svelte

@@ -0,0 +1,19 @@
+<script lang="ts">
+	export let className = 'size-4';
+	export let strokeWidth = '2';
+</script>
+
+<svg
+	xmlns="http://www.w3.org/2000/svg"
+	fill="none"
+	viewBox="0 0 24 24"
+	stroke-width={strokeWidth}
+	stroke="currentColor"
+	class={className}
+>
+	<path
+		stroke-linecap="round"
+		stroke-linejoin="round"
+		d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"
+	/>
+</svg>