mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-17 14:49:39 +02:00
PillNav overhaul: - Dropdown-as-bar: theme/AI/sync/user menus render as horizontal bars in the bottom stack (PillDropdownBar) instead of floating popovers. New onOpenBar/activeBarId props on PillNavigation. - iconOnly pills: tags/search/workbench-tabs pills show only icons. Home pill removed. New iconOnly flag on PillNavItem. - Segmented toggle groups: items sharing a `group` id render as a single segmented pill (e.g. Light/Dark/System triple). - Fullscreen mode: press "f" to hide all bottom chrome, Esc to exit. - QuickInputBar + bottom bar visibility toggles via new pills. - Progress ring on AI trigger pill during model download (conic-gradient ::after, follows pill border-radius). @mana/local-stt — new package for browser-local speech-to-text: - Whisper models via transformers.js v4 (WebGPU + WASM fallback) - Same Web Worker architecture as @mana/local-llm - Two models: Whisper Tiny (150 MB) and Whisper Small (950 MB) - Reactive Svelte 5 bindings (getLocalSttStatus, loadLocalStt, transcribe) Voice-to-text integration: - useLocalStt() composable: mic capture via AudioContext + ScriptProcessor, resample to 16kHz mono, feed into Whisper worker - Mic button in QuickInputBar (leftAction slot) with recording/loading/transcribing states + pulse animation - Transcribed text injected into InputBar via new injectedText prop - STT model selector in AI bar alongside LLM tier controls Also: vite.config.ts server.fs.allow expanded to monorepo root so workspace package workers resolve in dev. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
22 lines
735 B
TypeScript
22 lines
735 B
TypeScript
/**
|
|
* Check if a Whisper model is already cached in the browser.
|
|
*
|
|
* Same approach as @mana/local-llm: probe for the model's config.json
|
|
* in the Cache API. Whisper models always have this file and it's
|
|
* downloaded first, so its presence reliably indicates "downloaded before".
|
|
*/
|
|
export async function hasModelInCache(modelId: string): Promise<boolean> {
|
|
if (typeof caches === 'undefined') return false;
|
|
try {
|
|
const cacheNames = await caches.keys();
|
|
const url = `https://huggingface.co/${modelId}/resolve/main/config.json`;
|
|
for (const name of cacheNames) {
|
|
const cache = await caches.open(name);
|
|
const match = await cache.match(url);
|
|
if (match) return true;
|
|
}
|
|
return false;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|