- M3: hand-rolled service worker (precache + runtime /ort caching), precache manifest injection, SW registration/update toast, manifest + generated icons, production build script, offline indicator in ModelPicker (D-005/D-007) - M4 backend: bun:sqlite users/sessions (D-009), Passport local strategy behind connect-compat adapter (D-008), /api/auth routes wired into dev+prod serving, Bun.password Argon2id, 38 auth tests - M4 frontend: AuthForms + useAuth + framework-free authClient, session-aware header, anonymous-first fail-silent offline handling, 18 client tests - D-013: server engine (M5) will use faster-whisper via Python sidecar; browser side stays Transformers.js (CTranslate2 has no WASM build) - bun test: 83 pass / tsc --noEmit clean - Note: M3 doc closeout (WorkBreakdown/Architecture/tests/offline.md) still in flight from a background agent; follow-up commit will finish docs Co-Authored-By: Claude Fable 5 <[email protected]>
50 lines
1.9 KiB
TypeScript
50 lines
1.9 KiB
TypeScript
import { describe, test, expect } from "bun:test";
|
|
import { matchCachedModels } from "../src/lib/modelCache";
|
|
|
|
// Pure URL matching (D-005 downloaded badge); the `caches` wrapper is
|
|
// browser-only and exercised manually.
|
|
|
|
const TINY = "onnx-community/whisper-tiny.en";
|
|
const BASE = "onnx-community/whisper-base";
|
|
|
|
function hubUrl(modelId: string, file: string): string {
|
|
return `https://huggingface.co/${modelId}/resolve/main/${file}`;
|
|
}
|
|
|
|
describe("matchCachedModels", () => {
|
|
test("matches models with cached .onnx weights", () => {
|
|
const urls = [
|
|
hubUrl(TINY, "onnx/encoder_model_quantized.onnx"),
|
|
hubUrl(TINY, "onnx/decoder_model_merged_quantized.onnx"),
|
|
hubUrl(TINY, "tokenizer.json"),
|
|
];
|
|
expect(matchCachedModels(urls, [TINY, BASE])).toEqual(new Set([TINY]));
|
|
});
|
|
|
|
test("configs/tokenizer alone do not count as downloaded", () => {
|
|
const urls = [hubUrl(BASE, "tokenizer.json"), hubUrl(BASE, "config.json")];
|
|
expect(matchCachedModels(urls, [TINY, BASE])).toEqual(new Set());
|
|
});
|
|
|
|
test("ignores query strings when checking the .onnx extension", () => {
|
|
const urls = [`${hubUrl(BASE, "onnx/encoder_model_q4.onnx")}?download=true`];
|
|
expect(matchCachedModels(urls, [BASE])).toEqual(new Set([BASE]));
|
|
});
|
|
|
|
test("does not confuse '.en' variants with their multilingual sibling", () => {
|
|
// "onnx-community/whisper-tiny.en/..." contains the substring
|
|
// "whisper-tiny" but must only match the .en id thanks to the trailing /.
|
|
const urls = [hubUrl(TINY, "onnx/encoder_model_quantized.onnx")];
|
|
expect(
|
|
matchCachedModels(urls, [TINY, "onnx-community/whisper-tiny"]),
|
|
).toEqual(new Set([TINY]));
|
|
});
|
|
|
|
test("empty inputs yield an empty set", () => {
|
|
expect(matchCachedModels([], [TINY])).toEqual(new Set());
|
|
expect(matchCachedModels([hubUrl(TINY, "onnx/encoder_model.onnx")], [])).toEqual(
|
|
new Set(),
|
|
);
|
|
});
|
|
});
|