Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
chenpangpang
open-webui
Commits
587101da
Commit
587101da
authored
Dec 03, 2023
by
Timothy J. Baek
Browse files
feat: modelfile content linked to chat page
parent
12d7ae96
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
149 additions
and
129 deletions
+149
-129
src/lib/components/chat/MessageInput.svelte
src/lib/components/chat/MessageInput.svelte
+3
-3
src/lib/components/chat/MessageInput/Suggestions.svelte
src/lib/components/chat/MessageInput/Suggestions.svelte
+36
-115
src/lib/components/chat/Messages.svelte
src/lib/components/chat/Messages.svelte
+23
-4
src/routes/(app)/+page.svelte
src/routes/(app)/+page.svelte
+46
-4
src/routes/(app)/c/[id]/+page.svelte
src/routes/(app)/c/[id]/+page.svelte
+41
-3
No files found.
src/lib/components/chat/MessageInput.svelte
View file @
587101da
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
export let submitPrompt: Function;
export let submitPrompt: Function;
export let stopResponse: Function;
export let stopResponse: Function;
export let suggestion
s = 'true'
;
export let suggestion
Prompts = []
;
export let autoScroll = true;
export let autoScroll = true;
let filesInputElement;
let filesInputElement;
...
@@ -87,8 +87,8 @@
...
@@ -87,8 +87,8 @@
<div class="fixed bottom-0 w-full bg-white dark:bg-gray-800">
<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=" 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">
<div class="max-w-3xl px-2.5 pt-2.5 -mb-0.5 mx-auto inset-x-0">
{#if messages.length == 0 && suggestion
s !== 'false'
}
{#if messages.length == 0 && suggestion
Prompts.length !== 0
}
<Suggestions {submitPrompt} />
<Suggestions
{suggestionPrompts}
{submitPrompt} />
{/if}
{/if}
{#if autoScroll === false && messages.length > 0}
{#if autoScroll === false && messages.length > 0}
...
...
src/lib/components/chat/MessageInput/Suggestions.svelte
View file @
587101da
<script lang="ts">
<script lang="ts">
export let submitPrompt: Function;
export let submitPrompt: Function;
export let suggestionPrompts = [];
</script>
</script>
<div class=" grid sm:grid-cols-2 gap-2.5 mb-4 md:p-2 text-left">
<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
<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"
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={() => {
on:click={() => {
submitPrompt(
`Tell me a random fun fact about the Roman Empire`
);
submitPrompt(
prompt.content
);
}}
}}
>
>
<div class="flex flex-col text-left">
<div class="flex flex-col text-left self-center">
<div class="text-sm font-medium dark:text-gray-300">Tell me a fun fact</div>
{#if prompt.title}
<div class="text-sm text-gray-500">about the Roman Empire</div>
<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>
</div>
<div
<div
...
@@ -31,92 +38,6 @@
...
@@ -31,92 +38,6 @@
</svg>
</svg>
</div>
</div>
</button>
</button>
<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>
<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>
<div
{/each}
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>
src/lib/components/chat/Messages.svelte
View file @
587101da
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
import
auto_render
from
'
katex/dist/contrib/auto-render.mjs
'
;
import
auto_render
from
'
katex/dist/contrib/auto-render.mjs
'
;
import
'
katex/dist/katex.min.css
'
;
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
{
tick
}
from
'
svelte
'
;
import
toast
from
'
svelte-french-toast
'
;
import
toast
from
'
svelte-french-toast
'
;
...
@@ -16,9 +16,12 @@
...
@@ -16,9 +16,12 @@
export
let
regenerateResponse
:
Function
;
export
let
regenerateResponse
:
Function
;
export
let
autoScroll
;
export
let
autoScroll
;
export
let
selectedModels
;
export
let
history
=
{};
export
let
history
=
{};
export
let
messages
=
[];
export
let
messages
=
[];
export
let
selectedModelfile
=
null
;
$
:
if
(
messages
&&
messages
.
length
>
0
&&
(
messages
.
at
(
-
1
).
done
??
false
))
{
$
:
if
(
messages
&&
messages
.
length
>
0
&&
(
messages
.
at
(
-
1
).
done
??
false
))
{
(
async
()
=>
{
(
async
()
=>
{
await
tick
();
await
tick
();
...
@@ -306,10 +309,18 @@
...
@@ -306,10 +309,18 @@
{#if messages.length == 0}
{#if messages.length == 0}
<div
class=
"m-auto text-center max-w-md pb-56 px-2"
>
<div
class=
"m-auto text-center max-w-md pb-56 px-2"
>
<div
class=
"flex justify-center mt-8"
>
<div
class=
"flex justify-center mt-8"
>
{#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"
/>
<img
src=
"/ollama.png"
class=
" w-16 invert-[10%] dark:invert-[100%] rounded-full"
/>
{/if}
</div>
</div>
<div
class=
" mt-1 text-2xl text-gray-800 dark:text-gray-100 font-semibold"
>
<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?
How can I help you today?
{/if}
</div>
</div>
</div>
</div>
{:else}
{:else}
...
@@ -332,6 +343,12 @@
...
@@ -332,6 +343,12 @@
alt=
"User profile"
alt=
"User profile"
/>
/>
{/if}
{/if}
{:else if selectedModelfile}
<img
src=
{selectedModelfile?.imageUrl
??
'/
favicon.png
'}
class=
" max-w-[28px] object-cover rounded-full"
alt=
"Ollama profile"
/>
{:else}
{:else}
<img
<img
src=
"/favicon.png"
src=
"/favicon.png"
...
@@ -345,6 +362,8 @@
...
@@ -345,6 +362,8 @@
<div
class=
" self-center font-bold mb-0.5"
>
<div
class=
" self-center font-bold mb-0.5"
>
{#if message.role === 'user'}
{#if message.role === 'user'}
You
You
{:else if selectedModelfile}
{selectedModelfile.title}
{:else}
{:else}
Ollama
<span
class=
" text-gray-500 text-sm font-medium"
Ollama
<span
class=
" text-gray-500 text-sm font-medium"
>
{message.model ? ` ${message.model}` : ''}
</span
>
{message.model ? ` ${message.model}` : ''}
</span
...
...
src/routes/(app)/+page.svelte
View file @
587101da
...
@@ -7,17 +7,24 @@
...
@@ -7,17 +7,24 @@
import { splitStream } from '$lib/utils';
import { splitStream } from '$lib/utils';
import { goto } from '$app/navigation';
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 MessageInput from '$lib/components/chat/MessageInput.svelte';
import Messages from '$lib/components/chat/Messages.svelte';
import Messages from '$lib/components/chat/Messages.svelte';
import ModelSelector from '$lib/components/chat/ModelSelector.svelte';
import ModelSelector from '$lib/components/chat/ModelSelector.svelte';
import Navbar from '$lib/components/layout/Navbar.svelte';
import Navbar from '$lib/components/layout/Navbar.svelte';
import { page } from '$app/stores';
let stopResponseFlag = false;
let stopResponseFlag = false;
let autoScroll = true;
let autoScroll = true;
let selectedModels = [''];
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 title = '';
let prompt = '';
let prompt = '';
...
@@ -64,7 +71,9 @@
...
@@ -64,7 +71,9 @@
messages: {},
messages: {},
currentId: null
currentId: null
};
};
selectedModels = $settings.models ?? [''];
selectedModels = $page.url.searchParams.get('models')
? $page.url.searchParams.get('models')?.split(',')
: $settings.models ?? [''];
};
};
//////////////////////////
//////////////////////////
...
@@ -487,9 +496,42 @@
...
@@ -487,9 +496,42 @@
</div>
</div>
<div class=" h-full mt-10 mb-32 w-full flex flex-col">
<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>
</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>
</div>
src/routes/(app)/c/[id]/+page.svelte
View file @
587101da
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
import { onMount, tick } from 'svelte';
import { onMount, tick } from 'svelte';
import { convertMessagesToHistory, splitStream } from '$lib/utils';
import { convertMessagesToHistory, splitStream } from '$lib/utils';
import { goto } from '$app/navigation';
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 MessageInput from '$lib/components/chat/MessageInput.svelte';
import Messages from '$lib/components/chat/Messages.svelte';
import Messages from '$lib/components/chat/Messages.svelte';
...
@@ -20,6 +20,12 @@
...
@@ -20,6 +20,12 @@
// let chatId = $page.params.id;
// let chatId = $page.params.id;
let selectedModels = [''];
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 title = '';
let prompt = '';
let prompt = '';
...
@@ -521,10 +527,42 @@
...
@@ -521,10 +527,42 @@
</div>
</div>
<div class=" h-full mt-10 mb-32 w-full flex flex-col">
<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>
</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>
</div>
{/if}
{/if}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment