[#141] Pre-provision alignment models so no model downloads mid-transcription - #147
Conversation
QA Confidence Verdict — #141 (PR #147)Backend transcription-pipeline change; no UI surface, so Playwright is N/A. Verified by diff review + unit suite (WhisperX present in the local venv, so the drift-guard tests actually executed rather than skipping). What was verified
Unit suite: 338 passed ( What needs human eyes
Risk areas
Suggested QA focusQuick: one clean-install provisioning run watching for the Thai model in the progress list. Thorough: an upgrade-path run (already-provisioned install) to confirm re-provisioning fires and a Thai transcription aligns without the 50% stall. ~15 min total. Verdict: high confidence, all 5 AC met. No code issues found. Residual risk is entirely in un-mocked network/E2E behavior, appropriately flagged for human validation. #145 correctly tracks the remaining lazy-download UI case for un-provisioned languages. |
Closes #141
Summary
WhisperX HuggingFace wav2vec2 alignment models were downloading lazily at the align stage (50%) the first time a language was used, into the bundled service's isolated
HF_HOME. During that download the job sat frozen at "Aligning timestamps… 50%" — indistinguishable from a hang, with no download messaging. Only first-run provisioning had a real download-progress UI.This pre-downloads the alignment models for a configured language set during provisioning, so the align step never downloads mid-transcription. The default set is Thai (
th) — the one HuggingFace-backed language this deployment commonly uses. English and the other torch-native languages (French, German, Spanish, Italian) live in the shared~/.cache/torchand never needed an HF download. TheALIGNMENT_TIMEOUT_SECwatchdog remains the safety net for any language left unprovisioned (auto-detect landing on an HF language, or a language outside the configured set) — surfacing that residual case with its own download indicator is tracked in #145.Approach
Option 2 from the issue (prefetch a configured common set during provisioning), chosen over per-selection download (option 1 — large cross-surface diff across the web and native Swift upload forms) and prefetch-all (option 3 — ~15 GB, too heavy). It reuses the existing provisioning download + version-gate + progress-UI mechanism end to end, so no frontend or Swift changes are needed.
backend/services/align_models.pyholdsHF_ALIGN_REPOS(a copy of WhisperX'sDEFAULT_ALIGN_MODELS_HFplus this app'sthoverride) as the single source of truth, so provisioning pre-fetches exactly the repo the transcriber loads. Kept free ofwhisperx/torch/huggingface_hubimports so provisioning and its tests stay lightweight (those deps are absent in CI).ServiceConfig.align_languages(default["th"]) makes the prefetch set configurable via the persisted config.provisioning.required_repos()appends the resolved align repos (deduped);PROVISIONING_VERSIONis bumped 2 → 3 so already-provisioned installs re-provision and fetch the addition instead of downloading it lazily — the same mechanism used for the earlier wespeaker fix.transcriber.pynow resolves the align model name from the shared mapping (removing the localCUSTOM_ALIGN_MODELS); behavior-preserving because the values equal WhisperX's own defaults andthis unchanged.Full design in
docs/plans/141-pre-provision-alignment-models.md.Verification
ruff checkandruff format --check: clean.pytest tests/unit: 337 passed (plus the new/updatedtest_align_models.pyandtest_provisioning.py).align_repos_for(skips torch-native/unknown, dedup, order-stable), the default-set provisioning list, and drift guards assertingHF_ALIGN_REPOS/TORCH_ALIGN_LANGUAGESstay in sync with WhisperX where it is importable (the guard ran and passed locally).