Import initial de la documentation : statut, roadmap, plans V1/V2, specs verticales (creche, sport), audits securite, plan de test, analyse concurrentielle et maquettes de design. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5.4 KiB
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 |