Pruebas y evaluación
Hay dos niveles: pruebas rápidas del núcleo, que corren en cualquier equipo, y herramientas de medición que usan los modelos reales y la GPU. Las decisiones de diseño (motor de voz, traductor, umbral de diarización, largo de las referencias) salieron de estas herramientas.
Pruebas sin GPU
Sección titulada «Pruebas sin GPU»python -m pytest testsTambién corren sin pytest: python tests/test_core.py ejecuta todas e imprime ok. No cargan Whisper, el traductor ni el motor de voz (el reconocimiento se reemplaza por uno falso), así que bastan numpy y lo de requirements.txt, más pytest si lo usas.
| Prueba | Qué comprueba |
|---|---|
test_streaming_commits_sentences |
Con un reconocedor falso que dice un guion, el streaming confirma y cierra exactamente «Hello world.» y «This is a test.», y avanza final_t hasta el final. |
test_store_overlap_and_ranges |
Una frase que se solapa reemplaza a la anterior; los tramos cubiertos se unen; la transcripción se guarda y se vuelve a leer igual. |
test_textproc |
División en oraciones con abreviaturas, montos y decimales; modismos; forma de los fragmentos; convenciones latinoamericanas. |
test_audiofx |
WSOLA comprime 1,3 veces sin cambiar el tono (150 Hz ± 3) y el re-muestreo de 16 a 24 kHz conserva el tono. |
test_speaker_tracker |
Agrupa dos personas; una frase corta no crea persona nueva; el estado se guarda en JSON y se restaura; las referencias nunca se recortan (más de 12 s nunca entran, una de 10 s solo a falta de otra, una normal la reemplaza). |
test_cookies_import |
De un cookies.txt solo quedan las cookies de YouTube y Google, y se detecta la sesión iniciada. |
test_playlist_library_and_srt |
Id de playlist (los mix RD… no cuentan), importación como colección, colecciones automáticas, reimportar sin duplicar, eliminar una playlist conservando lo descargado, formato SRT y nombres de archivo seguros. |
test_download_only_queue |
«Solo descargar»: no se procesa solo, «Procesar» lo pone en cola, «Limpiar terminados» lo quita y «Bajar video» descarga el video completo sin volver a procesar. |
test_vaults |
Crear una biblioteca, mover un video con sus archivos, rutas con prefijo /v/<biblioteca>, ninguna ruta sale de su carpeta, persistencia al reiniciar y eliminar solo lo propio de la carpeta. |
test_access_and_webhooks |
Dueño desde este equipo pero no por un túnel; bibliotecas privadas, públicas y con contraseña; cambiar la contraseña invalida las sesiones; claves de API de lectura; webhooks filtrados por biblioteca y evento, firmados con HMAC-SHA256. |
test_hardware (tests/test_hardware.py) |
Forma de lo detectado (GPU, RAM, CPU), sin GPU, la lectura de nvidia-smi, y el equipo de un lab con TRANSLAY_EMULATE (VRAM, RAM, hilos, sin GPU). |
test_trash (tests/test_trash.py) |
Vaciar y borrar videos los mueve a la papelera y restaurar devuelve videos, archivos y colecciones (con sus videos); una biblioteca eliminada vuelve con open_folder; se purga lo de más de 30 días y todo. |
test_security (tests/test_security.py) |
El JSON guardado deja copia y se recupera si se daña; iniciar sesión siempre da un token nuevo; un id raro nunca apunta fuera de la biblioteca; el WebSocket rechaza marcos sin máscara, continuaciones sueltas, controles largos y códigos desconocidos. |
Herramientas de medición
Sección titulada «Herramientas de medición»Las herramientas de tools/ usan el mismo código que el servidor (vt/), sin navegador. Se corren desde la raíz del repositorio con el Python del servidor, salvo make_dialogue.py (entorno de Kokoro) y make_sample.ps1 (PowerShell). Leen el audio con PyAV; dub_file.py, make_dialogue.py y make_sample.ps1 además escriben video con ffmpeg, que debe estar en el PATH.
Material de prueba
Sección titulada «Material de prueba»Los diálogos de prueba tienen una verdad de referencia (<nombre>.truth.json: quién habla, cuándo y qué dice) contra la que se mide.
-
make_dialogue.pygenera diálogos con varias voces de Kokoro y sus variantes con ruido. Corre con el entorno.venvs/kokoro:Ventana de terminal .venvs/kokoro/Scripts/python tools/make_dialogue.py tools/samples/podcast.txt --noise clean cafe:10 music:12 pink:5El guion tiene una línea
voz|textopor intervención (voces de Kokoro comoaf_heart,am_michael,bf_emma,bm_lewis) y una línea vacía es una pausa larga.--noiseaceptacleanotipo:snrcon los ruidos devt/audiofx.py:white,pink,brown,hum,music,babbleycafe. Escribe ensamples/(o en--out)<nombre>[_<ruido><snr>].mp4y<nombre>.truth.json. -
make_sample.ps1genera un video simple con las voces en inglés de Windows, sobre un fondo con un reloj:Ventana de terminal powershell -File tools/make_sample.ps1powershell -File tools/make_sample.ps1 -Script tools/samples/dialogue.txt -Out samples/dialogue.mp4Cada línea es
Voz|texto, dondeVozes parte del nombre de una voz instalada (Zira, George…); una línea vacía agrega una pausa. Por defecto leetools/samples/demo.txty escribesamples/demo.mp4. No genera verdad de referencia.
Guiones incluidos en tools/samples/: demo, dialogue, friends, lecture, panel y podcast.
transcribe_file.py
Sección titulada «transcribe_file.py»Simula la reproducción de un video y corre el reconocimiento en streaming con la misma cadencia que en vivo: mientras la GPU trabaja, el video sigue avanzando y ese audio se acumula para la siguiente inferencia. Sirve para ajustar la política de vt/streaming.py de forma reproducible.
python tools/transcribe_file.py samples/demo.mp4 --srt out.srt| Opción | Por defecto | |
|---|---|---|
media |
Video o audio. | |
--model |
large-v3-turbo |
Modelo de Whisper. |
--beam |
5 |
Ancho de búsqueda. |
--chunk |
0.1 |
Segundos por bloque de audio, como los que llegan del navegador. |
--translator |
opus-big |
Traductor (none para no traducir). |
--srt |
Escribe los subtítulos en ese archivo. |
Imprime cada frase con sus tiempos, el retraso con que se habría mostrado y su traducción. Al final: duración del audio, segundos de GPU, factor de tiempo real (RTF), retraso medio y máximo, tiempo total y mediana de traducción por frase.
eval_pipeline.py
Sección titulada «eval_pipeline.py»Mide reconocimiento y diarización contra la verdad de referencia, con la misma cadencia que en vivo:
python tools/eval_pipeline.py samples/podcast.mp4 samples/podcast_cafe10.mp4 --threshold 0.25 0.30 0.35 --relabel| Opción | Por defecto | |
|---|---|---|
media |
Uno o más videos; la verdad se busca en <nombre antes del primer _>.truth.json. |
|
--threshold |
0.30 |
Uno o varios umbrales de similitud para crear una persona nueva: los barre todos. |
--relabel |
Aplica la misma corrección de frases cortas que Dubber.relabel. |
|
-v |
Muestra cada frase con la persona detectada y la real. |
Por archivo y umbral imprime el error de palabras (WER), el porcentaje de frases con la persona correcta (con el mejor mapeo uno a uno entre personas detectadas y reales: una persona de más cuenta como error), personas detectadas sobre reales y cantidad de frases; al final, el promedio. Con 12 videos dio 97,6 % de frases bien asignadas (Diarización).
eval_translation.py
Sección titulada «eval_translation.py»Compara traductores en 39 frases típicas de video (tutoriales, vlogs, modismos y verbos frasales, salida tipo Whisper), una a la vez como en vivo:
python tools/eval_translation.py --models opus-base opus-big nllb-1.3b madlad-3b| Opción | Por defecto | |
|---|---|---|
--models |
opus-base opus-big nllb-1.3b madlad-3b |
Modelos de vt/translate.py. |
--compute-type |
el de cada modelo | Precisión de CTranslate2 (por ejemplo int8 para comparar cuantizaciones). |
--beam |
4 |
Ancho de búsqueda. |
--only |
0 |
Solo las últimas N frases. |
Imprime la traducción de cada modelo lado a lado y una tabla con tiempo de carga, mediana y máximo por frase. La calidad se juzga leyendo. De aquí salió la elección del traductor y varias reglas de vt/textproc.py.
eval_tts.py
Sección titulada «eval_tts.py»Compara motores de voz con métricas objetivas. Para cada diálogo arma la referencia de cada persona con su voz original (según la verdad de referencia), traduce sus frases y las sintetiza con su voz clonada:
python tools/eval_tts.py --engines chatterbox omnivoice voxcpm --samples podcast panel friends --fit| Métrica | Qué mide |
|---|---|
sim |
Parecido de voz: coseno entre la huella (WeSpeaker) del clon en español y la del original en inglés. |
id |
% de frases en que el clon se parece más a su persona que a las demás del diálogo. |
wer |
Inteligibilidad: Whisper en español transcribe el clon y se compara con el texto pedido. |
f0 |
Tono: mediana de F0 (YIN) del clon sobre la del original; 1,00 es igual. |
rtf |
Segundos de GPU por segundo de audio generado. |
dur |
Duración del clon sobre la de la frase original en inglés. |
| Opción | Por defecto | |
|---|---|---|
--engines |
chatterbox omnivoice voxcpm |
Motores (cada uno en .venvs/<motor>). |
--samples |
podcast panel friends |
Diálogos de samples/ con su verdad de referencia. |
--noise |
Sufijo de la variante con ruido, p. ej. _cafe10. Las métricas se comparan siempre contra la voz limpia. |
|
--ref-s |
10.0 |
Segundos máximos de referencia por persona. |
--ref-sr |
16000 |
Frecuencia de la referencia. |
--clean |
none |
Limpieza de la referencia: gate (compuerta espectral si la SNR es menor que 25 dB) o wiener (realce de vt/audiofx.py con la misma condición). |
--ref-wav |
Otro audio para las referencias, p. ej. una versión limpia con DeepFilterNet: samples/tts_eval/{s}_pink5_df.wav. |
|
--lines |
6 |
Frases por diálogo. |
--fit |
Le pide al motor la duración de la frase original + 10 %, si el motor lo permite. | |
--params |
{} |
JSON con parámetros del motor. |
Trabaja en tres fases para medir la velocidad real: primero prepara frases y referencias, después genera con cada motor solo en la GPU y al final carga Whisper para puntuar. Los audios quedan en samples/tts_eval/<motor>/ para escucharlos. De aquí salió la elección del motor.
dub_file.py
Sección titulada «dub_file.py»Dobla un video completo sin navegador, con el pipeline del servidor, y exporta <nombre>.es.mp4:
python tools/dub_file.py samples/podcast.mp4 --voice omnivoice| Opción | Por defecto | |
|---|---|---|
media |
Video a doblar. | |
--voice |
omnivoice |
Motor de voz. |
--data |
data/offline |
Dónde guarda transcripción, voces y audio. La transcripción del video (off_<nombre>) se borra al empezar: cada corrida empieza de cero. |
La pista doblada pone cada frase en su momento sobre el original atenuado (amplitud × 0,14, el nivel «Bajo»); si una frase pisa a la siguiente, la siguiente espera. Por frase imprime persona, compresión aplicada, segundos de GPU y traducción. Al final: frases, personas, segundos de GPU de la voz y su RTF, cuántas frases se comprimieron y cuánto como máximo, el mayor desfase, y cuánto después del final de cada frase original estaría lista su voz en vivo (mediana y máximo, suponiendo 1,5 s de reconocimiento). Si existe la verdad de referencia, también la diarización.
Labs de hardware
Sección titulada «Labs de hardware»tools/lab/ corre el pipeline de la cola como si fuera otro equipo, con límites reales en esta máquina (no estimaciones). De ahí salen los perfiles y las velocidades de Rendimiento.
| Herramienta | Qué hace |
|---|---|
ballast.py |
Ocupa VRAM con la API del driver de CUDA (ctypes, sin torch) para que solo quede la del lab, con el mismo escritorio encima. Si el lab no alcanza, el driver desborda a memoria compartida, igual que en esa tarjeta. |
vt/limits.py |
Job Object de Windows: tope duro de memoria residente por proceso (sin permisos de administrador) y afinidad a N hilos; el proceso de voz lo hereda. |
bench.py |
El camino de la cola con una configuración (modelo, precisión, beam, traductor, voz, pasos, dispositivo). Mide velocidad (segundos de video por segundo de reloj), espera para ver en vivo, cálculo y espera de turno por etapa, voz p50/p95, carga de cada modelo, pico de VRAM, error de palabras y personas acertadas. |
run.py |
Corre cada configuración en cada lab y deja un JSON por prueba y resumen.md en data/labs/<corrida>/. |
python tools/lab/run.py --listpython tools/lab/run.py --labs gpu-4g gpu-6g --configs calidad ligero --media samples/podcast_cafe10.mp4 --limit-s 90Labs: rtx4060-8g (el equipo, sin límites), gpu-6g, gpu-4g, gpu-2g (VRAM con lastre y la RAM que le queda a Translay en un equipo de 16 u 8 GB) y cpu-8, cpu-4 (sin GPU). Configuraciones: calidad, equilibrado, ligero, texto y texto-ligero (los perfiles de vt/profiles.py).