// por dentro
Como foi construído
O narrar é um app Python 3.13 que converte PDF, Markdown e TXT em mp3/wav sem nenhuma chamada de rede na síntese. São dois motores TTS neurais em ONNX: o Piper (vozes pt-BR medium faber, cadu e jeff), que é o padrão e roda a ~25x o tempo real em CPU, e o Kokoro (kokoro-onnx, vozes alex, santa e dora), mais natural e a ~4x o tempo real. O código é dividido em módulos de responsabilidade única (extrair, prosodia, falar, vozes_ia, interface, atualizacao), e a janela Tkinter e a CLI são duas cascas finas sobre os mesmos módulos. A distribuição é um bundle PyInstaller com dois executáveis que compartilham dependências, publicado por GitHub Actions a cada tag. O site é Next.js 16 com App Router, estático com ISR, que consulta a API de releases do GitHub para mostrar e servir a versão mais recente.
- App
- Python 3.13piper-tts 1.7+kokoro-onnx 0.6+ (ONNX Runtime em CPU)pypdf 6 com fallback para pdftotextffmpeg para wav → mp3
- Interface
- Tkinter/ttk (tema clam customizado) e CLI com argparse e menu interativo
- Empacotamento e CI
- PyInstaller 6.11 (spec com dois EXE e um COLLECT)GitHub Actions publicando narrar-linux.tar.gz em cada tag v*
- Site
- Next.js 16.3React 19.2Tailwind CSS 4TypeScript 5qrcode (SVG gerado no servidor)
- SEO do site
- Metadata APIJSON-LD SoftwareApplicationWebSite e FAQPageimagens Open Graph geradas com next/ogsitemaprobotsllms.txt e llms-full.txt
Arquitetura
Uma regra de negócio, duas interfaces
Extração, prosódia, síntese e atualização ficam em módulos que não conhecem a interface. A janela Tkinter e a CLI só encadeiam chamadas, então o resultado é idêntico nos dois modos e um motor de voz novo é um módulo ao lado de vozes_ia.py mais um ramo em falar.py.
IA
Fonetização reaproveitada do Piper
O espeak-ng embutido no kokoro-onnx traz o caminho dos dados da máquina de build e falha em phontab. O app fonetiza em pt-br com o espeak que o Piper já carrega e entrega os fonemas ao Kokoro com is_phonemes=True, sem nova dependência de sistema e com 21 MB a menos no pacote.
IA
Prosódia própria para ritmo de audiolivro
Os dois motores leem a cerca de 190 palavras por minuto e o sentence_pause do Kokoro só vale a cada 510 fonemas. O módulo prosodia corrige a pontuação colada (53% das fronteiras de frase nos textos de teste), corta em fatias de até 260 caracteres e insere silêncio proporcional a cada sinal, chegando a ~153 palavras por minuto no ritmo padrão.
Performance
Janela responsiva com síntese em segundo plano
A síntese roda numa thread daemon e manda eventos por uma queue.Queue que a janela drena com after(120 ms). Diálogos modais, como a confirmação do download de 338 MB do modelo, ficam na thread do Tk para não travar a interface.
DevOps
Release e autoatualização seguras
O workflow falha se a tag não bater com o arquivo VERSION embutido no binário, o que evitaria um ciclo infinito de atualização. Como sobrescrever o _internal/ de um PyInstaller em execução derruba o processo, a nova versão fica numa pasta de espera e um script externo faz a troca depois que o app fecha.
Performance
Site estático que acompanha a release
lib/release.ts consulta /releases/latest da API do GitHub com revalidate de 1 hora e cai num fallback estático se a API falhar. A rota /api/download responde 307 para o asset mais recente, e o QR Code do Pix é gerado em SVG no servidor, sem JavaScript no cliente.