6.7 KiB
⛔ ABANDONNÉ — 2026-09-02
Ce plan n'est pas réalisable en l'état, et sa fonction est reprise ailleurs.
Pourquoi. Le lipsync décrit ici repose sur les word timestamps de Google Cloud TTS (
enable_time_pointing, voir plus bas). Or le code livré tourne sur Gemini TTS (GeminiTtsEngine,gemini-2.5-flash-preview-tts, voix Sulafat / Umbriel) : il n'existe aucune source de timestamps. Le plan n'est pas « à faire », il est sans fondation.Ce qui le remplace. Le portrait canon d'un
Persona(voir studio-plan.md §3.8) donne déjà un visage à afficher à côté du lecteur audio — l'essentiel de la valeur perçue, pour zéro travail supplémentaire. Si du mouvement est voulu plus tard, une boucle vidéo de 6–8 s (Kling 3.0 / Veo 3.1, lot 10 du plan Studio) est un meilleur produit qu'un lipsync 3 frames.Ce qui reste vrai et a été récupéré dans
studio-plan.md: générer des vues d'un même personnage en réinjectant la première en référence. C'est exactement le mécanisme du canon en jeu de vues dePersona— ce plan l'avait trouvé avant, sur un cas particulier.Conservé pour l'historique de décision. Ne pas implémenter.
Avatar Parlant (Talking Head) — Plan d'intégration
Contexte : Delta technique #6 issu de
myinfomate-ai-persona-analysis.md. Feature V2 — app mobile et borne uniquement. Hors scope smart glasses (pas d'écran).
Concept
Portrait 2D animé par lipsync synchronisé au TTS pré-généré ou dynamique. 3 frames PNG par persona, animées côté Flutter selon les timestamps retournés par Google Cloud TTS.
Assets par persona
| Frame | État bouche | Usage |
|---|---|---|
frame_0.png |
Fermée | Idle, fin de phrase, consonnes labiales (M, B, P) |
frame_1.png |
Mi-ouverte | Consonnes courantes, transition |
frame_2.png |
Ouverte | Voyelles (A, E, I, O, U) |
Modèle de génération — À tester
Deux candidats dans l'écosystème Google (même billing GCP que Gemini et Cloud TTS) :
| Modèle | Prix/image | 3 frames | Notes |
|---|---|---|---|
| Gemini 2.5 Flash Image | $0.039 | ~$0.12 | Bon rapport qualité/prix |
| Gemini 3 Pro Image | $0.134 | ~$0.40 | Meilleure qualité, meilleure consistance de style |
Test à faire : générer les 3 frames d'un même personnage avec chaque modèle et comparer la cohérence de style entre les frames (critère numéro 1 pour un lipsync crédible). Si Gemini 3 Pro est significativement plus consistant, le surcoût de $0.28 par persona est négligeable.
Par défaut dans le code : Gemini 2.5 Flash Image, configurable via constante pour switcher facilement.
Prompts de génération
Trois appels séquentiels — les prompts 2 et 3 doivent envoyer l'image de référence (frame 0) pour garantir la cohérence visuelle.
Prompt 1 — Base (bouche fermée)
2D cartoon illustration of a friendly [description du persona],
warm smile, mouth closed, facing slightly to the right,
bust portrait, clean white background, consistent art style,
flat colors, soft shading. Reference sheet style.
Prompt 2 — Mi-ouverte (+ image de référence)
Same character as the reference image, exact same art style,
same colors, same angle, same lighting,
mouth slightly open as if mid-speech.
Prompt 3 — Ouverte (+ image de référence)
Same character as the reference image, exact same art style,
same colors, same angle, same lighting,
mouth open as if speaking a vowel sound.
Coût
- Gemini 2.5 Flash : ~$0.12 par persona (one-shot)
- Gemini 3 Pro : ~$0.40 par persona (one-shot)
Stockage Firebase
{instanceId}/personas/{wakewordId}/frame_0.png ← bouche fermée
{instanceId}/personas/{wakewordId}/frame_1.png ← mi-ouverte
{instanceId}/personas/{wakewordId}/frame_2.png ← ouverte
Les URLs sont stockées dans la config du persona (aux côtés de VoiceName et PersonaPrompt).
UX dans le CMS (manager-app)
Dans la page "Configuration du guide IA", section par persona :
- Champ
PersonaPrompt(description du personnage : "chevalier médiéval jovial") - Bouton "Générer l'avatar" → appel backend → DALL-E 3 × 3 → upload Firebase → prévisualisation des 3 frames
- Possibilité de re-générer (coût ~$0.12 à chaque fois, à afficher clairement)
- Prévisualisation : animation en loop des 3 frames dans le CMS pour validation
Lipsync Flutter
Mode simple — loop (V2 MVP)
// Pendant la lecture audio : boucle les 3 frames
Timer.periodic(Duration(milliseconds: 90), (timer) {
if (!isPlaying) { setState(() => currentFrame = 0); timer.cancel(); return; }
setState(() => currentFrame = (currentFrame + 1) % 3);
});
~30 lignes, zéro dépendance. Suffisant pour une première version convaincante.
Mode avancé — word timestamps (V2+)
Google Cloud TTS avec enable_time_pointing: SSML_MARK (ou WORD) retourne des timestamps par mot.
Mapping côté Flutter :
String getFirstSignificantChar(String word) => word.toUpperCase().trimLeft()[0];
int frameForWord(String word) {
final c = getFirstSignificantChar(word);
if ('MBP'.contains(c)) return 0; // bouche fermée
if ('AEIOU'.contains(c)) return 2; // bouche ouverte
return 1; // mi-ouverte
}
À chaque timestamp : setState(() => currentFrame = frameForWord(word)).
Note :
enable_time_pointingretourne des timestamps au niveau du mot, pas du phonème. Le mapping par première lettre est une approximation raisonnable — suffisant visuellement à la vitesse de lecture normale.
Intégration avec le TTS pré-généré
Pour le contenu pré-généré (articles, POIs), les timestamps sont générés en même temps que le MP3 et stockés à côté :
{instanceId}/tts/article/{sectionId}/{wakewordId}/{lang}.mp3
{instanceId}/tts/article/{sectionId}/{wakewordId}/{lang}.json ← timestamps
Le JSON contient la liste [{word, startTime, endTime}] — Flutter le charge une fois et l'utilise pour l'animation.
Pour les questions libres (TTS dynamique), les timestamps sont retournés en même temps que l'audio dans la réponse de l'endpoint /ask.
Dépendances avec les autres deltas
| Delta | Lien |
|---|---|
| #2 — Persona config | PersonaConfig stocke les URLs des 3 frames + le PersonaPrompt utilisé pour DALL-E |
| #4 — TTS pré-généré | Génère le MP3 + timestamps en même temps ; même job Hangfire |
#3 — Endpoint /ask |
Retourne audio + timestamps pour questions libres |
| #5 — Canal Flutter | Intègre le widget Talking Head ; smart glasses = hors scope |