¿Qué hace TTS Local?
La voz por defecto: Qwen3-TTS 1.7B CustomVoice, altavoz aiden, 8-bit GGUF (Q8_0), ejecutado por
qwentts.cpp (C++/ggml, MIT) con esta instrucción de estilo:
Cálida, clara y curiosa, como un narrador amigable de vídeos explicativos de tecnología. Ritmo relajado y constante.
Ganó una prueba de escucha ciega contra Kokoro, Chatterbox, PyTorch Qwen3-TTS, VoxCPM2 y Phonon
(consulta references/benchmarks.md). En una GPU de portátil RTX 4070 de 8 GB funciona a ~4x tiempo real incluyendo la carga del modelo: una narración de 18 minutos tarda ~4.5 minutos.
Configuración (una vez por máquina)
Ejecuta python -I <skill>/scripts/say.py --check primero. Si imprime OK, omite esta sección.
De lo contrario, configura el motor, o pide al usuario que lo haga. Tarda entre 10 y 20 minutos y requiere ~2.5 GB de disco.
- Compilar qwentts.cpp. No existe un binario precompilado para Windows, así que compílalo desde el código fuente:
En Windows, instala las Herramientas de compilación de VS 2022 (o superior) con la carga de trabajo de C++, CMake, Ninja y el CUDA Toolkit, luego ejecutagit clone --recurse-submodules https://github.com/ServeurpersoCom/qwentts.cpp ~/tools/qwentts.cpp cd ~/tools/qwentts.cpp ./buildcuda.sh # NVIDIA (Linux); ./buildvulkan.sh para AMD/Intel; ./buildcpu.sh solo CPU (p. ej. macOS)buildcuda.cmddesde el repositorio. Sivcvars64.batestá en otra ubicación, edita la ruta al inicio de ese script. Para apuntar solo a una GPU, añade-DCMAKE_CUDA_ARCHITECTURES=89(RTX 40xx; 86 = RTX 30xx, 120 = RTX 50xx) a la línea de cmake. - Descargar los pesos (~2 GB) desde Hugging Face
Serveurperso/Qwen3-TTS-GGUF:pip install -U huggingface_hub hf download Serveurperso/Qwen3-TTS-GGUF qwen-talker-1.7b-customvoice-Q8_0.gguf qwen-tokenizer-12hz-Q8_0.gguf --local-dir ~/tools/qwen-gguf - Apuntar say.py a ellos si usaste otras carpetas: configura
QWEN_TTS_HOME(el checkout),QWEN_TTS_EXE(el binario) oQWEN_TTS_MODELS(la carpeta .gguf). En Windows,say.pyañade%CUDA_PATH%\bin\x64al PATH por ti (sobrescribe conCUDA_BIN). say.py --checkde nuevo, luego genera una línea de prueba.
Hardware: 8 GB de VRAM son suficientes para Q8_0 (~3 GB en uso). Sin GPU, una compilación para CPU funciona aproximadamente a un
cuarto de la velocidad. GGML_BACKEND=CPU fuerza una compilación para GPU a ejecutarse en la CPU.
Antes de generar
- ¿Hay algo más usando la GPU? Un juego u otra aplicación pesada de GPU hace la generación ~4x más lenta
y hace que esa aplicación se entrecorte. Pregunta antes de comenzar un trabajo largo. Si el usuario nombra tales aplicaciones, establece
TTS_BUSY_APPS=app1,app2ysay.pyadvierte cuando una está en ejecución. - ¿Vale la pena comprobar un modelo más nuevo? Consulta "Sigue buscando mejores modelos" más abajo. Si la última comprobación tiene más de ~6 semanas y la tarea es una narración real (no una prueba de una línea), haz el escaneo rápido primero.
- ¿El texto suena humano? Una voz lee el lenguaje de IA con la misma entonación cada vez, por lo que el patrón
resalta más que en una página. Para cualquier narración de más de unas pocas líneas, lee
natural-narration.mdde la habilidadwhiteboard-explainer(mismo plugin,references/) y ejecuta suscripts/aispeak_scan.py, que acepta un script.py o un archivo de texto plano.
Generar
El script usa solo la biblioteca estándar, por lo que cualquier Python 3.10+ funciona. <skill> es la carpeta de esta habilidad.
python -I <skill>/scripts/say.py "Primera línea." "Segunda línea." -o salida.wav # un WAV, espacios de 0.35 s
python -I <skill>/scripts/say.py --file lineas.txt -o clips/ # 000.wav, 001.wav, ...
Opciones:
| Indicador | Qué hace |
|---|---|
--speaker | aiden (predeterminado); ryan es la otra voz nativa en inglés |
--instruct | Texto de estilo, p. ej. "Emocionado, rápido" o "Tranquilo y serio" |
--seed N | Da una toma repetible |
--gap S | Segundos de silencio entre líneas en un archivo unido |
--srt F | También escribe subtítulos sincronizados con el WAV unido (consulta Subtítulos) |
--quant | Q8_0 (predeterminado, mejor) o Q4_K_M (más pequeño, un poco más plano; descárgalo primero) |
--check | Informa del motor, modelos y carpetas CUDA encontrados |
Cómo funciona:
- Cada línea pasa por un solo proceso, por lo que el modelo se carga una vez (3–8 s). Pasa las líneas en bloque, no una llamada por línea.
- La salida es WAV mono de 24 kHz, 16 bits.
Las tomas se muestrean, por lo que cada ejecución difiere:
- Conserva los clips que te gusten. Caché por línea, clave por texto más configuración.
- Vuelve a tomar una línea si su duración se aleja mucho de ~0.07 s por carácter. Eso significa que se omitieron o inventaron palabras.
Para una narración de vídeo, además:
- Recorta el silencio de cada clip a ~50 ms de relleno, luego coloca las líneas en la línea de tiempo con tus propios espacios.
- Normaliza el volumen de la pista final:
ffmpeg -af loudnorm=I=-16:TP=-1.5:LRA=11.
Subtítulos (.srt): ofrécelos con cada vídeo narrado
Ya sabes cuándo comienza y termina cada línea, por lo que no hay nada que transcribir. Construye los subtítulos a partir de esas marcas de tiempo.
- Con
say.py: añade--srt narracion.srt(necesita un.wavcon-o). Los subtítulos coinciden exactamente con la pista unida. - En tu propio pipeline: llama a
scripts/srt.py,to_srt([(inicio_s, fin_s, texto), ...], display=[...]), con inicio/fin en tiempo de vídeo por línea hablada. O usa la CLI:python srt.py marcas.tsv -o video.srt. - Corrige las ortografías de voz. El texto de la narración suele estar escrito para la voz: "D I L", nombres reescritos
fonéticamente, "punto HTML de ejecutor", números en palabras. Mapea de vuelta con
display/--display display.tsv(habladoescrito). Toma las formas escritas de lo que se muestra en pantalla, y usa cifras para los números ("$232", "83%"). - Verifica el resultado. Búscalo con grep en busca de mayúsculas espaciadas restantes (
[A-Z] [A-Z]) y " punto ". - Reglas que aplica el módulo:
- como máximo 2 líneas de 42 caracteres por subtítulo
- divide en oración, luego cláusula, luego palabra
- oraciones cortas fusionadas para que nada pase rápido
- tiempo compartido en proporción a la duración
- Nómbralo como el vídeo (
Nombre del Video.srtjunto aNombre del Video.mp4) para que los reproductores lo carguen automáticamente. En VLC,--sub-file=fuerza un archivo.
El template/narration/build_vo.py de la habilidad whiteboard-explainer es un pipeline de trabajo completo:
caché por línea, retomas, recorte de silencios, modelado de pausas, alineación de palabras, una tabla de señales y una
envolvente de sincronización labial.
Problemas comunes
- Los DLL de CUDA deben estar en PATH (Windows). CUDA 13 los mantiene en
...\CUDA\v13.x\bin\x64. Sin esa carpeta en PATH,qwen-tts.exesale silenciosamente sin salida.say.pylo añade por ti. --stream-by-line -o -escribe cabeceras WAV en streaming (tamaños 0x7fffffff), una por línea. Divide enRIFF....WAVEfmty descarta cada cabecera de 44 bytes. No confíes en los campos de tamaño.- Aiden lee mal letras individuales y tokens extraños. Encontrado por una auditoría no solicitada de Whisper:
- "h estrella" salió como "un hap" o "nuestra estrella", "y t" como "VT", "y" como "nosotros", y "arXiv" como "ArcSireFolk".
- Estos funcionan: "H mayúscula estrella" / "bajo H", "por qué tee" / "por qué tilde", "archivo", y "verificación SMILES".
- "aitch" es errático. Un nombre puede estar bien solo y distorsionado en medio de una oración: pruébalo dentro de toda la línea.
- Una K al inicio de la oración puede caerse ("Kwenputer" → "When Pooter"): comienza esas líneas con "Y" o "Entonces".
- Audita transcribiendo cada clip sin el guión como aviso inicial, luego compara con
el guión. Un Whisper con aviso "oye" las palabras previstas y oculta los errores. Herramientas:
whiteboard-explainer/template/narration/audit_vo.pyytts_try.py.
- Pausas en dos puntos. Qwen pausa 0.6-0.8 s en un dos puntos y a veces en medio de una frase. En una narración,
limita cada silencio por la puntuación anterior (
shape()en el build_vo.py de la plantilla) y evita líneas fragmentadas por dos puntos ("Primero: ..."). - Respaldo de CPU: Kokoro 82M (
kokoro-onnx) es plano pero rápido en CPU, bueno para borradores mientras la GPU está ocupada.
Sigue buscando mejores modelos
El TTS local está mejorando rápidamente, y la elección actual será superada. Trátalo como el campeón actual, no la respuesta final. Busca modelos más nuevos y mejores, especialmente antes de un gran trabajo de narración, o cuando la última comprobación a continuación tenga más de ~6 semanas.
- Escanea. Busca en la web modelos TTS de pesos abiertos publicados o actualizados desde la última comprobación. Mira en:
- TTS Arena / tablas de clasificación de voz de Artificial Analysis
- Modelos de conversión de texto a voz en tendencia de Hugging Face
- r/LocalLLaMA
- Lanzamientos de GitHub de los motores a continuación
- Filtra. Mantén un candidato solo si:
- se puede usar localmente de forma gratuita (pesos abiertos, licencia permisiva o de uso personal)
- funciona en la memoria GPU y sistema operativo del usuario
- habla el idioma necesario
- supera al campeón en calidad, o lo iguala siendo mucho más rápido
- Prueba. Genera
eval/lineas.txtcon el candidato. Puntúalo contra el campeón conscripts/voice_metrics.py(pip install numpy librosa; las grabaciones del campeón y la línea base están eneval/):- Desviación estándar del tono ≥ ~5 semitonos y rango ≥ ~17 semitonos son necesarios para sonar natural.
- Mide la velocidad como segundos de audio por segundo de generación.
- Escucha. Pide al usuario que elija de oído entre el candidato y
eval/campeon_*.wav(ffplay -nodisp -autoexit archivo.wav). Las métricas solo preseleccionan candidatos; el oído decide. - Registra. Actualiza la línea "Última comprobación" a continuación y
references/benchmarks.md, tanto si algo cambió como si no. Si el campeón cambia, reemplazaeval/campeon_*.wavy actualizasay.py, y pregunta antes de eliminar el modelo antiguo.
Última comprobación: 2026-11-02 (encuesta web más pruebas locales de VoxCPM2 Q8 y Phonon 31m/Miles). Aiden fue
preferido de oído sobre ambos. Aún no probados localmente: Phonon 40m, OmniVoice, Breeze TTS 2, Drama 3,
Orpheus, Dia, Sesame CSM, Spark-TTS, IndexTTS-2, VibeVoice, Higgs Audio, Kyutai TTS y
Fish/OpenAudio. Los detalles están en references/benchmarks.md.