mirror of
https://github.com/ggml-org/llama.cpp.git
synced 2026-09-19 09:15:04 +02:00
ui : wire the discover dialog to live data and downloads
Load the selected model's details, file tree and README via HuggingFaceService on selection change, and expose the download progress type globally for the status feed. The download options already read their state from the models status store. Assisted-by: pi
This commit is contained in:
Vendored
+1
@@ -83,6 +83,7 @@ declare global {
|
||||
ApiLlamaCppServerProps,
|
||||
ApiModelDataEntry,
|
||||
ApiModelLoadStage,
|
||||
ModelDownloadProgress,
|
||||
ApiModelsSseProgress,
|
||||
ApiModelsSseData,
|
||||
ApiModelsSseDownloadProgressData,
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
<script lang="ts">
|
||||
import { SearchInput } from '$lib/components/app';
|
||||
import { ModelsDiscoverDetails, ModelsDiscoverList } from '$lib/components/app/models/discover';
|
||||
import { HuggingFaceService } from '$lib/services';
|
||||
import { modelsHubStore } from '$lib/stores';
|
||||
import type { HfModelDetailInfo, HfModelSibling } from '$lib/types';
|
||||
|
||||
let selectedId = $state<string | null>(null);
|
||||
let searchQuery = $state('');
|
||||
let searchTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
// Detail pane state, reloaded when the selection changes.
|
||||
let details = $state<HfModelDetailInfo | null>(null);
|
||||
let files = $state<HfModelSibling[]>([]);
|
||||
let readme = $state<string | null>(null);
|
||||
let detailLoading = $state(false);
|
||||
let detailError = $state<string | null>(null);
|
||||
|
||||
// Load the sidebar list on mount (the component is mounted when the dialog opens).
|
||||
$effect(() => {
|
||||
void modelsHubStore.fetch();
|
||||
@@ -31,6 +40,54 @@
|
||||
void modelsHubStore.search(value);
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// Load the detail pane for the selected model (component is reused across
|
||||
// selections, so this re-fetches on every change).
|
||||
$effect(() => {
|
||||
const id = selectedId;
|
||||
|
||||
if (!id) return;
|
||||
|
||||
let cancelled = false;
|
||||
|
||||
detailLoading = true;
|
||||
detailError = null;
|
||||
|
||||
void (async () => {
|
||||
try {
|
||||
const [info, tree, readmeText] = await Promise.all([
|
||||
HuggingFaceService.getDetails(id),
|
||||
HuggingFaceService.getTree(id),
|
||||
HuggingFaceService.getReadme(id)
|
||||
]);
|
||||
|
||||
if (cancelled) return;
|
||||
|
||||
if (!info) {
|
||||
detailError = 'Model not found';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
details = info;
|
||||
files = HuggingFaceService.filterByExtension(
|
||||
HuggingFaceService.collapseGgufShards(tree),
|
||||
'.gguf'
|
||||
);
|
||||
readme = readmeText;
|
||||
} catch (err) {
|
||||
if (cancelled) return;
|
||||
|
||||
detailError = err instanceof Error ? err.message : 'Failed to load model';
|
||||
} finally {
|
||||
if (!cancelled) detailLoading = false;
|
||||
}
|
||||
})();
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<aside
|
||||
@@ -65,13 +122,13 @@
|
||||
|
||||
<main class="overflow-y-auto">
|
||||
{#if selectedId}
|
||||
<!-- TODO: load details/tree/readme via HuggingFaceService in the integration branch -->
|
||||
<ModelsDiscoverDetails
|
||||
details={null}
|
||||
files={[]}
|
||||
loading={true}
|
||||
details={details}
|
||||
error={detailError}
|
||||
files={files}
|
||||
loading={detailLoading}
|
||||
modelId={selectedId}
|
||||
readme={null}
|
||||
readme={readme}
|
||||
/>
|
||||
{/if}
|
||||
</main>
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
import DownloadProgressBar from '$lib/components/app/models/discover/DownloadProgressBar.svelte';
|
||||
import ModelsDiscover from '$lib/components/app/models/discover/ModelsDiscover.svelte';
|
||||
import { ModelDraftSidecar } from '$lib/enums';
|
||||
import { modelsHubStore } from '$lib/stores';
|
||||
import { modelsHubStore, modelsStore } from '$lib/stores';
|
||||
import { SvelteSet } from 'svelte/reactivity';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
tags: ['autodocs'],
|
||||
@@ -18,7 +19,15 @@
|
||||
modelsHubStore.loading = false;
|
||||
modelsHubStore.error = null;
|
||||
|
||||
const PROGRESS = { downloadedBytes: 3_600_000_000, totalBytes: 7_300_000_000 };
|
||||
// Mark the Q4_K_M tag as failed for the previous-failure story. The status
|
||||
// manager keeps this in a private SvelteSet keyed by `<repo>:<tag>`.
|
||||
const FAILED_TAG = 'ggml-org/gemma-4-12b-it-GGUF:Q4_K_M';
|
||||
|
||||
(
|
||||
modelsStore.status as unknown as { failedDownloads: Set<string> }
|
||||
).failedDownloads = new SvelteSet([FAILED_TAG]);
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<Story name="Progress bar">
|
||||
@@ -54,9 +63,7 @@
|
||||
<DialogModelDownload
|
||||
filePath="Q4_K_M/gemma-4-12b-it-Q4_K_M.gguf"
|
||||
formattedSize="7.3 GB"
|
||||
onCancelDownload={() => {}}
|
||||
onClose={() => {}}
|
||||
onDownload={() => {}}
|
||||
open
|
||||
quant="Q4_K_M"
|
||||
repoId="ggml-org/gemma-4-12b-it-GGUF"
|
||||
@@ -70,31 +77,11 @@
|
||||
<DialogModelDownload
|
||||
filePath="Q4_K_M/gemma-4-12b-it-Q4_K_M.gguf"
|
||||
formattedSize="7.3 GB"
|
||||
onCancelDownload={() => {}}
|
||||
onClose={() => {}}
|
||||
onDownload={() => {}}
|
||||
open
|
||||
previousFailure
|
||||
quant="Q4_K_M"
|
||||
repoId="ggml-org/gemma-4-12b-it-GGUF"
|
||||
sidecar={null}
|
||||
/>
|
||||
</div>
|
||||
</Story>
|
||||
|
||||
<Story name="Download dialog (downloading)">
|
||||
<div class="p-4">
|
||||
<DialogModelDownload
|
||||
filePath="Q4_K_M/gemma-4-12b-it-Q4_K_M.gguf"
|
||||
inFlight
|
||||
onCancelDownload={() => {}}
|
||||
onClose={() => {}}
|
||||
onDownload={() => {}}
|
||||
open
|
||||
progress={PROGRESS}
|
||||
quant="Q4_K_M"
|
||||
repoId="ggml-org/gemma-4-12b-it-GGUF"
|
||||
sidecar={null}
|
||||
/>
|
||||
</div>
|
||||
</Story>
|
||||
|
||||
Reference in New Issue
Block a user