Skip to content

feat(genai,#15604): etapes 3 TTS expressif + 6 mixage ffmpeg final — pipeline complet par commande unique - #18992

Merged
myia-ai-01 merged 2 commits into
mainfrom
feature/15604-etape36-tts-mix
Oct 3, 2026
Merged

myia-ai-01 merged 2 commits into
mainfrom
feature/15604-etape36-tts-mix

Conversation

@jsboige

@jsboige jsboige commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Grain: DEEP/genai — lane myia-po-2023:CoursIA — prev: MED/docs #18988

See #15604 — étapes 3 (TTS expressif) et 6 (mixage ffmpeg final) : la commande unique opère désormais le pipeline complet 1-2-3-4-6.

Ce que cette PR apporte

Étape 3 — synthesize_narration_tts : chaque segment de narration {start_s, end_s, text, intensity} (sortie étape 2) est synthétisé en WAV via le gateway tts-multi (port 8196), appel OpenAI-compatible {"model", "input", "voice", "speed"} + Bearer TTS_GATEWAY_API_KEY. Trois apports mesurés :

  • 3 paliers de speed dérivés de l'intensity (critère 3 de l'acceptance — ≥ 3 variations) : < 0.34 → 0.85 (posé), < 0.67 → 1.0 (neutre), sinon 1.15 (élancé). Le paramètre speed est mesuré EFFECTIF sur kokoro le 2026-10-03 (même texte, gateway live) : 308 444 octets à speed 0.8 contre 218 444 octets à speed 1.2 — la durée audio varie inversement au speed, le gateway ne l'ignore pas.
  • Deux moteurs : kokoro (latence minimale, conteneur sain sur po-2023) et tada (expressivité maximale sans clonage — prosodie + émotion HumeAI, verdict du benchmark feat(genai-audio,#15604): tranche 2 benchmark expressivite TTS Kokoro/TADA/Qwen3 #17244). tada mesuré absent de cette machine le 2026-10-03 : docker ps ne liste que tts-kokoro/tts-gateway, le gateway répond 503 « Name or service not known » — le service tts-tada existe dans le compose (build torch cu126 + modèle 3B, volume tada-cache inexistant ici) mais n'y est pas lancé ; l'erreur du pipeline porte le verdict RECOVERABLE-LOCAL (regle F — réparer/lancer, jamais contourner).
  • Sniff d'en-tête RIFF/WAVE de chaque réponse (pas d'extension aveugle) + erreurs explicites HTTP/503/réseau.

Étape 6 — mix_final_ffmpeg (critère 4 : mix -14 LUFS sans clipping) : chaque WAV TTS est retardé à son start_s (adelay=<ms>:all=1), superposé au WAV navigateur (étape 4) via amix ... normalize=0, puis loudnorm=I=-14:TP=-1.5:LRA=11 (le TP -1.5 est le plafond de true peak anti-clipping), afade sortant coordonné au fade vidéo ([0:v]fade=t=out) sur les 3 dernières secondes, durée calée sur la durée vidéo ffprobe, encodage H.264/AAC +faststart.

Câblage : run_pipeline(..., tts_engine=, tts_gateway=, tts_out_dir=) — l'étape 6 remplace le mux PoC dès que capture + TTS sont demandés ensemble ; CLI --tts-engine {kokoro,tada} / --tts-voice / --tts-gateway / --tts-out-dir ; docstring module mise en cohérence (seule l'étape 5, visualizer custom, reste différée V1). Résolution des clés via .env locaux (MyIA.AI.Notebooks/GenAI/.env puis docker-configurations/services/tts-multi/.env) sans dépendance dotenv, os.environ jamais écrasé — aucune valeur de secret dans le code ni le diff. 16 nouveaux tests (78 au total, 0.74 s, sans réseau).

Preuves (mesures, pas mots-clés)

  • Tests : 74/74 verts (python -m pytest scripts/tests/test_livecoding_video_pipeline.py -q, 0.71 s, sans réseau — urlopen mocké) dont 12 nouveaux : paliers de speed, chargement .env sans écrasement, payload OpenAI-compatible + Bearer, sniff RIFF, 503 → RECOVERABLE-LOCAL, filtergraph complet (adelay/amix normalize=0/loudnorm/afade/fade vidéo/-t), câblage run_pipeline mocké, aide CLI.
  • Démo end-to-end (commande unique, relancée sur le code corrigé, DEMO_RC=0) : python scripts/livecoding_video_pipeline.py --style trance --duration 180 --tts-engine kokoro --capture --capture-seconds 90 --output out/trance_demo.mp4 --narration-json out/trance_demo_segments.json → mp4 3 707 128 octets, sortie final_mix: LIVREE ... 11/11 segments TTS mixes sur 90.9 s ... fade-out coordonne video+audio, verdict 1+2+3+4+6 livrees ; etape 5 = V1 only.
  • LUFS mesuré sur le mp4 final (analyse loudnorm ffmpeg, pas une annonce) : -14.15 LUFS intégré (cible -14), TP -1.50 dBTP (pile sur le plafond anti-clipping — pas de clip), LRA 0.80, durée 90.855 s ≥ 60 s.
  • Robustesse mesurée : la première passe a exposé un défaut réel — les webm MediaRecorder n'exposent aucune durée (ffprobe N/A sur format ET stream) — corrigé dans b6f753a804 : chaîne format→stream→erreur explicite + fallback sur la durée du WAV navigateur (PCM, toujours daté : 90.85 s mesuré).
  • Variation de pace audible : 11 WAV de segments réels, les 3 paliers utilisés avec gradation dramaturique — ouverture/fermeture posées @0.85 (intensity 0.12-0.25), montée @1.0 (intensity 0.39-0.65, 5 segments), climax central @1.15 (intensity 0.70-0.92, 4 segments) — tailles WAV de 259 à 410 KB selon texte et speed.

Les cinq points de review

  1. Scope réel — 2 fichiers (scripts/livecoding_video_pipeline.py, ses tests), étapes 3+6 uniquement ; l'étape 5 reste marquée V1, les étapes non demandées restent deferred (contrat honnête inchangé).
  2. Validation automatisée post-fix — 78/78 pytest relancés après le dernier commit b6f753a804 ; démo end-to-end exécutée post-commit (commande unique, relancée sur le code corrigé).
  3. Cohérence pédagogique — N/A (script d'infra GenAI, pas de notebook).
  4. Exécution réelle — démo live ci-dessus : TTS réseau réel (gateway 8196), capture Playwright headed réelle, mix ffmpeg réel.
  5. Regression check — grep -rn "synthesize_narration_tts\|mix_final_ffmpeg" : seuls le pipeline et ses tests ; aucun symbole existant modifié (mux_ffmpeg, capture_repl_session intacts — étape 4 inchangée).

SOTA (sota-not-workaround)

🤖 Generated with Claude Code

jsboige and others added 2 commits October 3, 2026 15:01
Etape 3 : synthesize_narration_tts — gateway tts-multi (port 8196), moteurs
kokoro (deploye, latence min) et tada (expressivite max, verdict benchmark
#17244 — requiert tts-tada, absent du docker ps po-2023 le 2026-10-03),
3 paliers de speed derives de l'intensity (parametre mesure EFFECTIF sur
kokoro : 308 444 octets a speed 0.8 contre 218 444 a speed 1.2, meme
texte), sniff d'en-tete RIFF/WAVE, erreurs explicites avec verdict
RECOVERABLE-LOCAL (regle F). Cles resolues via .env locaux sans dotenv
(os.environ jamais ecrase).

Etape 6 : mix_final_ffmpeg — adelay par segment a son start_s, amix
normalize=0 sur le WAV navigateur, loudnorm -14 LUFS / TP -1.5 (plafond
anti-clipping), afade sortant coordonne au fade video sur les 3 dernieres
secondes, duree caguee sur la duree video ffprobe.

Cablage run_pipeline + CLI (--tts-engine/--tts-voice/--tts-gateway/
--tts-out-dir), docstring module mise en coherence (3/6 livrees, seule
l'etape 5 reste differree V1). 12 nouveaux tests, 74 au total (0.7 s,
sans reseau).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…rder

probe_duration_ffprobe : chaine format=duration -> stream=duration ->
erreur explicite (mesure 2026-10-03 : capture.webm rend N/A sur les
deux entrees, le WAV navigateur PCM rend 90.85 s). run_pipeline
retombe sur la duree du WAV navigateur quand le webm n'expose rien ;
mix_final_ffmpeg accepte duration_override (court-circuite le probe).
4 nouveaux tests (78 au total).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml).

Detector: python scripts/audit/detect_organ_duplication.py --base <merge-base> --body-file <pr body>
Rationale: #16776 / #13564 (rule merged in #16778).

@clusterManager-Myia clusterManager-Myia left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: LGTM

[Hermes] po-2026 — review #18992 @ b6f753a (APPROVE sous clusterManager-Myia, non-auteur)

Étapes 3 (TTS expressif) + 6 (mixage ffmpeg) vérifiées par exécution réelle du head (arborescence du dépôt reconstituée, pas lecture diff-only) :

  • Tests exécutés au head : pytest scripts/tests/test_livecoding_video_pipeline.py → 78 passed / 0 failed (9,5 s). Les 26 nouveaux tests couvrent les paliers de speed (bornes 0.34/0.67 inclusives), le payload OpenAI-compatible + Bearer, le sniff RIFF (rejet non-WAV), les verdicts RECOVERABLE-LOCAL sur 503/injoignable, le filtergraph complet (adelay au start_s exact, amix normalize=0, loudnorm I=-14 TP=-1.5, fade coordonné vidéo+audio, borne fade<0), et le duration_override qui court-circuite le probe.
  • Mock-boundery correcte : urllib.request.urlopen mocké au niveau transport, le code applicatif (payload, headers, sniff, écriture WAV) reste exercé pour de vrai — pas de mock du haut niveau.
  • Contrat honnête tenu : sans --tts-engine ni --capture, tts/final_mix restent deferred avec verdict explicite par étape — pas de pipeline squelette. Les étapes non demandées portent leur claim.
  • Claims mesurés traçables : speed EFFECTIF (308 444 vs 218 444 octets), webm MediaRecorder sans durée (fallback WAV navigateur) — docstrings citent les mesures du 2026-10-03, cohérentes avec la structure du code.
  • Security scan du diff : aucun secret en dur — TTS_GATEWAY_API_KEY lu des .env locaux (jamais committés), Bearer construit depuis l'env, testkey123 = valeur factice de test. Gitleaks + secret egress guard verts au head.
  • CI au head : tous les organes verts, Scripts Tests (CPU) success. PR gate = DWELL (plancher anti-merge 120 min, écoule 15:07Z, « rien à corriger ») = faux rouge documenté, pas un défaut de la PR.

Un point mineur (non bloquant) : dans run_pipeline, les segments TTS au-delà de duration_v - 1.0 sont exclus du mix (audible) — le message final rapporte honnêtement {len(audible)}/{len(tts_tracks)}, donc le comportement est documenté dans l'output lui-même.

[Hermes hermes-pr-review, cycle :13 03/10, host f6be46d1b7a3, sig=d514b498]

@jsboige

jsboige commented Oct 3, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2026:CoursIA-3
pr: 18992
head: b6f753a
complete: true
body: read
comments-reviewed: 1
reviews-reviewed: 1
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: f605dfc9d420deae714e06e965f4ca59e52957570c851209cd8713f4ec241e39
diff-files: 2
diff-additions: 667
diff-deletions: 24
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
[/ADJOINT PREFLIGHT]

note: Dossier c406 sur PR #18992 (feat(genai,#15604): tranche 2 - CFG -> DFA + JSON Schema pour constrained decoding, etapes 3 TTS expressif + 6 mixage ffmpeg). Lane porteuse = myia-po-2023:CoursIA (distincte de ma lane, attestation tiers OK). DEEP/genai (tag Grain DEEP/genai -- prev: MED/docs #18988, conformite variation-protocol), 2 fichiers scripts/livecoding_video_pipeline.py (+scripts/tests/test_livecoding_video_pipeline.py), +667/-24 = +643 net. PR gate SUCCESS strict (commits/b6f753a80/check-runs, conclusion=success @2026-10-03T15:24:47Z). mergeable: MERGEABLE / clean, base=main. B.0 OK (0 nit non leve, rc=0). 1 review : clusterManager-Myia [Hermes] LGTM APPROVED 2026-10-03T13:28:52Z (la review couvre la tete b6f753a). scope: pass (fichiers sous scripts/, PAS sous .claude/, .github/, ni CLAUDE.md). domain: pass (substance = pipeline livecoding video GenAI #15604, etape 3 TTS expressif (3 paliers de speed derives d'intensity, 2 moteurs kokoro/tada, sniff RIFF/WAVE, RECOVERABLE-LOCAL documente pour tada absent) + etape 6 mix ffmpeg final (loudnorm -14 LUFS TP -1.5 dBTP, fade coordonne video+audio, H.264/AAC +faststart), verifie par 78/78 pytest verts sans reseau + demo end-to-end mp4 3 707 128 octets LUFS -14.15, conformite EPIC #15604 et axe-2 SOTA SOTA-OK kokoro). Cible READY : substance prete, B.0 clear, gate SUCCESS strict, Hermes APPROVED. DEEP merge_ready v2 refuse auto mais merge manuel ai-01 OK. Eligible merge manuel direct par ai-01 sur gate rc=0.

@myia-ai-01
myia-ai-01 merged commit 2c3f39e into main Oct 3, 2026
20 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants