Commit
•
2606dde
1
Parent(s):
e5611df
Models selector (#164)
Browse filesCo-authored-by: Victor Mustar <[email protected]>
Co-authored-by: Julien Chaumond <[email protected]>
Co-authored-by: coyotte508 <[email protected]>
- .env +60 -18
- src/lib/buildPrompt.ts +14 -17
- src/lib/components/AnnouncementBanner.svelte +15 -0
- src/lib/components/EthicsModal.svelte +2 -2
- src/lib/components/Modal.svelte +3 -1
- src/lib/components/ModelCardMetadata.svelte +48 -0
- src/lib/components/ModelsModal.svelte +78 -0
- src/lib/components/SettingsModal.svelte +3 -0
- src/lib/components/chat/ChatIntroduction.svelte +49 -71
- src/lib/components/chat/ChatMessage.svelte +1 -1
- src/lib/components/chat/ChatMessages.svelte +8 -2
- src/lib/components/chat/ChatWindow.svelte +7 -1
- src/lib/components/icons/IconChevron.svelte +3 -3
- src/lib/constants/publicSepToken.ts +1 -0
- src/lib/server/modelEndpoint.ts +1 -3
- src/lib/server/models.ts +47 -22
- src/lib/types/Model.ts +7 -0
- src/lib/types/Settings.ts +1 -0
- src/lib/utils/models.ts +4 -0
- src/routes/+layout.server.ts +19 -5
- src/routes/+page.svelte +5 -2
- src/routes/conversation/+server.ts +2 -2
- src/routes/conversation/[id]/+page.server.ts +1 -0
- src/routes/conversation/[id]/+page.svelte +6 -14
- src/routes/conversation/[id]/+server.ts +11 -4
- src/routes/conversation/[id]/summarize/+server.ts +3 -10
- src/routes/r/[id]/+page.server.ts +1 -0
- src/routes/r/[id]/+page.svelte +3 -1
- src/routes/settings/+page.server.ts +4 -1
- tailwind.config.cjs +1 -0
.env
CHANGED
@@ -5,25 +5,67 @@ MONGODB_URL=#your mongodb URL here
|
|
5 |
MONGODB_DB_NAME=chat-ui
|
6 |
COOKIE_NAME=hf-chat
|
7 |
HF_ACCESS_TOKEN=#hf_<token> from from https://huggingface.co/settings/token
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
|
20 |
-
# Increase depending on the model
|
21 |
-
PUBLIC_MAX_INPUT_TOKENS=1000
|
22 |
PUBLIC_ORIGIN=#https://hf.co
|
23 |
-
PUBLIC_DISABLE_INTRO_TILES=false
|
24 |
-
PUBLIC_USER_MESSAGE_TOKEN=<|prompter|>
|
25 |
-
PUBLIC_ASSISTANT_MESSAGE_TOKEN=<|assistant|>
|
26 |
-
PUBLIC_SEP_TOKEN=</s>
|
27 |
-
PUBLIC_PREPROMPT="Below are a series of dialogues between various people and an AI assistant. The AI tries to be helpful, polite, honest, sophisticated, emotionally aware, and humble-but-knowledgeable. The assistant is happy to help with almost anything, and will do its best to understand exactly what is needed. It also tries to avoid giving false or misleading information, and it caveats when it isn't entirely sure about the right answer. That said, the assistant is practical and really does its best, and doesn't let caution get too much in the way of being useful."
|
28 |
PUBLIC_GOOGLE_ANALYTICS_ID=#G-XXXXXXXX / Leave empty to disable
|
29 |
PUBLIC_DEPRECATED_GOOGLE_ANALYTICS_ID=#UA-XXXXXXXX-X / Leave empty to disable
|
|
|
5 |
MONGODB_DB_NAME=chat-ui
|
6 |
COOKIE_NAME=hf-chat
|
7 |
HF_ACCESS_TOKEN=#hf_<token> from from https://huggingface.co/settings/token
|
8 |
+
# 'name', 'userMessageToken', 'assistantMessageToken', 'parameters' are required
|
9 |
+
MODELS=`[
|
10 |
+
{
|
11 |
+
"name": "OpenAssistant/oasst-sft-4-pythia-12b-epoch-3.5",
|
12 |
+
"datasetName": "OpenAssistant/oasst1",
|
13 |
+
"websiteUrl": "https://open-assistant.io",
|
14 |
+
"userMessageToken": "<|prompter|>",
|
15 |
+
"assistantMessageToken": "<|assistant|>",
|
16 |
+
"preprompt": "Below are a series of dialogues between various people and an AI assistant. The AI tries to be helpful, polite, honest, sophisticated, emotionally aware, and humble-but-knowledgeable. The assistant is happy to help with almost anything, and will do its best to understand exactly what is needed. It also tries to avoid giving false or misleading information, and it caveats when it isn't entirely sure about the right answer. That said, the assistant is practical and really does its best, and doesn't let caution get too much in the way of being useful.\n-----\n",
|
17 |
+
"promptExamples": [
|
18 |
+
{
|
19 |
+
"title": "Write an email from bullet list",
|
20 |
+
"prompt": "As a restaurant owner, write a professional email to the supplier to get these products every week: \n\n- Wine (x10)\n- Eggs (x24)\n- Bread (x12)"
|
21 |
+
}, {
|
22 |
+
"title": "Code a snake game",
|
23 |
+
"prompt": "Code a basic snake game in python, give explanations for each step."
|
24 |
+
}, {
|
25 |
+
"title": "Assist in a task",
|
26 |
+
"prompt": "How do I make a delicious lemon cheesecake?"
|
27 |
+
}
|
28 |
+
],
|
29 |
+
"parameters": {
|
30 |
+
"temperature": 0.9,
|
31 |
+
"top_p": 0.95,
|
32 |
+
"repetition_penalty": 1.2,
|
33 |
+
"top_k": 50,
|
34 |
+
"truncate": 1000,
|
35 |
+
"max_new_tokens": 1024,
|
36 |
+
"stop":["</s>"]
|
37 |
+
}
|
38 |
+
},
|
39 |
+
{
|
40 |
+
"name":"bigcode/starcoder",
|
41 |
+
"displayName":"BigCode/StarCoder",
|
42 |
+
"datasetName":"bigcode/the-stack-dedup",
|
43 |
+
"websiteUrl":"https://www.bigcode-project.org/",
|
44 |
+
"prepromptUrl": "https://huggingface.co/datasets/coyotte508/bigcodeprompt/raw/main/prompt.txt",
|
45 |
+
"promptExamples": [
|
46 |
+
{
|
47 |
+
"title": "Write a code snippet",
|
48 |
+
"prompt": "How to install pytorch with cuda?"
|
49 |
+
}, {
|
50 |
+
"title": "Explain a technical concept",
|
51 |
+
"prompt": "What is a Dockerfile?"
|
52 |
+
}, {
|
53 |
+
"title": "Solve a technical task",
|
54 |
+
"prompt": "Write a functions that loads a file and filters line starting with \"Star\"?"
|
55 |
+
}
|
56 |
+
],
|
57 |
+
"userMessageToken": "\n\nHuman: ",
|
58 |
+
"assistantMessageToken": "\n\nAssistant: ",
|
59 |
+
"parameters": {
|
60 |
+
"temperature": 0.2,
|
61 |
+
"top_p": 0.9,
|
62 |
+
"repetition_penalty": 1.2,
|
63 |
+
"truncate": 8000,
|
64 |
+
"max_new_tokens": 2000
|
65 |
+
}
|
66 |
+
}
|
67 |
+
]`
|
68 |
|
|
|
|
|
69 |
PUBLIC_ORIGIN=#https://hf.co
|
|
|
|
|
|
|
|
|
|
|
70 |
PUBLIC_GOOGLE_ANALYTICS_ID=#G-XXXXXXXX / Leave empty to disable
|
71 |
PUBLIC_DEPRECATED_GOOGLE_ANALYTICS_ID=#UA-XXXXXXXX-X / Leave empty to disable
|
src/lib/buildPrompt.ts
CHANGED
@@ -1,10 +1,4 @@
|
|
1 |
-
import {
|
2 |
-
PUBLIC_ASSISTANT_MESSAGE_TOKEN,
|
3 |
-
PUBLIC_MAX_INPUT_TOKENS,
|
4 |
-
PUBLIC_PREPROMPT,
|
5 |
-
PUBLIC_SEP_TOKEN,
|
6 |
-
PUBLIC_USER_MESSAGE_TOKEN,
|
7 |
-
} from "$env/static/public";
|
8 |
import type { Message } from "./types/Message";
|
9 |
|
10 |
/**
|
@@ -12,22 +6,25 @@ import type { Message } from "./types/Message";
|
|
12 |
*
|
13 |
* <|assistant|>hi<|endoftext|><|prompter|>hello<|endoftext|><|assistant|>
|
14 |
*/
|
15 |
-
export function buildPrompt(
|
|
|
|
|
|
|
16 |
const prompt =
|
17 |
messages
|
18 |
.map(
|
19 |
(m) =>
|
20 |
(m.from === "user"
|
21 |
-
?
|
22 |
-
:
|
23 |
-
(
|
|
|
|
|
|
|
|
|
24 |
)
|
25 |
-
.join("") +
|
26 |
|
27 |
// Not super precise, but it's truncated in the model's backend anyway
|
28 |
-
return (
|
29 |
-
PUBLIC_PREPROMPT +
|
30 |
-
"\n-----\n" +
|
31 |
-
prompt.split(" ").slice(-parseInt(PUBLIC_MAX_INPUT_TOKENS)).join(" ")
|
32 |
-
);
|
33 |
}
|
|
|
1 |
+
import type { BackendModel } from "./server/models";
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
import type { Message } from "./types/Message";
|
3 |
|
4 |
/**
|
|
|
6 |
*
|
7 |
* <|assistant|>hi<|endoftext|><|prompter|>hello<|endoftext|><|assistant|>
|
8 |
*/
|
9 |
+
export function buildPrompt(
|
10 |
+
messages: Pick<Message, "from" | "content">[],
|
11 |
+
model: BackendModel
|
12 |
+
): string {
|
13 |
const prompt =
|
14 |
messages
|
15 |
.map(
|
16 |
(m) =>
|
17 |
(m.from === "user"
|
18 |
+
? model.userMessageToken + m.content
|
19 |
+
: model.assistantMessageToken + m.content) +
|
20 |
+
(model.parameters.stop
|
21 |
+
? m.content.endsWith(model.parameters.stop[0])
|
22 |
+
? ""
|
23 |
+
: model.parameters.stop[0]
|
24 |
+
: "")
|
25 |
)
|
26 |
+
.join("") + model.assistantMessageToken;
|
27 |
|
28 |
// Not super precise, but it's truncated in the model's backend anyway
|
29 |
+
return model.preprompt + prompt.split(" ").slice(-model.parameters.truncate).join(" ");
|
|
|
|
|
|
|
|
|
30 |
}
|
src/lib/components/AnnouncementBanner.svelte
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
export let title = "";
|
3 |
+
export let classNames = "";
|
4 |
+
</script>
|
5 |
+
|
6 |
+
<div class="flex items-center rounded-xl bg-gray-100 p-1 text-sm dark:bg-gray-800 {classNames}">
|
7 |
+
<span
|
8 |
+
class="mr-2 inline-flex items-center rounded-lg bg-gradient-to-br from-yellow-300 px-2 py-1 text-xxs font-medium uppercase leading-3 text-yellow-700 dark:from-[#373010] dark:text-yellow-400"
|
9 |
+
>New</span
|
10 |
+
>
|
11 |
+
{title}
|
12 |
+
<div class="ml-auto shrink-0">
|
13 |
+
<slot />
|
14 |
+
</div>
|
15 |
+
</div>
|
src/lib/components/EthicsModal.svelte
CHANGED
@@ -4,9 +4,9 @@
|
|
4 |
import { PUBLIC_VERSION } from "$env/static/public";
|
5 |
import Logo from "$lib/components/icons/Logo.svelte";
|
6 |
import Modal from "$lib/components/Modal.svelte";
|
7 |
-
import type {
|
8 |
|
9 |
-
export let settings:
|
10 |
</script>
|
11 |
|
12 |
<Modal>
|
|
|
4 |
import { PUBLIC_VERSION } from "$env/static/public";
|
5 |
import Logo from "$lib/components/icons/Logo.svelte";
|
6 |
import Modal from "$lib/components/Modal.svelte";
|
7 |
+
import type { LayoutData } from "../../routes/$types";
|
8 |
|
9 |
+
export let settings: LayoutData["settings"];
|
10 |
</script>
|
11 |
|
12 |
<Modal>
|
src/lib/components/Modal.svelte
CHANGED
@@ -1,13 +1,15 @@
|
|
1 |
<script lang="ts">
|
2 |
import { cubicOut } from "svelte/easing";
|
3 |
import { fade } from "svelte/transition";
|
|
|
|
|
4 |
</script>
|
5 |
|
6 |
<div
|
7 |
transition:fade={{ easing: cubicOut, duration: 300 }}
|
8 |
class="fixed inset-0 z-40 flex items-center justify-center bg-black/80 p-8 backdrop-blur-sm dark:bg-black/50"
|
9 |
>
|
10 |
-
<div class="-mt-10
|
11 |
<slot />
|
12 |
</div>
|
13 |
</div>
|
|
|
1 |
<script lang="ts">
|
2 |
import { cubicOut } from "svelte/easing";
|
3 |
import { fade } from "svelte/transition";
|
4 |
+
|
5 |
+
export let width = "max-w-sm";
|
6 |
</script>
|
7 |
|
8 |
<div
|
9 |
transition:fade={{ easing: cubicOut, duration: 300 }}
|
10 |
class="fixed inset-0 z-40 flex items-center justify-center bg-black/80 p-8 backdrop-blur-sm dark:bg-black/50"
|
11 |
>
|
12 |
+
<div class="-mt-10 overflow-hidden rounded-2xl bg-white shadow-2xl md:-mt-20 {width}">
|
13 |
<slot />
|
14 |
</div>
|
15 |
</div>
|
src/lib/components/ModelCardMetadata.svelte
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import CarbonEarth from "~icons/carbon/earth";
|
3 |
+
import CarbonArrowUpRight from "~icons/carbon/arrow-up-right";
|
4 |
+
import type { Model } from "$lib/types/Model";
|
5 |
+
|
6 |
+
export let model: Pick<Model, "name" | "datasetName" | "websiteUrl">;
|
7 |
+
|
8 |
+
export let variant: "light" | "dark" = "light";
|
9 |
+
</script>
|
10 |
+
|
11 |
+
<div
|
12 |
+
class="flex items-center gap-5 rounded-xl bg-gray-100 px-3 py-2 text-sm
|
13 |
+
{variant === 'dark'
|
14 |
+
? 'text-gray-600 dark:bg-gray-800 dark:text-gray-300'
|
15 |
+
: 'text-gray-800 dark:bg-gray-100 dark:text-gray-600'}"
|
16 |
+
>
|
17 |
+
<a
|
18 |
+
href="https://huggingface.co/datasets/{model.name}"
|
19 |
+
target="_blank"
|
20 |
+
rel="noreferrer"
|
21 |
+
class="flex items-center hover:underline"
|
22 |
+
><CarbonArrowUpRight class="mr-1.5 shrink-0 text-xs text-gray-400" />
|
23 |
+
Model
|
24 |
+
<div class="max-sm:hidden"> page</div></a
|
25 |
+
>
|
26 |
+
{#if model.datasetName}
|
27 |
+
<a
|
28 |
+
href="https://huggingface.co/datasets/{model.datasetName}"
|
29 |
+
target="_blank"
|
30 |
+
rel="noreferrer"
|
31 |
+
class="flex items-center hover:underline"
|
32 |
+
><CarbonArrowUpRight class="mr-1.5 shrink-0 text-xs text-gray-400" />
|
33 |
+
Dataset
|
34 |
+
<div class="max-sm:hidden"> page</div></a
|
35 |
+
>
|
36 |
+
{/if}
|
37 |
+
{#if model.websiteUrl}
|
38 |
+
<a
|
39 |
+
href={model.websiteUrl}
|
40 |
+
target="_blank"
|
41 |
+
class="ml-auto flex items-center hover:underline"
|
42 |
+
rel="noreferrer"
|
43 |
+
>
|
44 |
+
<CarbonEarth class="mr-1.5 shrink-0 text-xs text-gray-400" />
|
45 |
+
Website
|
46 |
+
</a>
|
47 |
+
{/if}
|
48 |
+
</div>
|
src/lib/components/ModelsModal.svelte
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import { createEventDispatcher } from "svelte";
|
3 |
+
|
4 |
+
import Modal from "$lib/components/Modal.svelte";
|
5 |
+
import CarbonClose from "~icons/carbon/close";
|
6 |
+
import CarbonCheckmark from "~icons/carbon/checkmark-filled";
|
7 |
+
import ModelCardMetadata from "./ModelCardMetadata.svelte";
|
8 |
+
import type { Model } from "$lib/types/Model";
|
9 |
+
import type { LayoutData } from "../../routes/$types";
|
10 |
+
import { enhance } from "$app/forms";
|
11 |
+
import { base } from "$app/paths";
|
12 |
+
|
13 |
+
export let settings: LayoutData["settings"];
|
14 |
+
export let models: Array<Model>;
|
15 |
+
|
16 |
+
let selectedModelName = settings.activeModel;
|
17 |
+
|
18 |
+
const dispatch = createEventDispatcher<{ close: void }>();
|
19 |
+
</script>
|
20 |
+
|
21 |
+
<Modal width="max-w-lg">
|
22 |
+
<form
|
23 |
+
action="{base}/settings"
|
24 |
+
method="post"
|
25 |
+
use:enhance={() => {
|
26 |
+
dispatch("close");
|
27 |
+
}}
|
28 |
+
class="flex w-full flex-col gap-5 p-6"
|
29 |
+
>
|
30 |
+
{#each Object.entries(settings).filter(([k]) => k !== "activeModel") as [key, val]}
|
31 |
+
<input type="hidden" name={key} value={val} />
|
32 |
+
{/each}
|
33 |
+
<div class="flex items-start justify-between text-xl font-semibold text-gray-800">
|
34 |
+
<h2>Models</h2>
|
35 |
+
<button type="button" class="group" on:click={() => dispatch("close")}>
|
36 |
+
<CarbonClose class="text-gray-900 group-hover:text-gray-500" />
|
37 |
+
</button>
|
38 |
+
</div>
|
39 |
+
|
40 |
+
<div class="space-y-4">
|
41 |
+
{#each models as model}
|
42 |
+
<div
|
43 |
+
class="rounded-xl border border-gray-100 {model.name === selectedModelName
|
44 |
+
? 'bg-gradient-to-r from-yellow-200/40 via-yellow-500/10'
|
45 |
+
: ''}"
|
46 |
+
>
|
47 |
+
<label class="group flex cursor-pointer p-3" on:change aria-label={model.displayName}>
|
48 |
+
<input
|
49 |
+
type="radio"
|
50 |
+
class="sr-only"
|
51 |
+
name="activeModel"
|
52 |
+
value={model.name}
|
53 |
+
bind:group={selectedModelName}
|
54 |
+
/>
|
55 |
+
<span>
|
56 |
+
<span class="text-md block font-semibold leading-tight text-gray-800"
|
57 |
+
>{model.displayName}</span
|
58 |
+
>
|
59 |
+
<span class="text-xs text-[#9FA8B5]">A good alternative to ChatGPT</span>
|
60 |
+
</span>
|
61 |
+
<CarbonCheckmark
|
62 |
+
class="-mr-1 -mt-1 ml-auto shrink-0 text-xl {model.name === selectedModelName
|
63 |
+
? 'text-yellow-400'
|
64 |
+
: 'text-transparent group-hover:text-gray-200'}"
|
65 |
+
/>
|
66 |
+
</label>
|
67 |
+
<ModelCardMetadata {model} />
|
68 |
+
</div>
|
69 |
+
{/each}
|
70 |
+
</div>
|
71 |
+
<button
|
72 |
+
type="submit"
|
73 |
+
class="mt-2 rounded-full bg-black px-5 py-2 text-lg font-semibold text-gray-100 ring-gray-400 ring-offset-1 transition-colors hover:ring"
|
74 |
+
>
|
75 |
+
Apply
|
76 |
+
</button>
|
77 |
+
</form>
|
78 |
+
</Modal>
|
src/lib/components/SettingsModal.svelte
CHANGED
@@ -30,6 +30,9 @@
|
|
30 |
</div>
|
31 |
|
32 |
<label class="flex cursor-pointer select-none items-center gap-2 text-gray-500">
|
|
|
|
|
|
|
33 |
<Switch
|
34 |
name="shareConversationsWithModelAuthors"
|
35 |
bind:checked={settings.shareConversationsWithModelAuthors}
|
|
|
30 |
</div>
|
31 |
|
32 |
<label class="flex cursor-pointer select-none items-center gap-2 text-gray-500">
|
33 |
+
{#each Object.entries(settings).filter(([k]) => k !== "shareConversationsWithModelAuthors") as [key, val]}
|
34 |
+
<input type="hidden" name={key} value={val} />
|
35 |
+
{/each}
|
36 |
<Switch
|
37 |
name="shareConversationsWithModelAuthors"
|
38 |
bind:checked={settings.shareConversationsWithModelAuthors}
|
src/lib/components/chat/ChatIntroduction.svelte
CHANGED
@@ -1,11 +1,23 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import {
|
3 |
import Logo from "$lib/components/icons/Logo.svelte";
|
4 |
-
import CarbonArrowUpRight from "~icons/carbon/arrow-up-right";
|
5 |
-
import CarbonEarth from "~icons/carbon/earth";
|
6 |
import { createEventDispatcher } from "svelte";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
|
8 |
-
export let currentModel: { name: string; displayName: string };
|
9 |
const dispatch = createEventDispatcher<{ message: string }>();
|
10 |
</script>
|
11 |
|
@@ -27,80 +39,46 @@
|
|
27 |
</div>
|
28 |
</div>
|
29 |
<div class="lg:col-span-2 lg:pl-24">
|
30 |
-
<
|
31 |
-
<
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
class="flex items-center gap-5 rounded-xl bg-gray-100 px-3 py-2 text-sm text-gray-600 dark:bg-gray-800 dark:text-gray-300"
|
37 |
>
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
Model
|
46 |
-
<div class="
|
47 |
-
</
|
48 |
-
<
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
>
|
54 |
-
<CarbonArrowUpRight class="mr-1.5 text-xs text-gray-400" />
|
55 |
-
Dataset
|
56 |
-
<div class="max-sm:hidden"> page</div>
|
57 |
-
</a>
|
58 |
-
<a
|
59 |
-
href="https://open-assistant.io/"
|
60 |
-
target="_blank"
|
61 |
-
class="ml-auto flex items-center hover:underline"
|
62 |
-
rel="noreferrer"
|
63 |
>
|
64 |
-
<CarbonEarth class="mr-1.5 text-xs text-gray-400" />
|
65 |
-
Open Assistant Website
|
66 |
-
</a>
|
67 |
</div>
|
|
|
68 |
</div>
|
69 |
</div>
|
70 |
-
{#if
|
71 |
<div class="lg:col-span-3 lg:mt-12">
|
72 |
<p class="mb-3 text-gray-600 dark:text-gray-300">Examples</p>
|
73 |
<div class="grid gap-3 lg:grid-cols-3 lg:gap-5">
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
dispatch(
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
"Write an email from bullet list"
|
84 |
-
</button>
|
85 |
-
<button
|
86 |
-
type="button"
|
87 |
-
class="rounded-xl border bg-gray-50 p-2.5 text-gray-600 hover:bg-gray-100 dark:border-gray-800 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700 sm:p-4"
|
88 |
-
on:click={() =>
|
89 |
-
dispatch(
|
90 |
-
"message",
|
91 |
-
"Code a basic snake game in python, give explanations for each step."
|
92 |
-
)}
|
93 |
-
>
|
94 |
-
"Code a snake game"
|
95 |
-
</button>
|
96 |
-
<button
|
97 |
-
type="button"
|
98 |
-
class="rounded-xl border bg-gray-50 p-2.5 text-gray-600 hover:bg-gray-100 dark:border-gray-800 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700 sm:p-4"
|
99 |
-
on:click={() => dispatch("message", "How do I make a delicious lemon cheesecake?")}
|
100 |
-
>
|
101 |
-
"Assist in a task"
|
102 |
-
</button>
|
103 |
</div>
|
104 |
-
</div>
|
105 |
-
{/if}
|
106 |
</div>
|
|
|
1 |
<script lang="ts">
|
2 |
+
import { PUBLIC_VERSION } from "$env/static/public";
|
3 |
import Logo from "$lib/components/icons/Logo.svelte";
|
|
|
|
|
4 |
import { createEventDispatcher } from "svelte";
|
5 |
+
import IconChevron from "$lib/components/icons/IconChevron.svelte";
|
6 |
+
import AnnouncementBanner from "../AnnouncementBanner.svelte";
|
7 |
+
import ModelsModal from "../ModelsModal.svelte";
|
8 |
+
import type { Model } from "$lib/types/Model";
|
9 |
+
import ModelCardMetadata from "../ModelCardMetadata.svelte";
|
10 |
+
import type { LayoutData } from "../../../routes/$types";
|
11 |
+
import { findCurrentModel } from "$lib/utils/models";
|
12 |
+
|
13 |
+
export let currentModel: Model;
|
14 |
+
export let settings: LayoutData["settings"];
|
15 |
+
export let models: Model[];
|
16 |
+
|
17 |
+
let isModelsModalOpen = false;
|
18 |
+
|
19 |
+
$: currentModelMetadata = findCurrentModel(models, settings.activeModel);
|
20 |
|
|
|
21 |
const dispatch = createEventDispatcher<{ message: string }>();
|
22 |
</script>
|
23 |
|
|
|
39 |
</div>
|
40 |
</div>
|
41 |
<div class="lg:col-span-2 lg:pl-24">
|
42 |
+
<AnnouncementBanner classNames="mb-4" title="BigCode/StarCoder is now available">
|
43 |
+
<button
|
44 |
+
type="button"
|
45 |
+
on:click={() => (isModelsModalOpen = true)}
|
46 |
+
class="mr-2 flex items-center underline hover:no-underline"
|
47 |
+
><IconChevron classNames="mr-1" /> Switch model</button
|
|
|
48 |
>
|
49 |
+
</AnnouncementBanner>
|
50 |
+
{#if isModelsModalOpen}
|
51 |
+
<ModelsModal {settings} {models} on:close={() => (isModelsModalOpen = false)} />
|
52 |
+
{/if}
|
53 |
+
<div class="overflow-hidden rounded-xl border dark:border-gray-800">
|
54 |
+
<div class="flex p-3">
|
55 |
+
<div>
|
56 |
+
<div class="text-sm text-gray-600 dark:text-gray-400">Current Model</div>
|
57 |
+
<div class="font-semibold">{currentModel.displayName}</div>
|
58 |
+
</div>
|
59 |
+
<button
|
60 |
+
type="button"
|
61 |
+
on:click={() => (isModelsModalOpen = true)}
|
62 |
+
class="btn ml-auto flex h-7 w-7 self-start rounded-full bg-gray-100 p-1 text-xs hover:bg-gray-100 dark:border-gray-600 dark:bg-gray-800 dark:hover:bg-gray-600"
|
63 |
+
><IconChevron /></button
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
>
|
|
|
|
|
|
|
65 |
</div>
|
66 |
+
<ModelCardMetadata variant="dark" model={currentModel} />
|
67 |
</div>
|
68 |
</div>
|
69 |
+
{#if currentModelMetadata.promptExamples}
|
70 |
<div class="lg:col-span-3 lg:mt-12">
|
71 |
<p class="mb-3 text-gray-600 dark:text-gray-300">Examples</p>
|
72 |
<div class="grid gap-3 lg:grid-cols-3 lg:gap-5">
|
73 |
+
{#each currentModelMetadata.promptExamples as example}
|
74 |
+
<button
|
75 |
+
type="button"
|
76 |
+
class="rounded-xl border bg-gray-50 p-2.5 text-gray-600 hover:bg-gray-100 dark:border-gray-800 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700 sm:p-4"
|
77 |
+
on:click={() => dispatch("message", example.prompt)}
|
78 |
+
>
|
79 |
+
{example.title}
|
80 |
+
</button>
|
81 |
+
{/each}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
</div>
|
83 |
+
</div>{/if}
|
|
|
84 |
</div>
|
src/lib/components/chat/ChatMessage.svelte
CHANGED
@@ -7,7 +7,7 @@
|
|
7 |
import CodeBlock from "../CodeBlock.svelte";
|
8 |
import IconLoading from "../icons/IconLoading.svelte";
|
9 |
import CarbonRotate360 from "~icons/carbon/rotate-360";
|
10 |
-
import { PUBLIC_SEP_TOKEN } from "$
|
11 |
|
12 |
function sanitizeMd(md: string) {
|
13 |
return md
|
|
|
7 |
import CodeBlock from "../CodeBlock.svelte";
|
8 |
import IconLoading from "../icons/IconLoading.svelte";
|
9 |
import CarbonRotate360 from "~icons/carbon/rotate-360";
|
10 |
+
import { PUBLIC_SEP_TOKEN } from "$lib/constants/publicSepToken";
|
11 |
|
12 |
function sanitizeMd(md: string) {
|
13 |
return md
|
src/lib/components/chat/ChatMessages.svelte
CHANGED
@@ -7,13 +7,17 @@
|
|
7 |
import ChatIntroduction from "./ChatIntroduction.svelte";
|
8 |
import ChatMessage from "./ChatMessage.svelte";
|
9 |
import { randomUUID } from "$lib/utils/randomUuid";
|
|
|
|
|
10 |
|
11 |
const dispatch = createEventDispatcher<{ retry: { id: Message["id"]; content: string } }>();
|
12 |
|
13 |
export let messages: Message[];
|
14 |
export let loading: boolean;
|
15 |
export let pending: boolean;
|
16 |
-
export let currentModel:
|
|
|
|
|
17 |
|
18 |
let chatContainer: HTMLElement;
|
19 |
|
@@ -41,7 +45,9 @@
|
|
41 |
on:retry={() => dispatch("retry", { id: message.id, content: message.content })}
|
42 |
/>
|
43 |
{:else}
|
44 |
-
|
|
|
|
|
45 |
{/each}
|
46 |
{#if pending}
|
47 |
<ChatMessage message={{ from: "assistant", content: "", id: randomUUID() }} />
|
|
|
7 |
import ChatIntroduction from "./ChatIntroduction.svelte";
|
8 |
import ChatMessage from "./ChatMessage.svelte";
|
9 |
import { randomUUID } from "$lib/utils/randomUuid";
|
10 |
+
import type { Model } from "$lib/types/Model";
|
11 |
+
import type { LayoutData } from "../../../routes/$types";
|
12 |
|
13 |
const dispatch = createEventDispatcher<{ retry: { id: Message["id"]; content: string } }>();
|
14 |
|
15 |
export let messages: Message[];
|
16 |
export let loading: boolean;
|
17 |
export let pending: boolean;
|
18 |
+
export let currentModel: Model;
|
19 |
+
export let settings: LayoutData["settings"];
|
20 |
+
export let models: Model[] | undefined;
|
21 |
|
22 |
let chatContainer: HTMLElement;
|
23 |
|
|
|
45 |
on:retry={() => dispatch("retry", { id: message.id, content: message.content })}
|
46 |
/>
|
47 |
{:else}
|
48 |
+
{#if models}
|
49 |
+
<ChatIntroduction {settings} {models} {currentModel} on:message />
|
50 |
+
{/if}
|
51 |
{/each}
|
52 |
{#if pending}
|
53 |
<ChatMessage message={{ from: "assistant", content: "", id: randomUUID() }} />
|
src/lib/components/chat/ChatWindow.svelte
CHANGED
@@ -8,12 +8,16 @@
|
|
8 |
import ChatMessages from "./ChatMessages.svelte";
|
9 |
import ChatInput from "./ChatInput.svelte";
|
10 |
import StopGeneratingBtn from "../StopGeneratingBtn.svelte";
|
|
|
|
|
11 |
|
12 |
export let messages: Message[] = [];
|
13 |
export let disabled = false;
|
14 |
export let loading = false;
|
15 |
export let pending = false;
|
16 |
-
export let currentModel:
|
|
|
|
|
17 |
|
18 |
let message: string;
|
19 |
|
@@ -35,7 +39,9 @@
|
|
35 |
<ChatMessages
|
36 |
{loading}
|
37 |
{pending}
|
|
|
38 |
{currentModel}
|
|
|
39 |
{messages}
|
40 |
on:message
|
41 |
on:retry={(ev) => {
|
|
|
8 |
import ChatMessages from "./ChatMessages.svelte";
|
9 |
import ChatInput from "./ChatInput.svelte";
|
10 |
import StopGeneratingBtn from "../StopGeneratingBtn.svelte";
|
11 |
+
import type { Model } from "$lib/types/Model";
|
12 |
+
import type { LayoutData } from "../../../routes/$types";
|
13 |
|
14 |
export let messages: Message[] = [];
|
15 |
export let disabled = false;
|
16 |
export let loading = false;
|
17 |
export let pending = false;
|
18 |
+
export let currentModel: Model;
|
19 |
+
export let models: Model[] | undefined = undefined;
|
20 |
+
export let settings: LayoutData["settings"];
|
21 |
|
22 |
let message: string;
|
23 |
|
|
|
39 |
<ChatMessages
|
40 |
{loading}
|
41 |
{pending}
|
42 |
+
{settings}
|
43 |
{currentModel}
|
44 |
+
{models}
|
45 |
{messages}
|
46 |
on:message
|
47 |
on:retry={(ev) => {
|
src/lib/components/icons/IconChevron.svelte
CHANGED
@@ -3,9 +3,9 @@
|
|
3 |
</script>
|
4 |
|
5 |
<svg
|
6 |
-
width="
|
7 |
-
height="
|
8 |
-
viewBox="0 0 15
|
9 |
class={classNames}
|
10 |
fill="none"
|
11 |
xmlns="http://www.w3.org/2000/svg"
|
|
|
3 |
</script>
|
4 |
|
5 |
<svg
|
6 |
+
width="1em"
|
7 |
+
height="1em"
|
8 |
+
viewBox="0 0 15 6"
|
9 |
class={classNames}
|
10 |
fill="none"
|
11 |
xmlns="http://www.w3.org/2000/svg"
|
src/lib/constants/publicSepToken.ts
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
export const PUBLIC_SEP_TOKEN = "</s>";
|
src/lib/server/modelEndpoint.ts
CHANGED
@@ -10,9 +10,7 @@ export function modelEndpoint(model: string): {
|
|
10 |
authorization: string;
|
11 |
weight: number;
|
12 |
} {
|
13 |
-
const modelDefinition = models.find(
|
14 |
-
(m) => m === model || (typeof m === "object" && m.name === model)
|
15 |
-
);
|
16 |
if (!modelDefinition) {
|
17 |
throw new Error(`Invalid model: ${model}`);
|
18 |
}
|
|
|
10 |
authorization: string;
|
11 |
weight: number;
|
12 |
} {
|
13 |
+
const modelDefinition = models.find((m) => m.name === model);
|
|
|
|
|
14 |
if (!modelDefinition) {
|
15 |
throw new Error(`Invalid model: ${model}`);
|
16 |
}
|
src/lib/server/models.ts
CHANGED
@@ -1,30 +1,55 @@
|
|
1 |
import { HF_ACCESS_TOKEN, MODELS } from "$env/static/private";
|
2 |
import { z } from "zod";
|
3 |
|
4 |
-
|
5 |
.array(
|
6 |
-
z.
|
7 |
-
z.string().min(1),
|
8 |
-
z.
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
)
|
23 |
.parse(JSON.parse(MODELS));
|
24 |
|
25 |
-
export const
|
26 |
-
|
27 |
-
|
28 |
-
|
|
|
|
|
|
|
29 |
);
|
30 |
-
|
|
|
|
|
|
|
|
1 |
import { HF_ACCESS_TOKEN, MODELS } from "$env/static/private";
|
2 |
import { z } from "zod";
|
3 |
|
4 |
+
const modelsRaw = z
|
5 |
.array(
|
6 |
+
z.object({
|
7 |
+
name: z.string().min(1),
|
8 |
+
displayName: z.string().min(1).optional(),
|
9 |
+
websiteUrl: z.string().url().optional(),
|
10 |
+
datasetName: z.string().min(1).optional(),
|
11 |
+
userMessageToken: z.string().min(1),
|
12 |
+
assistantMessageToken: z.string().min(1),
|
13 |
+
preprompt: z.string().default(""),
|
14 |
+
prepromptUrl: z.string().url().optional(),
|
15 |
+
promptExamples: z
|
16 |
+
.array(
|
17 |
+
z.object({
|
18 |
+
title: z.string().min(1),
|
19 |
+
prompt: z.string().min(1),
|
20 |
+
})
|
21 |
+
)
|
22 |
+
.optional(),
|
23 |
+
endpoints: z
|
24 |
+
.array(
|
25 |
+
z.object({
|
26 |
+
url: z.string().url(),
|
27 |
+
authorization: z.string().min(1).default(`Bearer ${HF_ACCESS_TOKEN}`),
|
28 |
+
weight: z.number().int().positive().default(1),
|
29 |
+
})
|
30 |
+
)
|
31 |
+
.optional(),
|
32 |
+
parameters: z
|
33 |
+
.object({
|
34 |
+
temperature: z.number().min(0).max(1),
|
35 |
+
truncate: z.number().int().positive(),
|
36 |
+
max_new_tokens: z.number().int().positive(),
|
37 |
+
stop: z.array(z.string()).min(1).optional(),
|
38 |
+
})
|
39 |
+
.passthrough(),
|
40 |
+
})
|
41 |
)
|
42 |
.parse(JSON.parse(MODELS));
|
43 |
|
44 |
+
export const models = await Promise.all(
|
45 |
+
modelsRaw.map(async (m) => ({
|
46 |
+
...m,
|
47 |
+
displayName: m.displayName || m.name,
|
48 |
+
preprompt: m.prepromptUrl ? await fetch(m.prepromptUrl).then((r) => r.text()) : m.preprompt,
|
49 |
+
promptExamples: m.promptExamples || [],
|
50 |
+
}))
|
51 |
);
|
52 |
+
|
53 |
+
export type BackendModel = (typeof models)[0];
|
54 |
+
|
55 |
+
export const defaultModel = models[0];
|
src/lib/types/Model.ts
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export interface Model {
|
2 |
+
name: string;
|
3 |
+
displayName?: string;
|
4 |
+
websiteUrl?: string;
|
5 |
+
datasetName?: string;
|
6 |
+
promptExamples?: Array<{ title: string; prompt: string }>;
|
7 |
+
}
|
src/lib/types/Settings.ts
CHANGED
@@ -10,4 +10,5 @@ export interface Settings extends Timestamps {
|
|
10 |
* */
|
11 |
shareConversationsWithModelAuthors: boolean;
|
12 |
ethicsModalAcceptedAt: Date | null;
|
|
|
13 |
}
|
|
|
10 |
* */
|
11 |
shareConversationsWithModelAuthors: boolean;
|
12 |
ethicsModalAcceptedAt: Date | null;
|
13 |
+
activeModel: string;
|
14 |
}
|
src/lib/utils/models.ts
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import type { Model } from "$lib/types/Model";
|
2 |
+
|
3 |
+
export const findCurrentModel = (models: Model[], name?: string) =>
|
4 |
+
models.find((m) => m.name === name) ?? models[0];
|
src/routes/+layout.server.ts
CHANGED
@@ -2,9 +2,9 @@ import type { LayoutServerLoad } from "./$types";
|
|
2 |
import { collections } from "$lib/server/database";
|
3 |
import type { Conversation } from "$lib/types/Conversation";
|
4 |
import { UrlDependency } from "$lib/types/UrlDependency";
|
5 |
-
import {
|
6 |
|
7 |
-
export const load: LayoutServerLoad = async ({ locals, depends }) => {
|
8 |
const { conversations } = collections;
|
9 |
|
10 |
depends(UrlDependency.ConversationList);
|
@@ -17,18 +17,32 @@ export const load: LayoutServerLoad = async ({ locals, depends }) => {
|
|
17 |
sessionId: locals.sessionId,
|
18 |
})
|
19 |
.sort({ updatedAt: -1 })
|
20 |
-
.project<Pick<Conversation, "title" | "_id" | "updatedAt" | "createdAt">>({
|
21 |
title: 1,
|
|
|
22 |
_id: 1,
|
23 |
updatedAt: 1,
|
24 |
createdAt: 1,
|
25 |
})
|
26 |
-
.map((conv) => ({
|
|
|
|
|
|
|
|
|
27 |
.toArray(),
|
28 |
settings: {
|
29 |
shareConversationsWithModelAuthors: settings?.shareConversationsWithModelAuthors ?? true,
|
30 |
ethicsModalAcceptedAt: settings?.ethicsModalAcceptedAt ?? null,
|
|
|
|
|
31 |
},
|
32 |
-
models:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
};
|
34 |
};
|
|
|
2 |
import { collections } from "$lib/server/database";
|
3 |
import type { Conversation } from "$lib/types/Conversation";
|
4 |
import { UrlDependency } from "$lib/types/UrlDependency";
|
5 |
+
import { defaultModel, models } from "$lib/server/models";
|
6 |
|
7 |
+
export const load: LayoutServerLoad = async ({ locals, depends, url }) => {
|
8 |
const { conversations } = collections;
|
9 |
|
10 |
depends(UrlDependency.ConversationList);
|
|
|
17 |
sessionId: locals.sessionId,
|
18 |
})
|
19 |
.sort({ updatedAt: -1 })
|
20 |
+
.project<Pick<Conversation, "title" | "model" | "_id" | "updatedAt" | "createdAt">>({
|
21 |
title: 1,
|
22 |
+
model: 1,
|
23 |
_id: 1,
|
24 |
updatedAt: 1,
|
25 |
createdAt: 1,
|
26 |
})
|
27 |
+
.map((conv) => ({
|
28 |
+
id: conv._id.toString(),
|
29 |
+
title: conv.title,
|
30 |
+
model: conv.model ?? defaultModel,
|
31 |
+
}))
|
32 |
.toArray(),
|
33 |
settings: {
|
34 |
shareConversationsWithModelAuthors: settings?.shareConversationsWithModelAuthors ?? true,
|
35 |
ethicsModalAcceptedAt: settings?.ethicsModalAcceptedAt ?? null,
|
36 |
+
activeModel:
|
37 |
+
url.searchParams.get("model") ?? settings?.activeModel ?? defaultModel.name,
|
38 |
},
|
39 |
+
models: models.map((model) => ({
|
40 |
+
name: model.name,
|
41 |
+
websiteUrl: model.websiteUrl,
|
42 |
+
datasetName: model.datasetName,
|
43 |
+
displayName: model.displayName,
|
44 |
+
promptExamples: model.promptExamples,
|
45 |
+
parameters: model.parameters,
|
46 |
+
})),
|
47 |
};
|
48 |
};
|
src/routes/+page.svelte
CHANGED
@@ -4,6 +4,7 @@
|
|
4 |
import ChatWindow from "$lib/components/chat/ChatWindow.svelte";
|
5 |
import { ERROR_MESSAGES, error } from "$lib/stores/errors";
|
6 |
import { pendingMessage } from "$lib/stores/pendingMessage";
|
|
|
7 |
|
8 |
export let data;
|
9 |
let loading = false;
|
@@ -16,7 +17,7 @@
|
|
16 |
headers: {
|
17 |
"Content-Type": "application/json",
|
18 |
},
|
19 |
-
body: JSON.stringify({ model: data.
|
20 |
});
|
21 |
|
22 |
if (!res.ok) {
|
@@ -44,5 +45,7 @@
|
|
44 |
<ChatWindow
|
45 |
on:message={(ev) => createConversation(ev.detail)}
|
46 |
{loading}
|
47 |
-
currentModel={data.models
|
|
|
|
|
48 |
/>
|
|
|
4 |
import ChatWindow from "$lib/components/chat/ChatWindow.svelte";
|
5 |
import { ERROR_MESSAGES, error } from "$lib/stores/errors";
|
6 |
import { pendingMessage } from "$lib/stores/pendingMessage";
|
7 |
+
import { findCurrentModel } from "$lib/utils/models.js";
|
8 |
|
9 |
export let data;
|
10 |
let loading = false;
|
|
|
17 |
headers: {
|
18 |
"Content-Type": "application/json",
|
19 |
},
|
20 |
+
body: JSON.stringify({ model: data.settings.activeModel }),
|
21 |
});
|
22 |
|
23 |
if (!res.ok) {
|
|
|
45 |
<ChatWindow
|
46 |
on:message={(ev) => createConversation(ev.detail)}
|
47 |
{loading}
|
48 |
+
currentModel={findCurrentModel(data.models, data.settings.activeModel)}
|
49 |
+
models={data.models}
|
50 |
+
settings={data.settings}
|
51 |
/>
|
src/routes/conversation/+server.ts
CHANGED
@@ -5,7 +5,7 @@ import { error, redirect } from "@sveltejs/kit";
|
|
5 |
import { base } from "$app/paths";
|
6 |
import { z } from "zod";
|
7 |
import type { Message } from "$lib/types/Message";
|
8 |
-
import { defaultModel,
|
9 |
|
10 |
export const POST: RequestHandler = async (input) => {
|
11 |
const body = await input.request.text();
|
@@ -17,7 +17,7 @@ export const POST: RequestHandler = async (input) => {
|
|
17 |
.object({
|
18 |
fromShare: z.string().optional(),
|
19 |
model: z
|
20 |
-
.enum([
|
21 |
.default(defaultModel.name),
|
22 |
})
|
23 |
.parse(JSON.parse(body));
|
|
|
5 |
import { base } from "$app/paths";
|
6 |
import { z } from "zod";
|
7 |
import type { Message } from "$lib/types/Message";
|
8 |
+
import { defaultModel, models } from "$lib/server/models";
|
9 |
|
10 |
export const POST: RequestHandler = async (input) => {
|
11 |
const body = await input.request.text();
|
|
|
17 |
.object({
|
18 |
fromShare: z.string().optional(),
|
19 |
model: z
|
20 |
+
.enum([models[0].name, ...models.slice(1).map((m) => m.name)])
|
21 |
.default(defaultModel.name),
|
22 |
})
|
23 |
.parse(JSON.parse(body));
|
src/routes/conversation/[id]/+page.server.ts
CHANGED
@@ -29,5 +29,6 @@ export const load: PageServerLoad = async (event) => {
|
|
29 |
return {
|
30 |
messages: conversation.messages,
|
31 |
title: conversation.title,
|
|
|
32 |
};
|
33 |
};
|
|
|
29 |
return {
|
30 |
messages: conversation.messages,
|
31 |
title: conversation.title,
|
32 |
+
model: conversation.model,
|
33 |
};
|
34 |
};
|
src/routes/conversation/[id]/+page.svelte
CHANGED
@@ -4,14 +4,14 @@
|
|
4 |
import { pendingMessageIdToRetry } from "$lib/stores/pendingMessageIdToRetry";
|
5 |
import { onMount } from "svelte";
|
6 |
import { page } from "$app/stores";
|
7 |
-
import { textGenerationStream } from "@huggingface/inference";
|
8 |
import { invalidate } from "$app/navigation";
|
9 |
import { base } from "$app/paths";
|
10 |
-
import { PUBLIC_MAX_INPUT_TOKENS, PUBLIC_SEP_TOKEN } from "$env/static/public";
|
11 |
import { shareConversation } from "$lib/shareConversation";
|
12 |
import { UrlDependency } from "$lib/types/UrlDependency";
|
13 |
import { ERROR_MESSAGES, error } from "$lib/stores/errors";
|
14 |
import { randomUUID } from "$lib/utils/randomUuid";
|
|
|
15 |
|
16 |
export let data;
|
17 |
|
@@ -36,16 +36,7 @@
|
|
36 |
model: $page.url.href,
|
37 |
inputs,
|
38 |
parameters: {
|
39 |
-
|
40 |
-
temperature: 0.9,
|
41 |
-
top_p: 0.95,
|
42 |
-
repetition_penalty: 1.2,
|
43 |
-
top_k: 50,
|
44 |
-
truncate: parseInt(PUBLIC_MAX_INPUT_TOKENS),
|
45 |
-
// @ts-expect-error this param is not available in @huggingface/inference
|
46 |
-
watermark: false,
|
47 |
-
max_new_tokens: 1024,
|
48 |
-
stop: [PUBLIC_SEP_TOKEN],
|
49 |
return_full_text: false,
|
50 |
},
|
51 |
},
|
@@ -53,7 +44,7 @@
|
|
53 |
id: messageId,
|
54 |
is_retry: isRetry,
|
55 |
use_cache: false,
|
56 |
-
}
|
57 |
);
|
58 |
|
59 |
for await (const output of response) {
|
@@ -181,5 +172,6 @@
|
|
181 |
on:retry={(message) => writeMessage(message.detail.content, message.detail.id)}
|
182 |
on:share={() => shareConversation($page.params.id, data.title)}
|
183 |
on:stop={() => (isAborted = true)}
|
184 |
-
currentModel={data.models
|
|
|
185 |
/>
|
|
|
4 |
import { pendingMessageIdToRetry } from "$lib/stores/pendingMessageIdToRetry";
|
5 |
import { onMount } from "svelte";
|
6 |
import { page } from "$app/stores";
|
7 |
+
import { textGenerationStream, type Options } from "@huggingface/inference";
|
8 |
import { invalidate } from "$app/navigation";
|
9 |
import { base } from "$app/paths";
|
|
|
10 |
import { shareConversation } from "$lib/shareConversation";
|
11 |
import { UrlDependency } from "$lib/types/UrlDependency";
|
12 |
import { ERROR_MESSAGES, error } from "$lib/stores/errors";
|
13 |
import { randomUUID } from "$lib/utils/randomUuid";
|
14 |
+
import { findCurrentModel } from "$lib/utils/models.js";
|
15 |
|
16 |
export let data;
|
17 |
|
|
|
36 |
model: $page.url.href,
|
37 |
inputs,
|
38 |
parameters: {
|
39 |
+
...data.models.find((m) => m.name === data.model)?.parameters,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
return_full_text: false,
|
41 |
},
|
42 |
},
|
|
|
44 |
id: messageId,
|
45 |
is_retry: isRetry,
|
46 |
use_cache: false,
|
47 |
+
} as Options
|
48 |
);
|
49 |
|
50 |
for await (const output of response) {
|
|
|
172 |
on:retry={(message) => writeMessage(message.detail.content, message.detail.id)}
|
173 |
on:share={() => shareConversation($page.params.id, data.title)}
|
174 |
on:stop={() => (isAborted = true)}
|
175 |
+
currentModel={findCurrentModel(data.models, data.model)}
|
176 |
+
settings={data.settings}
|
177 |
/>
|
src/routes/conversation/[id]/+server.ts
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
-
import { PUBLIC_SEP_TOKEN } from "$env/static/public";
|
2 |
import { buildPrompt } from "$lib/buildPrompt.js";
|
|
|
3 |
import { abortedGenerations } from "$lib/server/abortedGenerations.js";
|
4 |
import { collections } from "$lib/server/database.js";
|
5 |
import { modelEndpoint } from "$lib/server/modelEndpoint.js";
|
6 |
-
import { defaultModel } from "$lib/server/models.js";
|
7 |
import type { Message } from "$lib/types/Message.js";
|
8 |
import { concatUint8Arrays } from "$lib/utils/concatUint8Arrays.js";
|
9 |
import { streamToAsyncIterable } from "$lib/utils/streamToAsyncIterable";
|
@@ -67,7 +67,14 @@ export async function POST({ request, fetch, locals, params }) {
|
|
67 |
message.id = crypto.randomUUID();
|
68 |
}
|
69 |
}
|
70 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
|
72 |
const randomEndpoint = modelEndpoint(model);
|
73 |
|
@@ -189,7 +196,7 @@ async function parseGeneratedText(
|
|
189 |
}
|
190 |
|
191 |
if (lastIndex === -1) {
|
192 |
-
console.error("Could not parse
|
193 |
}
|
194 |
|
195 |
let lastMessage = message.slice(lastIndex).trim().slice("data:".length);
|
|
|
|
|
1 |
import { buildPrompt } from "$lib/buildPrompt.js";
|
2 |
+
import { PUBLIC_SEP_TOKEN } from "$lib/constants/publicSepToken.js";
|
3 |
import { abortedGenerations } from "$lib/server/abortedGenerations.js";
|
4 |
import { collections } from "$lib/server/database.js";
|
5 |
import { modelEndpoint } from "$lib/server/modelEndpoint.js";
|
6 |
+
import { defaultModel, models } from "$lib/server/models.js";
|
7 |
import type { Message } from "$lib/types/Message.js";
|
8 |
import { concatUint8Arrays } from "$lib/utils/concatUint8Arrays.js";
|
9 |
import { streamToAsyncIterable } from "$lib/utils/streamToAsyncIterable";
|
|
|
67 |
message.id = crypto.randomUUID();
|
68 |
}
|
69 |
}
|
70 |
+
|
71 |
+
const modelInfo = models.find((m) => m.name === model);
|
72 |
+
|
73 |
+
if (!modelInfo) {
|
74 |
+
throw error(400, "Model not availalbe anymore");
|
75 |
+
}
|
76 |
+
|
77 |
+
const prompt = buildPrompt(messages, modelInfo);
|
78 |
|
79 |
const randomEndpoint = modelEndpoint(model);
|
80 |
|
|
|
196 |
}
|
197 |
|
198 |
if (lastIndex === -1) {
|
199 |
+
console.error("Could not parse last message", message);
|
200 |
}
|
201 |
|
202 |
let lastMessage = message.slice(lastIndex).trim().slice("data:".length);
|
src/routes/conversation/[id]/summarize/+server.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
-
import { PUBLIC_MAX_INPUT_TOKENS, PUBLIC_SEP_TOKEN } from "$env/static/public";
|
2 |
import { buildPrompt } from "$lib/buildPrompt";
|
|
|
3 |
import { collections } from "$lib/server/database.js";
|
4 |
import { modelEndpoint } from "$lib/server/modelEndpoint.js";
|
5 |
import { defaultModel } from "$lib/server/models.js";
|
@@ -27,17 +27,10 @@ export async function POST({ params, locals, fetch }) {
|
|
27 |
`Please summarize the following message as a single sentence of less than 5 words:\n` +
|
28 |
firstMessage?.content;
|
29 |
|
30 |
-
const prompt = buildPrompt([{ from: "user", content: userPrompt }]);
|
31 |
|
32 |
const parameters = {
|
33 |
-
|
34 |
-
top_p: 0.95,
|
35 |
-
repetition_penalty: 1.2,
|
36 |
-
top_k: 50,
|
37 |
-
watermark: false,
|
38 |
-
max_new_tokens: 1024,
|
39 |
-
truncate: parseInt(PUBLIC_MAX_INPUT_TOKENS),
|
40 |
-
stop: [PUBLIC_SEP_TOKEN],
|
41 |
return_full_text: false,
|
42 |
};
|
43 |
|
|
|
|
|
1 |
import { buildPrompt } from "$lib/buildPrompt";
|
2 |
+
import { PUBLIC_SEP_TOKEN } from "$lib/constants/publicSepToken.js";
|
3 |
import { collections } from "$lib/server/database.js";
|
4 |
import { modelEndpoint } from "$lib/server/modelEndpoint.js";
|
5 |
import { defaultModel } from "$lib/server/models.js";
|
|
|
27 |
`Please summarize the following message as a single sentence of less than 5 words:\n` +
|
28 |
firstMessage?.content;
|
29 |
|
30 |
+
const prompt = buildPrompt([{ from: "user", content: userPrompt }], defaultModel);
|
31 |
|
32 |
const parameters = {
|
33 |
+
...defaultModel.parameters,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
return_full_text: false,
|
35 |
};
|
36 |
|
src/routes/r/[id]/+page.server.ts
CHANGED
@@ -14,5 +14,6 @@ export const load: PageServerLoad = async ({ params }) => {
|
|
14 |
return {
|
15 |
messages: conversation.messages,
|
16 |
title: conversation.title,
|
|
|
17 |
};
|
18 |
};
|
|
|
14 |
return {
|
15 |
messages: conversation.messages,
|
16 |
title: conversation.title,
|
17 |
+
model: conversation.model,
|
18 |
};
|
19 |
};
|
src/routes/r/[id]/+page.svelte
CHANGED
@@ -6,6 +6,7 @@
|
|
6 |
import { ERROR_MESSAGES, error } from "$lib/stores/errors";
|
7 |
import { pendingMessage } from "$lib/stores/pendingMessage";
|
8 |
import { pendingMessageIdToRetry } from "$lib/stores/pendingMessageIdToRetry";
|
|
|
9 |
import { share } from "$lib/utils/share";
|
10 |
import type { PageData } from "./$types";
|
11 |
|
@@ -71,6 +72,7 @@
|
|
71 |
})
|
72 |
.finally(() => (loading = false))}
|
73 |
messages={data.messages}
|
74 |
-
currentModel={data.models
|
|
|
75 |
{loading}
|
76 |
/>
|
|
|
6 |
import { ERROR_MESSAGES, error } from "$lib/stores/errors";
|
7 |
import { pendingMessage } from "$lib/stores/pendingMessage";
|
8 |
import { pendingMessageIdToRetry } from "$lib/stores/pendingMessageIdToRetry";
|
9 |
+
import { findCurrentModel } from "$lib/utils/models";
|
10 |
import { share } from "$lib/utils/share";
|
11 |
import type { PageData } from "./$types";
|
12 |
|
|
|
72 |
})
|
73 |
.finally(() => (loading = false))}
|
74 |
messages={data.messages}
|
75 |
+
currentModel={findCurrentModel(data.models, data.model)}
|
76 |
+
settings={data.settings}
|
77 |
{loading}
|
78 |
/>
|
src/routes/settings/+page.server.ts
CHANGED
@@ -1,7 +1,8 @@
|
|
1 |
import { base } from "$app/paths";
|
2 |
-
import { collections } from "$lib/server/database
|
3 |
import { redirect } from "@sveltejs/kit";
|
4 |
import { z } from "zod";
|
|
|
5 |
|
6 |
export const actions = {
|
7 |
default: async function ({ request, locals }) {
|
@@ -11,10 +12,12 @@ export const actions = {
|
|
11 |
.object({
|
12 |
shareConversationsWithModelAuthors: z.boolean({ coerce: true }).default(true),
|
13 |
ethicsModalAccepted: z.boolean({ coerce: true }).optional(),
|
|
|
14 |
})
|
15 |
.parse({
|
16 |
shareConversationsWithModelAuthors: formData.get("shareConversationsWithModelAuthors"),
|
17 |
ethicsModalAccepted: formData.get("ethicsModalAccepted"),
|
|
|
18 |
});
|
19 |
|
20 |
await collections.settings.updateOne(
|
|
|
1 |
import { base } from "$app/paths";
|
2 |
+
import { collections } from "$lib/server/database";
|
3 |
import { redirect } from "@sveltejs/kit";
|
4 |
import { z } from "zod";
|
5 |
+
import { defaultModel, models } from "$lib/server/models";
|
6 |
|
7 |
export const actions = {
|
8 |
default: async function ({ request, locals }) {
|
|
|
12 |
.object({
|
13 |
shareConversationsWithModelAuthors: z.boolean({ coerce: true }).default(true),
|
14 |
ethicsModalAccepted: z.boolean({ coerce: true }).optional(),
|
15 |
+
activeModel: z.enum([models[0].name, ...models.slice(1).map((m) => m.name)]),
|
16 |
})
|
17 |
.parse({
|
18 |
shareConversationsWithModelAuthors: formData.get("shareConversationsWithModelAuthors"),
|
19 |
ethicsModalAccepted: formData.get("ethicsModalAccepted"),
|
20 |
+
activeModel: formData.get("activeModel") ?? defaultModel.name,
|
21 |
});
|
22 |
|
23 |
await collections.settings.updateOne(
|
tailwind.config.cjs
CHANGED
@@ -10,6 +10,7 @@ export default {
|
|
10 |
// sans: ['"Inter"', ...defaultTheme.fontFamily.sans]
|
11 |
// },
|
12 |
fontSize: {
|
|
|
13 |
smd: "0.94rem",
|
14 |
},
|
15 |
},
|
|
|
10 |
// sans: ['"Inter"', ...defaultTheme.fontFamily.sans]
|
11 |
// },
|
12 |
fontSize: {
|
13 |
+
xxs: "0.625rem",
|
14 |
smd: "0.94rem",
|
15 |
},
|
16 |
},
|