forked from open-webui/open-webui
		
	feat: modelfile content linked to chat page
This commit is contained in:
		
							parent
							
								
									12d7ae96b9
								
							
						
					
					
						commit
						587101da88
					
				
					 5 changed files with 148 additions and 128 deletions
				
			
		|  | @ -6,7 +6,7 @@ | |||
| 	export let submitPrompt: Function; | ||||
| 	export let stopResponse: Function; | ||||
| 
 | ||||
| 	export let suggestions = 'true'; | ||||
| 	export let suggestionPrompts = []; | ||||
| 	export let autoScroll = true; | ||||
| 
 | ||||
| 	let filesInputElement; | ||||
|  | @ -87,8 +87,8 @@ | |||
| <div class="fixed bottom-0 w-full bg-white dark:bg-gray-800"> | ||||
| 	<div class=" absolute right-0 left-0 bottom-0 mb-20"> | ||||
| 		<div class="max-w-3xl px-2.5 pt-2.5 -mb-0.5 mx-auto inset-x-0"> | ||||
| 			{#if messages.length == 0 && suggestions !== 'false'} | ||||
| 				<Suggestions {submitPrompt} /> | ||||
| 			{#if messages.length == 0 && suggestionPrompts.length !== 0} | ||||
| 				<Suggestions {suggestionPrompts} {submitPrompt} /> | ||||
| 			{/if} | ||||
| 
 | ||||
| 			{#if autoScroll === false && messages.length > 0} | ||||
|  |  | |||
|  | @ -1,122 +1,43 @@ | |||
| <script lang="ts"> | ||||
| 	export let submitPrompt: Function; | ||||
| 	export let suggestionPrompts = []; | ||||
| </script> | ||||
| 
 | ||||
| <div class=" grid sm:grid-cols-2 gap-2.5 mb-4 md:p-2 text-left"> | ||||
| 	<button | ||||
| 		class=" flex justify-between w-full px-4 py-2.5 bg-white hover:bg-gray-50 dark:bg-gray-800 dark:hover:bg-gray-700 outline outline-1 outline-gray-200 dark:outline-gray-600 rounded-lg transition group" | ||||
| 		on:click={() => { | ||||
| 			submitPrompt(`Tell me a random fun fact about the Roman Empire`); | ||||
| 		}} | ||||
| 	> | ||||
| 		<div class="flex flex-col text-left"> | ||||
| 			<div class="text-sm font-medium dark:text-gray-300">Tell me a fun fact</div> | ||||
| 			<div class="text-sm text-gray-500">about the Roman Empire</div> | ||||
| 		</div> | ||||
| 
 | ||||
| 		<div | ||||
| 			class="self-center p-1 rounded-lg text-white group-hover:bg-gray-100 group-hover:text-gray-800 dark:group-hover:bg-gray-800 dark:group-hover:text-gray-300 dark:text-gray-800 transition" | ||||
| 		> | ||||
| 			<svg | ||||
| 				xmlns="http://www.w3.org/2000/svg" | ||||
| 				viewBox="0 0 20 20" | ||||
| 				fill="currentColor" | ||||
| 				class="w-4 h-4" | ||||
| <div class=" flex flex-wrap-reverse mb-3 md:p-1 text-left"> | ||||
| 	{#each suggestionPrompts as prompt, promptIdx} | ||||
| 		<div class="{promptIdx > 1 ? 'hidden sm:inline-flex' : ''} basis-full sm:basis-1/2 p-[5px]"> | ||||
| 			<button | ||||
| 				class=" flex-1 flex justify-between w-full px-4 py-2.5 bg-white hover:bg-gray-50 dark:bg-gray-800 dark:hover:bg-gray-700 outline outline-1 outline-gray-200 dark:outline-gray-600 rounded-lg transition group" | ||||
| 				on:click={() => { | ||||
| 					submitPrompt(prompt.content); | ||||
| 				}} | ||||
| 			> | ||||
| 				<path | ||||
| 					fill-rule="evenodd" | ||||
| 					d="M10 17a.75.75 0 01-.75-.75V5.612L5.29 9.77a.75.75 0 01-1.08-1.04l5.25-5.5a.75.75 0 011.08 0l5.25 5.5a.75.75 0 11-1.08 1.04l-3.96-4.158V16.25A.75.75 0 0110 17z" | ||||
| 					clip-rule="evenodd" | ||||
| 				/> | ||||
| 			</svg> | ||||
| 		</div> | ||||
| 	</button> | ||||
| 				<div class="flex flex-col text-left self-center"> | ||||
| 					{#if prompt.title} | ||||
| 						<div class="text-sm font-medium dark:text-gray-300">{prompt.title[0]}</div> | ||||
| 						<div class="text-sm text-gray-500">{prompt.title[1]}</div> | ||||
| 					{:else} | ||||
| 						<div class=" self-center text-sm font-medium dark:text-gray-300">{prompt.content}</div> | ||||
| 					{/if} | ||||
| 				</div> | ||||
| 
 | ||||
| 	<button | ||||
| 		class=" flex justify-between w-full px-4 py-2.5 bg-white hover:bg-gray-50 dark:bg-gray-800 dark:hover:bg-gray-700 outline outline-1 outline-gray-200 dark:outline-gray-600 rounded-lg transition group" | ||||
| 		on:click={() => { | ||||
| 			submitPrompt(`Show me a code snippet of a website's sticky header in CSS and JavaScript.`); | ||||
| 		}} | ||||
| 	> | ||||
| 		<div class="flex flex-col text-left"> | ||||
| 			<div class="text-sm font-medium dark:text-gray-300">Show me a code snippet</div> | ||||
| 			<div class="text-sm text-gray-500">of a website's sticky header</div> | ||||
| 				<div | ||||
| 					class="self-center p-1 rounded-lg text-white group-hover:bg-gray-100 group-hover:text-gray-800 dark:group-hover:bg-gray-800 dark:group-hover:text-gray-300 dark:text-gray-800 transition" | ||||
| 				> | ||||
| 					<svg | ||||
| 						xmlns="http://www.w3.org/2000/svg" | ||||
| 						viewBox="0 0 20 20" | ||||
| 						fill="currentColor" | ||||
| 						class="w-4 h-4" | ||||
| 					> | ||||
| 						<path | ||||
| 							fill-rule="evenodd" | ||||
| 							d="M10 17a.75.75 0 01-.75-.75V5.612L5.29 9.77a.75.75 0 01-1.08-1.04l5.25-5.5a.75.75 0 011.08 0l5.25 5.5a.75.75 0 11-1.08 1.04l-3.96-4.158V16.25A.75.75 0 0110 17z" | ||||
| 							clip-rule="evenodd" | ||||
| 						/> | ||||
| 					</svg> | ||||
| 				</div> | ||||
| 			</button> | ||||
| 		</div> | ||||
| 		<div | ||||
| 			class="self-center p-1 rounded-lg text-white group-hover:bg-gray-100 group-hover:text-gray-800 dark:group-hover:bg-gray-800 dark:group-hover:text-gray-300 dark:text-gray-800 transition" | ||||
| 		> | ||||
| 			<svg | ||||
| 				xmlns="http://www.w3.org/2000/svg" | ||||
| 				viewBox="0 0 20 20" | ||||
| 				fill="currentColor" | ||||
| 				class="w-4 h-4" | ||||
| 			> | ||||
| 				<path | ||||
| 					fill-rule="evenodd" | ||||
| 					d="M10 17a.75.75 0 01-.75-.75V5.612L5.29 9.77a.75.75 0 01-1.08-1.04l5.25-5.5a.75.75 0 011.08 0l5.25 5.5a.75.75 0 11-1.08 1.04l-3.96-4.158V16.25A.75.75 0 0110 17z" | ||||
| 					clip-rule="evenodd" | ||||
| 				/> | ||||
| 			</svg> | ||||
| 		</div> | ||||
| 	</button> | ||||
| 
 | ||||
| 	<button | ||||
| 		class="  hidden sm:flex justify-between w-full px-4 py-2.5 bg-white hover:bg-gray-50 dark:bg-gray-800 dark:hover:bg-gray-700 outline outline-1 outline-gray-200 dark:outline-gray-600 rounded-lg transition group" | ||||
| 		on:click={() => { | ||||
| 			submitPrompt( | ||||
| 				`Help me study vocabulary: write a sentence for me to fill in the blank, and I'll try to pick the correct option.` | ||||
| 			); | ||||
| 		}} | ||||
| 	> | ||||
| 		<div class="flex flex-col text-left"> | ||||
| 			<div class="text-sm font-medium dark:text-gray-300">Help me study</div> | ||||
| 			<div class="text-sm text-gray-500">vocabulary for a college entrance exam</div> | ||||
| 		</div> | ||||
| 		<div | ||||
| 			class="self-center p-1 rounded-lg text-white group-hover:bg-gray-100 group-hover:text-gray-800 dark:group-hover:bg-gray-800 dark:group-hover:text-gray-300 dark:text-gray-800 transition" | ||||
| 		> | ||||
| 			<svg | ||||
| 				xmlns="http://www.w3.org/2000/svg" | ||||
| 				viewBox="0 0 20 20" | ||||
| 				fill="currentColor" | ||||
| 				class="w-4 h-4" | ||||
| 			> | ||||
| 				<path | ||||
| 					fill-rule="evenodd" | ||||
| 					d="M10 17a.75.75 0 01-.75-.75V5.612L5.29 9.77a.75.75 0 01-1.08-1.04l5.25-5.5a.75.75 0 011.08 0l5.25 5.5a.75.75 0 11-1.08 1.04l-3.96-4.158V16.25A.75.75 0 0110 17z" | ||||
| 					clip-rule="evenodd" | ||||
| 				/> | ||||
| 			</svg> | ||||
| 		</div> | ||||
| 	</button> | ||||
| 
 | ||||
| 	<button | ||||
| 		class="  hidden sm:flex justify-between w-full px-4 py-2.5 bg-white hover:bg-gray-50 dark:bg-gray-800 dark:hover:bg-gray-700 outline outline-1 outline-gray-200 dark:outline-gray-600 rounded-lg transition group" | ||||
| 		on:click={() => { | ||||
| 			submitPrompt( | ||||
| 				`What are 5 creative things I could do with my kids' art? I don't want to throw them away, but it's also so much clutter.` | ||||
| 			); | ||||
| 		}} | ||||
| 	> | ||||
| 		<div class="flex flex-col text-left"> | ||||
| 			<div class="text-sm font-medium dark:text-gray-300">Give me ideas</div> | ||||
| 			<div class="text-sm text-gray-500">for what to do with my kids' art</div> | ||||
| 		</div> | ||||
| 		<div | ||||
| 			class="self-center p-1 rounded-lg text-white group-hover:bg-gray-100 group-hover:text-gray-800 dark:group-hover:bg-gray-800 dark:group-hover:text-gray-300 dark:text-gray-800 transition" | ||||
| 		> | ||||
| 			<svg | ||||
| 				xmlns="http://www.w3.org/2000/svg" | ||||
| 				viewBox="0 0 20 20" | ||||
| 				fill="currentColor" | ||||
| 				class="w-4 h-4" | ||||
| 			> | ||||
| 				<path | ||||
| 					fill-rule="evenodd" | ||||
| 					d="M10 17a.75.75 0 01-.75-.75V5.612L5.29 9.77a.75.75 0 01-1.08-1.04l5.25-5.5a.75.75 0 011.08 0l5.25 5.5a.75.75 0 11-1.08 1.04l-3.96-4.158V16.25A.75.75 0 0110 17z" | ||||
| 					clip-rule="evenodd" | ||||
| 				/> | ||||
| 			</svg> | ||||
| 		</div> | ||||
| 	</button> | ||||
| 	{/each} | ||||
| </div> | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ | |||
| 	import auto_render from 'katex/dist/contrib/auto-render.mjs'; | ||||
| 	import 'katex/dist/katex.min.css'; | ||||
| 
 | ||||
| 	import { config, db, settings, user } from '$lib/stores'; | ||||
| 	import { config, db, modelfiles, settings, user } from '$lib/stores'; | ||||
| 	import { tick } from 'svelte'; | ||||
| 
 | ||||
| 	import toast from 'svelte-french-toast'; | ||||
|  | @ -16,9 +16,12 @@ | |||
| 	export let regenerateResponse: Function; | ||||
| 
 | ||||
| 	export let autoScroll; | ||||
| 	export let selectedModels; | ||||
| 	export let history = {}; | ||||
| 	export let messages = []; | ||||
| 
 | ||||
| 	export let selectedModelfile = null; | ||||
| 
 | ||||
| 	$: if (messages && messages.length > 0 && (messages.at(-1).done ?? false)) { | ||||
| 		(async () => { | ||||
| 			await tick(); | ||||
|  | @ -306,10 +309,18 @@ | |||
| {#if messages.length == 0} | ||||
| 	<div class="m-auto text-center max-w-md pb-56 px-2"> | ||||
| 		<div class="flex justify-center mt-8"> | ||||
| 			<img src="/ollama.png" class=" w-16 invert-[10%] dark:invert-[100%] rounded-full" /> | ||||
| 			{#if selectedModelfile && selectedModelfile.imageUrl} | ||||
| 				<img src={selectedModelfile?.imageUrl} class=" w-20 mb-2 rounded-full" /> | ||||
| 			{:else} | ||||
| 				<img src="/ollama.png" class=" w-16 invert-[10%] dark:invert-[100%] rounded-full" /> | ||||
| 			{/if} | ||||
| 		</div> | ||||
| 		<div class=" mt-1 text-2xl text-gray-800 dark:text-gray-100 font-semibold"> | ||||
| 			How can I help you today? | ||||
| 		<div class=" mt-2 text-2xl text-gray-800 dark:text-gray-100 font-semibold"> | ||||
| 			{#if selectedModelfile} | ||||
| 				{selectedModelfile.desc} | ||||
| 			{:else} | ||||
| 				How can I help you today? | ||||
| 			{/if} | ||||
| 		</div> | ||||
| 	</div> | ||||
| {:else} | ||||
|  | @ -332,6 +343,12 @@ | |||
| 									alt="User profile" | ||||
| 								/> | ||||
| 							{/if} | ||||
| 						{:else if selectedModelfile} | ||||
| 							<img | ||||
| 								src={selectedModelfile?.imageUrl ?? '/favicon.png'} | ||||
| 								class=" max-w-[28px] object-cover rounded-full" | ||||
| 								alt="Ollama profile" | ||||
| 							/> | ||||
| 						{:else} | ||||
| 							<img | ||||
| 								src="/favicon.png" | ||||
|  | @ -345,6 +362,8 @@ | |||
| 						<div class=" self-center font-bold mb-0.5"> | ||||
| 							{#if message.role === 'user'} | ||||
| 								You | ||||
| 							{:else if selectedModelfile} | ||||
| 								{selectedModelfile.title} | ||||
| 							{:else} | ||||
| 								Ollama <span class=" text-gray-500 text-sm font-medium" | ||||
| 									>{message.model ? ` ${message.model}` : ''}</span | ||||
|  |  | |||
|  | @ -7,17 +7,24 @@ | |||
| 	import { splitStream } from '$lib/utils'; | ||||
| 	import { goto } from '$app/navigation'; | ||||
| 
 | ||||
| 	import { config, user, settings, db, chats, chatId } from '$lib/stores'; | ||||
| 	import { config, modelfiles, user, settings, db, chats, chatId } from '$lib/stores'; | ||||
| 
 | ||||
| 	import MessageInput from '$lib/components/chat/MessageInput.svelte'; | ||||
| 	import Messages from '$lib/components/chat/Messages.svelte'; | ||||
| 	import ModelSelector from '$lib/components/chat/ModelSelector.svelte'; | ||||
| 	import Navbar from '$lib/components/layout/Navbar.svelte'; | ||||
| 	import { page } from '$app/stores'; | ||||
| 
 | ||||
| 	let stopResponseFlag = false; | ||||
| 	let autoScroll = true; | ||||
| 
 | ||||
| 	let selectedModels = ['']; | ||||
| 	let selectedModelfile = null; | ||||
| 	$: selectedModelfile = | ||||
| 		selectedModels.length === 1 && | ||||
| 		$modelfiles.filter((modelfile) => modelfile.tagName === selectedModels[0]).length > 0 | ||||
| 			? $modelfiles.filter((modelfile) => modelfile.tagName === selectedModels[0])[0] | ||||
| 			: null; | ||||
| 
 | ||||
| 	let title = ''; | ||||
| 	let prompt = ''; | ||||
|  | @ -64,7 +71,9 @@ | |||
| 			messages: {}, | ||||
| 			currentId: null | ||||
| 		}; | ||||
| 		selectedModels = $settings.models ?? ['']; | ||||
| 		selectedModels = $page.url.searchParams.get('models') | ||||
| 			? $page.url.searchParams.get('models')?.split(',') | ||||
| 			: $settings.models ?? ['']; | ||||
| 	}; | ||||
| 
 | ||||
| 	////////////////////////// | ||||
|  | @ -487,9 +496,42 @@ | |||
| 		</div> | ||||
| 
 | ||||
| 		<div class=" h-full mt-10 mb-32 w-full flex flex-col"> | ||||
| 			<Messages bind:history bind:messages bind:autoScroll {sendPrompt} {regenerateResponse} /> | ||||
| 			<Messages | ||||
| 				{selectedModels} | ||||
| 				{selectedModelfile} | ||||
| 				bind:history | ||||
| 				bind:messages | ||||
| 				bind:autoScroll | ||||
| 				{sendPrompt} | ||||
| 				{regenerateResponse} | ||||
| 			/> | ||||
| 		</div> | ||||
| 	</div> | ||||
| 
 | ||||
| 	<MessageInput bind:prompt bind:files bind:autoScroll {messages} {submitPrompt} {stopResponse} /> | ||||
| 	<MessageInput | ||||
| 		bind:prompt | ||||
| 		bind:files | ||||
| 		bind:autoScroll | ||||
| 		suggestionPrompts={selectedModelfile?.suggestionPrompts ?? [ | ||||
| 			{ | ||||
| 				title: ['Help me study', 'vocabulary for a college entrance exam'], | ||||
| 				content: `Help me study vocabulary: write a sentence for me to fill in the blank, and I'll try to pick the correct option.` | ||||
| 			}, | ||||
| 			{ | ||||
| 				title: ['Give me ideas', `for what to do with my kids' art`], | ||||
| 				content: `What are 5 creative things I could do with my kids' art? I don't want to throw them away, but it's also so much clutter.` | ||||
| 			}, | ||||
| 			{ | ||||
| 				title: ['Tell me a fun fact', 'about the Roman Empire'], | ||||
| 				content: 'Tell me a random fun fact about the Roman Empire' | ||||
| 			}, | ||||
| 			{ | ||||
| 				title: ['Show me a code snippet', `of a website's sticky header`], | ||||
| 				content: `Show me a code snippet of a website's sticky header in CSS and JavaScript.` | ||||
| 			} | ||||
| 		]} | ||||
| 		{messages} | ||||
| 		{submitPrompt} | ||||
| 		{stopResponse} | ||||
| 	/> | ||||
| </div> | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ | |||
| 	import { onMount, tick } from 'svelte'; | ||||
| 	import { convertMessagesToHistory, splitStream } from '$lib/utils'; | ||||
| 	import { goto } from '$app/navigation'; | ||||
| 	import { config, user, settings, db, chats, chatId } from '$lib/stores'; | ||||
| 	import { config, modelfiles, user, settings, db, chats, chatId } from '$lib/stores'; | ||||
| 
 | ||||
| 	import MessageInput from '$lib/components/chat/MessageInput.svelte'; | ||||
| 	import Messages from '$lib/components/chat/Messages.svelte'; | ||||
|  | @ -20,6 +20,12 @@ | |||
| 
 | ||||
| 	// let chatId = $page.params.id; | ||||
| 	let selectedModels = ['']; | ||||
| 	let selectedModelfile = null; | ||||
| 	$: selectedModelfile = | ||||
| 		selectedModels.length === 1 && | ||||
| 		$modelfiles.filter((modelfile) => modelfile.tagName === selectedModels[0]).length > 0 | ||||
| 			? $modelfiles.filter((modelfile) => modelfile.tagName === selectedModels[0])[0] | ||||
| 			: null; | ||||
| 
 | ||||
| 	let title = ''; | ||||
| 	let prompt = ''; | ||||
|  | @ -521,10 +527,42 @@ | |||
| 			</div> | ||||
| 
 | ||||
| 			<div class=" h-full mt-10 mb-32 w-full flex flex-col"> | ||||
| 				<Messages bind:history bind:messages bind:autoScroll {sendPrompt} {regenerateResponse} /> | ||||
| 				<Messages | ||||
| 					{selectedModels} | ||||
| 					{selectedModelfile} | ||||
| 					bind:history | ||||
| 					bind:messages | ||||
| 					bind:autoScroll | ||||
| 					{sendPrompt} | ||||
| 					{regenerateResponse} | ||||
| 				/> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 
 | ||||
| 		<MessageInput bind:prompt bind:autoScroll {messages} {submitPrompt} {stopResponse} /> | ||||
| 		<MessageInput | ||||
| 			bind:prompt | ||||
| 			bind:autoScroll | ||||
| 			suggestionPrompts={selectedModelfile?.suggestionPrompts ?? [ | ||||
| 				{ | ||||
| 					title: ['Help me study', 'vocabulary for a college entrance exam'], | ||||
| 					content: `Help me study vocabulary: write a sentence for me to fill in the blank, and I'll try to pick the correct option.` | ||||
| 				}, | ||||
| 				{ | ||||
| 					title: ['Give me ideas', `for what to do with my kids' art`], | ||||
| 					content: `What are 5 creative things I could do with my kids' art? I don't want to throw them away, but it's also so much clutter.` | ||||
| 				}, | ||||
| 				{ | ||||
| 					title: ['Tell me a fun fact', 'about the Roman Empire'], | ||||
| 					content: 'Tell me a random fun fact about the Roman Empire' | ||||
| 				}, | ||||
| 				{ | ||||
| 					title: ['Show me a code snippet', `of a website's sticky header`], | ||||
| 					content: `Show me a code snippet of a website's sticky header in CSS and JavaScript.` | ||||
| 				} | ||||
| 			]} | ||||
| 			{messages} | ||||
| 			{submitPrompt} | ||||
| 			{stopResponse} | ||||
| 		/> | ||||
| 	</div> | ||||
| {/if} | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Timothy J. Baek
						Timothy J. Baek