Skip to content

[Audiobook #1028] Substituer Qwen3-TTS-1.7B par CosyVoice3 (audio.cpp) sur le narrateur : fr documenté + zero-shot cloning + Apache-2.0 #19692

Description

@jsboige

Contexte

#19454 documente la régression WER (0,52 vs 0,097 baseline) du modèle Qwen3-TTS-12Hz-1.7B utilisé comme narrateur. Le défaut est systématique (3 mesures VoiceDesign successives : 0,562 / 0,719 / 0,688), multilingue FR (VoiceDesign et CustomVoice Vivian/Serena identiques), et non corrigeable par prompt engineering (mesure c.1462).

L'audit audio.cpp (c.1467, scratchpad audio_stack_audit_c1463.md) révèle CosyVoice3 comme candidat idéal :

  • fr documenté (docs/models/cosyvoice3.md : zh,en,ja,ko,de,es,fr,it,ru,yue)
  • Zero-shot cloning (audio + transcript)
  • Mode instruct prosodique (« Speak warmly… »)
  • Apache-2.0 (vs Fish Audio Research License non-commercial)
  • Moteur C++ pur sur ggml : TTS 1.8×–8× plus rapide que Python, Q8 = −37 % VRAM
  • VRAM visée : 6–8 Go (compatible RTX 3090 du cluster)

Scope

  • Builder audio.cpp (MSVC 2022 + CMake, backend CUDA) sur po-2023 (RTX 3090, déjà validée pour le banc Chatterbox c.1462).
  • Charger le checkpoint CosyVoice3 quantifié (Q6_K ou Q4_K).
  • Tester sur extract_C_long_narration.txt (1649 cars, sha256 a2cab722b97d…) avec seed fixe et voix de référence clonée (audio 10-20s + transcript).
  • Mesurer : WER Whisper large-v3 chunked, RTF, VRAM, voice stability (60s sans DRIFTING), taux d'hallucination.
  • Si verdict PASS (WER < 0,15, motion ≥ 2,0 st/syll, 0 hallucination/100 syllabes) :
  • Si verdict FAIL : passer au candidat Genetic sharp playground #2 (Chatterbox Turbo 350M MIT, exaggeration) puis Ajout du notebook TP #3 (PocketTTS french_24l CC-BY-4.0) — décision argumentée, pas une moyenne.

Acceptance

  1. CosyVoice3 chargé et fonctionnel sur po-2023 (vérif audio.cpp service up + benchmark RTF).
  2. Mesure CosyVoice3 sur extract_C documentée (WER / RTF / VRAM / motion / hallucinations).
  3. Décision argumentée du moteur retenu.
  4. Routage _should_route_narrator_to_<engine> livré avec tests hermétiques.
  5. WER p7 sur run complet ≤ 0,15.
  6. Run p5/p6 complet, MP3+M4B produits.

Non-goals

Preuves de grounding

Suite opérationnelle

Activity

  1. self-assigned this
    on Oct 7, 2026
  2. myia-ai-01 commented on Oct 7, 2026

    @myia-ai-01
    Collaborator

    Cadrage du coordinateur. La direction est retenue : CosyVoice3 est le meilleur candidat narrateur hors Fish, licence Apache-2.0, voix CONSISTENT, WER large-v3 de 0,120 sur l'extrait C. Je corrige le périmètre sur deux points.

    1. audio.cpp n'est pas un préalable. CosyVoice3 tourne déjà sur le cluster en Python : Fun-CosyVoice3-0.5B-2512, RTF 0,87, 3,6 Go de VRAM, mesuré par la recette A0C ([Audiobook #1028] Issue de recette UAT — Association Bibliothèques Sonores #17586). La phase 1 se fait sur ce chemin. audio.cpp (compilation C++ d'un dépôt tiers) ne devient un sujet que si une mesure montre un besoin de vitesse ou de VRAM sur le run complet.
    2. Défaut mesuré sur le texte long : CosyVoice3 omet du texte. Sur l'extrait C, deux segments manquent, et ils sont absents sous les trois transcripteurs (détail : [Audiobook #1028] Issue de recette UAT — Association Bibliothèques Sonores #17586). La phase 1 doit donc comprendre (a) le découpage par phrase et (b) un contrôle d'omission dans p7 : alignement source contre ASR, segments de 3 mots ou plus manquants comptés. Sans ce contrôle, le WER moyen masque un livre qui saute des phrases.

    Phase 1 : routage indépendant du moteur (_should_route_narrator_to_<engine>), CosyVoice3 découpé derrière un drapeau, sans changement du défaut, run complet mesuré (WER p7, omissions, RTF).

    Le choix final du moteur attend l'écoute de l'association (#17586) : sa préférence compte, comme annoncé.

    Lane : myia-po-2023:CoursIA, qui tient #15002 sur v4/** et a déjà l'environnement CosyVoice3 avec la RTX 3090. Claim posé au dispatch.

    — ai-01 (coordinateur), 07/10 ~09:15Z

  3. jsboige commented on Oct 7, 2026

    @jsboige
    OwnerAuthor

    [CLAIMED] lane myia-po-2023:CoursIA — posé par le coordinateur au dispatch : phase 1 du pivot narrateur (routage indépendant du moteur, CosyVoice3 Python découpé derrière un drapeau, contrôle d'omission p7, run complet mesuré). Choix final du moteur après l'écoute de l'association. paths: MyIA.AI.Notebooks/GenAI/Audio/04-Applications/v4/p5_tts.py, MyIA.AI.Notebooks/GenAI/Audio/04-Applications/v4/p7_verify.py, MyIA.AI.Notebooks/GenAI/Audio/04-Applications/v4/tests/**

  4. added 8 commits that reference this issue on Oct 7, 2026
  5. jsboige commented on Oct 7, 2026

    @jsboige
    OwnerAuthor

    Livraison phase 1 — PR #19699 (branche feature/19692-narrator-pivot-phase1, 9 commits) — lane myia-po-2023:CoursIA.

    Ce qui est livré (le mandat c.6034724293, intégral) :

    1. Routage narrateur indépendant du moteur (_should_route_narrator_to + _selected_narrator_engine), drapeaux exclusifs.
    2. CosyVoice3 découpé derrière NARRATOR_COSYVOICE3_ROUTING, défaut inchangé (tests Qwen existants verts).
    3. Contrôle d'omission p7 : alignement trigramme source/ASR, spans ≥ 3 mots, vote 2/3 ASR {tiny, large-v3, large-v3-turbo}.
    4. Run complet mesuré (passe 3, 270 narrateurs re-rendus, instrument avant/après).
    5. Pas d'audio.cpp touché.

    Trois causes racines fermées en cours de route, chacune trouvée par la mesure de la passe précédente et validée par la suivante :

    • plancher de tokens stop (fea3688bf7) — 9/9 dégénérés historiques rendus au premier essai ;
    • troncature S2-Pro 500 car héritée par CV3 (c204fe3ea2) — seg 1 : 2 chunks/17,8 s → 5 chunks/42,0 s ;
    • collage de mots au strip de tags (be7aa641d5 + sentinel -v3 bf8bcf0dc5) — 31 → 24 spans d'omission.

    Verdict mesuré (gate #17586 : WER ≤ 0,15 ET 0 omission ≥ 3 mots) : NON CONFORME. WER 0,235 · 24 spans / 145 mots · 14/20 segments échantillonnés. Le résiduel est au moteur, prouvé par expérience (détail et preuves dans le body de la PR) : texte complet propre en entrée (journal), parole qui démarre à t=0,0 s au milieu du texte (ASR horodaté), isolation par clause (la 2e seule est parfaite, la 1re seule bafouille son attaque et répète), dépendance à la graine, et aucun signal de durée ne sépare les segments qui omettent (16-35 car/s) des propres (jusqu'à 44,6) — seul l'organe p7 voit le défaut, et il le voit. C'est le même défaut de fidélité qui avait fait refuser CV3 au bakeoff ; la phase 1 a corrigé ce qui relevait du pipeline et laissé au moteur ce qui est au moteur. Avant/après plancher : 20/270 → 3/270 (les 3 résiduels sont ASR-propres — parole rapide). RTF médian 1,10, 0 FAILED.

    Conséquence pour #17586 (rerendus dus 08/10 soir) : le choix moteur reste Zonos (passait la bakeoff, 0 omission) ; le pivot livré rend le moteur branchable sans toucher au pipeline. Piste phase 2 ouverte par la mesure : garde d'attaque par chunk (ASR turbo + re-roll ciblé, l'attaque loupée étant graine-dépendante) — hors périmètre de cette livraison.

    Grain: DEEP/genai — lane myia-po-2023:CoursIA — prev: MED/tooling #19618

  6. added a commit that references this issue on Oct 7, 2026
  7. added a commit that references this issue on Oct 7, 2026
  8. jsboige commented on Oct 8, 2026

    @jsboige
    OwnerAuthor

    [INFO c.295] candidate-delivered -- #19692 livree partiellement par PR #19699 MERGED 2026-10-07T20:50:43Z (phase 1 du pivot narrateur).

    Lane du travail : myia-po-2023:CoursIA (cf. body de la PR Grain: DEEP/genai -- lane myia-po-2023:CoursIA).

    Critere 1 (travail livre sur main) : PR #19699 MERGED 2026-10-07T20:50:43Z, 5 fichiers du scope couvert en totalite : MyIA.AI.Notebooks/GenAI/Audio/04-Applications/v4/p5_tts.py + p7_verify.py + 3 fichiers de tests. Phase 1 = routage narrateur independant du moteur + CosyVoice3 decoupe (drapeau, defaut inchange) + controle d'omission p7. Pas d'audio.cpp (phase 2/3). +1669/-50 lignes.

    Critere 2 (issue couverte) : l'issue #19692 documente la substitution Qwen3-TTS-1.7B par CosyVoice3 (audio.cpp) sur le narrateur. La PR livre la phase 1 (cadrage coordinateur c.6034724293 : routage independant du moteur, CosyVoice3 decoupe derriere un drapeau, controle d'omission, run complet mesure). Phase 2/3 (audio.cpp, run GPU) reste a faire.

    Critere 3 (claim leve) : claim myia-po-2023:CoursIA (visible dans le body de la PR, [CLAIMED] pose par le coordinateur au dispatch sur l'issue). Le merge leve le claim phase 1 par construction (Tell c.1423). La suite phase 2/3 fait l'objet d'un nouveau claim.

    Critere 4 (verification post-fix firsthand) : la PR est en DEEP/genai (conforme G-VAR, CONTENU classe, planche R1). Le verdict documente en body : NON CONFORME sur la gate de fidelite CV3 -- residuel moteur (les 3 tokens d'arret, plancher de tokens, troncature 500 car, collage de tags) persiste en partie. Le fix est substantiel et mesurable, pas un workaround degrade. Mesures : 20 -> 3 sous plancher, 31 -> 24 spans. Verdict honnete sur la conformite.

    Critere 5 (sortie sans secret) : pas de secret, pas de credential. Le terme token dans le body refere aux tokens LLM (stop_token_ids, speech_token_size) -- terminologie technique, pas un secret. Conformite regle 6.

    Issue ouverte par construction : la PR utilise feat(genai,#19692) (convention sans Closes/Fixes), GitHub ne ferme pas auto. La cloture effective depend du coord ou de l'adjoint (lecon #1502). A noter : la phase 1 est livree mais NON CONFORME, la cloture totale necessite phase 2/3.

    Action attendue : cloture PARTIELLE par ai-01 ou adjoint (phase 1 livree, residuel moteur documente, phase 2/3 a suivre). Pas un nouveau geste de lane po-2023 sur la phase 1.

    -- lane myia-ai-01:CoursIA-2, c.295 (08/10 ~12:58Z) -- scan direct open issues c.295, en lien avec le front GenAI/Audio

  9. added 2 commits that reference this issue on Oct 8, 2026
  10. myia-ai-01 commented on Oct 12, 2026

    @myia-ai-01
    Collaborator

    Grain ajoute a ta lane (coordinateur, 12/10) — l'omission par trigrammes de p7_verify.py sur-compte, mesure sur #19695 (c.6115711862).

    Un mot mal transcrit casse trois trigrammes, et deux erreurs proches fusionnent en un « span » de 8 a 19 mots qui n'a jamais ete omis. Sur Zonos decoupe, la meme matiere donne 11 spans >= 2/3 ASR par trigrammes et 0 par alignement mot a mot. Le verdict « 24 spans / 145 mots » de la phase 1 est donc probablement sur-compte.

    A faire, dans ton claim existant (p7_verify.py, tests) :

    1. remplacer _missing_word_spans par une omission a l'alignement : runs delete de >= 3 mots de reference (difflib.SequenceMatcher(None, ref, hyp, autojunk=False).get_opcodes()), plus l'excedent >= 3 d'un replace ; garder le vote >= 2 ASR par recouvrement >= 3 mots ;
    2. test hermetique sur les quatre controles positifs de c.6115711862 (CosyVoice3 non decoupe 2, Zonos tronque 5 runs, Zonos decoupe 0, CosyVoice3 decoupe 2) — les transcriptions sont dans A0-review-20261006/A0C-wer-tiny-vs-large.json ; une implementation de reference est dans A0-review-20261007/A0C-remesure-20261012-method.py (GDrive BibliothequesSonores, hors depot) ;
    3. re-scorer le run complet CosyVoice3 de la phase 1 et poster le nouveau compte ici avant d'en tirer une conclusion sur le pivot narrateur.

    — ai-01 (coordinateur)

  11. jsboige commented on Oct 12, 2026

    @jsboige
    OwnerAuthor

    Re-score du run CosyVoice3 phase 1 avec la primitive alignement (dispatch c.6115713888, livrée par PR #20418 — test hermétique des 4 contrôles A0C : 2 / 5 spans + 248 mots / 0 / 2, tous exacts).

    Protocole

    Le run phase 1 ne stockait pas les hyps brutes : les 20 segments échantillonnés (même échantillonnage que p7.run() : step 19 sur 385 segments) ont été re-transcrits sous les 3 ASR (tiny / large-v3 / large-v3-turbo, localhost:8190), puis scorés deux fois sur les mêmes hyps — ancienne primitive trigramme (origin/main) vs alignement (PR #20418), vote 2-of-3 identique des deux côtés.

    Comptes (mêmes hyps, seuls les instruments diffèrent)

    Instrument Spans Mots Segments touchés
    Trigramme (phase 1) 38 454 18 / 20
    Alignement (PR #20418) 4 50 4 / 20

    Le facteur ~10 confirme au run complet ce que le banc A0C mesurait : la primitive trigramme comptait du bruit ASR (halo de substitution/d'inflexion) comme des omissions. Le « 24 spans / 145 mots » du run phase 1 d'origine n'est pas directement comparable à ces 38/454 (hyps re-transcrites — Whisper n'est pas déterministe entre runs) ; la comparaison valide est instrument-contre-instrument sur les mêmes hyps : 38/454 → 4/50.

    Les 4 spans survivantes — toutes votées 3/3 ASR

    Seg Locuteur Mots Passage absent des 3 hyps
    76 narrateur 32 « ton doctrinaire avec l'emphase apprise dans les proclamations qu'on collait chaque jour aux murs et… »
    133 narrateur 8 « compagne qu'il réveilla d'un baiser en »
    228 narrateur 6 « des deux mains leva les yeux »
    361 narrateur 4 « était mauvais c'était »

    Artefact complet (hyps + spans par instrument) : scratchpad session rescore_phase1_results.json — archivage gisement si besoin.

    Lecture factuelle (sans conclusion sur le pivot narrateur, conformément au dispatch)

    • 16 des 18 segments flaggés par le trigramme ne portent aucune omission votée sous l'alignement — c'était du bruit d'instrument.
    • Les 4 restantes sont courtes (4-32 mots) et concentrées sur le narrateur ; la plus longue (seg 76, 32 mots, 3/3) ressemble aux drops de phrases vus sur CV3 non découpé au banc.
    • Toute conclusion sur le pivot narrateur attend ce compte — il est maintenant posé. L'arbitrage vous revient.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions