Browse Source

feat:'@' model support

Timothy J. Baek 1 year ago
parent
commit
d680d52b85

+ 52 - 11
src/lib/components/chat/MessageInput.svelte

@@ -1,23 +1,25 @@
 <script lang="ts">
 	import { toast } from 'svelte-sonner';
 	import { onMount, tick, getContext } from 'svelte';
-	import { settings, showSidebar } from '$lib/stores';
+	import { modelfiles, settings, showSidebar } from '$lib/stores';
 	import { blobToFile, calculateSHA256, findWordIndices } from '$lib/utils';
 
-	import Prompts from './MessageInput/PromptCommands.svelte';
-	import Suggestions from './MessageInput/Suggestions.svelte';
 	import {
 		uploadDocToVectorDB,
 		uploadWebToVectorDB,
 		uploadYoutubeTranscriptionToVectorDB
 	} from '$lib/apis/rag';
+	import { SUPPORTED_FILE_TYPE, SUPPORTED_FILE_EXTENSIONS, WEBUI_BASE_URL } from '$lib/constants';
+
+	import { transcribeAudio } from '$lib/apis/audio';
+
+	import Prompts from './MessageInput/PromptCommands.svelte';
+	import Suggestions from './MessageInput/Suggestions.svelte';
 	import AddFilesPlaceholder from '../AddFilesPlaceholder.svelte';
-	import { SUPPORTED_FILE_TYPE, SUPPORTED_FILE_EXTENSIONS } from '$lib/constants';
 	import Documents from './MessageInput/Documents.svelte';
 	import Models from './MessageInput/Models.svelte';
-	import { transcribeAudio } from '$lib/apis/audio';
 	import Tooltip from '../common/Tooltip.svelte';
-	import Page from '../../../routes/(app)/+page.svelte';
+	import XMark from '$lib/components/icons/XMark.svelte';
 
 	const i18n = getContext('i18n');
 
@@ -25,6 +27,8 @@
 	export let stopResponse: Function;
 
 	export let autoScroll = true;
+	export let selectedModel = '';
+
 	let chatTextAreaElement: HTMLTextAreaElement;
 	let filesInputElement;
 
@@ -424,11 +428,11 @@
 
 <div class="fixed bottom-0 {$showSidebar ? 'left-0 lg:left-[260px]' : 'left-0'} right-0">
 	<div class="w-full">
-		<div class=" px-2.5 -mb-0.5 mx-auto inset-x-0 bg-transparent flex justify-center">
+		<div class="px-2.5 lg:px-16 -mb-0.5 mx-auto inset-x-0 bg-transparent flex justify-center">
 			<div class="flex flex-col max-w-5xl w-full">
 				<div class="relative">
 					{#if autoScroll === false && messages.length > 0}
-						<div class=" absolute -top-12 left-0 right-0 flex justify-center">
+						<div class=" absolute -top-12 left-0 right-0 flex justify-center z-30">
 							<button
 								class=" bg-white border border-gray-100 dark:border-none dark:bg-white/20 p-1.5 rounded-full"
 								on:click={() => {
@@ -488,14 +492,46 @@
 						bind:user
 						bind:chatInputPlaceholder
 						{messages}
+						on:select={(e) => {
+							selectedModel = e.detail;
+							chatTextAreaElement?.focus();
+						}}
 					/>
 
-					<!-- {#if messages.length == 0 && suggestionPrompts.length !== 0}
-						<Suggestions {suggestionPrompts} {submitPrompt} />
-					{/if} -->
+					{#if selectedModel !== ''}
+						<div
+							class="md:px-3 py-2.5 text-left w-full flex justify-between items-center absolute bottom-0 left-0 right-0 bg-gradient-to-t from-50% from-white dark:from-gray-900"
+						>
+							<div class="flex items-center gap-2 text-sm dark:text-gray-500">
+								<img
+									alt="model profile"
+									class="size-5 max-w-[28px] object-cover rounded-full"
+									src={$modelfiles.find((modelfile) => modelfile.tagName === selectedModel.id)
+										?.imageUrl ??
+										($i18n.language === 'dg-DG'
+											? `/doge.png`
+											: `${WEBUI_BASE_URL}/static/favicon.png`)}
+								/>
+								<div>
+									Talking to <span class=" font-medium">{selectedModel.name} </span>
+								</div>
+							</div>
+							<div>
+								<button
+									class="flex items-center"
+									on:click={() => {
+										selectedModel = '';
+									}}
+								>
+									<XMark />
+								</button>
+							</div>
+						</div>
+					{/if}
 				</div>
 			</div>
 		</div>
+
 		<div class="bg-white dark:bg-gray-900">
 			<div class="max-w-6xl px-2.5 lg:px-16 mx-auto inset-x-0">
 				<div class=" pb-2">
@@ -832,6 +868,11 @@
 										e.target.style.height = '';
 										e.target.style.height = Math.min(e.target.scrollHeight, 200) + 'px';
 									}
+
+									if (e.key === 'Escape') {
+										console.log('Escape');
+										selectedModel = '';
+									}
 								}}
 								rows="1"
 								on:input={(e) => {

+ 5 - 13
src/lib/components/chat/MessageInput/Models.svelte

@@ -1,4 +1,6 @@
 <script lang="ts">
+	import { createEventDispatcher } from 'svelte';
+
 	import { generatePrompt } from '$lib/apis/ollama';
 	import { models } from '$lib/stores';
 	import { splitStream } from '$lib/utils';
@@ -7,14 +9,14 @@
 
 	const i18n = getContext('i18n');
 
+	const dispatch = createEventDispatcher();
+
 	export let prompt = '';
 	export let user = null;
 
 	export let chatInputPlaceholder = '';
 	export let messages = [];
 
-	let selectedModel = null;
-
 	let selectedIdx = 0;
 	let filteredModels = [];
 
@@ -36,9 +38,7 @@
 
 	const confirmSelect = async (model) => {
 		prompt = '';
-		selectedModel = model;
-
-		console.log(selectedModel);
+		dispatch('select', model);
 	};
 
 	const confirmSelectCollaborativeChat = async (model) => {
@@ -170,11 +170,3 @@
 		</div>
 	{/if}
 {/if}
-
-{#if selectedModel !== null}
-	<div class="md:px-2 mb-3 text-left w-full absolute bottom-0 left-0 right-0">
-		<div>
-			{JSON.stringify(selectedModel)}
-		</div>
-	</div>
-{/if}

+ 15 - 0
src/lib/components/icons/XMark.svelte

@@ -0,0 +1,15 @@
+<script lang="ts">
+	export let className = 'size-3.5';
+	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="M6 18 18 6M6 6l12 12" />
+</svg>

+ 17 - 4
src/routes/(app)/+page.svelte

@@ -51,7 +51,9 @@
 	let currentRequestId = null;
 
 	let showModelSelector = true;
+
 	let selectedModels = [''];
+	let atSelectedModel = '';
 
 	let selectedModelfile = null;
 	$: selectedModelfile =
@@ -145,7 +147,8 @@
 		setTimeout(() => chatInput?.focus(), 0);
 	};
 
-	const scrollToBottom = () => {
+	const scrollToBottom = async () => {
+		await tick();
 		if (messagesContainerElement) {
 			messagesContainerElement.scrollTop = messagesContainerElement.scrollHeight;
 		}
@@ -243,7 +246,8 @@
 		const _chatId = JSON.parse(JSON.stringify($chatId));
 
 		await Promise.all(
-			selectedModels.map(async (modelId) => {
+			(atSelectedModel !== '' ? [atSelectedModel.id] : selectedModels).map(async (modelId) => {
+				console.log('modelId', modelId);
 				const model = $models.filter((m) => m.id === modelId).at(0);
 
 				if (model) {
@@ -537,7 +541,7 @@
 
 		console.log(docs);
 
-		console.log(model);
+		scrollToBottom();
 
 		const [res, controller] = await generateOpenAIChatCompletion(
 			localStorage.token,
@@ -884,4 +888,13 @@
 		</div>
 	</div>
 </div>
-<MessageInput bind:files bind:prompt bind:autoScroll {messages} {submitPrompt} {stopResponse} />
+
+<MessageInput
+	bind:files
+	bind:prompt
+	bind:autoScroll
+	bind:selectedModel={atSelectedModel}
+	{messages}
+	{submitPrompt}
+	{stopResponse}
+/>

+ 8 - 2
src/routes/(app)/c/[id]/+page.svelte

@@ -57,6 +57,8 @@
 	// let chatId = $page.params.id;
 	let showModelSelector = true;
 	let selectedModels = [''];
+	let atSelectedModel = '';
+
 	let selectedModelfile = null;
 
 	$: selectedModelfile =
@@ -167,7 +169,8 @@
 		}
 	};
 
-	const scrollToBottom = () => {
+	const scrollToBottom = async () => {
+		await tick();
 		if (messagesContainerElement) {
 			messagesContainerElement.scrollTop = messagesContainerElement.scrollHeight;
 		}
@@ -256,7 +259,7 @@
 		const _chatId = JSON.parse(JSON.stringify($chatId));
 
 		await Promise.all(
-			selectedModels.map(async (modelId) => {
+			(atSelectedModel !== '' ? [atSelectedModel.id] : selectedModels).map(async (modelId) => {
 				const model = $models.filter((m) => m.id === modelId).at(0);
 
 				if (model) {
@@ -550,6 +553,8 @@
 
 		console.log(docs);
 
+		scrollToBottom();
+
 		const [res, controller] = await generateOpenAIChatCompletion(
 			localStorage.token,
 			{
@@ -911,6 +916,7 @@
 		bind:files
 		bind:prompt
 		bind:autoScroll
+		bind:selectedModel={atSelectedModel}
 		suggestionPrompts={selectedModelfile?.suggestionPrompts ?? $config.default_prompt_suggestions}
 		{messages}
 		{submitPrompt}