diff --git a/tools/server/public/index.html.gz b/tools/server/public/index.html.gz index a5465fcd13..77362ce66d 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/actions/ActionIcon.svelte b/tools/server/webui/src/lib/components/app/actions/ActionIcon.svelte index 4494ea880b..c676e224a7 100644 --- a/tools/server/webui/src/lib/components/app/actions/ActionIcon.svelte +++ b/tools/server/webui/src/lib/components/app/actions/ActionIcon.svelte @@ -8,6 +8,7 @@ tooltip: string; variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'; size?: 'default' | 'sm' | 'lg' | 'icon'; + iconSize?: string; class?: string; disabled?: boolean; onclick: () => void; @@ -21,6 +22,7 @@ size = 'sm', class: className = '', disabled = false, + iconSize = 'h-3 w-3', onclick, 'aria-label': ariaLabel }: Props = $props(); @@ -38,7 +40,7 @@ > {@const IconComponent = icon} - + diff --git a/tools/server/webui/src/lib/components/app/badges/BadgeModality.svelte b/tools/server/webui/src/lib/components/app/badges/BadgeModality.svelte index a0d5e863c2..15936691a6 100644 --- a/tools/server/webui/src/lib/components/app/badges/BadgeModality.svelte +++ b/tools/server/webui/src/lib/components/app/badges/BadgeModality.svelte @@ -1,6 +1,6 @@ {#snippet badgeContent()} @@ -31,7 +33,9 @@ {/snippet} - {model} + {#if model} + + {/if} {#if showCopyIcon} @@ -39,7 +43,7 @@ {/snippet} -{#if model && isModelMode} +{#if shouldShow} {#if showTooltip} diff --git a/tools/server/webui/src/lib/components/app/models/ModelId.svelte b/tools/server/webui/src/lib/components/app/models/ModelId.svelte new file mode 100644 index 0000000000..817e882861 --- /dev/null +++ b/tools/server/webui/src/lib/components/app/models/ModelId.svelte @@ -0,0 +1,64 @@ + + +{#if resolvedShowRaw} + {modelId} +{:else} + + + {#if showOrgName}{parsed.orgName}/{/if}{parsed.modelName ?? modelId} + + + {#if parsed.params} + + {parsed.params}{parsed.activatedParams ? `-${parsed.activatedParams}` : ''} + + {/if} + + {#if parsed.quantization} + + {parsed.quantization} + + {/if} + + {#if aliases && aliases.length > 0} + {#each aliases as alias (alias)} + {alias} + {/each} + {/if} + + {#if tags && tags.length > 0} + {#each tags as tag (tag)} + {tag} + {/each} + {/if} + +{/if} 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 ebffae1212..a40501e2cc 100644 --- a/tools/server/webui/src/lib/components/app/models/ModelsSelector.svelte +++ b/tools/server/webui/src/lib/components/app/models/ModelsSelector.svelte @@ -1,6 +1,7 @@ @@ -260,10 +315,25 @@ {#if loading && options.length === 0 && isRouter}
+ Loading models…
{:else if options.length === 0 && isRouter} -

No models available.

+ {#if currentModel} + + + + + + {:else} +

No models available.

+ {/if} {:else} {@const selectedOption = getDisplayOption()} @@ -280,7 +350,7 @@ type="button" class={cn( `inline-grid cursor-pointer grid-cols-[1fr_auto_1fr] items-center gap-1.5 rounded-sm bg-muted-foreground/10 px-1.5 py-1 text-xs transition hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-60`, - !isCurrentModelInCache() + !isCurrentModelInCache ? 'bg-red-400/10 !text-red-400 hover:bg-red-400/20 hover:text-red-400' : forceForegroundText ? 'text-foreground' @@ -294,12 +364,21 @@ > - + {#if selectedOption} + + + + - {#if updating} + +

{selectedOption.model}

+
+
+ {:else} + Select model + {/if} + + {#if updating || isLoadingModel} {:else} @@ -316,10 +395,10 @@ placeholder="Search models..." onSearchKeyDown={handleSearchKeyDown} emptyMessage="No models found." - isEmpty={filteredOptions.length === 0 && isCurrentModelInCache()} + isEmpty={filteredOptions.length === 0 && isCurrentModelInCache} >
- {#if !isCurrentModelInCache() && currentModel} + {#if !isCurrentModelInCache && currentModel} -
{/if} + {#if filteredOptions.length === 0}

No models found.

{/if} - {#each filteredOptions as option, index (option.id)} - {@const status = getModelStatus(option.model)} - {@const isLoaded = status === ServerModelStatus.LOADED} - {@const isLoading = status === ServerModelStatus.LOADING} - {@const isSelected = currentModel === option.model || activeId === option.id} - {@const isHighlighted = index === highlightedIndex} -
handleSelect(option.id)} - onmouseenter={() => (highlightedIndex = index)} - onkeydown={(e) => { - if (e.key === 'Enter' || e.key === ' ') { - e.preventDefault(); - handleSelect(option.id); - } - }} - > - + Loaded models +

+ {:else if group.isFavouritesGroup} +

+ Favourite models +

+ {:else if group.orgName} +

- {option.model} - + {group.orgName} +

+ {/if} -
- {#if isLoading} - - - - - -

Loading model...

-
-
- {:else if isLoaded} - - - - - -

Unload model

-
-
- {:else} - - {/if} -
-
+ {#each group.items as { option, flatIndex } (group.isLoadedGroup ? `loaded-${option.id}` : group.isFavouritesGroup ? `fav-${option.id}` : option.id)} + {@const isSelected = currentModel === option.model || activeId === option.id} + {@const isHighlighted = flatIndex === highlightedIndex} + {@const isFav = modelsStore.favouriteModelIds.has(option.model)} + + (highlightedIndex = flatIndex)} + onKeyDown={(e) => { + if (e.key === KeyboardKey.ENTER || e.key === KeyboardKey.SPACE) { + e.preventDefault(); + handleSelect(option.id); + } + }} + /> + {/each} {/each}
@@ -422,7 +465,7 @@