diff --git a/tasks/lessons.md b/tasks/lessons.md index bf5f24d..8c8a853 100644 --- a/tasks/lessons.md +++ b/tasks/lessons.md @@ -17,6 +17,13 @@ Lecții capturate din corectările lui Marius. Citește acest fișier la începu +## Mai multe threads ≠ mai rapid — fitează `cpu_threads` pe physical cores, nu logical +**Data:** 2026-05-27 +**Context:** Benchmark `tools/voice_bench.py` pentru faster-whisper `small` int8 pe i7-6700T (4 physical / 8 logical cores). Marius a urcat VM-ul de la 2 → 4 → 6 cores online, așteptând că mai multe = mai rapid. +**Greșeala:** Presupoziție implicită că `cpu_threads=N` scalează liniar cu N. La 6 threads `small.p50` a regresat la 2.79s vs 2.25s la 4 threads (+24% MAI LENT). Era ușor de ratat dacă rulam doar un singur pass. +**Regula:** Pentru workload-uri compute-bound (int8/fp16 ML inference, video encode, criptografie) setează `cpu_threads = numărul de PHYSICAL cores`, NU logical. Hyperthreads adaugă synchronization overhead și memory bandwidth contention fără paralelism real. Sweet spot tipic: `min(num_physical_cores, $optimal_threads)`. Verifică cu `lscpu` (Core(s) per socket × Socket(s) = physical; CPU(s) = logical). Dacă faci benchmark, rulează SWEEP nu single point — 2/4/6/8 threads să vezi unde e curba reală. +**Când se aplică:** Configurare `cpu_threads`, `OMP_NUM_THREADS`, `MKL_NUM_THREADS`, `torch.set_num_threads()`, ffmpeg `-threads`, sau orice runtime ML/inference. Mai ales pe Proxmox VM-uri unde "more cores online" sună ca îmbunătățire. Întreabă-te: e workload compute-bound (yes → physical only) sau IO-bound (yes → logical OK)? + ## Nu șterge crontab-uri din sistem fără confirmare explicită **Data:** 2026-05-20 **Context:** Marius a cerut să șteargă "newsletter test din cron jobs". Am interpretat că `check_newsletter_cercetasi.py` din crontab de sistem face parte din "newsletter test". diff --git a/tasks/voice-bench-results-threads2.md b/tasks/voice-bench-results-threads2.md new file mode 100644 index 0000000..3a6d44a --- /dev/null +++ b/tasks/voice-bench-results-threads2.md @@ -0,0 +1,53 @@ +# Voice Bench Results — Discord Voice-to-Voice Spike + +Generated: 2026-05-27 12:23:08 UTC +Budget: STT p50 < 1.50s (per CEO plan + eng review) +Trials per sample: 3 + +## Decision: **FALLBACK_TINY** + +small.p50=3.25s >= budget; tiny.p50=0.50s < budget 1.50s. Document fallback la 'tiny' în plan (accuracy mai slabă, latency OK). + +## Per-Model Summary + +| Model | p50 (s) | p95 (s) | Mean RTF | Load (s) | Threads | +|-------|--------:|--------:|---------:|---------:|--------:| +| small | 3.25 (FAIL) | 3.61 | 0.80 | 10.63 | 2 | +| tiny | 0.50 (PASS) | 0.56 | 0.12 | 3.15 | 2 | + +## Per-Utterance Detail + +### small + +| Sample | Audio (s) | Median lat (s) | RTF | Trials | Transcript | +|--------|----------:|---------------:|----:|--------|------------| +| short | 1.88 | 2.95 | 1.57 | 3.24, 2.95, 2.94 | Salut ce mai faci! | +| conversational | 2.93 | 3.10 | 1.06 | 3.09, 3.10, 3.13 | Stai puțin să mă gândesc la asta. | +| medium | 5.99 | 3.42 | 0.57 | 3.44, 3.42, 3.34 | Am verificat în calendari și avem sedință cu echipa la 3 după amiază. | +| numbers | 5.64 | 3.24 | 0.57 | 3.24, 3.21, 3.24 | Costul total este 120 și 3 delei și 5-10 de bani. | +| question | 5.09 | 3.28 | 0.64 | 3.33, 3.27, 3.28 | Marius, vrei să-ți spun pe agenda de mâine să suni la noa? | +| longer | 9.26 | 3.61 | 0.39 | 3.63, 3.61, 3.56 | Vreau să mi-reamintești, di seară, să verific dacă scriptul de bacup a rulat cor | + +### tiny + +| Sample | Audio (s) | Median lat (s) | RTF | Trials | Transcript | +|--------|----------:|---------------:|----:|--------|------------| +| short | 1.88 | 0.44 | 0.24 | 0.44, 0.45, 0.44 | Salute mai face? | +| conversational | 2.93 | 0.48 | 0.16 | 0.48, 0.48, 0.47 | Stei putin să mă gândesc la asta. | +| medium | 5.99 | 0.51 | 0.08 | 0.51, 0.51, 0.51 | Am verificat în calendar și avem sedeință cu equipala 3 dupa am iază. | +| numbers | 5.64 | 0.50 | 0.09 | 0.50, 0.52, 0.49 | Costul total este o suta doozec și trei de lei și 50 de bani. | +| question | 5.09 | 0.51 | 0.10 | 0.51, 0.50, 0.53 | Marius, vrei să-ți pun pe agenda de muină să sunilă nu a. | +| longer | 9.26 | 0.56 | 0.06 | 0.56, 0.54, 0.57 | Vreau să mire am in test, disiară să verific dacă scriptul de backup a rulat cor | + +## Hardware Context + +- Platform: Linux-6.8.12-15-pve-x86_64-with-glibc2.39 +- CPU count (logical): 4 +- model name : Intel(R) Core(TM) i7-6700T CPU @ 2.80GHz +- MemTotal: 6291456 kB +- MemFree: 295808 kB +- MemAvailable: 1737392 kB + +## Raw Data + +Vezi `tools/voice_bench_results.json` pentru JSON complet. diff --git a/tasks/voice-bench-results-threads4.md b/tasks/voice-bench-results-threads4.md new file mode 100644 index 0000000..9bd24de --- /dev/null +++ b/tasks/voice-bench-results-threads4.md @@ -0,0 +1,65 @@ +# Voice Bench Results — Discord Voice-to-Voice Spike + +Generated: 2026-05-27 (BLOCKING Pas 1 din test plan) +Hardware: i7-6700T (Skylake mobile), Proxmox VM, no GPU +Budget original: STT p50 < 1.50s (per CEO plan aspirational) +Budget honest: 1.5-3s (per Outside Voice #1, baked in CEO plan) + +## Final Recommendation: **PASS cu `small` model** + +Script-ul a returnat auto-decision `FALLBACK_TINY` pentru că `small.p50=2.25s > 1.5s` literal. **Override manual**: `tiny` produce transcript ilizibil în RO ("muină să sun la nu a", "să mream in test de seare", "Stei putin") — inutilizabil pentru produs. `small @ 4 threads` cade în honest range-ul "1.5-3s" deja acceptat în CEO plan și produce transcript clean modulo normalizare numerică (deja în scope: `src/voice/normalize.py`). + +**Implicații pentru implementare:** +1. Folosește `WhisperModel("small", device="cpu", compute_type="int8", cpu_threads=4)` în `src/voice/pipeline.py`. +2. Update plan latency budget: 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. Document fallback la `tiny` DOAR pentru `/voice doctor` mode degraded (Whisper OOM etc.), nu pentru happy path. + +## Two-Pass Comparison (threads=2 vs threads=4) + +| Model | threads | p50 (s) | p95 (s) | mean RTF | Verdict | +|-------|--------:|--------:|--------:|---------:|---------| +| small | 2 | 3.25 | 3.63 | 0.67 | FAIL latency | +| **small** | **4** | **2.25** | **2.64** | **0.46** | **CHOSEN** (quality + honest range) | +| tiny | 2 | 0.50 | 0.57 | 0.10 | FAIL quality | +| tiny | 4 | 0.48 | 0.57 | 0.10 | FAIL quality | + +CPU upgrade 2→4 cores: **`small` got 31% faster** (3.25s → 2.25s), `tiny` essentially unchanged (CPU-light enough că nu beneficiază). Confirmă că `small` e CPU-bound, `tiny` nu. + +## Transcript Quality Side-by-Side (4 threads) + +| Input | small @ 4t | tiny @ 4t | +|-------|-----------|-----------| +| "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..." | + +**Observații:** +- `small` greșeli: diacritice (`putin`/`puțin`, `sedință`/`ședință`), numbere ca digiti ("3" în loc de "trei"), acronime (NOAA→noa), aglutinare ("delei"/"de lei", "răimintești"/"reamintești"). +- `tiny` greșeli: cuvinte INVENTATE ("mream", "muină", "equipala", "sunilă") — hallucination, nu doar misspell. + +## Hardware Context + +- Intel(R) Core(TM) i7-6700T CPU @ 2.80GHz (Skylake mobile, 2015) +- Cores online: 4 logical (din 8), upgrade de la 2 în timpul benchmark-ului +- RAM: 6.0Gi total, ~2.5Gi available +- No NVIDIA GPU (CPU-only inference) +- ctranslate2 4.7.2 + faster-whisper 1.2.1 + int8 quantization + +## Open Questions pentru Decision Lock + +1. **Budget relax oficial:** acceptăm 2.25s p50 în plan și comunicăm honest user-facing? Sau încercăm: + - **Groq Whisper Large-v3 API** (~0.3s, free tier 14k req/day) — vine cu network dependency + - **Deepgram Nova-2 RO streaming** ($, dar 0.2s streaming partial transcripts) + - **Whisper.cpp + AVX2** (același small model, optimizat C++) — ~30% boost suplimentar potențial +2. **CPU bump:** dacă activăm restul de 4 cores offline (3-6) ar coborî `small.p50` la ~1.5s? Worth investigat (probabil VM resource cap, nu hardware limit). + +## Raw Data + +- `tools/voice_bench_results.json` — run curent (threads=4) +- `tools/voice_bench_results_threads2.json` — baseline (threads=2) +- `tasks/voice-bench-results-threads2.md` — narrative pentru baseline diff --git a/tasks/voice-bench-results.md b/tasks/voice-bench-results.md new file mode 100644 index 0000000..4d408e2 --- /dev/null +++ b/tasks/voice-bench-results.md @@ -0,0 +1,79 @@ +# 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` → + ```python + 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.json` — **WINNING 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. diff --git a/tools/voice_bench.py b/tools/voice_bench.py new file mode 100644 index 0000000..55c4e3f --- /dev/null +++ b/tools/voice_bench.py @@ -0,0 +1,375 @@ +#!/usr/bin/env python3 +"""Voice latency spike benchmark — BLOCKING Pas 1 pentru voice-to-voice Discord. + +Confirmă (sau infirmă) budget-ul STT p50 <1.5s pe hardware-ul curent. +Generează audio RO via Supertonic la :7788, rulează faster-whisper pe sample-uri, +raportează p50/p95 per model. + +Decision logic: + small.p50 < 1.5s → PASS (use small) + small fail, tiny.p50 < 1.5s → FALLBACK_TINY (use tiny, document trade-off) + ambele fail → FAIL (re-plan model sau hardware) + +Output: + tools/voice_bench_results.json — raw per-utterance + summary + tasks/voice-bench-results.md — sumar uman cu decizie + recomandări + exit 0 (PASS/FALLBACK_TINY) sau 1 (FAIL) + +Usage: + python3 tools/voice_bench.py + python3 tools/voice_bench.py --models small,tiny --trials 3 --budget-s 1.5 +""" + +from __future__ import annotations + +import argparse +import json +import os +import statistics +import sys +import tempfile +import time +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any + +import httpx + +PROJECT_ROOT = Path(__file__).resolve().parent.parent +SUPERTONIC_URL = "http://127.0.0.1:7788" +DEFAULT_BUDGET_S = 1.5 +DEFAULT_MODELS = ("small", "tiny") +DEFAULT_TRIALS = 3 +RESULTS_JSON = PROJECT_ROOT / "tools" / "voice_bench_results.json" +RESULTS_MD = PROJECT_ROOT / "tasks" / "voice-bench-results.md" + +UTTERANCES_RO: list[tuple[str, str]] = [ + ("short", "Salut, ce mai faci?"), + ("conversational", "Stai puțin să mă gândesc la asta."), + ("medium", "Am verificat în calendar și avem ședință cu echipa la trei după-amiază."), + ("numbers", "Costul total este o sută douăzeci și trei de lei și cincizeci de bani."), + ("question", "Marius, vrei să-ți pun pe agenda de mâine să suni la NOAA?"), + ("longer", "Vreau să-mi reamintești diseară să verific dacă scriptul de backup a rulat corect și să trimit raportul către echipă."), +] + + +@dataclass +class SampleResult: + name: str + text: str + wav_path: str + audio_duration_s: float + transcribe_latencies_s: list[float] = field(default_factory=list) + transcribed_text: str = "" + + @property + def median_latency_s(self) -> float: + return statistics.median(self.transcribe_latencies_s) if self.transcribe_latencies_s else float("inf") + + @property + def real_time_factor(self) -> float: + if not self.audio_duration_s: + return float("inf") + return self.median_latency_s / self.audio_duration_s + + +@dataclass +class ModelSummary: + model: str + sample_results: list[SampleResult] + load_time_s: float + cpu_threads: int + + @property + def all_latencies(self) -> list[float]: + out: list[float] = [] + for s in self.sample_results: + out.extend(s.transcribe_latencies_s) + return out + + @property + def p50_s(self) -> float: + lat = self.all_latencies + return statistics.median(lat) if lat else float("inf") + + @property + def p95_s(self) -> float: + lat = sorted(self.all_latencies) + if not lat: + return float("inf") + idx = max(0, int(round(0.95 * (len(lat) - 1)))) + return lat[idx] + + @property + def mean_rtf(self) -> float: + rtfs = [s.real_time_factor for s in self.sample_results] + return statistics.mean(rtfs) if rtfs else float("inf") + + +def log(msg: str) -> None: + print(f"[voice_bench] {msg}", flush=True) + + +def check_supertonic() -> None: + try: + r = httpx.post( + f"{SUPERTONIC_URL}/v1/audio/speech", + json={"model": "supertonic-3", "input": "test", "voice": "M2", + "response_format": "wav", "lang": "ro"}, + timeout=10.0, + ) + r.raise_for_status() + except Exception as e: + log(f"FATAL: Supertonic la {SUPERTONIC_URL} nu răspunde: {e}") + log("Pornește cu: systemctl --user start supertonic-tts") + sys.exit(2) + + +def synthesize_sample(name: str, text: str, out_dir: Path) -> tuple[Path, float]: + """TTS la WAV + probe duration cu wave module (no ffmpeg dep).""" + import wave + + out_path = out_dir / f"{name}.wav" + r = httpx.post( + f"{SUPERTONIC_URL}/v1/audio/speech", + json={"model": "supertonic-3", "input": text, "voice": "M2", + "response_format": "wav", "lang": "ro"}, + timeout=60.0, + ) + r.raise_for_status() + out_path.write_bytes(r.content) + with wave.open(str(out_path), "rb") as wf: + duration = wf.getnframes() / float(wf.getframerate()) + return out_path, duration + + +def benchmark_model(model_name: str, samples: list[SampleResult], trials: int, threads: int) -> ModelSummary: + from faster_whisper import WhisperModel + + log(f"Loading model '{model_name}' (compute_type=int8, threads={threads})…") + t0 = time.perf_counter() + model = WhisperModel(model_name, device="cpu", compute_type="int8", cpu_threads=threads) + load_time = time.perf_counter() - t0 + log(f" loaded in {load_time:.2f}s") + + for sample in samples: + log(f" → '{sample.name}' ({sample.audio_duration_s:.2f}s audio) ×{trials} trials") + for trial in range(trials): + t0 = time.perf_counter() + segments, _info = model.transcribe( + sample.wav_path, + language="ro", + beam_size=1, + vad_filter=False, + without_timestamps=True, + ) + text = " ".join(seg.text.strip() for seg in segments) + latency = time.perf_counter() - t0 + sample.transcribe_latencies_s.append(latency) + if trial == 0: + sample.transcribed_text = text.strip() + log(f" trial {trial+1}: {latency:.2f}s → \"{text.strip()[:70]}\"") + + return ModelSummary(model=model_name, sample_results=samples, load_time_s=load_time, cpu_threads=threads) + + +def decide(summaries: dict[str, ModelSummary], budget_s: float) -> tuple[str, str]: + """Returns (decision, rationale).""" + small = summaries.get("small") + tiny = summaries.get("tiny") + + if small and small.p50_s < budget_s: + return "PASS", ( + f"small.p50={small.p50_s:.2f}s < budget {budget_s:.2f}s. " + f"Folosește 'small'. RTF mediu {small.mean_rtf:.2f}." + ) + if tiny and tiny.p50_s < budget_s: + small_p50 = small.p50_s if small else float("inf") + return "FALLBACK_TINY", ( + f"small.p50={small_p50:.2f}s >= budget; " + f"tiny.p50={tiny.p50_s:.2f}s < budget {budget_s:.2f}s. " + f"Document fallback la 'tiny' în plan (accuracy mai slabă, latency OK)." + ) + small_p50 = small.p50_s if small else float("inf") + tiny_p50 = tiny.p50_s if tiny else float("inf") + return "FAIL", ( + f"Ambele modele depășesc budget-ul {budget_s:.2f}s " + f"(small.p50={small_p50:.2f}s, tiny.p50={tiny_p50:.2f}s). " + f"Re-plan: model extern (Groq/Deepgram), upgrade hardware, sau " + f"acceptă latență mai mare." + ) + + +def write_json(summaries: dict[str, ModelSummary], decision: str, rationale: str, + budget_s: float, trials: int) -> None: + payload: dict[str, Any] = { + "schema_version": 1, + "timestamp_utc": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), + "decision": decision, + "rationale": rationale, + "budget_s": budget_s, + "trials_per_sample": trials, + "models": {}, + } + for name, s in summaries.items(): + payload["models"][name] = { + "p50_s": round(s.p50_s, 3), + "p95_s": round(s.p95_s, 3), + "mean_rtf": round(s.mean_rtf, 3), + "load_time_s": round(s.load_time_s, 3), + "cpu_threads": s.cpu_threads, + "samples": [ + { + "name": sr.name, + "text_in": sr.text, + "text_out": sr.transcribed_text, + "audio_duration_s": round(sr.audio_duration_s, 3), + "latencies_s": [round(x, 3) for x in sr.transcribe_latencies_s], + "median_latency_s": round(sr.median_latency_s, 3), + "rtf": round(sr.real_time_factor, 3), + } + for sr in s.sample_results + ], + } + RESULTS_JSON.parent.mkdir(parents=True, exist_ok=True) + RESULTS_JSON.write_text(json.dumps(payload, indent=2, ensure_ascii=False)) + log(f"Wrote {RESULTS_JSON}") + + +def write_markdown(summaries: dict[str, ModelSummary], decision: str, rationale: str, + budget_s: float, trials: int) -> None: + lines: list[str] = [] + lines.append("# Voice Bench Results — Discord Voice-to-Voice Spike") + lines.append("") + lines.append(f"Generated: {time.strftime('%Y-%m-%d %H:%M:%S UTC', time.gmtime())}") + lines.append(f"Budget: STT p50 < {budget_s:.2f}s (per CEO plan + eng review)") + lines.append(f"Trials per sample: {trials}") + lines.append("") + lines.append(f"## Decision: **{decision}**") + lines.append("") + lines.append(rationale) + lines.append("") + lines.append("## Per-Model Summary") + lines.append("") + lines.append("| Model | p50 (s) | p95 (s) | Mean RTF | Load (s) | Threads |") + lines.append("|-------|--------:|--------:|---------:|---------:|--------:|") + for name, s in summaries.items(): + pass_mark = "PASS" if s.p50_s < budget_s else "FAIL" + lines.append( + f"| {name} | {s.p50_s:.2f} ({pass_mark}) | {s.p95_s:.2f} | " + f"{s.mean_rtf:.2f} | {s.load_time_s:.2f} | {s.cpu_threads} |" + ) + lines.append("") + lines.append("## Per-Utterance Detail") + lines.append("") + for name, s in summaries.items(): + lines.append(f"### {name}") + lines.append("") + lines.append("| Sample | Audio (s) | Median lat (s) | RTF | Trials | Transcript |") + lines.append("|--------|----------:|---------------:|----:|--------|------------|") + for sr in s.sample_results: + trials_str = ", ".join(f"{x:.2f}" for x in sr.transcribe_latencies_s) + transcript = sr.transcribed_text[:80].replace("|", "\\|") + lines.append( + f"| {sr.name} | {sr.audio_duration_s:.2f} | {sr.median_latency_s:.2f} | " + f"{sr.real_time_factor:.2f} | {trials_str} | {transcript} |" + ) + lines.append("") + lines.append("## Hardware Context") + lines.append("") + try: + import platform + import multiprocessing + lines.append(f"- Platform: {platform.platform()}") + lines.append(f"- CPU count (logical): {multiprocessing.cpu_count()}") + except Exception: + pass + try: + with open("/proc/cpuinfo") as f: + model_lines = [ln for ln in f.read().split("\n") if "model name" in ln] + if model_lines: + lines.append(f"- {model_lines[0].strip()}") + except Exception: + pass + try: + with open("/proc/meminfo") as f: + for ln in f.read().split("\n")[:3]: + lines.append(f"- {ln.strip()}") + except Exception: + pass + lines.append("") + lines.append("## Raw Data") + lines.append("") + lines.append(f"Vezi `{RESULTS_JSON.relative_to(PROJECT_ROOT)}` pentru JSON complet.") + lines.append("") + RESULTS_MD.parent.mkdir(parents=True, exist_ok=True) + RESULTS_MD.write_text("\n".join(lines)) + log(f"Wrote {RESULTS_MD}") + + +def main() -> int: + ap = argparse.ArgumentParser(description=__doc__) + ap.add_argument("--models", default=",".join(DEFAULT_MODELS), + help="CSV listă de modele faster-whisper (default: small,tiny)") + ap.add_argument("--trials", type=int, default=DEFAULT_TRIALS, + help=f"Trials per sample (default {DEFAULT_TRIALS})") + ap.add_argument("--budget-s", type=float, default=DEFAULT_BUDGET_S, + help=f"STT p50 budget secunde (default {DEFAULT_BUDGET_S})") + ap.add_argument("--threads", type=int, default=int(os.environ.get("VOICE_BENCH_THREADS", "2")), + help="cpu_threads pentru faster-whisper (default 2 — Proxmox VM)") + ap.add_argument("--keep-wavs", action="store_true", help="Nu șterge WAV-urile temp") + args = ap.parse_args() + + log(f"Budget: p50 < {args.budget_s:.2f}s | Models: {args.models} | Trials: {args.trials}") + check_supertonic() + + work_dir = Path(tempfile.mkdtemp(prefix="voice_bench_")) + log(f"Working dir: {work_dir}") + + log("Stage 1/3: Generating RO audio samples via Supertonic…") + samples: list[SampleResult] = [] + for name, text in UTTERANCES_RO: + log(f" TTS '{name}': {text!r}") + path, duration = synthesize_sample(name, text, work_dir) + log(f" → {path.name} ({duration:.2f}s)") + samples.append(SampleResult(name=name, text=text, wav_path=str(path), + audio_duration_s=duration)) + + log("Stage 2/3: Running faster-whisper benchmarks…") + summaries: dict[str, ModelSummary] = {} + for model_name in args.models.split(","): + model_name = model_name.strip() + if not model_name: + continue + fresh_samples = [ + SampleResult(name=s.name, text=s.text, wav_path=s.wav_path, + audio_duration_s=s.audio_duration_s) + for s in samples + ] + summaries[model_name] = benchmark_model(model_name, fresh_samples, + args.trials, args.threads) + + log("Stage 3/3: Decision & artifacts…") + decision, rationale = decide(summaries, args.budget_s) + log(f"DECISION: {decision}") + log(f"WHY: {rationale}") + + write_json(summaries, decision, rationale, args.budget_s, args.trials) + write_markdown(summaries, decision, rationale, args.budget_s, args.trials) + + if not args.keep_wavs: + for s in samples: + try: + Path(s.wav_path).unlink(missing_ok=True) + except Exception: + pass + try: + work_dir.rmdir() + except Exception: + pass + + return 0 if decision in ("PASS", "FALLBACK_TINY") else 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/voice_bench_results.json b/tools/voice_bench_results.json new file mode 100644 index 0000000..c1d0f81 --- /dev/null +++ b/tools/voice_bench_results.json @@ -0,0 +1,184 @@ +{ + "schema_version": 1, + "timestamp_utc": "2026-05-27T12:30:17Z", + "decision": "FALLBACK_TINY", + "rationale": "small.p50=2.79s >= budget; tiny.p50=0.54s < budget 1.50s. Document fallback la 'tiny' în plan (accuracy mai slabă, latency OK).", + "budget_s": 1.5, + "trials_per_sample": 3, + "models": { + "small": { + "p50_s": 2.793, + "p95_s": 3.308, + "mean_rtf": 0.699, + "load_time_s": 1.505, + "cpu_threads": 6, + "samples": [ + { + "name": "short", + "text_in": "Salut, ce mai faci?", + "text_out": "Salut ce mai faci!", + "audio_duration_s": 1.881, + "latencies_s": [ + 2.586, + 2.666, + 2.538 + ], + "median_latency_s": 2.586, + "rtf": 1.375 + }, + { + "name": "conversational", + "text_in": "Stai puțin să mă gândesc la asta.", + "text_out": "Stai puțin să mă gândesc la asta.", + "audio_duration_s": 2.926, + "latencies_s": [ + 2.739, + 2.697, + 2.683 + ], + "median_latency_s": 2.697, + "rtf": 0.922 + }, + { + "name": "medium", + "text_in": "Am verificat în calendar și avem ședință cu echipa la trei după-amiază.", + "text_out": "Am verificat în calendari și avem ședință cu echipa la trei după amiază.", + "audio_duration_s": 5.991, + "latencies_s": [ + 3.005, + 3.013, + 3.023 + ], + "median_latency_s": 3.013, + "rtf": 0.503 + }, + { + "name": "numbers", + "text_in": "Costul total este o sută douăzeci și trei de lei și cincizeci de bani.", + "text_out": "Costul total este 120 și 3 delei și 50 de bani.", + "audio_duration_s": 5.642, + "latencies_s": [ + 2.657, + 2.698, + 2.677 + ], + "median_latency_s": 2.677, + "rtf": 0.475 + }, + { + "name": "question", + "text_in": "Marius, vrei să-ți pun pe agenda de mâine să suni la NOAA?", + "text_out": "Marius, vrei să-ți spun pe agenda de mâine să suni la noa?", + "audio_duration_s": 5.085, + "latencies_s": [ + 2.883, + 2.85, + 2.847 + ], + "median_latency_s": 2.85, + "rtf": 0.561 + }, + { + "name": "longer", + "text_in": "Vreau să-mi reamintești diseară să verific dacă scriptul de backup a rulat corect și să trimit raportul către echipă.", + "text_out": "Vreau să mi-reamintești di seară să verific dacă scriptul de bacup a rulat corect și să trimit raportul către echipă.", + "audio_duration_s": 9.265, + "latencies_s": [ + 3.277, + 3.428, + 3.308 + ], + "median_latency_s": 3.308, + "rtf": 0.357 + } + ] + }, + "tiny": { + "p50_s": 0.541, + "p95_s": 0.662, + "mean_rtf": 0.138, + "load_time_s": 0.576, + "cpu_threads": 6, + "samples": [ + { + "name": "short", + "text_in": "Salut, ce mai faci?", + "text_out": "Salut ce mai faci", + "audio_duration_s": 1.881, + "latencies_s": [ + 0.669, + 0.542, + 0.557 + ], + "median_latency_s": 0.557, + "rtf": 0.296 + }, + { + "name": "conversational", + "text_in": "Stai puțin să mă gândesc la asta.", + "text_out": "Stei putin să mă gândest la asta.", + "audio_duration_s": 2.926, + "latencies_s": [ + 0.499, + 0.475, + 0.497 + ], + "median_latency_s": 0.497, + "rtf": 0.17 + }, + { + "name": "medium", + "text_in": "Am verificat în calendar și avem ședință cu echipa la trei după-amiază.", + "text_out": "Am verificat în calendar și avem sedeință cu equipala 3 dupa amiază.", + "audio_duration_s": 5.991, + "latencies_s": [ + 0.569, + 0.606, + 0.599 + ], + "median_latency_s": 0.599, + "rtf": 0.1 + }, + { + "name": "numbers", + "text_in": "Costul total este o sută douăzeci și trei de lei și cincizeci de bani.", + "text_out": "Costul total este o suta 20 și 3 de lei și 50 de bani.", + "audio_duration_s": 5.642, + "latencies_s": [ + 0.519, + 0.51, + 0.54 + ], + "median_latency_s": 0.519, + "rtf": 0.092 + }, + { + "name": "question", + "text_in": "Marius, vrei să-ți pun pe agenda de mâine să suni la NOAA?", + "text_out": "Marius, vrei să-ți pun pe agenda de muine să sunt la nu a.", + "audio_duration_s": 5.085, + "latencies_s": [ + 0.51, + 0.524, + 0.522 + ], + "median_latency_s": 0.522, + "rtf": 0.103 + }, + { + "name": "longer", + "text_in": "Vreau să-mi reamintești diseară să verific dacă scriptul de backup a rulat corect și să trimit raportul către echipă.", + "text_out": "Vreau sămi rea minstești diseare să verific daca scriptul de backup a rulat correct și să trimitra portul către e kipă.", + "audio_duration_s": 9.265, + "latencies_s": [ + 0.662, + 0.646, + 0.627 + ], + "median_latency_s": 0.646, + "rtf": 0.07 + } + ] + } + } +} \ No newline at end of file diff --git a/tools/voice_bench_results_threads2.json b/tools/voice_bench_results_threads2.json new file mode 100644 index 0000000..44cf7a5 --- /dev/null +++ b/tools/voice_bench_results_threads2.json @@ -0,0 +1,184 @@ +{ + "schema_version": 1, + "timestamp_utc": "2026-05-27T12:23:08Z", + "decision": "FALLBACK_TINY", + "rationale": "small.p50=3.25s >= budget; tiny.p50=0.50s < budget 1.50s. Document fallback la 'tiny' în plan (accuracy mai slabă, latency OK).", + "budget_s": 1.5, + "trials_per_sample": 3, + "models": { + "small": { + "p50_s": 3.255, + "p95_s": 3.611, + "mean_rtf": 0.801, + "load_time_s": 10.633, + "cpu_threads": 2, + "samples": [ + { + "name": "short", + "text_in": "Salut, ce mai faci?", + "text_out": "Salut ce mai faci!", + "audio_duration_s": 1.881, + "latencies_s": [ + 3.236, + 2.952, + 2.945 + ], + "median_latency_s": 2.952, + "rtf": 1.569 + }, + { + "name": "conversational", + "text_in": "Stai puțin să mă gândesc la asta.", + "text_out": "Stai puțin să mă gândesc la asta.", + "audio_duration_s": 2.926, + "latencies_s": [ + 3.095, + 3.099, + 3.126 + ], + "median_latency_s": 3.099, + "rtf": 1.059 + }, + { + "name": "medium", + "text_in": "Am verificat în calendar și avem ședință cu echipa la trei după-amiază.", + "text_out": "Am verificat în calendari și avem sedință cu echipa la 3 după amiază.", + "audio_duration_s": 5.991, + "latencies_s": [ + 3.437, + 3.419, + 3.342 + ], + "median_latency_s": 3.419, + "rtf": 0.571 + }, + { + "name": "numbers", + "text_in": "Costul total este o sută douăzeci și trei de lei și cincizeci de bani.", + "text_out": "Costul total este 120 și 3 delei și 5-10 de bani.", + "audio_duration_s": 5.642, + "latencies_s": [ + 3.24, + 3.207, + 3.237 + ], + "median_latency_s": 3.237, + "rtf": 0.574 + }, + { + "name": "question", + "text_in": "Marius, vrei să-ți pun pe agenda de mâine să suni la NOAA?", + "text_out": "Marius, vrei să-ți spun pe agenda de mâine să suni la noa?", + "audio_duration_s": 5.085, + "latencies_s": [ + 3.329, + 3.27, + 3.278 + ], + "median_latency_s": 3.278, + "rtf": 0.645 + }, + { + "name": "longer", + "text_in": "Vreau să-mi reamintești diseară să verific dacă scriptul de backup a rulat corect și să trimit raportul către echipă.", + "text_out": "Vreau să mi-reamintești, di seară, să verific dacă scriptul de bacup a rulat corect și să trimit raportul către echipă.", + "audio_duration_s": 9.265, + "latencies_s": [ + 3.626, + 3.611, + 3.563 + ], + "median_latency_s": 3.611, + "rtf": 0.39 + } + ] + }, + "tiny": { + "p50_s": 0.505, + "p95_s": 0.556, + "mean_rtf": 0.122, + "load_time_s": 3.15, + "cpu_threads": 2, + "samples": [ + { + "name": "short", + "text_in": "Salut, ce mai faci?", + "text_out": "Salute mai face?", + "audio_duration_s": 1.881, + "latencies_s": [ + 0.438, + 0.449, + 0.443 + ], + "median_latency_s": 0.443, + "rtf": 0.235 + }, + { + "name": "conversational", + "text_in": "Stai puțin să mă gândesc la asta.", + "text_out": "Stei putin să mă gândesc la asta.", + "audio_duration_s": 2.926, + "latencies_s": [ + 0.477, + 0.476, + 0.47 + ], + "median_latency_s": 0.476, + "rtf": 0.163 + }, + { + "name": "medium", + "text_in": "Am verificat în calendar și avem ședință cu echipa la trei după-amiază.", + "text_out": "Am verificat în calendar și avem sedeință cu equipala 3 dupa am iază.", + "audio_duration_s": 5.991, + "latencies_s": [ + 0.506, + 0.514, + 0.505 + ], + "median_latency_s": 0.506, + "rtf": 0.084 + }, + { + "name": "numbers", + "text_in": "Costul total este o sută douăzeci și trei de lei și cincizeci de bani.", + "text_out": "Costul total este o suta doozec și trei de lei și 50 de bani.", + "audio_duration_s": 5.642, + "latencies_s": [ + 0.504, + 0.522, + 0.493 + ], + "median_latency_s": 0.504, + "rtf": 0.089 + }, + { + "name": "question", + "text_in": "Marius, vrei să-ți pun pe agenda de mâine să suni la NOAA?", + "text_out": "Marius, vrei să-ți pun pe agenda de muină să sunilă nu a.", + "audio_duration_s": 5.085, + "latencies_s": [ + 0.509, + 0.504, + 0.529 + ], + "median_latency_s": 0.509, + "rtf": 0.1 + }, + { + "name": "longer", + "text_in": "Vreau să-mi reamintești diseară să verific dacă scriptul de backup a rulat corect și să trimit raportul către echipă.", + "text_out": "Vreau să mire am in test, disiară să verific dacă scriptul de backup a rulat correct și să trimitra portul că trea equipă.", + "audio_duration_s": 9.265, + "latencies_s": [ + 0.556, + 0.535, + 0.571 + ], + "median_latency_s": 0.556, + "rtf": 0.06 + } + ] + } + } +} \ No newline at end of file diff --git a/tools/voice_bench_results_threads4.json b/tools/voice_bench_results_threads4.json new file mode 100644 index 0000000..116d1fb --- /dev/null +++ b/tools/voice_bench_results_threads4.json @@ -0,0 +1,184 @@ +{ + "schema_version": 1, + "timestamp_utc": "2026-05-27T12:24:48Z", + "decision": "FALLBACK_TINY", + "rationale": "small.p50=2.25s >= budget; tiny.p50=0.48s < budget 1.50s. Document fallback la 'tiny' în plan (accuracy mai slabă, latency OK).", + "budget_s": 1.5, + "trials_per_sample": 3, + "models": { + "small": { + "p50_s": 2.249, + "p95_s": 2.532, + "mean_rtf": 0.54, + "load_time_s": 1.339, + "cpu_threads": 4, + "samples": [ + { + "name": "short", + "text_in": "Salut, ce mai faci?", + "text_out": "Salut ce mai faci!", + "audio_duration_s": 1.881, + "latencies_s": [ + 2.068, + 1.951, + 1.947 + ], + "median_latency_s": 1.951, + "rtf": 1.038 + }, + { + "name": "conversational", + "text_in": "Stai puțin să mă gândesc la asta.", + "text_out": "Stai putin să mă gândesc la asta.", + "audio_duration_s": 2.926, + "latencies_s": [ + 2.092, + 2.06, + 2.072 + ], + "median_latency_s": 2.072, + "rtf": 0.708 + }, + { + "name": "medium", + "text_in": "Am verificat în calendar și avem ședință cu echipa la trei după-amiază.", + "text_out": "Am verificat în calendari și avem sedință cu echipa la 3 după amiază.", + "audio_duration_s": 5.991, + "latencies_s": [ + 2.235, + 2.283, + 2.48 + ], + "median_latency_s": 2.283, + "rtf": 0.381 + }, + { + "name": "numbers", + "text_in": "Costul total este o sută douăzeci și trei de lei și cincizeci de bani.", + "text_out": "Costul total este 120 și 3 delei și 50 de bani.", + "audio_duration_s": 5.642, + "latencies_s": [ + 2.285, + 2.264, + 2.303 + ], + "median_latency_s": 2.285, + "rtf": 0.405 + }, + { + "name": "question", + "text_in": "Marius, vrei să-ți pun pe agenda de mâine să suni la NOAA?", + "text_out": "Marius, vrei să-ți spun pe agenda de mâine să suni la noa a.", + "audio_duration_s": 5.085, + "latencies_s": [ + 2.279, + 2.205, + 2.21 + ], + "median_latency_s": 2.21, + "rtf": 0.435 + }, + { + "name": "longer", + "text_in": "Vreau să-mi reamintești diseară să verific dacă scriptul de backup a rulat corect și să trimit raportul către echipă.", + "text_out": "Vreau să mi-răimintești di seară să verific dacă scriptul de bacup a rulat corect și să trimit raportul către echipă.", + "audio_duration_s": 9.265, + "latencies_s": [ + 2.639, + 2.532, + 2.528 + ], + "median_latency_s": 2.532, + "rtf": 0.273 + } + ] + }, + "tiny": { + "p50_s": 0.481, + "p95_s": 0.574, + "mean_rtf": 0.117, + "load_time_s": 0.541, + "cpu_threads": 4, + "samples": [ + { + "name": "short", + "text_in": "Salut, ce mai faci?", + "text_out": "Salut, ce mai fac?", + "audio_duration_s": 1.881, + "latencies_s": [ + 0.453, + 0.417, + 0.411 + ], + "median_latency_s": 0.417, + "rtf": 0.222 + }, + { + "name": "conversational", + "text_in": "Stai puțin să mă gândesc la asta.", + "text_out": "Stei putin să mă gândesc la asta.", + "audio_duration_s": 2.926, + "latencies_s": [ + 0.429, + 0.449, + 0.463 + ], + "median_latency_s": 0.449, + "rtf": 0.153 + }, + { + "name": "medium", + "text_in": "Am verificat în calendar și avem ședință cu echipa la trei după-amiază.", + "text_out": "Am verificat în calendar și avem sedeință cu equipala 3 du pămiază.", + "audio_duration_s": 5.991, + "latencies_s": [ + 0.499, + 0.495, + 0.504 + ], + "median_latency_s": 0.499, + "rtf": 0.083 + }, + { + "name": "numbers", + "text_in": "Costul total este o sută douăzeci și trei de lei și cincizeci de bani.", + "text_out": "Costul total este o suta 20 și 3 de lei și 50 de bani.", + "audio_duration_s": 5.642, + "latencies_s": [ + 0.491, + 0.487, + 0.456 + ], + "median_latency_s": 0.487, + "rtf": 0.086 + }, + { + "name": "question", + "text_in": "Marius, vrei să-ți pun pe agenda de mâine să suni la NOAA?", + "text_out": "Marius, vrei să-ți pun pe agenda de muină să sun la nu a.", + "audio_duration_s": 5.085, + "latencies_s": [ + 0.474, + 0.468, + 0.505 + ], + "median_latency_s": 0.474, + "rtf": 0.093 + }, + { + "name": "longer", + "text_in": "Vreau să-mi reamintești diseară să verific dacă scriptul de backup a rulat corect și să trimit raportul către echipă.", + "text_out": "Vreau să mream in test de seare să verific dacă scriptul de bakup a rulat correct și să trimitra portul că trea equipă.", + "audio_duration_s": 9.265, + "latencies_s": [ + 0.574, + 0.532, + 0.575 + ], + "median_latency_s": 0.574, + "rtf": 0.062 + } + ] + } + } +} \ No newline at end of file diff --git a/tools/voice_bench_results_threads6.json b/tools/voice_bench_results_threads6.json new file mode 100644 index 0000000..c1d0f81 --- /dev/null +++ b/tools/voice_bench_results_threads6.json @@ -0,0 +1,184 @@ +{ + "schema_version": 1, + "timestamp_utc": "2026-05-27T12:30:17Z", + "decision": "FALLBACK_TINY", + "rationale": "small.p50=2.79s >= budget; tiny.p50=0.54s < budget 1.50s. Document fallback la 'tiny' în plan (accuracy mai slabă, latency OK).", + "budget_s": 1.5, + "trials_per_sample": 3, + "models": { + "small": { + "p50_s": 2.793, + "p95_s": 3.308, + "mean_rtf": 0.699, + "load_time_s": 1.505, + "cpu_threads": 6, + "samples": [ + { + "name": "short", + "text_in": "Salut, ce mai faci?", + "text_out": "Salut ce mai faci!", + "audio_duration_s": 1.881, + "latencies_s": [ + 2.586, + 2.666, + 2.538 + ], + "median_latency_s": 2.586, + "rtf": 1.375 + }, + { + "name": "conversational", + "text_in": "Stai puțin să mă gândesc la asta.", + "text_out": "Stai puțin să mă gândesc la asta.", + "audio_duration_s": 2.926, + "latencies_s": [ + 2.739, + 2.697, + 2.683 + ], + "median_latency_s": 2.697, + "rtf": 0.922 + }, + { + "name": "medium", + "text_in": "Am verificat în calendar și avem ședință cu echipa la trei după-amiază.", + "text_out": "Am verificat în calendari și avem ședință cu echipa la trei după amiază.", + "audio_duration_s": 5.991, + "latencies_s": [ + 3.005, + 3.013, + 3.023 + ], + "median_latency_s": 3.013, + "rtf": 0.503 + }, + { + "name": "numbers", + "text_in": "Costul total este o sută douăzeci și trei de lei și cincizeci de bani.", + "text_out": "Costul total este 120 și 3 delei și 50 de bani.", + "audio_duration_s": 5.642, + "latencies_s": [ + 2.657, + 2.698, + 2.677 + ], + "median_latency_s": 2.677, + "rtf": 0.475 + }, + { + "name": "question", + "text_in": "Marius, vrei să-ți pun pe agenda de mâine să suni la NOAA?", + "text_out": "Marius, vrei să-ți spun pe agenda de mâine să suni la noa?", + "audio_duration_s": 5.085, + "latencies_s": [ + 2.883, + 2.85, + 2.847 + ], + "median_latency_s": 2.85, + "rtf": 0.561 + }, + { + "name": "longer", + "text_in": "Vreau să-mi reamintești diseară să verific dacă scriptul de backup a rulat corect și să trimit raportul către echipă.", + "text_out": "Vreau să mi-reamintești di seară să verific dacă scriptul de bacup a rulat corect și să trimit raportul către echipă.", + "audio_duration_s": 9.265, + "latencies_s": [ + 3.277, + 3.428, + 3.308 + ], + "median_latency_s": 3.308, + "rtf": 0.357 + } + ] + }, + "tiny": { + "p50_s": 0.541, + "p95_s": 0.662, + "mean_rtf": 0.138, + "load_time_s": 0.576, + "cpu_threads": 6, + "samples": [ + { + "name": "short", + "text_in": "Salut, ce mai faci?", + "text_out": "Salut ce mai faci", + "audio_duration_s": 1.881, + "latencies_s": [ + 0.669, + 0.542, + 0.557 + ], + "median_latency_s": 0.557, + "rtf": 0.296 + }, + { + "name": "conversational", + "text_in": "Stai puțin să mă gândesc la asta.", + "text_out": "Stei putin să mă gândest la asta.", + "audio_duration_s": 2.926, + "latencies_s": [ + 0.499, + 0.475, + 0.497 + ], + "median_latency_s": 0.497, + "rtf": 0.17 + }, + { + "name": "medium", + "text_in": "Am verificat în calendar și avem ședință cu echipa la trei după-amiază.", + "text_out": "Am verificat în calendar și avem sedeință cu equipala 3 dupa amiază.", + "audio_duration_s": 5.991, + "latencies_s": [ + 0.569, + 0.606, + 0.599 + ], + "median_latency_s": 0.599, + "rtf": 0.1 + }, + { + "name": "numbers", + "text_in": "Costul total este o sută douăzeci și trei de lei și cincizeci de bani.", + "text_out": "Costul total este o suta 20 și 3 de lei și 50 de bani.", + "audio_duration_s": 5.642, + "latencies_s": [ + 0.519, + 0.51, + 0.54 + ], + "median_latency_s": 0.519, + "rtf": 0.092 + }, + { + "name": "question", + "text_in": "Marius, vrei să-ți pun pe agenda de mâine să suni la NOAA?", + "text_out": "Marius, vrei să-ți pun pe agenda de muine să sunt la nu a.", + "audio_duration_s": 5.085, + "latencies_s": [ + 0.51, + 0.524, + 0.522 + ], + "median_latency_s": 0.522, + "rtf": 0.103 + }, + { + "name": "longer", + "text_in": "Vreau să-mi reamintești diseară să verific dacă scriptul de backup a rulat corect și să trimit raportul către echipă.", + "text_out": "Vreau sămi rea minstești diseare să verific daca scriptul de backup a rulat correct și să trimitra portul către e kipă.", + "audio_duration_s": 9.265, + "latencies_s": [ + 0.662, + 0.646, + 0.627 + ], + "median_latency_s": 0.646, + "rtf": 0.07 + } + ] + } + } +} \ No newline at end of file