From cdac3a729decfdf69999b2d7acef5784704676fc Mon Sep 17 00:00:00 2001 From: Aleksander Grygier Date: Tue, 1 Sep 2026 11:20:34 +0200 Subject: [PATCH] feat: WIP --- .../app/models/ModelsSelectorDropdown.svelte | 2 +- .../app/models/ModelsSelectorList.svelte | 2 +- ...DiscoverModelDetailsDownloadOptions.svelte | 335 ++++-------------- ...etailsDownloadOptionsDownloadButton.svelte | 18 + ...tailsDownloadOptionsDownloadCommand.svelte | 124 +++++++ ...elDetailsDownloadOptionsQuantToggle.svelte | 109 ++++++ ...coverModelDetailsDownloadOptionsRow.svelte | 42 +++ .../models/discover/download-options.utils.ts | 51 +++ .../components/app/models/discover/index.ts | 31 ++ .../app/{models => navigation}/utils.ts | 0 .../lib/hooks/use-models-selector.svelte.ts | 2 +- .../stories/ModelsSelector.stories.svelte | 2 +- 12 files changed, 439 insertions(+), 279 deletions(-) create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptionsDownloadButton.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptionsDownloadCommand.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptionsQuantToggle.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptionsRow.svelte create mode 100644 tools/ui/src/lib/components/app/models/discover/download-options.utils.ts rename tools/ui/src/lib/components/app/{models => navigation}/utils.ts (100%) diff --git a/tools/ui/src/lib/components/app/models/ModelsSelectorDropdown.svelte b/tools/ui/src/lib/components/app/models/ModelsSelectorDropdown.svelte index d17059bc9f..274f47e62f 100644 --- a/tools/ui/src/lib/components/app/models/ModelsSelectorDropdown.svelte +++ b/tools/ui/src/lib/components/app/models/ModelsSelectorDropdown.svelte @@ -1,6 +1,6 @@ {#if bitDepthRows.length} -
+
- {#each bitDepthRows as row (row.bitDepth)} - {@const mainFile = row.files.find( - (f) => !HuggingFaceService.extractQuantMeta(f.path)?.sidecar - )} - {@const draftFile = row.files.find((f) => { - const sidecar = HuggingFaceService.extractQuantMeta(f.path)?.sidecar; - - return sidecar && !isAuxSidecar(sidecar); - })} - {@const mainMemGb = mainFile ? minMemoryTierGb(mainFile.size ?? 0) : null} - {@const draftMemGb = draftFile ? minMemoryTierGb(draftFile.size ?? 0) : null} -
-
- {#if row.bitDepth === 99} - Other - {:else} - {row.bitDepth}-bit - {/if} - - {#if mainMemGb} - - needs at least {mainMemGb}GB{draftMemGb ? ` + ${draftMemGb}GB` : ''}+ memory - - {/if} -
- -
- {#each row.files as file (file.path)} - {@const meta = HuggingFaceService.extractQuantMeta(file.path)} - {@const label = labelFor(file.path)} - {@const hfRepoWithTag = ModelsService.buildDownloadTag( - modelId, - meta?.quant ?? null, - meta?.sidecar ?? null - )} - {@const state = stateFor(hfRepoWithTag, file.path, Boolean(meta?.sidecar))} - {@const isDownloading = state.isDownloading} - {@const progress = state.progress} - {@const isDownloaded = state.isDownloaded} - {@const isFailed = state.isFailed} - {@const tooltipText = isDownloading - ? `Downloading ${file.path}` - : isDownloaded - ? `Already downloaded: ${file.path}` - : isFailed - ? `Last attempt failed: ${file.path}` - : `Download ${file.path}`} - - - {#if isDownloaded} - -
- {#if meta?.sidecar && !isAuxSidecar(meta.sidecar)} - - {meta.sidecar} - - {/if} - - {label} - - - - {HuggingFaceService.formatFileSize(file.size ?? 0)} - - -
- {:else} - - {#if isFailed && !isDownloading} - - Failed - - {/if} - - {#if meta?.sidecar && !isAuxSidecar(meta.sidecar)} - - {meta.sidecar} - - {/if} - - {label} - - - - - {#if isDownloading && progress && progress.totalBytes > 0} - {Math.round((progress.downloadedBytes / progress.totalBytes) * 100)}% - {:else} - {HuggingFaceService.formatFileSize(file.size ?? 0)} - {/if} - - - {#if isDownloading && progress} - - {/if} - - {/if} -
- - -

{tooltipText}

-
-
- {/each} -
-
+ {#each rows as row (row.bitDepth)} + {/each}
- -
-
-
- llama + +
+ - serve + - - +
- + setPick('main', path)} + onDraftPick={(path) => setPick('draft', path)} + specType={draftEntry && draftSidecar ? SPEC_TYPE[draftSidecar] : null} + />
{/if} diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptionsDownloadButton.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptionsDownloadButton.svelte new file mode 100644 index 0000000000..ae01397a3f --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptionsDownloadButton.svelte @@ -0,0 +1,18 @@ + + + diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptionsDownloadCommand.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptionsDownloadCommand.svelte new file mode 100644 index 0000000000..5c60c3afd3 --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptionsDownloadCommand.svelte @@ -0,0 +1,124 @@ + + +
+ + +
+ llama + + serve + + -hf + + {modelId}{mainQuant ? ':' : ''} + + + {#if baseOptions.length} + + {/if} + + + {#if specType !== null} + -hfd + + {modelId}{draftQuant ? ':' : ''} + + + + --spec-type + + {specType} + {/if} +
+ + +
diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptionsQuantToggle.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptionsQuantToggle.svelte new file mode 100644 index 0000000000..cb613355d9 --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptionsQuantToggle.svelte @@ -0,0 +1,109 @@ + + + + + {#if state.isDownloaded} + +
+ {#if meta?.sidecar && !isAuxSidecar(meta.sidecar)} + + {meta.sidecar} + + {/if} + + {label} + + + + {HuggingFaceService.formatFileSize(file.size ?? 0)} + + +
+ {:else} + + {#if state.isFailed && !state.isDownloading} + + Failed + + {/if} + + {#if meta?.sidecar && !isAuxSidecar(meta.sidecar)} + + {meta.sidecar} + + {/if} + + {label} + + + + + {#if state.isDownloading && state.progress && state.progress.totalBytes > 0} + {Math.round((state.progress.downloadedBytes / state.progress.totalBytes) * 100)}% + {:else} + {HuggingFaceService.formatFileSize(file.size ?? 0)} + {/if} + + + {#if state.isDownloading && state.progress} + + {/if} + + {/if} +
+ + +

{tooltipText}

+
+
diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptionsRow.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptionsRow.svelte new file mode 100644 index 0000000000..85a62a66cb --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptionsRow.svelte @@ -0,0 +1,42 @@ + + +
+
+ {#if bitDepth === 99} + Other + {:else} + {bitDepth}-bit + {/if} + + {#if mainMemGb} + + needs at least {mainMemGb}GB{draftMemGb ? ` + ${draftMemGb}GB` : ''}+ memory + + {/if} +
+ +
+ {#each files as file (file.path)} + + {/each} +
+
diff --git a/tools/ui/src/lib/components/app/models/discover/download-options.utils.ts b/tools/ui/src/lib/components/app/models/discover/download-options.utils.ts new file mode 100644 index 0000000000..a76ca621fd --- /dev/null +++ b/tools/ui/src/lib/components/app/models/discover/download-options.utils.ts @@ -0,0 +1,51 @@ +import { isAuxSidecar } from '$lib/constants'; +import { HuggingFaceService } from '$lib/services'; +import type { HfModelSibling } from '$lib/types/huggingface'; + +/** Download state of a single repo entry, injected by the integration layer. */ +export interface DownloadEntryState { + isDownloading: boolean; + progress: ModelDownloadProgress | null; + isDownloaded: boolean; + isFailed: boolean; +} + +export type BitDepthRow = { bitDepth: number; files: HfModelSibling[] }; + +/** A selectable GGUF, tagged with its kind: main weights, draft, or aux (mmproj). */ +export type SelectableFile = HfModelSibling & { kind: 'main' | 'draft' | 'aux' }; + +/** Option of a quant `