O que TTS Local (Local TTS) faz?
A voz padrão: Qwen3-TTS 1.7B CustomVoice, locutor aiden, 8-bit GGUF (Q8_0), executado por
qwentts.cpp (C++/ggml, MIT) com esta instrução de estilo:
Calorosa, clara e curiosa, como um narrador amigável de vídeo explicativo. Ritmo relaxado e constante.
Ele venceu um teste cego de escuta contra Kokoro, Chatterbox, PyTorch Qwen3-TTS, VoxCPM2 e Phonon
(veja references/benchmarks.md). Em uma GPU Laptop RTX 4070 de 8 GB, roda a ~4x o tempo real, incluindo
carregamento do modelo: uma narração de 18 minutos leva ~4,5 minutos.
Configuração (uma vez por máquina)
Execute python -I <skill>/scripts/say.py --check primeiro. Se imprimir OK, pule esta seção.
Caso contrário, configure o motor, ou peça ao usuário para fazê-lo. Leva de 10 a 20 minutos e ~2,5 GB de disco.
- Compilar qwentts.cpp. Não existe binário pré-compilado para Windows, então compile a partir do código fonte:
No Windows, instale as Ferramentas de Build do VS 2022 (ou mais recente) com a carga de trabalho C++, CMake, Ninja e o CUDA Toolkit, depois executegit 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 apenas CPU (ex.: macOS)buildcuda.cmda partir do repositório. Sevcvars64.batestiver em outro local, edite o caminho no topo desse script. Para segmentar apenas uma GPU, adicione-DCMAKE_CUDA_ARCHITECTURES=89(RTX 40xx; 86 = RTX 30xx, 120 = RTX 50xx) à linha do cmake. - Baixar os pesos (~2 GB) do 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 - Apontar say.py para eles se você usou outras pastas: defina
QWEN_TTS_HOME(o checkout),QWEN_TTS_EXE(o binário) ouQWEN_TTS_MODELS(a pasta .gguf). No Windows,say.pyadiciona%CUDA_PATH%\bin\x64ao PATH para você (substitua comCUDA_BIN). - Execute
say.py --checknovamente e depois gere uma linha de teste.
Hardware: 8 GB de VRAM são suficientes para Q8_0 (~3 GB em uso). Sem GPU, uma compilação para CPU funciona a aproximadamente
um quarto da velocidade. GGML_BACKEND=CPU força uma compilação GPU a rodar na CPU.
Antes de gerar
- Há algo mais usando a GPU? Um jogo ou outro aplicativo pesado na GPU torna a geração ~4x mais lenta
e faz esse aplicativo travar. Pergunte antes de iniciar um trabalho longo. Se o usuário nomear tais aplicativos, defina
TTS_BUSY_APPS=app1,app2esay.pyavisará quando um estiver em execução. - Vale a pena verificar um modelo mais novo? Veja "Continue procurando por modelos melhores" abaixo. Se a última verificação tiver mais de ~6 semanas e a tarefa for uma narração real (não um teste de uma linha), faça a varredura rápida primeiro.
- O texto soa humano? Uma voz lê jargão de IA com a mesma entonação sempre, então o padrão se destaca
mais do que no papel. Para qualquer narração com mais de algumas linhas, leia
natural-narration.mddo skillwhiteboard-explainer(mesmo plugin,references/) e execute seuscripts/aispeak_scan.py, que aceita um script.py ou um arquivo de texto simples.
Gerar
O script usa apenas a biblioteca padrão, então qualquer Python 3.10+ funciona. <skill> é a pasta deste skill.
python -I <skill>/scripts/say.py "Primeira linha." "Segunda linha." -o saida.wav # um WAV, lacunas de 0,35 s
python -I <skill>/scripts/say.py --file linhas.txt -o clips/ # 000.wav, 001.wav, ...
Opções:
| Flag | O que faz |
|---|---|
--speaker | aiden (padrão); ryan é a outra voz nativa em inglês |
--instruct | Texto de estilo, ex.: "Animado, ritmo acelerado" ou "Calmo e sério" |
--seed N | Gera uma tomada repetível |
--gap S | Segundos de silêncio entre linhas em um arquivo unido |
--srt F | Também escreve legendas sincronizadas com o WAV unido (veja Legendas) |
--quant | Q8_0 (padrão, melhor) ou Q4_K_M (menor, um pouco mais plano; baixe-o primeiro) |
--check | Reporta o motor, modelos e pastas CUDA encontrados |
Como funciona:
- Cada linha passa por um único processo, então o modelo carrega uma vez (3–8 s). Passe linhas em lote, não uma chamada por linha.
- A saída é WAV mono de 24 kHz, 16 bits.
As tomadas são amostradas, então cada execução difere:
- Mantenha os clipes de que gostar. Cache por linha, indexado por texto mais configurações.
- Refazer uma linha se seu comprimento estiver muito distante de ~0,07 s por caractere. Isso significa que palavras foram descartadas ou inventadas.
Para uma narração em vídeo, também:
- Aparar o silêncio de cada clipe para ~50 ms de preenchimento e, em seguida, posicione as linhas na linha do tempo com seus próprios intervalos.
- Normalizar o volume da faixa final:
ffmpeg -af loudnorm=I=-16:TP=-1.5:LRA=11.
Legendas (.srt): ofereça-as com cada vídeo narrado
Você já sabe quando cada linha começa e termina, então não há nada para transcrever. Construa as legendas a partir desses tempos.
- Com
say.py: adicione--srt narracao.srt(precisa de um.wav-o). As legendas correspondem exatamente à faixa unida. - Em seu próprio pipeline: chame
scripts/srt.py,to_srt([(inicio_s, fim_s, texto), ...], exibir=[...]), com início/fim em tempo de vídeo por linha falada. Ou use a CLI:python srt.py tempos.tsv -o video.srt. - Corrigir grafias da voz. O texto da narração é frequentemente escrito para a voz: "D I L", nomes reescritos
foneticamente, "runner ponto HTML", números por extenso. Mapeie-os de volta com
display/--display exibir.tsv(faladoescrito). Use as formas escritas do que é mostrado na tela e use algarismos para números ("$232", "83%"). - Verifique o resultado. Pesquise por letras maiúsculas espaçadas restantes (
[A-Z] [A-Z]) e " ponto ". - Regras que o módulo aplica:
- no máximo 2 linhas de 42 caracteres por legenda
- quebra em frase, depois em oração, depois em palavra
- frases curtas mescladas para que nada passe rápido demais
- tempo dividido proporcionalmente ao comprimento
- Nomeie como o vídeo (
Nome do Video.srtao lado deNome do Video.mp4) para que os players o carreguem automaticamente. No VLC,--sub-file=força um arquivo.
O skill whiteboard-explainer contém em template/narration/build_vo.py um pipeline completo:
cache por linha, refilmagens, corte de silêncio, modelagem de pausas, alinhamento de palavras, tabela de dicas e envelope de sincronização labial.
Armadilhas
- As DLLs CUDA devem estar no PATH (Windows). O CUDA 13 as mantém em
...\CUDA\v13.x\bin\x64. Sem essa pasta no PATH,qwen-tts.exetermina silenciosamente sem saída.say.pyadiciona para você. --stream-by-line -o -escreve cabeçalhos WAV streaming (tamanhos 0x7fffffff), um por linha. Divida emRIFF....WAVEfmte descarte cada cabeçalho de 44 bytes. Não confie nos campos de tamanho.- Aiden lê mal letras soltas e tokens estranhos. Descoberto por uma auditoria não solicitada do Whisper:
- "h star" saiu como "a hap" ou "our star", "y t" como "VT", "y" como "we", e "arXiv" como "ArcSireFolk".
- Funcionam: "H star" maiúsculo / "under H", "why tee" / "why tilde", "archive", e "SMILES check".
- "aitch" é errático. Um nome pode funcionar sozinho e ser distorcido no meio da frase: teste dentro da linha inteira.
- Um K inicial de frase pode cair ("Kwenputer" → "When Pooter"): comece essas linhas com "And" ou "So".
- Audite transcrevendo cada clipe sem o script como prompt inicial e depois compare com
o script. Um Whisper com prompt "ouve" as palavras pretendidas e esconde os erros. Ferramentas:
whiteboard-explainer/template/narration/audit_vo.pyetts_try.py.
- Pausas em dois-pontos. O Qwen pausa 0,6-0,8 s em um dois-pontos e às vezes no meio da frase. Em uma narração,
limite cada silêncio pela pontuação anterior (
shape()no build_vo.py do template) e evite linhas fragmentadas com dois-pontos ("Primeiro: ..."). - Fallback para CPU: Kokoro 82M (
kokoro-onnx) é monótono, mas rápido na CPU, adequado para rascunhos enquanto a GPU estiver ocupada.
Continue procurando por modelos melhores
O TTS local está melhorando rapidamente, e a escolha atual será superada. Trate-a como a campeã atual, não como a resposta final. Procure por modelos mais novos e melhores, especialmente antes de um grande trabalho de narração ou quando a última verificação abaixo tiver mais de ~6 semanas.
- Varredura. Pesquise na web por modelos TTS de pesos abertos lançados ou atualizados desde a última verificação. Veja:
- TTS Arena / Artificial Analysis speech leaderboards
- Hugging Face trending text-to-speech models
- r/LocalLLaMA
- Lançamentos no GitHub dos motores abaixo
- Filtrar. Mantenha um candidato apenas se ele:
- puder ser usado localmente gratuitamente (pesos abertos, licença permissiva ou de uso pessoal)
- rodar na memória GPU e sistema operacional do usuário
- falar o idioma necessário
- superar o campeão em qualidade, ou igualá-lo sendo muito mais rápido
- Teste. Gere
eval/linhas.txtcom o candidato. Pontue-o contra o campeão comscripts/voice_metrics.py(pip install numpy librosa; as gravações do campeão e baseline estão emeval/):- Desvio padrão da altura (pitch) ≥ ~5 semitons e alcance ≥ ~17 semitons são necessários para soar natural.
- Meça a velocidade como segundos de áudio por segundo de geração.
- Ouça. Peça ao usuário para escolher de ouvido entre o candidato e
eval/champion_*.wav(ffplay -nodisp -autoexit arquivo.wav). As métricas apenas pré-selecionam candidatos; o ouvido decide. - Registre. Atualize a linha "Última verificação" abaixo e
references/benchmarks.md, independentemente de algo ter mudado. Se o campeão mudar, substituaeval/champion_*.wave atualizesay.py, e pergunte antes de excluir o modelo antigo.
Última verificação: 2026-11-02 (pesquisa na web mais testes locais com VoxCPM2 Q8 e Phonon 31m/Miles). Aiden foi
preferido de ouvido em relação a ambos. Ainda não testado localmente: Phonon 40m, OmniVoice, Breeze TTS 2, Drama 3,
Orpheus, Dia, Sesame CSM, Spark-TTS, IndexTTS-2, VibeVoice, Higgs Audio, Kyutai TTS e
Fish/OpenAudio. Detalhes em references/benchmarks.md.