Files
echo-core/tasks/voice-bench-results.md
Marius Mutu c6d11bdf9f chore(voice): spike STT latency benchmark + HT contention lesson
Pas 1 (BLOCKING) din Discord voice-to-voice test plan. Sweet spot empiric
pe i7-6700T: faster-whisper small int8 @ cpu_threads=4 → p50 2.25s,
p95 2.64s, mean RTF 0.46. Curba HT: 2t=3.25s → 4t=2.25s (sweet) →
6t=2.79s (regres +24% prin contention). tiny respinge — halucinează RO.

- tools/voice_bench.py: harness benchmark cu 8 sample-uri RO sintetizate
  via Supertonic API, măsoară p50/p95/RTF pentru small+tiny pe N threads.
- tools/voice_bench_results*.json: raw output 3 pass-uri (threads 2/4/6).
- tasks/voice-bench-results*.md: summary markdown per pass.
- tasks/lessons.md: HT contention rule — cpu_threads = physical cores,
  rulează sweep nu single-point pentru ML inference compute-bound.

Budget updated în plan-uri: STT p50 1.5s → 2.5s, perceived 4s → 5s p50.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 12:52:11 +00:00

5.1 KiB

Voice Bench Results — Discord Voice-to-Voice Spike (BLOCKING Pas 1)

Generated: 2026-05-27 Hardware: i7-6700T (4 physical cores / 8 logical), Proxmox VM, no GPU Budget original: STT p50 < 1.50s (per CEO plan aspirational) Budget honest range: 1.5-3s (per Outside Voice #1, baked in CEO plan)

Final Recommendation: PASS cu small model + cpu_threads=4

small @ 4t → p50 2.25s, p95 2.64s, mean RTF 0.46. Cade în honest range "1.5-3s" deja acceptat. Transcript clean modulo normalizare numerică (deja în scope: src/voice/normalize.py).

Auto-decision script-ul (FALLBACK_TINY) este override-uit manual: tiny produce transcript ilizibil ("Stei putin", "muină să sun la nu a", "să mream in test de seare") — neutilizabil în RO. Latency-ul rapid nu compensează lipsa de înțelegere.

Surprise Finding: Threads Sweet Spot = 4, nu 6

Sweep complet:

cpu_threads small.p50 small.p95 mean RTF Δ p50 vs threads=4
2 3.25s 3.63s 0.67 +44% (slower)
4 2.25s 2.64s 0.46 baseline
6 2.79s 3.31s 0.70 +24% (slower!)

tiny essentially flat (~0.5s) la orice thread count — CPU-light enough că nu beneficiază.

Explicație: i7-6700T = 4 physical cores + 4 hyperthreads. cpu_threads=4 fitează exact pe physical cores (no hyperthread contention). cpu_threads=6 spill-uiește pe hyperthreads care HURT compute-bound int8 inference (memory bandwidth contention, fără parallelism real). Lock în plan: cpu_threads=4 regardless of VM core count. Adăugarea de cores în VM nu mai accelerează small peste 4 threads.

Implicații pentru implementare

  1. src/voice/pipeline.py
    WhisperModel("small", device="cpu", compute_type="int8", cpu_threads=4)
    
  2. Plan budget update: STT p50 = 2.25s (era 1.5s); perceived round-trip estimate = 3.5-5s (STT 2.25s + Claude TTFB 0.5-1s + streaming TTS first clause ~0.5s).
  3. Streaming Claude→TTS rămâne critic — fără el, total perceived = 6-8s, peste limita conversațională.
  4. Filler audio "Stai să-mi adun gândurile" (deja în plan) maschează cazurile p95 (>3s).
  5. Tiny model rămâne instalat dar doar pentru /voice doctor degraded mode (Whisper OOM, low memory), NU pentru happy path.

Transcript Quality (4 threads run)

Input small output tiny output
"Salut, ce mai faci?" "Salut ce mai faci!" "Salut, ce mai fac?"
"Stai puțin să mă gândesc la asta." "Stai putin să mă gândesc la asta." "Stei putin să mă gândesc la asta."
"Am verificat în calendar și avem ședință cu echipa la trei după-amiază." "Am verificat în calendari și avem sedință cu echipa la 3 după amiază." "Am verificat în calendar și avem sedeință cu equipala 3 du pămiază."
"Costul total este o sută douăzeci și trei de lei și cincizeci de bani." "Costul total este 120 și 3 delei și 50 de bani." "Costul total este o suta 20 și 3 de lei și 50 de bani."
"Marius, vrei să-ți pun pe agenda de mâine să suni la NOAA?" "Marius, vrei să-ți spun pe agenda de mâine să suni la noa a." "Marius, vrei să-ți pun pe agenda de muină să sun la nu a."
"Vreau să-mi reamintești diseară..." "Vreau să mi-răimintești di seară..." "Vreau să mream in test de seare..."

Pattern erori:

  • small: diacritice missing (putin/puțin, sedință/ședință), numere ca digiti ("3" în loc de "trei" — normalizator inverse din scope), acronime ("noa" pentru NOAA — expected, deferr), aglutinare minoră ("delei", "răimintești").
  • tiny: cuvinte INVENTATE ("mream", "muină", "equipala", "sunilă"). Hallucination, nu doar misspell. Unusable.

Open Questions (pentru decizie finală)

  1. Acceptăm 2.25s p50? YES — în honest range CEO plan deja aprobat. User-facing communication: "Echo gândește 2-3 secunde înainte să răspundă" (vs. aspirational sub-secundă).
  2. Activate restul de 2 cores offline (5,6)? Marginal — nu va îmbunătăți peste threads=4 sweet spot. Worth doar pentru concurrent workloads (TTS + STT simultan, alte servicii).
  3. Network STT alternative (Groq/Deepgram)? Deferred — small @ 4t confirmat sufficient. Reconsiderăm DOAR dacă post-implementation p95 perceived >7s.

Hardware Context

  • Intel(R) Core(TM) i7-6700T CPU @ 2.80GHz (Skylake mobile, 2015)
  • Cores online (final): 6 logical (0-4, 7), 2 offline (5, 6)
  • Physical cores: 4 (TUI 8 logical via HT)
  • RAM: 6.0Gi total, ~2.0Gi available
  • No GPU (CPU-only int8 inference)
  • ctranslate2 4.7.2 + faster-whisper 1.2.1

Raw Data

  • tools/voice_bench_results.json — last run (threads=6)
  • tools/voice_bench_results_threads4.jsonWINNING config (threads=4)
  • tools/voice_bench_results_threads2.json — baseline (threads=2)
  • tasks/voice-bench-results-threads2.md — narrative threads=2
  • tasks/voice-bench-results-threads4.md — narrative threads=4

Status

BLOCKING Pas 1 → CLEARED. Sweet spot identificat. Plan file ready pentru update.