Synthèse vocale chinoise : normalisation textuelle et ingénierie
Ce skill provient d'un animal de bureau IA qui parle tous les jours (voir « Source et maintenance » en bas) : Claude répond en streaming, phrase par phrase, lues par un TTS local. Les règles ci-dessous ont toutes été testées, les chiffres ont été mesurés.
Principe en une phrase : La prononciation est déterminée ici ; le moteur ne fait que prononcer. Si on laisse la prononciation au moteur, changer de moteur change la lecture ; si on utilise une bibliothèque TN toute faite, il y a quelques endroits où le résultat se dégrade. Les bibliothèques existantes (wetext, PaddleSpeech) servent de référence et pour compléter les règles.
Flux
Texte streaming du modèle
→ ① Filtrage : supprimer les décorations, emojis, puces de liste ; remplacer les blocs de code, tableaux et liens par une phrase (doit reconnaître les morceaux séparés en streaming)
→ ② Conversion en prononciation : nombres, heures, unités, symboles, table de remplacement (maintien des frontières en streaming)
→ ③ Découpage en phrases : la première partie coupée au premier point-virgule, puis couper à la virgule quand ça dépasse 40 caractères
→ ④ Synthèse : ne générer qu'environ 20 secondes d'avance ; lors d'une interruption, vraiment arrêter l'inférence
L'ordre ne peut pas être changé : d'abord la conversion, puis le découpage. Lorsqu'on découpe d'abord puis nettoie, trois erreurs ont été constatées :
| Original | Résultat après découpage d'abord | Problème |
|---|---|---|
下午14:30开会 | 下午14: / 30开会 | Le deux-points est pris pour une virgule, l'heure est coupée |
看这里:https://…/pull/7 就行 | https: / //…/pull/7 就行 | Le lien est coupé en deux, l'adresse est lue lettre par lettre |
大概3~5天 | 大概35天 | ~ est supprimé comme décoration, lu « trente-cinq jours » |
Le : demi-largeur n'est traité comme virgule que s'il est suivi d'un espace.
Maintien des frontières en streaming
Une phrase correctement convertie en bloc ne l'est pas forcément en streaming. En streaming caractère par caractère, « 工作了26年 » et « 80年代 » sont lus « èr liù nián » et « bā líng nián dài », parce que les caractères après le nombre ne sont pas encore arrivés ; -10°C est lu comme anglais.
- Attendre encore 2 caractères après un nombre avant de le relâcher ; les unités séparées par un espace doivent être reconnues (par ex. « 跑了 5 » est retenu en attendant
km). - En passant à la section suivante, inclure les derniers caractères de la section précédente (pour reconnaître « 了 26 年 », il faut voir le « 了 » précédent).
- Maximum 200 caractères retenus, 4000 pour les blocs de code et tableaux ; relâcher si la limite est atteinte.
- Chaque test doit être exécuté à la fois en « flux caractère par caractère » et en « phrase complète » : les résultats doivent être identiques.
Aide-mémoire des règles (voir references/rules.md pour les détails)
| Catégorie | Exemple | Prononciation |
|---|---|---|
| Année | 2026年, 2026届, 26年见 | Chiffre par chiffre : èr líng èr liù nián, èr líng èr liù jiè, èr liù nián jiàn |
| Durée | 工作了26年, 80年代, 26年前 | En nombre : èr shí liù nián, bā shí nián dài, èr shí liù nián qián |
| Numéro | Téléphone, code de vérification, 编号27149, 房间1201 | Chiffre par chiffre, « 1 » prononcé « yāo », pause au trait d'union et à l'espace |
| Cinq chiffres | 95588 / 价钱 12999 | Pas d'unité, ne se termine pas par 0, pas précédé d'argent → numéro ; sinon en nombre |
| Argot internet | 666, 2333, 520 seuls / 666个赞, 花了888 | Chiffre par chiffre / en nombre (liste fixe) |
| 2 devant unité | 2个, 2L, 2℃ | Deux (liǎng) sauf température : èr shè shì dù |
| Unité | 60km/h, 3kWh, 5min, 10mg | 60 kilomètres par heure, 3 kilowattheures, 5 minutes, 10 milligrammes |
| Unité non convertie | 4g网络, 5A景区, 16GB | Laissé tel quel au moteur |
| Plage, pourcentage | 3~5%, 3-5km, -1.5~2 | 3 à 5 %, 3 à 5 km, moins 1,5 à 2 |
| Heure | 14:30, 13:00, 9:05 | 14 h 30, 13 h 00, 9 h 05 (format 24 h) |
| Date, fraction | 10/26 交 / 有7/12的观众 | 26 octobre / 7 sur 12 (fraction seulement si précédé de « 有, 占, 约 ») |
| Symbole | #15, 2x, x3, 100w | Numéro 15, double, fois 3, 1 million |
Vérification avec cas de test
references/golden-cases.json contient 115 cas de phrase complète et 24 cas de streaming, tous validés par le projet d'origine. scripts/check-tn.mjs les utilise pour tester votre implémentation :
node scripts/check-tn.mjs ./my-tn.mjs # Le module exporte normalize(texte) et (optionnel) createStream()
node scripts/check-tn.mjs ./my-tn.mjs --only 号码 # Tester seulement un groupe
- La comparaison ignore les espaces et la ponctuation courante, ne compare que la prononciation. Les cas avec
notesont des « références », signalés mais pas considérés comme des échecs. - Utilisez-le comme ligne de validation pour une nouvelle TN ; en modifiant des règles, exécutez-le pour éviter de casser un autre cas.
- Les prononciations controversées (par ex. « 这台电脑 12999 » lue comme un numéro) sont acceptées par le projet d'origine. Si votre produit veut une autre prononciation, modifiez le cas de test et ajoutez une explication à côté.
Comment trouver une prononciation erronée
Quatre causes possibles : la conversion n'a pas été écrite en prononciation ; un homographe mal choisi par le modèle ; un enregistrement de référence défectueux ; aléatoire (relancer une fois).
Faites lire la même phrase avec la voix actuelle et deux autres voix : si chaque voix se trompe sur le même caractère, ajoutez la règle dans la table de remplacement ; si une seule voix est étrange, changez de voix. Enregistrez toujours l'original et la prononciation convertie dans un journal (jsonl) pour pouvoir revenir en arrière.
Ingénierie (voir references/engines.md)
- Latence de la première phrase : La première partie est coupée après le premier point-virgule. Matcha produit la première piste audio 0,65 seconde après l'arrivée du premier caractère.
- Le moyen le plus efficace d'accélérer est le cache : CosyVoice met 2,6 à 3 secondes pour un premier bloc non en cache, 6 millisecondes si en cache. Pré-synthétisez des mots de remplissage (« euh », « laisse-moi réfléchir ») dès que l'utilisateur commence à parler.
- L'annulation doit vraiment arrêter l'inférence : Si la connexion vLLM est interrompue sans
abort_request, la phrase suivante attend 4,9 secondes (avec, 0,8 à 1,7 seconde). - L'anglais peut être silencieusement ignoré : Certains moteurs ne prononcent pas
GitHub,PR,%; vérifiez à nouveau l'anglais après une mise à jour de dépendance. - Moteur de secours : Si le moteur principal n'est pas prêt ou échoue immédiatement, basculer sur le secours ; en cas d'erreur en cours de phrase, ne pas relire. Le fait que le service HTTP soit lancé ne signifie pas que le modèle est chargé ; en cas de 503, réessayer.
Source et maintenance
- Source : Cirra (animal de bureau IA, RedCarpG/cirra-deskpet) et son service vocal cirra-voice, d'octobre 2026 à novembre 2026.
- Code :
sidecar/src/tts/speech/(numbers.ts,units.ts,links.ts,filter.ts,overrides.ts,speech.test.ts),sidecar/src/tts/splitter.ts,sidecar/src/tts/pronunciations.ts. - Documentation :
docs/speech.md,docs/speech-tn.md(119 phrases de référence),docs/tts.md,docs/voices.md,docs/voice-chat.md,docs/voice-chat-2.md,docs/voice-install.md,docs/perf-checkup.md. - Expériences :
lessons/chinese-tts.mddans un dépôt privé.
- Code :
- Origine :
skills/chinese-tts/dans RedCarpG/redcarpg-skills. Le dossier~/.claude/skills/contient une copie installée, ne pas modifier directement.references/golden-cases.jsona été extrait le 10 novembre 2026 despeech.test.tsde Cirra via un script ; les deux ne sont pas synchronisés automatiquement. - Comment modifier :
- Modifier dans redcarpg-skills, via une PR ; incrémenter la version dans
manifest.json, exécuternode scripts/validate.mjs, publier une release (tagchinese-tts-v<version>), puis réinstaller la copie locale. Vérifier d'abord silessons/chinese-tts.mdcontient de nouvelles entrées à intégrer. - Si les règles TN de Cirra changent, réextraire les cas (méthode : lire les
[original, prononciation]dans le groupereadNumberset le groupe « streaming » despeech.test.ts), puis utiliser un module d'adaptation avecsidecar/dist/tts/compilé par Cirra et exécutercheck-tn.mjs; tout doit passer. - Les chiffres des moteurs (latence, temps réel, mémoire GPU) ont été mesurés en octobre 2026 sur une machine avec 8 Go de mémoire GPU et un processeur sans VNNI ; à remesurer avec un matériel différent.
- Modifier dans redcarpg-skills, via une PR ; incrémenter la version dans
- Historique des mises à jour :
- 12 novembre 2026 · 1.0.0, publication publique dans redcarpg-skills. Chemins absolus locaux modifiés, projet source écrit en lien ; contenu inchangé.
- 10 novembre 2026 · Cirra · Première version : flux et ordre, frontières de streaming, aide-mémoire et règles détaillées, recherche d'erreurs de prononciation, ingénierie des moteurs ; 139 cas de test et
check-tn.mjs(testé avec l'implémentation de Cirra, tout passé) ; deux prompts de test dansevals/.