feat(huddle): make STT model selectable + add multilingual Parakeet v3 (#2478) - #2520
feat(huddle): make STT model selectable + add multilingual Parakeet v3 (#2478)#2520artile wants to merge 1 commit into
Conversation
…block#2478) Huddle transcription was hard-pinned to an English-only STT model, so non-English speech transcribed as garbage (block#2478). There was no language setting, env override, or model-swap path — the loader knew one model. Make the huddle STT model selectable behind a small registry: - `STT_MODELS` in huddle/models.rs is the single source of truth for each model: id, download URL, archive checksum, expected files, sherpa-onnx family, manifest version, license, and language coverage. - `select_stt_model` picks a model from the `BUZZ_STT_MODEL` override, then the system locale (non-English -> multilingual), then the English default. The function is pure and unit-tested. - Two models ship: the existing Parakeet TDT-CTC 110M (English, default) and Parakeet TDT 0.6B v3 (multilingual, 25 European languages). Both carry a pinned SHA-256; the v3 hash was computed from the k2-fsa release archive. - huddle/stt.rs configures the sherpa-onnx recognizer per family: NeMo CTC (single model.int8.onnx) or transducer (encoder/decoder/joiner). tokens.txt is shared. The archive checksum is now optional per model (size cap, safe extraction, and expected-files verification always apply); the English default stays pinned. Coverage note: Parakeet v3 covers European languages only. Korean/CJK — the concrete case in block#2478 — is a follow-up: the registry makes adding a CJK model (e.g. SenseVoice-Small) one data entry plus a family already modelled. Zero unsafe, no panics/unwraps on the new paths. New model selection logic is covered by unit tests in huddle::models. Refs block#2478 Signed-off-by: Taras Kornichuk <dread9ko@gmail.com>
d6c3482 to
9236cb8
Compare
LauraGPT
left a comment
There was a problem hiding this comment.
Thanks for opening the model-selection path. I tested the exact language from #2478 and found one correctness gap: the current locale fallback still routes ko-KR to Parakeet v3, although v3 does not support Korean.
I verified the official sherpa-onnx SenseVoice export end to end:
- archive:
sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17.tar.bz2 - size:
163002883bytes - SHA-256:
7d1efa2138a65b0b488df37f8b89e3d91a60676e416f515b952358d83dfd347e - required files:
model.int8.onnx,tokens.txt - coverage: zh/en/ja/ko/yue
- live CPU check with sherpa-onnx 1.13.4: the packaged 4.608 s Korean sample decoded in 0.211 s, detected
<|ko|>, and produced normal Korean text. The packaged zh/ja/en/yue samples also decoded successfully.
The smallest complete fix is to add a SenseVoice family and registry entry, then select models by declared primary-language tags: zh/ja/ko/yue -> SenseVoice, Parakeet's supported European tags -> v3, en -> the existing English default. Unknown non-English locales should not silently select a model that does not support them.
One licensing detail: SenseVoice is under the FunASR Model Open Source License 1.1, not CC-BY-4.0. The archive includes a LICENSE pointer to the FunASR license, so the generic license_text comments should not assume every model is CC-BY.
| .unwrap_or("") | ||
| .to_ascii_lowercase(); | ||
| if !lang.is_empty() && lang != "en" { | ||
| if let Some(model) = STT_MODELS.iter().find(|m| m.multilingual) { |
There was a problem hiding this comment.
This selects the first multilingual model for every non-English locale. In the reported case, ko-KR therefore selects parakeet-v3, but the registry itself documents that v3 has no Korean coverage. Please dispatch on supported primary-language tags rather than a boolean (and add a regression test for ko-KR). If SenseVoice is deferred, at minimum only auto-select v3 for its 25 declared language tags so this PR does not replace one unsupported model with another.
| // Coverage note: Parakeet v3 covers European languages only. CJK/Korean | ||
| // (the concrete case in #2478) is not covered by this model; the registry | ||
| // makes adding a CJK model (e.g. SenseVoice-Small) a follow-up — one data | ||
| // entry, no engine change beyond a family already handled here. |
There was a problem hiding this comment.
SenseVoice is not one data entry with the currently handled families: sherpa-onnx 1.13.4 exposes it through cfg.model_config.sense_voice, so this needs a SttFamily::SenseVoice arm in stt.rs. The configuration is a single model.int8.onnx path plus language = "auto" and use_itn = true; it should not be configured as NemoCtc or Transducer.
|
I implemented the complete SenseVoice follow-up and opened a collaboration PR directly against your current branch: artile#1 It is based exactly on Validation completed on the exact patch:
|
|
@artile, the #2478 reporter has now explicitly confirmed that Korean coverage is the acceptance criterion and asked for the SenseVoice path to be included in this PR. The ready collaboration PR is still cleanly based on your exact head |
|
Data point from a French self-hosted deployment, plus a Whisper comparison that may be useful for the registry design. Same symptom as the Korean report in #2478, in French: "Tu me reçois Smart ? Est-ce que ça marche ?" comes back as "do you feelar Miss Mart? Is it walking". I benchmarked the currently bundled model against this PR's
"Exact" is strict: character-for-character, accents and punctuation included. The current model is unusable on all four. For "Peux-tu vérifier les échecs du DAG Airflow de cette nuit et me dire si c'est une erreur transitoire ?" it returns:
On Whisper. It came up as an alternative, so I measured it rather than guessing. One option worth noting for the registry. Caveats, stated plainly. This is macOS On the Korean acceptance criterion in #2478: this PR does not cover it, but it is what makes covering it possible, and it already fixes the user-facing bug for the 25 languages it does cover. Since #3349 (closed) showed the sherpa-onnx Whisper wiring works, a Happy to re-run any of this, test a CJK model if one is added, or provide the raw outputs. |
|
I have carried this work forward in #4534 on the current |
Summary
Huddle transcription was hard-pinned to an English-only STT model, so non-English speech transcribed as garbage (#2478). There was no language setting, env override, or model-swap path — the loader knew exactly one model.
This makes the huddle STT model selectable, and ships a multilingual option alongside the English default.
Closes the "no model-swap path" root cause in #2478; see the coverage note below for what is and isn't covered by the bundled multilingual model.
What changed
huddle/models.rs— a small STT model registry.STT_MODELSis the single source of truth for each model: id, download URL, archive SHA-256, expected files, sherpa-onnx family, manifest version, license text, and language coverage.select_stt_model(override, locale)— pure, unit-tested selection. Precedence (issue Huddle transcription is English-only: non-English speech (e.g. Korean) produces garbled transcripts #2478 options 2 + 3):BUZZ_STT_MODELenv override, when it names a known model (case-insensitive),parakeet-en(default)parakeet-v3huddle/stt.rsconfigures sherpa-onnx per family: NeMo CTC (singlemodel.int8.onnx) or transducer (encoder/decoder/joiner.int8.onnx);tokens.txtis shared. Downloaded on demand via the existing flow.Option. The size cap, safe extraction, and expected-files verification always apply; the English default stays hash-pinned. Both shipped models are pinned today (the v3 hash was computed from the k2-fsa release archive, since upstream publishes none).Model choice — why Parakeet v3, and the honest coverage note
The issue suggested NVIDIA Parakeet v3, and a sherpa-onnx export exists (
sherpa-onnx-nemo-parakeet-tdt-0.6b-v3-int8), so it is what this PR bundles. It adds 25 European languages with automatic language-ID.Parakeet v3 covers European languages only. The concrete case in #2478 is Korean, which v3 does not cover. This PR removes the architectural root cause (the English-only hard pin) and adds the multilingual model + per-family config path; a CJK model (e.g. SenseVoice-Small, KO/EN/JA/ZH/yue) is now a one-entry follow-up in the registry — the transducer/CTC plumbing it would reuse is already here. Happy to add it in a follow-up if you'd like Korean in this same PR instead.
Testing
cargo check -p buzz-desktop— clean.cargo clippy -p buzz-desktop— clean, no warnings.cargo fmt— clean.cargo test -p buzz-desktop huddle::models— 8 passed, 0 failed. New tests cover: English default, non-English locale → multilingual, override precedence + case-insensitivity, unknown/empty override fallback, registry invariants (unique ids, English default hash-pinned, a multilingual model exists), license-sidecar readiness, and per-family (transducer) readiness.I can't run a live non-English transcription in CI here (it needs the ~465 MB v3 model + a huddle), but the selection/config/readiness paths are unit-tested and the archive contents/subdir/files were verified against the k2-fsa release. Glad to help test Korean once a CJK model lands (ties back to #2478).
Notes
unsafe; no panics/unwraps on the new paths.Refs #2478