Spaces:
				
			
			
	
			
			
		Paused
		
	
	
	
			
			
	
	
	
	
		
		
		Paused
		
	Disable models (#187)
Browse files* add ability for a model to be disabled
* fallback to default model if user has invalid/disabled model in settings
* set conversations to read-only if conv model is disabled
* add better disabled state on chat input
* fix inverted if statement
* remove bigcode from .env
* fix not updating settings
Co-authored-by: Eliott C. <coyotte508@gmail.com>
* refactor solution to use an OLD_MODELS env var instead
* OLD_MODELS needs to be in .env but can be empty
* fix typing issue + typo
* refactor models validation
* old models displayName is optional
* set read only prop on user message not assistant messages
* remove console.log
* ♻️ Refacto isReadOnly
* 🩹 Fluff: use 410 http code
---------
Co-authored-by: Eliott C. <coyotte508@gmail.com>
- .env +1 -30
 - src/lib/buildPrompt.ts +7 -1
 - src/lib/components/chat/ChatIntroduction.svelte +8 -15
 - src/lib/components/chat/ChatMessage.svelte +12 -9
 - src/lib/components/chat/ChatMessages.svelte +4 -4
 - src/lib/components/chat/ChatWindow.svelte +8 -4
 - src/lib/server/models.ts +22 -2
 - src/lib/utils/models.ts +2 -8
 - src/routes/+layout.server.ts +11 -2
 - src/routes/+page.svelte +1 -1
 - src/routes/conversation/+server.ts +1 -2
 - src/routes/conversation/[id]/+page.svelte +2 -1
 - src/routes/conversation/[id]/+server.ts +3 -3
 - src/routes/r/[id]/+page.svelte +1 -0
 - src/routes/settings/+page.server.ts +1 -2
 
    	
        .env
    CHANGED
    
    | 
         @@ -41,38 +41,9 @@ MODELS=`[ 
     | 
|
| 41 | 
         
             
                  "truncate": 1000,
         
     | 
| 42 | 
         
             
                  "max_new_tokens": 1024
         
     | 
| 43 | 
         
             
                }
         
     | 
| 44 | 
         
            -
              },
         
     | 
| 45 | 
         
            -
              {
         
     | 
| 46 | 
         
            -
                "name":"bigcode/starcoderbase",
         
     | 
| 47 | 
         
            -
                "displayName":"BigCode/StarCoderBase",
         
     | 
| 48 | 
         
            -
                "datasetName":"bigcode/the-stack-dedup",
         
     | 
| 49 | 
         
            -
                "description": "A good model for answering technical questions",
         
     | 
| 50 | 
         
            -
                "websiteUrl":"https://huggingface.co/bigcode/",
         
     | 
| 51 | 
         
            -
                "prepromptUrl": "https://huggingface.co/datasets/coyotte508/bigcodeprompt/raw/main/prompt.txt",
         
     | 
| 52 | 
         
            -
                "promptExamples": [
         
     | 
| 53 | 
         
            -
                  {
         
     | 
| 54 | 
         
            -
                    "title": "Write a code snippet",
         
     | 
| 55 | 
         
            -
                    "prompt": "Write a function that loads a file and filters line starting with \"Star\"?"
         
     | 
| 56 | 
         
            -
                  }, {
         
     | 
| 57 | 
         
            -
                    "title": "Explain a technical concept",
         
     | 
| 58 | 
         
            -
                    "prompt": "What is a Dockerfile?"
         
     | 
| 59 | 
         
            -
                  }, {
         
     | 
| 60 | 
         
            -
                    "title": "Solve a technical task",
         
     | 
| 61 | 
         
            -
                    "prompt": "How to install pytorch with cuda?"
         
     | 
| 62 | 
         
            -
                  }
         
     | 
| 63 | 
         
            -
                ],
         
     | 
| 64 | 
         
            -
                "userMessageToken": "\n\nHuman: ",
         
     | 
| 65 | 
         
            -
                "assistantMessageToken": "\n\nAssistant:",
         
     | 
| 66 | 
         
            -
                "parameters": {
         
     | 
| 67 | 
         
            -
                  "temperature": 0.1,
         
     | 
| 68 | 
         
            -
                  "top_p": 0.9,
         
     | 
| 69 | 
         
            -
                  "repetition_penalty": 1.2,
         
     | 
| 70 | 
         
            -
                  "truncate": 8000,
         
     | 
| 71 | 
         
            -
                  "max_new_tokens": 2000,
         
     | 
| 72 | 
         
            -
                  "stop": ["Human:", "-----", "Assistant:"]
         
     | 
| 73 | 
         
            -
                }
         
     | 
| 74 | 
         
             
              }
         
     | 
| 75 | 
         
             
            ]`
         
     | 
| 
         | 
|
| 76 | 
         | 
| 77 | 
         
             
            PUBLIC_ORIGIN=#https://hf.co
         
     | 
| 78 | 
         
             
            PUBLIC_GOOGLE_ANALYTICS_ID=#G-XXXXXXXX / Leave empty to disable
         
     | 
| 
         | 
|
| 41 | 
         
             
                  "truncate": 1000,
         
     | 
| 42 | 
         
             
                  "max_new_tokens": 1024
         
     | 
| 43 | 
         
             
                }
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 44 | 
         
             
              }
         
     | 
| 45 | 
         
             
            ]`
         
     | 
| 46 | 
         
            +
            OLD_MODELS=`[]`# any removed models, `{ name: string, displayName?: string, id?: string }`
         
     | 
| 47 | 
         | 
| 48 | 
         
             
            PUBLIC_ORIGIN=#https://hf.co
         
     | 
| 49 | 
         
             
            PUBLIC_GOOGLE_ANALYTICS_ID=#G-XXXXXXXX / Leave empty to disable
         
     | 
    	
        src/lib/buildPrompt.ts
    CHANGED
    
    | 
         @@ -26,5 +26,11 @@ export function buildPrompt( 
     | 
|
| 26 | 
         
             
            			.join("") + model.assistantMessageToken;
         
     | 
| 27 | 
         | 
| 28 | 
         
             
            	// Not super precise, but it's truncated in the model's backend anyway
         
     | 
| 29 | 
         
            -
            	return  
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 30 | 
         
             
            }
         
     | 
| 
         | 
|
| 26 | 
         
             
            			.join("") + model.assistantMessageToken;
         
     | 
| 27 | 
         | 
| 28 | 
         
             
            	// Not super precise, but it's truncated in the model's backend anyway
         
     | 
| 29 | 
         
            +
            	return (
         
     | 
| 30 | 
         
            +
            		model.preprompt +
         
     | 
| 31 | 
         
            +
            		prompt
         
     | 
| 32 | 
         
            +
            			.split(" ")
         
     | 
| 33 | 
         
            +
            			.slice(-(model.parameters?.truncate ?? 0))
         
     | 
| 34 | 
         
            +
            			.join(" ")
         
     | 
| 35 | 
         
            +
            	);
         
     | 
| 36 | 
         
             
            }
         
     | 
    	
        src/lib/components/chat/ChatIntroduction.svelte
    CHANGED
    
    | 
         @@ -3,7 +3,6 @@ 
     | 
|
| 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";
         
     | 
| 
         @@ -39,14 +38,6 @@ 
     | 
|
| 39 | 
         
             
            		</div>
         
     | 
| 40 | 
         
             
            	</div>
         
     | 
| 41 | 
         
             
            	<div class="lg:col-span-2 lg:pl-24">
         
     | 
| 42 | 
         
            -
            		<AnnouncementBanner classNames="mb-4" title="BigCode/StarCoderBase 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}
         
     | 
| 
         @@ -56,12 +47,14 @@ 
     | 
|
| 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 | 
         
            -
            				 
     | 
| 60 | 
         
            -
            					 
     | 
| 61 | 
         
            -
             
     | 
| 62 | 
         
            -
             
     | 
| 63 | 
         
            -
             
     | 
| 64 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 65 | 
         
             
            			</div>
         
     | 
| 66 | 
         
             
            			<ModelCardMetadata variant="dark" model={currentModel} />
         
     | 
| 67 | 
         
             
            		</div>
         
     | 
| 
         | 
|
| 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 ModelsModal from "../ModelsModal.svelte";
         
     | 
| 7 | 
         
             
            	import type { Model } from "$lib/types/Model";
         
     | 
| 8 | 
         
             
            	import ModelCardMetadata from "../ModelCardMetadata.svelte";
         
     | 
| 
         | 
|
| 38 | 
         
             
            		</div>
         
     | 
| 39 | 
         
             
            	</div>
         
     | 
| 40 | 
         
             
            	<div class="lg:col-span-2 lg:pl-24">
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 41 | 
         
             
            		{#if isModelsModalOpen}
         
     | 
| 42 | 
         
             
            			<ModelsModal {settings} {models} on:close={() => (isModelsModalOpen = false)} />
         
     | 
| 43 | 
         
             
            		{/if}
         
     | 
| 
         | 
|
| 47 | 
         
             
            					<div class="text-sm text-gray-600 dark:text-gray-400">Current Model</div>
         
     | 
| 48 | 
         
             
            					<div class="font-semibold">{currentModel.displayName}</div>
         
     | 
| 49 | 
         
             
            				</div>
         
     | 
| 50 | 
         
            +
            				{#if models.length > 1}
         
     | 
| 51 | 
         
            +
            					<button
         
     | 
| 52 | 
         
            +
            						type="button"
         
     | 
| 53 | 
         
            +
            						on:click={() => (isModelsModalOpen = true)}
         
     | 
| 54 | 
         
            +
            						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"
         
     | 
| 55 | 
         
            +
            						><IconChevron /></button
         
     | 
| 56 | 
         
            +
            					>
         
     | 
| 57 | 
         
            +
            				{/if}
         
     | 
| 58 | 
         
             
            			</div>
         
     | 
| 59 | 
         
             
            			<ModelCardMetadata variant="dark" model={currentModel} />
         
     | 
| 60 | 
         
             
            		</div>
         
     | 
    	
        src/lib/components/chat/ChatMessage.svelte
    CHANGED
    
    | 
         @@ -23,7 +23,7 @@ 
     | 
|
| 23 | 
         
             
            			.replaceAll("<", "<")
         
     | 
| 24 | 
         
             
            			.trim();
         
     | 
| 25 | 
         | 
| 26 | 
         
            -
            		for (const stop of [...(model.parameters 
     | 
| 27 | 
         
             
            			if (ret.endsWith(stop)) {
         
     | 
| 28 | 
         
             
            				ret = ret.slice(0, -stop.length).trim();
         
     | 
| 29 | 
         
             
            			}
         
     | 
| 
         @@ -38,6 +38,7 @@ 
     | 
|
| 38 | 
         
             
            	export let model: Model;
         
     | 
| 39 | 
         
             
            	export let message: Message;
         
     | 
| 40 | 
         
             
            	export let loading = false;
         
     | 
| 
         | 
|
| 41 | 
         | 
| 42 | 
         
             
            	const dispatch = createEventDispatcher<{ retry: void }>();
         
     | 
| 43 | 
         | 
| 
         @@ -131,14 +132,16 @@ 
     | 
|
| 131 | 
         
             
            						<CarbonDownload />
         
     | 
| 132 | 
         
             
            					</a>
         
     | 
| 133 | 
         
             
            				{/if}
         
     | 
| 134 | 
         
            -
            				 
     | 
| 135 | 
         
            -
            					 
     | 
| 136 | 
         
            -
             
     | 
| 137 | 
         
            -
             
     | 
| 138 | 
         
            -
             
     | 
| 139 | 
         
            -
             
     | 
| 140 | 
         
            -
            					 
     | 
| 141 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 142 | 
         
             
            			</div>
         
     | 
| 143 | 
         
             
            		{/if}
         
     | 
| 144 | 
         
             
            	</div>
         
     | 
| 
         | 
|
| 23 | 
         
             
            			.replaceAll("<", "<")
         
     | 
| 24 | 
         
             
            			.trim();
         
     | 
| 25 | 
         | 
| 26 | 
         
            +
            		for (const stop of [...(model.parameters?.stop ?? []), "<|endoftext|>"]) {
         
     | 
| 27 | 
         
             
            			if (ret.endsWith(stop)) {
         
     | 
| 28 | 
         
             
            				ret = ret.slice(0, -stop.length).trim();
         
     | 
| 29 | 
         
             
            			}
         
     | 
| 
         | 
|
| 38 | 
         
             
            	export let model: Model;
         
     | 
| 39 | 
         
             
            	export let message: Message;
         
     | 
| 40 | 
         
             
            	export let loading = false;
         
     | 
| 41 | 
         
            +
            	export let readOnly = false;
         
     | 
| 42 | 
         | 
| 43 | 
         
             
            	const dispatch = createEventDispatcher<{ retry: void }>();
         
     | 
| 44 | 
         | 
| 
         | 
|
| 132 | 
         
             
            						<CarbonDownload />
         
     | 
| 133 | 
         
             
            					</a>
         
     | 
| 134 | 
         
             
            				{/if}
         
     | 
| 135 | 
         
            +
            				{#if !readOnly}
         
     | 
| 136 | 
         
            +
            					<button
         
     | 
| 137 | 
         
            +
            						class="cursor-pointer rounded-lg border border-gray-100 p-1 text-xs text-gray-400 group-hover:block hover:text-gray-500 dark:border-gray-800 dark:text-gray-400 dark:hover:text-gray-300 md:hidden lg:-right-2"
         
     | 
| 138 | 
         
            +
            						title="Retry"
         
     | 
| 139 | 
         
            +
            						type="button"
         
     | 
| 140 | 
         
            +
            						on:click={() => dispatch("retry")}
         
     | 
| 141 | 
         
            +
            					>
         
     | 
| 142 | 
         
            +
            						<CarbonRotate360 />
         
     | 
| 143 | 
         
            +
            					</button>
         
     | 
| 144 | 
         
            +
            				{/if}
         
     | 
| 145 | 
         
             
            			</div>
         
     | 
| 146 | 
         
             
            		{/if}
         
     | 
| 147 | 
         
             
            	</div>
         
     | 
    	
        src/lib/components/chat/ChatMessages.svelte
    CHANGED
    
    | 
         @@ -17,7 +17,8 @@ 
     | 
|
| 17 | 
         
             
            	export let pending: boolean;
         
     | 
| 18 | 
         
             
            	export let currentModel: Model;
         
     | 
| 19 | 
         
             
            	export let settings: LayoutData["settings"];
         
     | 
| 20 | 
         
            -
            	export let models: Model[] 
     | 
| 
         | 
|
| 21 | 
         | 
| 22 | 
         
             
            	let chatContainer: HTMLElement;
         
     | 
| 23 | 
         | 
| 
         @@ -43,12 +44,11 @@ 
     | 
|
| 43 | 
         
             
            				loading={loading && i === messages.length - 1}
         
     | 
| 44 | 
         
             
            				{message}
         
     | 
| 45 | 
         
             
            				model={currentModel}
         
     | 
| 
         | 
|
| 46 | 
         
             
            				on:retry={() => dispatch("retry", { id: message.id, content: message.content })}
         
     | 
| 47 | 
         
             
            			/>
         
     | 
| 48 | 
         
             
            		{:else}
         
     | 
| 49 | 
         
            -
            			{ 
     | 
| 50 | 
         
            -
            				<ChatIntroduction {settings} {models} {currentModel} on:message />
         
     | 
| 51 | 
         
            -
            			{/if}
         
     | 
| 52 | 
         
             
            		{/each}
         
     | 
| 53 | 
         
             
            		{#if pending}
         
     | 
| 54 | 
         
             
            			<ChatMessage
         
     | 
| 
         | 
|
| 17 | 
         
             
            	export let pending: boolean;
         
     | 
| 18 | 
         
             
            	export let currentModel: Model;
         
     | 
| 19 | 
         
             
            	export let settings: LayoutData["settings"];
         
     | 
| 20 | 
         
            +
            	export let models: Model[];
         
     | 
| 21 | 
         
            +
            	export let readOnly: boolean;
         
     | 
| 22 | 
         | 
| 23 | 
         
             
            	let chatContainer: HTMLElement;
         
     | 
| 24 | 
         | 
| 
         | 
|
| 44 | 
         
             
            				loading={loading && i === messages.length - 1}
         
     | 
| 45 | 
         
             
            				{message}
         
     | 
| 46 | 
         
             
            				model={currentModel}
         
     | 
| 47 | 
         
            +
            				{readOnly}
         
     | 
| 48 | 
         
             
            				on:retry={() => dispatch("retry", { id: message.id, content: message.content })}
         
     | 
| 49 | 
         
             
            			/>
         
     | 
| 50 | 
         
             
            		{:else}
         
     | 
| 51 | 
         
            +
            			<ChatIntroduction {settings} {models} {currentModel} on:message />
         
     | 
| 
         | 
|
| 
         | 
|
| 52 | 
         
             
            		{/each}
         
     | 
| 53 | 
         
             
            		{#if pending}
         
     | 
| 54 | 
         
             
            			<ChatMessage
         
     | 
    	
        src/lib/components/chat/ChatWindow.svelte
    CHANGED
    
    | 
         @@ -12,13 +12,14 @@ 
     | 
|
| 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[] 
     | 
| 20 | 
         
             
            	export let settings: LayoutData["settings"];
         
     | 
| 21 | 
         | 
| 
         | 
|
| 
         | 
|
| 22 | 
         
             
            	let message: string;
         
     | 
| 23 | 
         | 
| 24 | 
         
             
            	const dispatch = createEventDispatcher<{
         
     | 
| 
         @@ -43,6 +44,7 @@ 
     | 
|
| 43 | 
         
             
            		{currentModel}
         
     | 
| 44 | 
         
             
            		{models}
         
     | 
| 45 | 
         
             
            		{messages}
         
     | 
| 
         | 
|
| 46 | 
         
             
            		on:message
         
     | 
| 47 | 
         
             
            		on:retry={(ev) => {
         
     | 
| 48 | 
         
             
            			if (!loading) dispatch("retry", ev.detail);
         
     | 
| 
         @@ -58,7 +60,8 @@ 
     | 
|
| 58 | 
         
             
            		/>
         
     | 
| 59 | 
         
             
            		<form
         
     | 
| 60 | 
         
             
            			on:submit|preventDefault={handleSubmit}
         
     | 
| 61 | 
         
            -
            			class="relative flex w-full max-w-4xl flex-1 items-center rounded-xl border bg-gray-100 focus-within:border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:focus-within:border-gray-500  
     | 
| 
         | 
|
| 62 | 
         
             
            		>
         
     | 
| 63 | 
         
             
            			<div class="flex w-full flex-1 border-none bg-transparent">
         
     | 
| 64 | 
         
             
            				<ChatInput
         
     | 
| 
         @@ -66,10 +69,11 @@ 
     | 
|
| 66 | 
         
             
            					bind:value={message}
         
     | 
| 67 | 
         
             
            					on:submit={handleSubmit}
         
     | 
| 68 | 
         
             
            					maxRows={4}
         
     | 
| 
         | 
|
| 69 | 
         
             
            				/>
         
     | 
| 70 | 
         
             
            				<button
         
     | 
| 71 | 
         
             
            					class="btn mx-1 my-1 h-[2.4rem] self-end rounded-lg bg-transparent p-1 px-[0.7rem] text-gray-400 disabled:opacity-60 enabled:hover:text-gray-700 dark:disabled:opacity-40 enabled:dark:hover:text-gray-100"
         
     | 
| 72 | 
         
            -
            					disabled={!message || loading ||  
     | 
| 73 | 
         
             
            					type="submit"
         
     | 
| 74 | 
         
             
            				>
         
     | 
| 75 | 
         
             
            					<CarbonSendAltFilled />
         
     | 
| 
         | 
|
| 12 | 
         
             
            	import type { LayoutData } from "../../../routes/$types";
         
     | 
| 13 | 
         | 
| 14 | 
         
             
            	export let messages: Message[] = [];
         
     | 
| 
         | 
|
| 15 | 
         
             
            	export let loading = false;
         
     | 
| 16 | 
         
             
            	export let pending = false;
         
     | 
| 17 | 
         
             
            	export let currentModel: Model;
         
     | 
| 18 | 
         
            +
            	export let models: Model[];
         
     | 
| 19 | 
         
             
            	export let settings: LayoutData["settings"];
         
     | 
| 20 | 
         | 
| 21 | 
         
            +
            	$: isReadOnly = !models.some((model) => model.id === currentModel.id);
         
     | 
| 22 | 
         
            +
             
     | 
| 23 | 
         
             
            	let message: string;
         
     | 
| 24 | 
         | 
| 25 | 
         
             
            	const dispatch = createEventDispatcher<{
         
     | 
| 
         | 
|
| 44 | 
         
             
            		{currentModel}
         
     | 
| 45 | 
         
             
            		{models}
         
     | 
| 46 | 
         
             
            		{messages}
         
     | 
| 47 | 
         
            +
            		readOnly={isReadOnly}
         
     | 
| 48 | 
         
             
            		on:message
         
     | 
| 49 | 
         
             
            		on:retry={(ev) => {
         
     | 
| 50 | 
         
             
            			if (!loading) dispatch("retry", ev.detail);
         
     | 
| 
         | 
|
| 60 | 
         
             
            		/>
         
     | 
| 61 | 
         
             
            		<form
         
     | 
| 62 | 
         
             
            			on:submit|preventDefault={handleSubmit}
         
     | 
| 63 | 
         
            +
            			class="relative flex w-full max-w-4xl flex-1 items-center rounded-xl border bg-gray-100 focus-within:border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:focus-within:border-gray-500 
         
     | 
| 64 | 
         
            +
            			{isReadOnly ? 'opacity-30' : ''}"
         
     | 
| 65 | 
         
             
            		>
         
     | 
| 66 | 
         
             
            			<div class="flex w-full flex-1 border-none bg-transparent">
         
     | 
| 67 | 
         
             
            				<ChatInput
         
     | 
| 
         | 
|
| 69 | 
         
             
            					bind:value={message}
         
     | 
| 70 | 
         
             
            					on:submit={handleSubmit}
         
     | 
| 71 | 
         
             
            					maxRows={4}
         
     | 
| 72 | 
         
            +
            					disabled={isReadOnly}
         
     | 
| 73 | 
         
             
            				/>
         
     | 
| 74 | 
         
             
            				<button
         
     | 
| 75 | 
         
             
            					class="btn mx-1 my-1 h-[2.4rem] self-end rounded-lg bg-transparent p-1 px-[0.7rem] text-gray-400 disabled:opacity-60 enabled:hover:text-gray-700 dark:disabled:opacity-40 enabled:dark:hover:text-gray-100"
         
     | 
| 76 | 
         
            +
            					disabled={!message || loading || isReadOnly}
         
     | 
| 77 | 
         
             
            					type="submit"
         
     | 
| 78 | 
         
             
            				>
         
     | 
| 79 | 
         
             
            					<CarbonSendAltFilled />
         
     | 
    	
        src/lib/server/models.ts
    CHANGED
    
    | 
         @@ -1,4 +1,4 @@ 
     | 
|
| 1 | 
         
            -
            import { HF_ACCESS_TOKEN, MODELS } from "$env/static/private";
         
     | 
| 2 | 
         
             
            import { z } from "zod";
         
     | 
| 3 | 
         | 
| 4 | 
         
             
            const modelsRaw = z
         
     | 
| 
         @@ -41,7 +41,8 @@ const modelsRaw = z 
     | 
|
| 41 | 
         
             
            					max_new_tokens: z.number().int().positive(),
         
     | 
| 42 | 
         
             
            					stop: z.array(z.string()).optional(),
         
     | 
| 43 | 
         
             
            				})
         
     | 
| 44 | 
         
            -
            				.passthrough() 
     | 
| 
         | 
|
| 45 | 
         
             
            		})
         
     | 
| 46 | 
         
             
            	)
         
     | 
| 47 | 
         
             
            	.parse(JSON.parse(MODELS));
         
     | 
| 
         @@ -55,6 +56,25 @@ export const models = await Promise.all( 
     | 
|
| 55 | 
         
             
            	}))
         
     | 
| 56 | 
         
             
            );
         
     | 
| 57 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 58 | 
         
             
            export type BackendModel = (typeof models)[0];
         
     | 
| 59 | 
         | 
| 60 | 
         
             
            export const defaultModel = models[0];
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            import { HF_ACCESS_TOKEN, MODELS, OLD_MODELS } from "$env/static/private";
         
     | 
| 2 | 
         
             
            import { z } from "zod";
         
     | 
| 3 | 
         | 
| 4 | 
         
             
            const modelsRaw = z
         
     | 
| 
         | 
|
| 41 | 
         
             
            					max_new_tokens: z.number().int().positive(),
         
     | 
| 42 | 
         
             
            					stop: z.array(z.string()).optional(),
         
     | 
| 43 | 
         
             
            				})
         
     | 
| 44 | 
         
            +
            				.passthrough()
         
     | 
| 45 | 
         
            +
            				.optional(),
         
     | 
| 46 | 
         
             
            		})
         
     | 
| 47 | 
         
             
            	)
         
     | 
| 48 | 
         
             
            	.parse(JSON.parse(MODELS));
         
     | 
| 
         | 
|
| 56 | 
         
             
            	}))
         
     | 
| 57 | 
         
             
            );
         
     | 
| 58 | 
         | 
| 59 | 
         
            +
            // Models that have been deprecated
         
     | 
| 60 | 
         
            +
            export const oldModels = OLD_MODELS
         
     | 
| 61 | 
         
            +
            	? z
         
     | 
| 62 | 
         
            +
            			.array(
         
     | 
| 63 | 
         
            +
            				z.object({
         
     | 
| 64 | 
         
            +
            					id: z.string().optional(),
         
     | 
| 65 | 
         
            +
            					name: z.string().min(1),
         
     | 
| 66 | 
         
            +
            					displayName: z.string().min(1).optional(),
         
     | 
| 67 | 
         
            +
            				})
         
     | 
| 68 | 
         
            +
            			)
         
     | 
| 69 | 
         
            +
            			.parse(JSON.parse(OLD_MODELS))
         
     | 
| 70 | 
         
            +
            			.map((m) => ({ ...m, id: m.id || m.name, displayName: m.displayName || m.name }))
         
     | 
| 71 | 
         
            +
            	: [];
         
     | 
| 72 | 
         
            +
             
     | 
| 73 | 
         
             
            export type BackendModel = (typeof models)[0];
         
     | 
| 74 | 
         | 
| 75 | 
         
             
            export const defaultModel = models[0];
         
     | 
| 76 | 
         
            +
             
     | 
| 77 | 
         
            +
            export const validateModel = (_models: BackendModel[]) => {
         
     | 
| 78 | 
         
            +
            	// Zod enum function requires 2 parameters
         
     | 
| 79 | 
         
            +
            	return z.enum([_models[0].id, ..._models.slice(1).map((m) => m.id)]);
         
     | 
| 80 | 
         
            +
            };
         
     | 
    	
        src/lib/utils/models.ts
    CHANGED
    
    | 
         @@ -1,10 +1,4 @@ 
     | 
|
| 1 | 
         
             
            import type { Model } from "$lib/types/Model";
         
     | 
| 2 | 
         
            -
            import { z } from "zod";
         
     | 
| 3 | 
         | 
| 4 | 
         
            -
            export const findCurrentModel = (models: Model[],  
     | 
| 5 | 
         
            -
            	models.find((m) => m.id ===  
     | 
| 6 | 
         
            -
             
     | 
| 7 | 
         
            -
            export const validateModel = (models: Model[]) => {
         
     | 
| 8 | 
         
            -
            	// Zod enum function requires 2 parameters
         
     | 
| 9 | 
         
            -
            	return z.enum([models[0].id, ...models.slice(1).map((m) => m.id)]);
         
     | 
| 10 | 
         
            -
            };
         
     | 
| 
         | 
|
| 1 | 
         
             
            import type { Model } from "$lib/types/Model";
         
     | 
| 
         | 
|
| 2 | 
         | 
| 3 | 
         
            +
            export const findCurrentModel = (models: Model[], id?: string) =>
         
     | 
| 4 | 
         
            +
            	models.find((m) => m.id === id) ?? models[0];
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
    	
        src/routes/+layout.server.ts
    CHANGED
    
    | 
         @@ -3,8 +3,7 @@ import type { LayoutServerLoad } from "./$types"; 
     | 
|
| 3 | 
         
             
            import { collections } from "$lib/server/database";
         
     | 
| 4 | 
         
             
            import type { Conversation } from "$lib/types/Conversation";
         
     | 
| 5 | 
         
             
            import { UrlDependency } from "$lib/types/UrlDependency";
         
     | 
| 6 | 
         
            -
            import { defaultModel, models } from "$lib/server/models";
         
     | 
| 7 | 
         
            -
            import { validateModel } from "$lib/utils/models";
         
     | 
| 8 | 
         
             
            import { authCondition } from "$lib/server/auth";
         
     | 
| 9 | 
         | 
| 10 | 
         
             
            export const load: LayoutServerLoad = async ({ locals, depends, url }) => {
         
     | 
| 
         @@ -29,6 +28,15 @@ export const load: LayoutServerLoad = async ({ locals, depends, url }) => { 
     | 
|
| 29 | 
         | 
| 30 | 
         
             
            	const settings = await collections.settings.findOne(authCondition(locals));
         
     | 
| 31 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 32 | 
         
             
            	return {
         
     | 
| 33 | 
         
             
            		conversations: await conversations
         
     | 
| 34 | 
         
             
            			.find(authCondition(locals))
         
     | 
| 
         @@ -61,5 +69,6 @@ export const load: LayoutServerLoad = async ({ locals, depends, url }) => { 
     | 
|
| 61 | 
         
             
            			promptExamples: model.promptExamples,
         
     | 
| 62 | 
         
             
            			parameters: model.parameters,
         
     | 
| 63 | 
         
             
            		})),
         
     | 
| 
         | 
|
| 64 | 
         
             
            	};
         
     | 
| 65 | 
         
             
            };
         
     | 
| 
         | 
|
| 3 | 
         
             
            import { collections } from "$lib/server/database";
         
     | 
| 4 | 
         
             
            import type { Conversation } from "$lib/types/Conversation";
         
     | 
| 5 | 
         
             
            import { UrlDependency } from "$lib/types/UrlDependency";
         
     | 
| 6 | 
         
            +
            import { defaultModel, models, oldModels, validateModel } from "$lib/server/models";
         
     | 
| 
         | 
|
| 7 | 
         
             
            import { authCondition } from "$lib/server/auth";
         
     | 
| 8 | 
         | 
| 9 | 
         
             
            export const load: LayoutServerLoad = async ({ locals, depends, url }) => {
         
     | 
| 
         | 
|
| 28 | 
         | 
| 29 | 
         
             
            	const settings = await collections.settings.findOne(authCondition(locals));
         
     | 
| 30 | 
         | 
| 31 | 
         
            +
            	// If the active model in settings is not valid, set it to the default model. This can happen if model was disabled.
         
     | 
| 32 | 
         
            +
            	if (settings && !validateModel(models).safeParse(settings?.activeModel).success) {
         
     | 
| 33 | 
         
            +
            		settings.activeModel = defaultModel.id;
         
     | 
| 34 | 
         
            +
            		await collections.settings.updateOne(
         
     | 
| 35 | 
         
            +
            			{ sessionId: locals.sessionId },
         
     | 
| 36 | 
         
            +
            			{ $set: { activeModel: defaultModel.id } }
         
     | 
| 37 | 
         
            +
            		);
         
     | 
| 38 | 
         
            +
            	}
         
     | 
| 39 | 
         
            +
             
     | 
| 40 | 
         
             
            	return {
         
     | 
| 41 | 
         
             
            		conversations: await conversations
         
     | 
| 42 | 
         
             
            			.find(authCondition(locals))
         
     | 
| 
         | 
|
| 69 | 
         
             
            			promptExamples: model.promptExamples,
         
     | 
| 70 | 
         
             
            			parameters: model.parameters,
         
     | 
| 71 | 
         
             
            		})),
         
     | 
| 72 | 
         
            +
            		oldModels,
         
     | 
| 73 | 
         
             
            	};
         
     | 
| 74 | 
         
             
            };
         
     | 
    	
        src/routes/+page.svelte
    CHANGED
    
    | 
         @@ -45,7 +45,7 @@ 
     | 
|
| 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 | 
         
             
            />
         
     | 
| 
         | 
|
| 45 | 
         
             
            <ChatWindow
         
     | 
| 46 | 
         
             
            	on:message={(ev) => createConversation(ev.detail)}
         
     | 
| 47 | 
         
             
            	{loading}
         
     | 
| 48 | 
         
            +
            	currentModel={findCurrentModel([...data.models, ...data.oldModels], data.settings.activeModel)}
         
     | 
| 49 | 
         
             
            	models={data.models}
         
     | 
| 50 | 
         
             
            	settings={data.settings}
         
     | 
| 51 | 
         
             
            />
         
     | 
    	
        src/routes/conversation/+server.ts
    CHANGED
    
    | 
         @@ -5,8 +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 { models } from "$lib/server/models";
         
     | 
| 9 | 
         
            -
            import { validateModel } from "$lib/utils/models";
         
     | 
| 10 | 
         
             
            import { authCondition } from "$lib/server/auth";
         
     | 
| 11 | 
         | 
| 12 | 
         
             
            export const POST: RequestHandler = async ({ locals, request }) => {
         
     | 
| 
         | 
|
| 5 | 
         
             
            import { base } from "$app/paths";
         
     | 
| 6 | 
         
             
            import { z } from "zod";
         
     | 
| 7 | 
         
             
            import type { Message } from "$lib/types/Message";
         
     | 
| 8 | 
         
            +
            import { models, validateModel } from "$lib/server/models";
         
     | 
| 
         | 
|
| 9 | 
         
             
            import { authCondition } from "$lib/server/auth";
         
     | 
| 10 | 
         | 
| 11 | 
         
             
            export const POST: RequestHandler = async ({ locals, request }) => {
         
     | 
    	
        src/routes/conversation/[id]/+page.svelte
    CHANGED
    
    | 
         @@ -173,6 +173,7 @@ 
     | 
|
| 173 | 
         
             
            	on:retry={(message) => writeMessage(message.detail.content, message.detail.id)}
         
     | 
| 174 | 
         
             
            	on:share={() => shareConversation($page.params.id, data.title)}
         
     | 
| 175 | 
         
             
            	on:stop={() => (isAborted = true)}
         
     | 
| 176 | 
         
            -
            	 
     | 
| 
         | 
|
| 177 | 
         
             
            	settings={data.settings}
         
     | 
| 178 | 
         
             
            />
         
     | 
| 
         | 
|
| 173 | 
         
             
            	on:retry={(message) => writeMessage(message.detail.content, message.detail.id)}
         
     | 
| 174 | 
         
             
            	on:share={() => shareConversation($page.params.id, data.title)}
         
     | 
| 175 | 
         
             
            	on:stop={() => (isAborted = true)}
         
     | 
| 176 | 
         
            +
            	models={data.models}
         
     | 
| 177 | 
         
            +
            	currentModel={findCurrentModel([...data.models, ...data.oldModels], data.model)}
         
     | 
| 178 | 
         
             
            	settings={data.settings}
         
     | 
| 179 | 
         
             
            />
         
     | 
    	
        src/routes/conversation/[id]/+server.ts
    CHANGED
    
    | 
         @@ -16,8 +16,8 @@ import { ObjectId } from "mongodb"; 
     | 
|
| 16 | 
         
             
            import { z } from "zod";
         
     | 
| 17 | 
         | 
| 18 | 
         
             
            export async function POST({ request, fetch, locals, params }) {
         
     | 
| 19 | 
         
            -
            	 
     | 
| 20 | 
         
            -
            	const convId = new ObjectId( 
     | 
| 21 | 
         
             
            	const date = new Date();
         
     | 
| 22 | 
         | 
| 23 | 
         
             
            	const conv = await collections.conversations.findOne({
         
     | 
| 
         @@ -32,7 +32,7 @@ export async function POST({ request, fetch, locals, params }) { 
     | 
|
| 32 | 
         
             
            	const model = models.find((m) => m.id === conv.model);
         
     | 
| 33 | 
         | 
| 34 | 
         
             
            	if (!model) {
         
     | 
| 35 | 
         
            -
            		throw error( 
     | 
| 36 | 
         
             
            	}
         
     | 
| 37 | 
         | 
| 38 | 
         
             
            	const json = await request.json();
         
     | 
| 
         | 
|
| 16 | 
         
             
            import { z } from "zod";
         
     | 
| 17 | 
         | 
| 18 | 
         
             
            export async function POST({ request, fetch, locals, params }) {
         
     | 
| 19 | 
         
            +
            	const id = z.string().parse(params.id);
         
     | 
| 20 | 
         
            +
            	const convId = new ObjectId(id);
         
     | 
| 21 | 
         
             
            	const date = new Date();
         
     | 
| 22 | 
         | 
| 23 | 
         
             
            	const conv = await collections.conversations.findOne({
         
     | 
| 
         | 
|
| 32 | 
         
             
            	const model = models.find((m) => m.id === conv.model);
         
     | 
| 33 | 
         | 
| 34 | 
         
             
            	if (!model) {
         
     | 
| 35 | 
         
            +
            		throw error(410, "Model not available anymore");
         
     | 
| 36 | 
         
             
            	}
         
     | 
| 37 | 
         | 
| 38 | 
         
             
            	const json = await request.json();
         
     | 
    	
        src/routes/r/[id]/+page.svelte
    CHANGED
    
    | 
         @@ -72,6 +72,7 @@ 
     | 
|
| 72 | 
         
             
            			})
         
     | 
| 73 | 
         
             
            			.finally(() => (loading = false))}
         
     | 
| 74 | 
         
             
            	messages={data.messages}
         
     | 
| 
         | 
|
| 75 | 
         
             
            	currentModel={findCurrentModel(data.models, data.model)}
         
     | 
| 76 | 
         
             
            	settings={data.settings}
         
     | 
| 77 | 
         
             
            	{loading}
         
     | 
| 
         | 
|
| 72 | 
         
             
            			})
         
     | 
| 73 | 
         
             
            			.finally(() => (loading = false))}
         
     | 
| 74 | 
         
             
            	messages={data.messages}
         
     | 
| 75 | 
         
            +
            	models={data.models}
         
     | 
| 76 | 
         
             
            	currentModel={findCurrentModel(data.models, data.model)}
         
     | 
| 77 | 
         
             
            	settings={data.settings}
         
     | 
| 78 | 
         
             
            	{loading}
         
     | 
    	
        src/routes/settings/+page.server.ts
    CHANGED
    
    | 
         @@ -2,8 +2,7 @@ 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 | 
         
            -
            import { validateModel } from "$lib/utils/models";
         
     | 
| 7 | 
         
             
            import { authCondition } from "$lib/server/auth";
         
     | 
| 8 | 
         | 
| 9 | 
         
             
            export const actions = {
         
     | 
| 
         | 
|
| 2 | 
         
             
            import { collections } from "$lib/server/database";
         
     | 
| 3 | 
         
             
            import { redirect } from "@sveltejs/kit";
         
     | 
| 4 | 
         
             
            import { z } from "zod";
         
     | 
| 5 | 
         
            +
            import { defaultModel, models, validateModel } from "$lib/server/models";
         
     | 
| 
         | 
|
| 6 | 
         
             
            import { authCondition } from "$lib/server/auth";
         
     | 
| 7 | 
         | 
| 8 | 
         
             
            export const actions = {
         
     |