Files
echo-core/tasks/voice-stt-quality.md
Marius Mutu ce273d14db feat(voice): improve Romanian STT — hallucination gate + finetuned model
Gemma 4 cloud audio was infeasible (31b-cloud has no audio; E4B broken
upstream, no deploy host), so improve faster-whisper instead.

- Pin temperature=0.0 to disable the fallback ladder that re-decoded unclear
  audio up to 6x (source of the 16-24s latency outliers); reject hallucinated
  segments via avg_logprob/compression_ratio in the new pure _filter_segments.
- Adopt mikr/whisper-small-ro-cv11 (CT2 int8) via configurable voice.stt_model:
  spike showed WER 24%->10%, numbers fixed at source, +0.33s p50 (in budget).
- Add tools/voice_stt_mine.py (log mining) + tools/voice_stt_spike.py (model
  eval with diacritic scoring) + tests for the gate and miner.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-27 18:16:16 +00:00

3.6 KiB

Voice STT Quality — îmbunătățiri Whisper

Branch: voice/stt-quality. Origine: cererea de a folosi Gemma 4 cloud pentru audio (infezabil — gemma4:31b-cloud n-are audio, E4B e stricat upstream, fără host de deploy). Pivot la îmbunătățirea Whisper, validat prin /autoplan (CEO + Eng review).

Ce s-a livrat

1. Gate rejection halucinații (cost zero latență) — src/voice/pipeline.py

  • model.transcribe(..., temperature=0.0)dezactivează scara de fallback a faster-whisper. Codul vechi nu pasa temperature, deci folosea implicit [0.0..1.0] (6 pași) care re-decoda segmentul pe audio prost → exact sursa latențelor de 24.4s / 16.7s din voice_stt_log.jsonl.
  • _filter_segments() — funcție pură nouă care dropează segmentele cu no_speech_prob mare, avg_logprob < -1.0 (decoder nesigur) sau compression_ratio > 2.4 (buclă/gunoi). Zero re-decodare. Prinde „Care pune o zana judiciul tugea" / „Acest lucru a fost foarte mult".
  • hotwords += Bitcoin. initial_prompt neatins (evită taxa de latență pe fiecare enunț).
  • Teste: tests/test_voice_pipeline_filter.py (8 cazuri).

2. Unealtă de mining — tools/voice_stt_mine.py

  • CLI read-only peste voice_stt_log.jsonl: frecvențe token, tokeni rari (candidați hotwords/corecții), candidați diacritice lipsă, rânduri suspecte de halucinație.
  • Tolerează rânduri fără text_corrected (citește text). Teste: tests/test_voice_stt_mine.py (13).

3. Spike model RO-finetuned (D1) — tools/voice_stt_spike.py

Compară modele faster-whisper pe audio RO sintetizat (Supertonic) cu ground-truth diacritizat.

Rezultat (threads=4, beam=5):

Model p50 p95 WER Diacritice
small (baseline) 2.59s 3.04s 24.2% 12/20
mikr/whisper-small-ro-cv11 (CT2 int8) 2.92s 3.25s 10.5% 17/20
  • WER se înjumătățește; diacritice 60%→85%; numere PERFECTE (baseline: „120 si 3 delei" → finetuned: „o sută douăzeci și trei de lei"). Cost: +0.33s p50 (în bugetul 1.5-3s).
  • Modelul CT2: ~/.cache/echo-ct2/whisper-small-ro-cv11-int8 (234M int8).

4. Model STT configurabil — src/voice/pipeline.py::_get_whisper_model

  • Citește voice.stt_model din config (default "small"). Adopția finetuned = flip config, nu cod. Default rămâne small până la decizia de adopție.

Cum adopți modelul finetuned (când decizi)

# config.json → "voice": { ..., "stt_model": "/home/moltbot/.cache/echo-ct2/whisper-small-ro-cv11-int8" }
systemctl --user restart echo-core   # reload model

Re-rulează spike-ul oricând: python3 tools/voice_stt_spike.py --models "small,<path>" --threads 4

Decizii autoplan respinse (din review)

  • temperature=[0.0..0.6] fallback → regresie latență pe worst-case. Înlocuit cu rejection.
  • canonicalize_wakewordnu există wake gate în cod (verificat); ar fi spart detect_voice_change.
  • Dicționar diacritice pe calea Claude → Claude citește română stâlcită OK; finetuned-ul rezolvă la sursă.
  • correct_vocab / src/voice/stt_correct.py → deferate (21 mostre = anecdotă; mining adună întâi date).

Note de mediu

  • transformers 5.12.1 instalat în .venv pentru conversia CT2 (one-time). A downgradat tokenizers 0.23.1→0.22.2 (faster-whisper încă OK, pin <1 respectat). Se poate pip uninstall transformers dacă nu mai e nevoie de conversii.
  • Pre-existent, neatins de mine: tools/tts.py modificat necommis sparge 2 teste din test_voice_normalize.py (truncare 200 cuvinte). Confirmat: cu tts.py committed, testele trec.