diff --git a/tools/server/public/index.html.gz b/tools/server/public/index.html.gz index 0e460373fd..f516db853a 100644 Binary files a/tools/server/public/index.html.gz and b/tools/server/public/index.html.gz differ diff --git a/tools/server/webui/src/lib/components/app/notebook/NotebookScreen.svelte b/tools/server/webui/src/lib/components/app/notebook/NotebookScreen.svelte index 40027c1f31..8c5c7e8b1d 100644 --- a/tools/server/webui/src/lib/components/app/notebook/NotebookScreen.svelte +++ b/tools/server/webui/src/lib/components/app/notebook/NotebookScreen.svelte @@ -5,7 +5,7 @@ import { Play, Square, Settings } from '@lucide/svelte'; import { config } from '$lib/stores/settings.svelte'; import DialogChatSettings from '$lib/components/app/dialogs/DialogChatSettings.svelte'; - import { ModelsSelector, ChatMessageStatistics } from '$lib/components/app'; + import { ModelsSelector, ChatMessageStatistics, DialogChatError } from '$lib/components/app'; import { useModelChangeValidation } from '$lib/hooks/use-model-change-validation.svelte'; import { modelsStore, modelOptions, selectedModelId } from '$lib/stores/models.svelte'; import { isRouterMode } from '$lib/stores/server.svelte'; @@ -34,6 +34,8 @@ let isRouter = $derived(isRouterMode()); + let errorDialog = $derived(notebookStore.error); + // Sync local input with store content $effect(() => { inputContent = notebookStore.content; @@ -44,6 +46,12 @@ notebookStore.content = target.value; } + function handleErrorDialogOpenChange(open: boolean) { + if (!open) { + notebookStore.dismissError(); + } + } + async function handleGenerate() { if (!disableAutoScroll) { userScrolledUp = false; @@ -57,6 +65,7 @@ await notebookStore.generate(notebookModel); } + function handleStop() { notebookStore.stop(); } @@ -271,4 +280,12 @@ (settingsOpen = open)} /> + + diff --git a/tools/server/webui/src/lib/stores/notebook.svelte.ts b/tools/server/webui/src/lib/stores/notebook.svelte.ts index 4ae1dc3b72..a4849aa61e 100644 --- a/tools/server/webui/src/lib/stores/notebook.svelte.ts +++ b/tools/server/webui/src/lib/stores/notebook.svelte.ts @@ -12,11 +12,18 @@ export class NotebookStore { predictedTokens = $state(0); predictedMs = $state(0); + error = $state<{ + message: string; + type: 'timeout' | 'server'; + contextInfo?: { n_prompt_tokens: number; n_ctx: number }; + } | null>(null); + async generate(model?: string) { if (this.isGenerating) return; this.isGenerating = true; this.abortController = new AbortController(); + this.error = null; // Reset stats this.promptTokens = 0; @@ -59,6 +66,10 @@ export class NotebookStore { // aborted by user } else { console.error('Notebook generation error:', error); + this.error = { + message: error instanceof Error ? error.message : String(error), + type: 'server' + }; } this.isGenerating = false; } @@ -67,10 +78,18 @@ export class NotebookStore { ); } catch (error) { console.error('Notebook generation failed:', error); + this.error = { + message: error instanceof Error ? error.message : String(error), + type: 'server' + }; this.isGenerating = false; } } + dismissError() { + this.error = null; + } + stop() { if (this.abortController) { this.abortController.abort();