Adrien Denat victor HF staff julien-c HF staff coyotte508 HF staff commited on
Commit
2606dde
1 Parent(s): e5611df

Models selector (#164)

Browse files

Co-authored-by: Victor Mustar <victor.mustar@gmail.com>
Co-authored-by: Julien Chaumond <julien@huggingface.co>
Co-authored-by: coyotte508 <coyotte508@gmail.com>

.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
- MODELS=`["OpenAssistant/oasst-sft-4-pythia-12b-epoch-3.5"]`
9
- # Alternative syntax (all fields are optional except 'name'):
10
- # MODELS=`[{
11
- # "name": "OpenAssistant/oasst-sft-4-pythia-12b-epoch-3.5",
12
- # "displayName": "OpenAssistant/oasst-sft-4-pythia-12b-epoch-3.5",
13
- # "endpoints": [{
14
- # "url": "https://api-inference.huggingface.co/models/OpenAssistant/oasst-sft-4-pythia-12b-epoch-3.5",
15
- # "authorization": "Bearer hf_<token>",
16
- # "weight": 1
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(messages: Pick<Message, "from" | "content">[]): string {
 
 
 
16
  const prompt =
17
  messages
18
  .map(
19
  (m) =>
20
  (m.from === "user"
21
- ? PUBLIC_USER_MESSAGE_TOKEN + m.content
22
- : PUBLIC_ASSISTANT_MESSAGE_TOKEN + m.content) +
23
- (m.content.endsWith(PUBLIC_SEP_TOKEN) ? "" : PUBLIC_SEP_TOKEN)
 
 
 
 
24
  )
25
- .join("") + PUBLIC_ASSISTANT_MESSAGE_TOKEN;
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 { Settings } from "$lib/types/Settings";
8
 
9
- export let settings: Omit<Settings, "sessionId" | "createdAt" | "updatedAt">;
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 max-w-sm overflow-hidden rounded-2xl bg-white shadow-2xl md:-mt-20">
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">&nbsp;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">&nbsp;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 { PUBLIC_DISABLE_INTRO_TILES, PUBLIC_VERSION } from "$env/static/public";
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
- <div class="overflow-hidden rounded-xl border dark:border-gray-800">
31
- <div class="p-3">
32
- <div class="text-sm text-gray-600 dark:text-gray-400">Current Model</div>
33
- <div class="font-semibold">{currentModel.displayName}</div>
34
- </div>
35
- <div
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
- <a
39
- href="https://huggingface.co/{currentModel.name}"
40
- target="_blank"
41
- rel="noreferrer"
42
- class="flex items-center hover:underline"
43
- >
44
- <CarbonArrowUpRight class="mr-1.5 text-xs text-gray-400" />
45
- Model
46
- <div class="max-sm:hidden">&nbsp;page</div>
47
- </a>
48
- <a
49
- href="https://huggingface.co/datasets/OpenAssistant/oasst1"
50
- target="_blank"
51
- rel="noreferrer"
52
- class="flex items-center hover:underline"
53
- >
54
- <CarbonArrowUpRight class="mr-1.5 text-xs text-gray-400" />
55
- Dataset
56
- <div class="max-sm:hidden">&nbsp;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 PUBLIC_DISABLE_INTRO_TILES !== "true"}
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
- <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={() =>
78
- dispatch(
79
- "message",
80
- "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)"
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 "$env/static/public";
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: { name: string; displayName: string };
 
 
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
- <ChatIntroduction on:message {currentModel} />
 
 
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: { name: string; displayName: string };
 
 
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="15"
7
- height="8"
8
- viewBox="0 0 15 8"
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
- export const models = z
5
  .array(
6
- z.union([
7
- z.string().min(1),
8
- z.object({
9
- name: z.string().min(1),
10
- displayName: z.string().min(1).optional(),
11
- endpoints: z
12
- .array(
13
- z.object({
14
- url: z.string().url(),
15
- authorization: z.string().min(1).default(`Bearer ${HF_ACCESS_TOKEN}`),
16
- weight: z.number().int().positive().default(1),
17
- })
18
- )
19
- .optional(),
20
- }),
21
- ])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  )
23
  .parse(JSON.parse(MODELS));
24
 
25
- export const modelNames: Array<{ name: string; displayName: string }> = models.map((m) =>
26
- typeof m === "string"
27
- ? { name: m, displayName: m }
28
- : { name: m.name, displayName: m.displayName ?? m.name }
 
 
 
29
  );
30
- export const defaultModel = modelNames[0];
 
 
 
 
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 { modelNames } from "$lib/server/models";
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) => ({ id: conv._id.toString(), title: conv.title }))
 
 
 
 
27
  .toArray(),
28
  settings: {
29
  shareConversationsWithModelAuthors: settings?.shareConversationsWithModelAuthors ?? true,
30
  ethicsModalAcceptedAt: settings?.ethicsModalAcceptedAt ?? null,
 
 
31
  },
32
- models: modelNames,
 
 
 
 
 
 
 
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.models[0].name }),
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[0]}
 
 
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, modelNames } from "$lib/server/models";
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([modelNames[0].name, ...modelNames.slice(1).map((m) => m.name)])
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
- // Taken from https://huggingface.co/spaces/huggingface/open-assistant-private-testing/blob/main/app.py#L54
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[0]}
 
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
- const prompt = buildPrompt(messages);
 
 
 
 
 
 
 
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 in last message");
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
- temperature: 0.9,
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[0]}
 
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.js";
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
  },