Files
Lumotia/docs/architecture-map/02-tauri-runtime/commands/models.md
Jake 26c7307607
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
agent: lumotia-rebrand — docs, scripts, root config, residuals
Phase 9 of the rebrand cascade. Sweep covers everything the Phase 8
frontend pass deliberately skipped: docs/, root markdown, scripts,
Cargo.toml descriptions, code comments that survived earlier
word-boundary sed, plus a handful of identifiers caught on the final
verify pass.

transcription-app changes:
- README.md, HANDOVER.md, KNOWN-ISSUES.md, run.sh — magnotia/Magnotia
  -> lumotia/Lumotia.
- docs/ — sweep across all subdirs except docs/handovers/ (preserved
  as immutable audit trail). Includes architecture-map references
  to magnotia_core::*, magnotia_storage::*, etc. now pointing at
  lumotia_*; dev-setup.md tracing output examples (lumotia_startup
  target); brief/ + superpowers/ + issues/ + whisper-ecosystem/ +
  audit/.
- Cargo.toml descriptions on 9 crates (core, audio, cloud-providers,
  hotkey, llm, mcp, plus referenced others).
- crates/core/src/{error,hardware,recommendation,paths}.rs +
  crates/audio/src/wav.rs + crates/llm/src/model_manager.rs +
  crates/cloud-providers/src/keystore.rs + crates/mcp/src/lib.rs —
  doc comments and a model-manager user-agent string.
- Caught on final pass: BroadcastChannel("magnotia_task_sync") -> ...
  ("lumotia_task_sync"); magnotia_locale i18n localStorage key
  renamed + migration shim added; CSS keyframe names
  magnotiaPulse / magnotiaBar / magnotiaFade renamed in the design-
  system kit; magnotia_viewer_item / magnotia_viewer_mode handoff
  keys renamed in HistoryPage + viewer/+page.svelte; src/assets/
  wordmark.svg text.
- src-tauri/src/lib.rs comment cleanup ("magnotia era" was sed'd
  to "lumotia era" earlier — restored).

Preserved (intentional):
- crates/core/src/paths.rs — keeps "magnotia" / "Magnotia" / ".magnotia"
  legacy detection strings in legacy_and_target_paths() so the
  migration shim can still find user data from the magnotia era.
- src/lib/stores/{page,focusTimer}.svelte.ts + src/lib/i18n/index.ts
  — migration call sites reference the legacy magnotia keys
  deliberately.
- docs/handovers/ — historical audit trail.

cargo build --workspace passes. npm run check: 0 errors / 0 warnings
(3958 files). cargo test --workspace: 339 pass / 0 fail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 12:38:03 +01:00

114 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: Model registry and runtime
type: architecture-map-page
slice: 02-tauri-runtime
last_verified: 2026/05/09
---
# `commands::models`
> **Where you are:** [Architecture map](../../README.md) → [Tauri runtime](../README.md) → [Commands](README.md) → Models
**Plain English summary.** Owns the Whisper and Parakeet model lifecycle: download with progress events, presence checks, list, load (with optional sequential-GPU coordination against the LLM), and the runtime-capabilities snapshot that Settings consumes (accelerators list, active compute device, CPU features, parallel-mode availability). Also owns the silent warm-up pass that pre-allocates the Whisper context window so the user's first transcription is fast. Emits runtime warnings on startup when the CPU lacks AVX2 / FMA or the Vulkan loader is absent.
## At a glance
- Path: `src-tauri/src/commands/models.rs`.
- LOC: 691.
- Tauri commands exposed (13 total):
- Whisper: `download_model(size)`, `check_model(size)`, `list_models()`, `load_model(size, concurrent)`, `prewarm_default_model_cmd()`, `check_engine()`, `get_runtime_capabilities()`.
- Parakeet: `download_parakeet_model(name)`, `check_parakeet_model(name)`, `list_parakeet_models()`, `load_parakeet_model(name, concurrent)`, `check_parakeet_engine()`.
- Public Rust helpers (used by other command modules): `default_model_id_for_engine`, `ensure_model_loaded`, `prewarm_default_model`, `load_model_from_disk`, `detect_active_compute_device`, `emit_runtime_warnings`.
- Events emitted: `model-download-progress` (whisper), `parakeet-download-progress`, `runtime-warning` (tagged enum: `Avx2Missing`, `VulkanLoaderMissing`, future `CudaFallback`).
- Depends on: `lumotia_transcription::{model_manager, load_whisper, load_parakeet, LocalEngine, Transcriber}`, `lumotia_core::{model_registry, hardware, constants, types}`.
- Called from frontend at: Settings → Models page (download, load, status), the dictation page boot path (`prewarm_default_model_cmd`), Settings → About (runtime capabilities).
## What's in here
### Model id mapping
- `whisper_model_id(size)` (`src-tauri/src/commands/models.rs:18`) — maps legacy size strings (`"tiny"`, `"base"`, `"small"`, `"distil-small"`, `"medium"`, `"distil-large-v3"`) to canonical `ModelId`s used by `model_registry`.
- `parakeet_model_id(name)` (`src-tauri/src/commands/models.rs:32`) — maps `"ctc-int8"` to `parakeet-ctc-0.6b-int8`.
### `load_model_from_disk` (`src-tauri/src/commands/models.rs:77`)
Looks up the registry entry, picks the engine path:
- `Engine::Whisper` (gated on `feature = "whisper"`) calls `load_whisper(&model_file)`. Without the feature, returns a clear error explaining the feature is off.
- `Engine::Parakeet` calls `load_parakeet(&dir)`.
- `Engine::Moonshine` returns "not yet supported".
Returns a `Box<dyn Transcriber + Send>`.
### `default_model_id_for_engine` (`src-tauri/src/commands/models.rs:111`)
Returns `parakeet-ctc-0.6b-int8` for `"parakeet"`, `whisper-base-en` for everything else. Used by `commands::transcription`, `commands::live`, and `prewarm_default_model`.
### `ensure_model_loaded` (`src-tauri/src/commands/models.rs:118`)
The shared model-load gateway used by both whisper and parakeet command paths. Validates the engine matches the model, checks the model is downloaded, and short-circuits if the engine already has the right model loaded. Implements the Phase A.1 sequential-GPU guard (brief item #28): when `concurrent == Some(false)` and the LLM is loaded, unloads the LLM before loading the transcription engine. The inverse guard lives in `commands::llm::load_llm_model`. Loads run inside `spawn_blocking`.
### `prewarm_default_model` (`src-tauri/src/commands/models.rs:180`)
Loads the default Whisper model (if downloaded and not already loaded) plus runs a 1-second silence pass through `transcribe_sync`. The silence run pre-allocates the Whisper context window and warms GPU shader caches so the first real user transcription completes in ≤ 1.5× steady-state latency rather than the 45 s cold-start path documented in `ufal/whisper_streaming` issues #96 and #135. All errors are logged, never panic.
### `prewarm_default_model_cmd` (`src-tauri/src/commands/models.rs:225`)
Tauri command wrapper. `ensure_main_window`. Triggers the warm-up. The frontend invokes this after the dictation page mounts, so warm-up runs in parallel with the first paint.
### Runtime-capabilities reporting
- `RuntimeCapabilities` (`src-tauri/src/commands/models.rs:237`) — frontend-facing struct. Contains `accelerators: Vec<String>`, `engines: Vec<EngineRuntimeCapabilities>`, `active_compute_device`, `cpu_features`, `parallel_mode_available`.
- `ActiveComputeDevice` (`:259`) — `kind`, `label`, optional `reason` (set when we fell back from a richer backend).
- `CpuFeaturesInfo` (`:270`) — avx2 / avx512f / fma / sse4_2 / neon plus a `has_ggml_baseline` shortcut.
- `EngineRuntimeCapabilities` and `ModelRuntimeCapabilities` carry per-engine and per-model status (downloaded, loaded, language support, default model id).
- `compose_accelerators` (`:337`) — pure helper combining whisper-feature flag + Vulkan-loader-availability + target family. Always starts with `"cpu"`, appends `"metal"` (macOS) or `"vulkan"` (other) only when whisper is compiled in AND the loader resolves. Replaces the old hard-coded `["cpu", "vulkan"]` (RB-07).
- `detect_active_compute_device` (`:369`) — returns the `ActiveComputeDevice` snapshot. macOS gets `"metal"` (via MoltenVK) or a CPU-fallback message; everything else gets `"vulkan"` or a CPU-fallback message naming the missing loader package.
- `emit_runtime_warnings` (`:428`) — called from `lib.rs::run` setup. Emits `runtime-warning` events for the `Avx2Missing` and `VulkanLoaderMissing` cases. The frontend renders a one-line banner.
- `get_runtime_capabilities` (`:454`) — assembles and returns the `RuntimeCapabilities` snapshot. Called by Settings.
### Whisper commands (`src-tauri/src/commands/models.rs:515`)
- `download_model(size) -> Result<String, String>` — main-window only. Calls `model_manager::download` with a closure that emits `model-download-progress`.
- `check_model(size) -> Result<bool, String>``model_manager::is_downloaded`.
- `list_models() -> Result<Vec<String>, String>` — returns human-readable size names of currently-downloaded whisper models.
- `load_model(size, concurrent) -> Result<String, String>` — main-window only. Calls `ensure_model_loaded`.
- `check_engine(state) -> Result<bool, String>` — returns whether the whisper engine has any model loaded.
### Parakeet commands (`src-tauri/src/commands/models.rs:576`)
Same shape as whisper, prefixed `parakeet_` and emitting `parakeet-download-progress`.
### Tests (`src-tauri/src/commands/models.rs:631`)
Five `compose_accelerators` permutations cover the RB-07 regression. Confirm:
- Whisper disabled + loader present → `["cpu"]`.
- Whisper enabled + loader missing → `["cpu"]`.
- Whisper enabled + loader present + macOS → `["cpu", "metal"]`.
- Whisper enabled + loader present + Linux/Windows → `["cpu", "vulkan"]`.
- `"cpu"` is always first (frontend index-0 contract).
## Data flow
- **Download:** frontend invokes `download_model(size)``model_manager::download` streams bytes → progress events fire on each chunk → frontend renders progress bar.
- **Load:** frontend invokes `load_model(size, concurrent)``ensure_model_loaded` validates and unloads LLM if `concurrent=false``load_model_from_disk` runs in `spawn_blocking``LocalEngine.load(model, model_id)` stashes the model on the engine.
- **Transcribe:** every transcription path calls `ensure_model_loaded` first. Idempotent when the right model is already loaded.
- **Runtime warnings:** fired once at startup via `lib.rs::run` setup → frontend listens for `runtime-warning` and shows a banner in Settings.
## Watch-outs
- **The `concurrent` flag is a tri-state.** `None` and `Some(true)` keep the legacy parallel-residency behaviour. Only `Some(false)` triggers the unload-the-other-engine guard. Live transcription explicitly passes `None`. If you ever ship a 4 GB-VRAM Settings preset that flips `concurrent=false` by default, also test the live transcription path.
- **`parallel_mode_available` is hard-wired to `false` until Phase A.4 lands a real GPU VRAM probe** (`src-tauri/src/commands/models.rs:509`). Today's frontend reads this and disables the toggle. Flag for follow-up.
- **`prewarm_default_model` only runs whisper.** Parakeet has no warm-up. The Parakeet model is also smaller and loads faster, so the cold-start gap is less obvious. If you swap Lumotia's default to Parakeet, add an equivalent warm-up.
- **Vulkan loader detection is per-platform** (`lumotia_core::hardware::vulkan_loader_available`). The CPU-fallback `reason` strings are user-visible; keep them actionable (the Linux one names `libvulkan1`, the macOS one names the Vulkan SDK runtime).
- **Whisper feature gating.** `--no-default-features` builds compile but `load_model_from_disk` returns a runtime error when the user requests a Whisper model. `list_models` will still show whisper models that happened to be downloaded already; consider hiding them when the feature is off if a no-whisper build ever ships to users.
- **Download progress events fire from a closure inside `model_manager::download`.** That closure is called from inside an async `spawn_blocking`-equivalent. The `let _ = app_clone.emit(...)` pattern silently drops emit errors; if a window has been closed mid-download the progress events stop landing but the download itself completes.
## See also
- [Transcription](transcription.md) — the consumer of `ensure_model_loaded`.
- [Live transcription](live.md) — also calls `ensure_model_loaded` (with `concurrent=None`).
- [LLM](llm.md) — the inverse sequential-GPU guard lives in `commands::llm::load_llm_model`.
- [App lifecycle](../app-lifecycle.md) — `emit_runtime_warnings` is called from setup.
- [Cargo and features](../cargo-and-features.md) — `feature = "whisper"` is what gates `load_model_from_disk`.