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>
6.9 KiB
name, type, slice, last_verified
| name | type | slice | last_verified |
|---|---|---|---|
| Whisper backend (whisper-rs) | architecture-map-page | 03-audio-transcription | 2026/05/09 |
Whisper backend (whisper-rs)
Where you are: Architecture map → Audio + Transcription → Whisper backend
Plain English summary. WhisperRsBackend owns a WhisperContext from whisper-rs 0.16 and runs Whisper directly (not via transcribe-rs). It is the only backend that pipes Lumotia's initial_prompt into the model. Each call to transcribe_sync builds a fresh WhisperState, applies language and prompt parameters, picks a thread count via the power-aware helper, and converts segment timestamps from centiseconds to seconds before returning Vec<Segment>. Vulkan GPU offload is additive behind a Cargo feature.
At a glance
- Crate:
lumotia-transcription - Path:
crates/transcription/src/whisper_rs_backend.rs - LOC: 128
- Cargo feature gate:
whisper(default on). Module is excluded entirely when the feature is off. - External deps:
whisper-rs 0.16(with optionalvulkansub-feature viawhisper-vulkan),thiserror 2,tracing 0.1. - Internal callers (best effort, slice 2 reconciles):
local_engine::load_whisper(crates/transcription/src/local_engine.rs:208) constructs it; production load path runs throughsrc-tauri/src/commands/models.rs.
Public surface:
pub struct WhisperRsBackend—crates/transcription/src/whisper_rs_backend.rs:30. Field:ctx: WhisperContext.pub fn WhisperRsBackend::load(model_path: &Path) -> std::result::Result<Self, WhisperBackendError>—crates/transcription/src/whisper_rs_backend.rs:35.pub enum WhisperBackendError { Load(String), State(String), Transcribe(String) }—crates/transcription/src/whisper_rs_backend.rs:21.thiserror-derived; convertible toMagnotiaError::TranscriptionFailedviato_string().impl Transcriber for WhisperRsBackend—crates/transcription/src/whisper_rs_backend.rs:42.
What's in here
load
whisper_rs_backend.rs:35. WhisperContext::new_with_params(model_path, WhisperContextParameters::default()). Errors map to WhisperBackendError::Load. The context is the heavy object (mmap'd GGML tensors, GPU buffers if Vulkan is active). It is held for the life of the backend.
capabilities
whisper_rs_backend.rs:43. Returns sample_rate = WHISPER_SAMPLE_RATE (slice 5 constant), channels = 1, supports_initial_prompt = true. The truth flag is what tells the Settings UI to surface the prompt field.
transcribe_sync
whisper_rs_backend.rs:56. The actual inference path:
tracing::info!boundary log capturinglanguageandhas_initial_prompt— used by the diagnostic bundle to confirm the prompt actually reached the backend.self.ctx.create_state()— freshWhisperStateper call. The header notes "state can be reused, but fresh-per-call is simpler and matches the transcribe-rs call style we are replacing".FullParams::new(SamplingStrategy::Greedy { best_of: 1 }).- Optional
params.set_language(Some(lang))ifoptions.languageis set and non-empty. - Optional
params.set_initial_prompt(prompt)ifoptions.initial_promptis set and non-empty. params.set_n_threads(inference_thread_count(Workload::Whisper, gpu_offloaded) as i32)wheregpu_offloaded = cfg!(feature = "whisper-vulkan") && vulkan_loader_available(). Power-aware (lumotia_core::tuning::inference_thread_countreads battery vs AC; helper returns a smaller count on battery to preserve runtime).set_print_special(false),set_print_progress(false),set_print_realtime(false)— keep stdout silent.state.full(params, samples)— runs inference.- Loops
state.full_n_segments()callingstate.get_segment(i), pullingseg.to_str(), and converting timestamps:start = seg.start_timestamp() as f64 * 0.01,end = seg.end_timestamp() as f64 * 0.01(whisper-rs reports centiseconds). - Returns
Vec<Segment>.
Errors all flow through MagnotiaError::TranscriptionFailed(WhisperBackendError::*.to_string()).
Data flow
samples (f32, 16 kHz mono)
options: TranscriptionOptions { language, initial_prompt }
└─ tracing::info(boundary)
└─ WhisperState (fresh per call)
└─ FullParams (greedy, best_of=1)
├─ set_language(options.language)
├─ set_initial_prompt(options.initial_prompt)
├─ set_n_threads(inference_thread_count(Whisper, gpu_offloaded))
└─ silence stdout flags
└─ state.full(params, samples)
└─ for i in 0..state.full_n_segments():
Segment { start = t0 * 0.01, end = t1 * 0.01, text = seg.to_str() }
→ Vec<Segment>
Watch-outs
whisper-rs-sysis the C++ link target. Brief item #6 documents the historical Whispering v7.11.0 failure linkingwhisper-rs-sys+tokenizerstogether on Windows MSVC. Thebuild.rsguard panics iftokenizersever lands in the workspace lockfile on a Windows target. See build-tokenizers-guard.md.- Vulkan is detected at runtime, not just compile time.
cfg!(feature = "whisper-vulkan")is the static check;vulkan_loader_available()(slice 5lumotia_core::hardware) confirmslibvulkan.soactually resolves. If the feature is on but the loader is missing, the helper falls back to CPU thread count. - Fresh state per call has a cost.
state.fullwarm-up is lower thanWhisperContextload but non-zero. Brief comment hints reuse is possible. Worth measuring once the live-streaming path is dogfooded. - No diarisation, no temperature fallback, no token suppression flags. Greedy with
best_of: 1is the simplest correct path. Tuning later is a single function. - Timestamp units. whisper-rs returns centiseconds (10 ms). Multiplying by
0.01gives seconds. A prior version that used milliseconds or token offsets would slice timing wrong; tests should pin this. initial_promptis the differentiator fromtranscribe-rs. The whole point of writing this backend (vs going throughSpeechModelAdapter) is that the adapter cannot pipe the prompt. Anyone tempted to "simplify" by routing Whisper through the adapter would silently drop the user-vocabulary feature.- Tracing field name typo immune.
language = ?options.languageuses Debug formatting. IfLanguageever stops implementingDebug, this breaks at compile time, not at runtime.
See also
- Transcription engines overview — the
Transcribertrait this implements. - Cargo features —
whisperandwhisper-vulkanflag matrix. - Build tokenizers guard — the Windows MSVC-CRT defence linked to this backend.
- Tests and fixtures —
whisper_rs_smoke.rsexercises the load + transcribe + initial-prompt path;jfk_bench.rsmeasures cold/warm RTF;thread_sweep.rsvalidates thread-count scaling. lumotia_core::hardware::vulkan_loader_available,lumotia_core::tuning::{inference_thread_count, Workload}(slice 5).