Show "Loading model from cache" instead of "Downloading" when weights are already cached

Transformers.js's progress_callback always fires status:"download" regardless
of whether the file is actually served from the Cache API — there's no
cacheHit signal for the worker to forward. Since App.tsx already tracks which
models are downloaded (for ModelPicker's badges), it now checks that before
starting a load and threads a loadedFromCache flag into ModelLoadProgress, so
the heading/hint reflect reality for the common already-cached case.

Adds Decisions.md D-033.
This commit is contained in:
Lucas Winther committed 2026-07-30 08:30:19 +02:00
1 parent bb77185e3f
commit c5d193600a
3 files changed
+85 -4

No files matched your search

+19 -1
View File
@@ -135,6 +135,10 @@ export function App() {
const [decoding, setDecoding] = useState(false);
const [loadStarted, setLoadStarted] = useState(false);
const [loadProgress, setLoadProgress] = useState(initialLoadProgress);
// Was the model already fully cached (D-005/`modelCache.ts`) when this load
// started? Threaded into ModelLoadProgress so its heading/hint don't say
// "Downloading" for a load that never touches the network (D-033).
const [loadedFromCache, setLoadedFromCache] = useState(false);
const [partialText, setPartialText] = useState("");
const [transcribeProgress, setTranscribeProgress] = useState<{
processedSeconds: number;
@@ -470,6 +474,12 @@ export function App() {
const worker = ensureWorker();
setLoadProgress(initialLoadProgress);
setLoadStarted(true);
// D-033: `downloaded` (refreshed via getDownloadedModels, D-005) already
// tells us whether this model's weights are cached before we ask the
// worker to load it — capture that now, since the worker/Transformers.js
// progress callback itself cannot distinguish a cached read from a
// network download (see the ADR for why we don't patch that upstream).
setLoadedFromCache(downloaded.has(nextModelId));
setError(null);
newLoadGate();
const device = effectiveDevice(nextModelId, preference);
@@ -500,6 +510,7 @@ export function App() {
// reports fresh progress for this model.
setLoadStarted(false);
setLoadProgress(initialLoadProgress);
setLoadedFromCache(false);
loadGate.current = null;
}
@@ -511,6 +522,7 @@ export function App() {
// No eager reload (D-020) — the next load picks up the new preference.
setLoadStarted(false);
setLoadProgress(initialLoadProgress);
setLoadedFromCache(false);
loadGate.current = null;
}
@@ -551,6 +563,7 @@ export function App() {
loadGate.current = null;
setLoadStarted(false);
setLoadProgress(initialLoadProgress);
setLoadedFromCache(false);
setActiveDevice(null);
setActiveThreads(null);
}
@@ -956,6 +969,7 @@ export function App() {
setResult(null);
setLoadStarted(false);
setLoadProgress(initialLoadProgress);
setLoadedFromCache(false);
}
}
}, [serverSelected, modelId, busy, liveStatus]);
@@ -1086,7 +1100,11 @@ export function App() {
)}
{showModelProgress && (
<ModelLoadProgress modelId={modelId} progress={loadProgress} />
<ModelLoadProgress
modelId={modelId}
progress={loadProgress}
loadedFromCache={loadedFromCache}
/>
)}
<TranscriptView
+13 -3
View File
@@ -3,6 +3,13 @@ import type { LoadProgressState } from "../worker/protocol";
interface ModelLoadProgressProps {
modelId: string;
progress: LoadProgressState;
/**
* Was the model already fully cached (`lib/modelCache.ts`, D-005) when this
* load started? Transformers.js's own progress callback cannot tell a
* cache hit from a network download (D-033) — the app decides this itself,
* before the load even starts, from Cache Storage.
*/
loadedFromCache: boolean;
}
function formatBytes(bytes: number): string {
@@ -12,15 +19,18 @@ function formatBytes(bytes: number): string {
}
/** Per-file model download progress (bytes and %), driven by load-progress messages. */
export function ModelLoadProgress({ modelId, progress }: ModelLoadProgressProps) {
export function ModelLoadProgress({ modelId, progress, loadedFromCache }: ModelLoadProgressProps) {
const files = Object.values(progress.files);
return (
<section className="model-progress" aria-label="Model download progress">
<h2>
Downloading model <code>{modelId}</code>
{loadedFromCache ? "Loading model from cache " : "Downloading model "}
<code>{modelId}</code>
</h2>
<p className="model-progress-hint">
This happens once — the weights are cached in your browser afterwards.
{loadedFromCache
? "This model is already downloaded — just loading it into memory."
: "This happens once — the weights are cached in your browser afterwards."}
</p>
{files.length === 0 && <p className="model-progress-hint">Preparing…</p>}
<ul>