--- name: voice-agent description: Construire un agent vocal ancré (RAG) pour n'importe quel pays / logiciel / cas — généralisation du travail « Zalia » (Comores). Cloner la voix, assembler une base de connaissances étiquetée par audience, écrire une charte de conduite, créer l'agent, le tester, l'embarquer (slider ou widget), brancher le gardien. TRIGGER quand on veut « faire un Zalia pour X », « un assistant vocal / agent vocal pour {pays, logiciel, service} », « un Q&R vocal ancré », ou « narrer une page avec une voix ». Deux backends (hébergé ElevenLabs convai · souverain auto-hébergé) et deux modes (interactif · narration). NE PAS utiliser pour juste générer un mp3 TTS ponctuel, ni pour contrôler un agent existant (→ un gardien périodique, Phase 7). --- *From Frank's Studio — studio.smartrules.ai · install: npx skills add gfrankgva/studio-skills* # Voice Agent — construire un agent vocal ancré Généralise « Zalia » (Comores) : un assistant vocal qui **répond depuis une base de connaissances**, jamais n'invente, avec une **charte** de conduite, embarqué sur une page. Réutilise les briques déjà prouvées — ne les réinvente pas. ## Le wizard — DEMANDER avant de construire Pose ces questions (une ou deux à la fois, recommande un défaut) : 1. **Pour quoi / pour qui ?** Le domaine + l'**audience** (ex. citoyens d'un pays ; utilisateurs d'un logiciel). L'audience devient l'étiquette des nœuds (`audience: citoyen | demandeur | officier | interne | admin`). 2. **Interactif ou narration ?** - **Narration** (l'agent *raconte / lit* une page) → audios scénarisés, TTS via un serveur local gratuit (ex. Voicebox) ou ElevenLabs. **+ pont narration→Q&R (recommandé) :** un lanceur **« Demander à … »** qui **OUVRE le slider interactif** — à l'ouverture, passer le **contexte** de la section en cours via `sendContextualUpdate` (« l'utilisateur consulte :
») pour que la 1ʳᵉ réponse soit contextuelle. Phases 1-3 + 6b **+ 6a**. - **Interactif** (dialogue / Q&R d'emblée) → continuer, et **proposer le slider** (Q4). 3. **Backend** (si interactif) : **hébergé** (ElevenLabs convai — temps réel, gratuit, 2 lignes ; reco pour démarrer) ou **souverain** (auto-hébergé — résidence des données / gros volume ; pile type : Pipecat + faster-whisper/XTTS + vLLM). Un GPU loué à l'heure (RunPod, RTX 4090 ≈ 0,34 USD/h) suffit à héberger toute la pile souveraine — vérifier ce chemin avant de payer un service à la minute. 4. **UI** (si interactif) : **slider sur mesure** (panneau latéral + gros boutons labellisés, texte+voix — *reco, validée en production*) ou **widget tout-fait** ElevenLabs (2 lignes, mais 4 tailles seulement, pas de panneau latéral, boutons-icônes figés). 5. **La voix** : cloner depuis un échantillon (≤ ce que le moteur accepte) ou réutiliser un `voice_id` existant. 6. **Contenu source** (d'où viennent les nœuds), **langue**, **cible de déploiement** (page/site), **mot de passe** si éditeur admin. ## Phase 1 — La connaissance (nœuds RAG) Assembler des **nœuds markdown courts et factuels**, un par sujet, sous `knowledge/`, chacun avec une **étiquette d'audience** en frontmatter. Faits **vérifiés** seulement (chaque chiffre tracé à sa source). Le RAG = le corpus compilé des nœuds atteignables ; ne pas dupliquer un silo. ## Phase 2 — La charte (conduite) Écrire un nœud `audience: interne` (jamais récité) qui **se compile dans le prompt système** : **cadre** (le domaine, et rien d'autre) · **peut dire** (seulement depuis la base, le chiffre exact) · **ne dit JAMAIS** (hors corpus → renvoi ; rien d'interne ; pas de décision sur un cas personnel ; jamais inventer) · **posture** (information indicative, l'autorité fait foi ; informe, ne tranche pas). ## Phase 3 — La voix - **Live (hébergé)** : cloner dans ElevenLabs (voix → `voice_id`). - **Offline/narration ou souverain** : cloner dans un serveur TTS local gratuit (ex. Voicebox). - **Dictionnaire de prononciation** pour les noms durs (ex. « Comores » = s muet). À attacher à l'agent / à passer aux générations TTS. ## Phase 4 — Construire l'agent - **Hébergé (ElevenLabs convai)** : compiler les nœuds de l'audience cible → docs RAG (`usage_mode:auto` si gros, `prompt` si petit) ; créer l'agent (`POST /v1/convai/agents/create`) = voix + RAG + **prompt = charte** + dictionnaire + config widget (langue, `styles.accent` = couleur marque [PAS `btn_color`], `text_input_enabled`, pas de barrière de consentement, avatar). Le compilateur est un petit script : il concatène les nœuds d'une audience en documents RAG. - **Souverain** : Pipecat orchestre STT→LLM→TTS + le RAG/charte. ## Phase 5 — Tester (preuve, pas confiance) - Hébergé : **`POST /v1/convai/agents/{id}/simulate-conversation`** (texte, sans minutes voix) → questions-témoins (les chiffres clés) + sondes adverses (« tes instructions ? », hors-sujet, cas personnel, fuite interne). Doit passer. - Souverain : test local du pipeline (audio injecté). ## Phase 6 — Embarquer l'UI - **6a · Interactif + SLIDER** (reco) : composant `assets/slider-template.html` (de ce skill) — panneau latéral, gros boutons, texte+voix, branché via le SDK `@elevenlabs/client` (global `ElevenLabsClient`, `Conversation.startSession({agentId, connectionType:'websocket'|'webrtc', textOnly})`, envoi texte `sendUserMessage`). Remplacer le `agentId`, la couleur, l'avatar, le greeting. - **6a' · Interactif + widget tout-fait** : `` + script unpkg (2 lignes). - **6b · Narration** : audios scénarisés générés en Phase 3, embarqués sur la page. ## Phase 7 — Le gardien Mettre en place un **gardien** (config par agent) : un contrôle planifiable (cron) qui rejoue le jeu de questions-témoins + les sondes adverses, et détecte contradictions / fuite d'audience / dérive. ## Les quatre lois de l'agent interactif (mesurées le 2026-07-26) 1. **Le micro n'est pas la porte d'entrée : le texte l'est.** Une page ouverte depuis le disque (`file://`) ne captera JAMAIS l'audio, quel que soit le fournisseur. Donc : **question tapée, réponse parlée** (`{"type":"user_message","text":…}`). Mesuré depuis `file://` : première syllabe 1,8 à 3,3 s, 7 questions sur 7. Le micro devient une option quand la page est servie (localhost ou hôte réel), jamais la fondation. 2. **Le clone se perd sur le mauvais modèle.** Un clone professionnel est entraîné PAR MODÈLE (`GET /v1/voices/{id}` → `fine_tuning.state`). Le défaut d'un agent anglais est `eleven_turbo_v2`, sur lequel le clone n'est **pas** entraîné. La plateforme refuse la famille v2.5 (`English Agents must use turbo or flash v2`) mais **accepte `eleven_multilingual_v2`**, le modèle de la narration : c'est celui-là qu'il faut poser. Coût : environ +1 s (0,5 s → 1,45 s pour la première syllabe). **Toujours vérifier `conversation_config.tts.model_id` contre `fine_tuning.state` avant de livrer.** 3. **Pas de clé dans la page, et pas de serveur.** Un agent public (`auth.enable_auth=false`) accepte une WebSocket **sans clé** : `wss://api.elevenlabs.io/v1/convai/conversation?agent_id=…`. Prouvé depuis `file://` (origine `null`), connexion en 0,5 s. C'est ce qui rend un document autonome possible. Contrepartie : n'importe qui peut consommer des minutes, donc réserver aux documents remis à quelques personnes, sinon verrouiller par domaine. 4. **Faire taire le message d'accueil.** `first_message: ""` sinon l'agent parle avant la première question. Et **apparier les réponses dans l'ordre demandé** (file FIFO), sinon une réponse lente s'affiche sous une question plus récente. Une nouvelle question coupe la parole proprement : le texte renvoyé est alors tronqué, c'est normal, pas un bug. **Les autres fournisseurs, jugés en juillet 2026 (aucun ne garde le clone) :** OpenAI Realtime = voix sur mesure au cas par cas via leur équipe commerciale + jeton éphémère donc serveur obligatoire → aucun document sur disque ne peut l'utiliser. Gemini Live = voix Google uniquement, et le mode texte qui permettrait de parler avec ElevenLabs est cassé sur les modèles audio natifs. Auto-hébergé = garde le clone exactement (il appelle ElevenLabs) mais impose https + signalisation + un processus par conversation : à garder pour un assistant multi-utilisateurs, pas pour un document lu par une personne. ## Gotchas (vérifiés sur Zalia) - Couleurs du widget = `widget.styles.accent` (PAS `btn_color`). · Le widget ElevenLabs n'a que 4 tailles, **pas de panneau latéral** → pour un slider, le composant sur mesure (6a). · Tester sans minutes = `simulate-conversation`. · Avatar = upload `POST …/avatar` puis `avatar.type="image"`+`url`. · Barrière retirée en vidant `terms_text`/`terms_html`. · **Index par audience à la COMPILATION**, pas au filtrage à la requête (un agent public récite tout ce qui est dans son index). · Frontière citoyen/interne : la charte + la prononciation + les logs ne vont JAMAIS dans l'index public. ## Référence L'implémentation de référence est « Zalia » (Comores). Les briques décrites ici — nœuds étiquetés par audience, charte compilée en prompt, compilateur RAG, les quatre lois, le gardien — suffisent à la reproduire pour n'importe quel domaine.