Forráskód Böngészése

refac: suggestion prompts

Timothy Jaeryang Baek 3 hónapja
szülő
commit
198b89faa5

+ 11 - 0
src/lib/components/chat/Chat.svelte

@@ -193,6 +193,15 @@
 		}
 	};
 
+	const onSelect = async (e) => {
+		const { type, data } = e;
+
+		if (type === 'prompt') {
+			// Handle prompt selection
+			messageInput?.setText(data);
+		}
+	};
+
 	$: if (selectedModels && chatIdProp !== '') {
 		saveSessionSelectedModels();
 	}
@@ -2117,6 +2126,7 @@
 										{chatActionHandler}
 										{addMessages}
 										bottomPadding={files.length > 0}
+										{onSelect}
 									/>
 								</div>
 							</div>
@@ -2202,6 +2212,7 @@
 									toolServers={$toolServers}
 									{stopResponse}
 									{createMessagePair}
+									{onSelect}
 									on:upload={async (e) => {
 										const { type, data } = e.detail;
 

+ 2 - 4
src/lib/components/chat/ChatPlaceholder.svelte

@@ -18,7 +18,7 @@
 	export let models = [];
 	export let atSelectedModel;
 
-	export let submitPrompt;
+	export let onSelect = (e) => {};
 
 	let mounted = false;
 	let selectedModelIdx = 0;
@@ -135,9 +135,7 @@
 					models[selectedModelIdx]?.info?.meta?.suggestion_prompts ??
 					$config?.default_prompt_suggestions ??
 					[]}
-				on:select={(e) => {
-					submitPrompt(e.detail);
-				}}
+				{onSelect}
 			/>
 		</div>
 	</div>

+ 1 - 0
src/lib/components/chat/MessageInput.svelte

@@ -119,6 +119,7 @@
 		if (chatInput) {
 			if ($settings?.richTextInput ?? true) {
 				chatInputElement.setText(text);
+				chatInputElement.focus();
 			} else {
 				chatInput.value = text;
 				prompt = text;

+ 3 - 19
src/lib/components/chat/Messages.svelte

@@ -51,6 +51,8 @@
 	export let bottomPadding = false;
 	export let autoScroll;
 
+	export let onSelect = (e) => {};
+
 	let messagesCount = 20;
 	let messagesLoading = false;
 
@@ -395,25 +397,7 @@
 
 <div class={className}>
 	{#if Object.keys(history?.messages ?? {}).length == 0}
-		<ChatPlaceholder
-			modelIds={selectedModels}
-			{atSelectedModel}
-			submitPrompt={async (p) => {
-				let text = p;
-
-				if (p.includes('{{CLIPBOARD}}')) {
-					const clipboardText = await navigator.clipboard.readText().catch((err) => {
-						toast.error($i18n.t('Failed to read clipboard contents'));
-						return '{{CLIPBOARD}}';
-					});
-
-					text = p.replaceAll('{{CLIPBOARD}}', clipboardText);
-				}
-
-				prompt = text;
-				await tick();
-			}}
-		/>
+		<ChatPlaceholder modelIds={selectedModels} {atSelectedModel} {onSelect} />
 	{:else}
 		<div class="w-full pt-2">
 			{#key chatId}

+ 3 - 38
src/lib/components/chat/Placeholder.svelte

@@ -43,45 +43,12 @@
 	export let codeInterpreterEnabled = false;
 	export let webSearchEnabled = false;
 
+	export let onSelect = (e) => {};
+
 	export let toolServers = [];
 
 	let models = [];
 
-	const selectSuggestionPrompt = async (p) => {
-		let text = p;
-
-		if (p.includes('{{CLIPBOARD}}')) {
-			const clipboardText = await navigator.clipboard.readText().catch((err) => {
-				toast.error($i18n.t('Failed to read clipboard contents'));
-				return '{{CLIPBOARD}}';
-			});
-
-			text = p.replaceAll('{{CLIPBOARD}}', clipboardText);
-
-			console.log('Clipboard text:', clipboardText, text);
-		}
-
-		prompt = text;
-
-		console.log(prompt);
-		await tick();
-
-		const chatInputContainerElement = document.getElementById('chat-input-container');
-		const chatInputElement = document.getElementById('chat-input');
-
-		if (chatInputContainerElement) {
-			chatInputContainerElement.scrollTop = chatInputContainerElement.scrollHeight;
-		}
-
-		await tick();
-		if (chatInputElement) {
-			chatInputElement.focus();
-			chatInputElement.dispatchEvent(new Event('input'));
-		}
-
-		await tick();
-	};
-
 	let selectedModelIdx = 0;
 
 	$: if (selectedModels.length > 0) {
@@ -255,9 +222,7 @@
 					$config?.default_prompt_suggestions ??
 					[]}
 				inputValue={prompt}
-				on:select={(e) => {
-					selectSuggestionPrompt(e.detail);
-				}}
+				{onSelect}
 			/>
 		</div>
 	</div>

+ 4 - 3
src/lib/components/chat/Suggestions.svelte

@@ -1,16 +1,16 @@
 <script lang="ts">
 	import Fuse from 'fuse.js';
 	import Bolt from '$lib/components/icons/Bolt.svelte';
-	import { onMount, getContext, createEventDispatcher } from 'svelte';
+	import { onMount, getContext } from 'svelte';
 	import { settings, WEBUI_NAME } from '$lib/stores';
 	import { WEBUI_VERSION } from '$lib/constants';
 
 	const i18n = getContext('i18n');
-	const dispatch = createEventDispatcher();
 
 	export let suggestionPrompts = [];
 	export let className = '';
 	export let inputValue = '';
+	export let onSelect = (e) => {};
 
 	let sortedPrompts = [];
 
@@ -85,13 +85,14 @@
 	{#if filteredPrompts.length > 0}
 		<div role="list" class="max-h-40 overflow-auto scrollbar-none items-start {className}">
 			{#each filteredPrompts as prompt, idx (prompt.id || prompt.content)}
+				<!-- svelte-ignore a11y-no-interactive-element-to-noninteractive-role -->
 				<button
 					role="listitem"
 					class="waterfall flex flex-col flex-1 shrink-0 w-full justify-between
 				       px-3 py-2 rounded-xl bg-transparent hover:bg-black/5
 				       dark:hover:bg-white/5 transition group"
 					style="animation-delay: {idx * 60}ms"
-					on:click={() => dispatch('select', prompt.content)}
+					on:click={() => onSelect({ type: 'prompt', data: prompt.content })}
 				>
 					<div class="flex flex-col text-left">
 						{#if prompt.title && prompt.title[0] !== ''}

+ 8 - 0
src/lib/components/common/RichTextInput.svelte

@@ -207,6 +207,14 @@
 		selectNextTemplate(editor.view.state, editor.view.dispatch);
 	};
 
+	export const focus = () => {
+		if (editor) {
+			editor.view.focus();
+			// Scroll to the top of the editor
+			editor.view.dispatch(editor.view.state.tr.scrollIntoView());
+		}
+	};
+
 	// Function to find the next template in the document
 	function findNextTemplate(doc, from = 0) {
 		const patterns = [{ start: '{{', end: '}}' }];