Communitygithub.com

local-tts

Générez une voix humaine réaliste localement sur votre GPU (ou CPU), sans frais d'API — voix-off, narration pour vidéos explicatives, lecture de textes à haute voix, clips audio à partir de texte — avec sous-titres .srt synchronisés. Utilise Qwen3-TTS 1.7B (GGUF 8 bits) via qwentts.cpp.

Qu'est-ce que local-tts ?

Cette compétence permet de synthétiser une parole de qualité humaine directement sur votre propre matériel, sans dépendre d'API coûteuses ou de services cloud. Elle repose sur le modèle Qwen3-TTS 1.7B en format GGUF 8 bits, exécuté via l'implémentation C++/ggml `qwentts.cpp`, avec une voix par défaut nommée `aiden` (locuteur masculin anglais). La compétence gère l'installation et la configuration complètes du moteur, la génération de fichiers audio WAV (24 kHz, 16 bits, mono) à partir d'une ou plusieurs lignes de texte, la production de sous-titres .srt synchronisés, ainsi que la vérification de la disponibilité GPU et la gestion des conflits d'utilisation. Elle inclut également des mécanismes pour évaluer et comparer de nouveaux modèles TTS locaux, afin de toujours utiliser le meilleur modèle disponible. Des scripts annexes (dans le dossier `scripts/`) automatisent la vérification de l'installation, la normalisation du volume audio et la détection de texte « non naturel » (style IA). La compétence est conçue pour s'intégrer dans des pipelines de production vidéo (HyperFrames, fframes, Remotion…) et remplace avantageusement les alternatives cloud ou les voix intégrées de moindre qualité.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Ayushmaniar/claude-explainer-skills/tree/HEAD/plugins/explainer-skills/skills/local-tts

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Synthèse Vocale Locale (TTS Local)

Voix par défaut : Qwen3-TTS 1.7B CustomVoice, locuteur aiden, GGUF 8 bits (Q8_0), piloté par qwentts.cpp (C++/ggml, MIT) avec cette instruction de style :

Chaleureux, clair et curieux, comme un narrateur sympathique de vidéo explicative technique. Rythme détendu et régulier.

Il a remporté un test d'écoute à l'aveugle face à Kokoro, Chatterbox, PyTorch Qwen3-TTS, VoxCPM2 et Phonon (voir references/benchmarks.md). Sur un GPU RTX 4070 Laptop 8 Go, il fonctionne à environ 4x la vitesse réelle, chargement du modèle compris : une narration de 18 minutes prend ~4,5 minutes.

Configuration (une fois par machine)

Exécutez python -I <skill>/scripts/say.py --check d'abord. S'il affiche OK, ignorez cette section. Sinon, configurez le moteur, ou demandez à l'utilisateur de le faire. Cela prend 10 à 20 minutes et environ 2,5 Go d'espace disque.

  1. Construire qwentts.cpp. Il n'existe pas de binaire Windows précompilé, donc construisez-le à partir des sources :
    git clone --recurse-submodules https://github.com/ServeurpersoCom/qwentts.cpp ~/tools/qwentts.cpp
    cd ~/tools/qwentts.cpp
    ./buildcuda.sh       # NVIDIA (Linux) ; ./buildvulkan.sh pour AMD/Intel ; ./buildcpu.sh pour CPU uniquement (ex. macOS)
    
    Sous Windows, installez les outils de build VS 2022 (ou plus récent) avec la charge de travail C++, CMake, Ninja et le CUDA Toolkit, puis exécutez buildcuda.cmd depuis le dépôt. Si vcvars64.bat se trouve ailleurs, modifiez le chemin en haut de ce script. Pour cibler un seul GPU, ajoutez -DCMAKE_CUDA_ARCHITECTURES=89 (RTX 40xx ; 86 = RTX 30xx, 120 = RTX 50xx) à la ligne cmake.
  2. Télécharger les poids (~2 Go) depuis 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
    
  3. Pointer say.py vers eux si vous avez utilisé d'autres dossiers : définissez QWEN_TTS_HOME (le checkout), QWEN_TTS_EXE (le binaire) ou QWEN_TTS_MODELS (le dossier .gguf). Sous Windows, say.py ajoute %CUDA_PATH%\bin\x64 au PATH pour vous (remplacez par CUDA_BIN).
  4. say.py --check à nouveau, puis testez une ligne vocale.

Matériel : 8 Go de VRAM suffisent pour Q8_0 (~3 Go utilisés). Sans GPU, une version CPU fonctionne environ un quart de la vitesse. GGML_BACKEND=CPU force une version GPU sur le CPU.

Avant de générer

  1. Quelque chose d'autre utilise-t-il le GPU ? Un jeu ou une autre application gourmande en GPU rend la génération ~4x plus lente et fait bégayer cette application. Demandez avant de lancer un long travail. Si l'utilisateur nomme de telles applications, définissez TTS_BUSY_APPS=app1,app2 et say.py prévient quand l'une d'elles est en cours.
  2. Un modèle plus récent mérite-t-il d'être vérifié ? Voir "Continuez à chercher de meilleurs modèles" ci-dessous. Si la dernière vérification date de plus de ~6 semaines et que la tâche est une véritable narration (pas un test d'une ligne), faites d'abord l'analyse rapide.
  3. Le texte sonne-t-il humain ? Une voix lit le langage IA avec la même intonation à chaque fois, donc le motif ressort plus qu'à l'écrit. Pour toute narration de plus de quelques lignes, lisez natural-narration.md depuis la compétence whiteboard-explainer (même plugin, references/) et exécutez son scripts/aispeak_scan.py, qui prend un script.py ou un fichier texte brut.

Générer

Le script utilise uniquement la bibliothèque standard, donc n'importe quel Python 3.10+ fonctionne. <skill> est le dossier de cette compétence.

python -I <skill>/scripts/say.py "Première ligne." "Deuxième ligne." -o out.wav       # un seul WAV, intervalles de 0,35 s
python -I <skill>/scripts/say.py --file lines.txt -o clips/                    # 000.wav, 001.wav, ...

Options :

OptionEffet
--speakeraiden (par défaut) ; ryan est l'autre voix anglaise native
--instructTexte de style, ex. "Excité, rapide" ou "Calme et sérieux"
--seed NDonne une prise reproductible
--gap SSecondes de silence entre les lignes dans un fichier joint
--srt FÉcrit également des sous-titres synchronisés avec le WAV joint (voir Sous-titres)
--quantQ8_0 (par défaut, meilleur) ou Q4_K_M (plus petit, un peu plus plat ; téléchargez-le d'abord)
--checkRapporte le moteur, les modèles et les dossiers CUDA trouvés

Comment ça marche :

  • Chaque ligne passe par un seul processus, donc le modèle ne se charge qu'une fois (3–8 s). Passez les lignes en bloc, pas un appel par ligne.
  • La sortie est un WAV 24 kHz mono 16 bits.

Les prises sont échantillonnées, donc chaque exécution diffère :

  • Gardez les clips que vous aimez. Mise en cache par ligne, indexée par texte et paramètres.
  • Refaites une ligne si sa longueur est très éloignée d'environ 0,07 s par caractère. Cela signifie que des mots ont été supprimés ou inventés.

Pour une narration vidéo, aussi :

  • Réduisez le silence de chaque clip à environ 50 ms de padding, puis placez les lignes sur la timeline avec vos propres intervalles.
  • Normalisez le volume de la piste finale : ffmpeg -af loudnorm=I=-16:TP=-1.5:LRA=11.

Sous-titres (.srt) : proposez-les avec chaque vidéo narrée

Vous savez déjà quand chaque ligne commence et se termine, donc il n'y a rien à transcrire. Construisez les sous-titres à partir de ces timings.

  • Avec say.py : ajoutez --srt narration.srt (nécessite un .wav -o). Les sous-titres correspondent exactement à la piste jointe.
  • Dans votre propre pipeline : appelez scripts/srt.py, to_srt([(start_s, end_s, text), ...], display=[...]), avec début/fin en temps vidéo par ligne parlée. Ou utilisez la CLI : python srt.py timings.tsv -o video.srt.
  • Corrigez les orthographes vocales. Le texte de narration est souvent écrit pour la voix : "D I L", noms réécrits phonétiquement, "runner point HTML", nombres en toutes lettres. Ramenez-les avec display / --display display.tsv (parléécrit). Prenez les formes écrites de ce qui est affiché à l'écran, et utilisez des chiffres pour les nombres ("232 $", "83 %").
  • Vérifiez le résultat. Cherchez les majuscules espacées restantes ([A-Z] [A-Z]) et " point ".
  • Règles appliquées par le module :
    • au maximum 2 lignes de 42 caractères par sous-titre
    • coupe à la phrase, puis à la proposition, puis au mot
    • les phrases courtes sont fusionnées pour que rien ne clignote
    • le temps est réparti proportionnellement à la longueur
  • Nommez-le comme la vidéo (Nom Vidéo.srt à côté de Nom Vidéo.mp4) pour que les lecteurs le chargent automatiquement. Dans VLC, --sub-file= force un fichier.

Le pipeline complet de la compétence whiteboard-explainer dans template/narration/build_vo.py est un exemple complet : mise en cache par ligne, reprises, réduction du silence, modelage des pauses, alignement des mots, table de repères et enveloppe de synchronisation labiale.

Pièges à éviter

  • Les DLL CUDA doivent être dans le PATH (Windows). CUDA 13 les garde dans ...\CUDA\v13.x\bin\x64. Sans ce dossier dans le PATH, qwen-tts.exe se ferme silencieusement sans sortie. say.py l'ajoute pour vous.
  • --stream-by-line -o - écrit des en-têtes WAV en streaming (tailles 0x7fffffff), une par ligne. Séparez à RIFF....WAVEfmt et supprimez chaque en-tête de 44 octets. Ne vous fiez pas aux champs de taille.
  • Aiden lit mal les lettres seules et les jetons étranges. Découvert par un audit Whisper non provoqué :
    • "h star" est sorti comme "a hap" ou "our star", "y t" comme "VT", "y" comme "we", et "arXiv" comme "ArcSireFolk".
    • Ces solutions fonctionnent : "H star" majuscule / "under H", "why tee" / "why tilde", "archive", et "SMILES check".
    • "aitch" est erratique. Un nom peut être correct seul et déformé au milieu d'une phrase : testez-le dans la ligne entière.
    • Un K en début de phrase peut disparaître ("Kwenputer" → "When Pooter") : commencez ces lignes par "And" ou "So".
    • Auditez en transcrivant chaque clip sans le script comme invite initiale, puis en comparant avec le script. Un Whisper amorcé "entend" les mots prévus et cache les erreurs. Outils : whiteboard-explainer/template/narration/audit_vo.py et tts_try.py.
  • Pauses aux deux-points. Qwen marque une pause de 0,6 à 0,8 s à un deux-points et parfois en milieu de phrase. Dans une narration, limitez chaque silence par la ponctuation qui le précède (shape() dans build_vo.py du template) et évitez les lignes fragmentées par deux-points ("Premier : ...").
  • Solution de secours CPU : Kokoro 82M (kokoro-onnx) est plat mais rapide sur CPU, idéal pour les brouillons pendant que le GPU est occupé.

Continuez à chercher de meilleurs modèles

La TTS locale s'améliore rapidement, et le choix actuel sera dépassé. Traitez-le comme le champion actuel, pas la réponse finale. Cherchez des modèles plus récents et meilleurs, surtout avant un gros travail de narration, ou lorsque la dernière vérification ci-dessous date de plus de ~6 semaines.

  1. Analysez. Recherchez sur le web des modèles TTS à poids ouverts publiés ou mis à jour depuis la dernière vérification. Consultez :
    • TTS Arena / Artificial Analysis speech leaderboards
    • Hugging Face tendances des modèles text-to-speech
    • r/LocalLLaMA
    • Versions GitHub des moteurs ci-dessous
  2. Filtrez. Ne gardez un candidat que s'il :
    • peut être utilisé localement gratuitement (poids ouverts, licence permissive ou usage personnel)
    • fonctionne sur la mémoire GPU et le système d'exploitation de l'utilisateur
    • parle la langue requise
    • bat le champion en qualité, ou l'égale tout en étant beaucoup plus rapide
  3. Testez. Générez eval/lines.txt avec le candidat. Notez-le contre le champion avec scripts/voice_metrics.py (pip install numpy librosa ; les enregistrements du champion et de référence sont dans eval/) :
    • Écart-type de la hauteur ≥ ~5 demi-tons et étendue ≥ ~17 demi-tons sont nécessaires pour sonner naturel.
    • Mesurez la vitesse en secondes d'audio par seconde de génération.
  4. Écoutez. Demandez à l'utilisateur de choisir à l'oreille entre le candidat et eval/champion_*.wav (ffplay -nodisp -autoexit file.wav). Les métriques ne font qu'établir une présélection ; l'oreille décide.
  5. Enregistrez. Mettez à jour la ligne "Dernière vérification" ci-dessous et references/benchmarks.md, que quelque chose ait changé ou non. Si le champion change, remplacez eval/champion_*.wav et mettez à jour say.py, et demandez avant de supprimer l'ancien modèle.

Dernière vérification : 2026-11-02 (enquête web plus essais locaux VoxCPM2 Q8 et Phonon 31m/Miles). Aiden a été préféré à l'oreille par rapport aux deux. Pas encore testés localement : Phonon 40m, OmniVoice, Breeze TTS 2, Drama 3, Orpheus, Dia, Sesame CSM, Spark-TTS, IndexTTS-2, VibeVoice, Higgs Audio, Kyutai TTS et Fish/OpenAudio. Les détails sont dans references/benchmarks.md.

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Skills associés