diff --git a/tools/server/public/index.html.gz b/tools/server/public/index.html.gz index 493058aa01..6645ae5081 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/dialogs/DialogModelInformation.svelte b/tools/server/webui/src/lib/components/app/dialogs/DialogModelInformation.svelte index eac83f234d..064ca9fa09 100644 --- a/tools/server/webui/src/lib/components/app/dialogs/DialogModelInformation.svelte +++ b/tools/server/webui/src/lib/components/app/dialogs/DialogModelInformation.svelte @@ -5,21 +5,38 @@ import { serverStore } from '$lib/stores/server.svelte'; import { modelsStore, modelOptions, modelsLoading } from '$lib/stores/models.svelte'; import { formatFileSize, formatParameters, formatNumber } from '$lib/utils'; + import type { ApiLlamaCppServerProps } from '$lib/types'; interface Props { open?: boolean; onOpenChange?: (open: boolean) => void; + // when set, fetch props from the child process (router mode) + modelId?: string | null; } - let { open = $bindable(), onOpenChange }: Props = $props(); + let { open = $bindable(), onOpenChange, modelId = null }: Props = $props(); - let serverProps = $derived(serverStore.props); - let modelName = $derived(modelsStore.singleModelName); + let isRouter = $derived(serverStore.isRouterMode); + + // per-model props fetched from the child process + let routerModelProps = $state(null); + let isLoadingRouterProps = $state(false); + + // in router mode use per-model props, otherwise use global props + let serverProps = $derived(isRouter && modelId ? routerModelProps : serverStore.props); + + let modelName = $derived(isRouter && modelId ? modelId : modelsStore.singleModelName); let models = $derived(modelOptions()); let isLoadingModels = $derived(modelsLoading()); - // Get the first model for single-model mode display - let firstModel = $derived(models[0] ?? null); + // in router mode, find the model option matching modelId + // in single mode, use the first model as before + let firstModel = $derived.by(() => { + if (isRouter && modelId) { + return models.find((m) => m.model === modelId) ?? null; + } + return models[0] ?? null; + }); // Get modalities from modelStore using the model ID from the first model let modalities = $derived.by(() => { @@ -33,6 +50,27 @@ modelsStore.fetch(); } }); + + // fetch per-model props from child process when dialog opens in router mode + $effect(() => { + if (open && isRouter && modelId) { + isLoadingRouterProps = true; + modelsStore + .fetchModelProps(modelId) + .then((props) => { + routerModelProps = props; + }) + .catch(() => { + routerModelProps = null; + }) + .finally(() => { + isLoadingRouterProps = false; + }); + } + if (!open) { + routerModelProps = null; + } + }); @@ -52,7 +90,7 @@
- {#if isLoadingModels} + {#if isLoadingModels || isLoadingRouterProps}
Loading model information...
@@ -212,7 +250,7 @@ Chat Template -
+
{serverProps.chat_template}
diff --git a/tools/server/webui/src/lib/components/app/models/ModelsSelector.svelte b/tools/server/webui/src/lib/components/app/models/ModelsSelector.svelte index a40501e2cc..14737f6472 100644 --- a/tools/server/webui/src/lib/components/app/models/ModelsSelector.svelte +++ b/tools/server/webui/src/lib/components/app/models/ModelsSelector.svelte @@ -164,6 +164,19 @@ let isOpen = $state(false); let showModelDialog = $state(false); + let infoModelId = $state(null); + + // key of the first "available" (non-loaded, non-favourite) group + // used to render the "Available models" separator exactly once + let firstAvailableOrgKey = $derived.by(() => { + const g = groupedFilteredOptions.find((g) => !g.isLoadedGroup && !g.isFavouritesGroup); + return g ? (g.orgName ?? '') : null; + }); + + function handleInfoClick(modelName: string) { + infoModelId = modelName; + showModelDialog = true; + } onMount(() => { modelsStore.fetch().catch((error) => { @@ -427,12 +440,19 @@

Favourite models

- {:else if group.orgName} -

- {group.orgName} -

+ {:else} + {#if (group.orgName ?? '') === firstAvailableOrgKey} +

+ Available models +

+ {/if} + {#if group.orgName} +

+ {group.orgName} +

+ {/if} {/if} {#each group.items as { option, flatIndex } (group.isLoadedGroup ? `loaded-${option.id}` : group.isFavouritesGroup ? `fav-${option.id}` : option.id)} @@ -447,6 +467,7 @@ {isFav} showOrgName={group.isFavouritesGroup || group.isLoadedGroup} onSelect={handleSelect} + onInfoClick={handleInfoClick} onMouseEnter={() => (highlightedIndex = flatIndex)} onKeyDown={(e) => { if (e.key === KeyboardKey.ENTER || e.key === KeyboardKey.SPACE) { @@ -500,6 +521,6 @@ {/if}
-{#if showModelDialog && !isRouter} - +{#if showModelDialog} + {/if} diff --git a/tools/server/webui/src/lib/components/app/models/ModelsSelectorOption.svelte b/tools/server/webui/src/lib/components/app/models/ModelsSelectorOption.svelte index d4239fb1a1..da41de39ab 100644 --- a/tools/server/webui/src/lib/components/app/models/ModelsSelectorOption.svelte +++ b/tools/server/webui/src/lib/components/app/models/ModelsSelectorOption.svelte @@ -1,5 +1,14 @@