# Prompt_t2live.md — Expria Backend # Spécification du prompt système T2 EO Live > **Document de référence — Sprint 6** > À lire conjointement avec PARCOURS_UTILISATEURS.md et PLANS_TARIFAIRES.md. > Ce document doit être commité dans `expria-backend/docs/` avant le démarrage du Sprint 6. --- ## 1. Contexte pédagogique La Tâche 2 de l'Expression Orale TCF Canada est une **interaction de service** : le candidat joue le rôle d'une personne dans une situation concrète du quotidien qui a besoin d'informations pour prendre une décision. Il pose des questions à un interlocuteur (joué par l'IA) qui détient ces informations. **Ce que cette tâche évalue :** - La capacité à initier et maintenir une conversation en français - La formulation de questions claires et adaptées au registre - Le lexique lié à la vie quotidienne - La morphosyntaxe en situation d'interaction orale - La phonologie (évaluée sur l'audio) **Ce que cette tâche n'est pas :** - Un débat d'opinions - Un exposé monologique - Un jeu de questions-réponses guidé par l'examinateur --- ## 2. Rôle de l'IA L'IA joue le rôle de l'interlocuteur de la situation décrite dans le sujet (ex : un bailleur, un employeur, un vendeur, un agent de voyage, etc.). **Règles absolues du comportement de l'IA :** 1. **Répondre uniquement en français** — quelle que soit la langue utilisée par le candidat. 2. **Ne pas faciliter la tâche** — ne pas reformuler les questions du candidat, ne pas anticiper ce qu'il veut savoir, ne pas lui souffler les mots. 3. **Répondre aux questions posées** — réponses naturelles, réalistes, ni trop courtes (monosyllabiques) ni trop longues (monologues). 4. **Ne pas relancer au-delà de** : *"Avez-vous d'autres questions ?"* si le candidat marque une pause prolongée ou semble avoir terminé. 5. **Ne pas évaluer le candidat** pendant la conversation — aucun commentaire sur sa langue, ses erreurs, ou sa performance. 6. **Ne pas sortir du rôle** — même si le candidat pose des questions hors sujet ou tente de changer de registre. 7. **Attendre que le candidat prenne la parole** — c'est le candidat qui initie la conversation, comme à l'examen réel. L'IA ne parle pas en premier. Elle attend en silence et répond dès que le candidat s'adresse à elle. --- ## 3. Prompt système (à injecter dans `geminiLive.ts`) ``` Tu joues le rôle de {role} dans la situation suivante : {contexte} Règles à respecter impérativement : - Tu réponds uniquement en français, quelle que soit la langue de ton interlocuteur. - Tu joues ton rôle de façon naturelle et réaliste. Tu n'es pas un examinateur — tu es {role}. - Tu réponds aux questions qu'on te pose de façon honnête et naturelle, comme le ferait une vraie personne dans cette situation. - Tu ne facilites pas la tâche : tu ne reformules pas les questions, tu n'anticipes pas ce que l'interlocuteur veut savoir, tu ne lui suggères pas quoi demander. - Si ton interlocuteur marque une longue pause ou semble avoir terminé, tu peux dire : "Avez-vous d'autres questions ?" — c'est la seule relance autorisée. - Tu ne fais aucun commentaire sur la langue, les erreurs ou le niveau de français de ton interlocuteur. - Tu ne sors jamais de ton rôle. - Tu ne prends PAS la parole en premier. Tu attends que ton interlocuteur s'adresse à toi, puis tu réponds naturellement dans ton rôle. - Tes réponses sont concises et naturelles : ni monosyllabiques, ni des monologues. ``` **Variables à substituer dynamiquement depuis le sujet :** - `{role}` — ex : "un bailleur qui loue un appartement" - `{contexte}` — la consigne + contexte du sujet issu de la table `sujets` --- ## 4. Format du sujet T2 en base Les sujets T2 sont stockés dans la table `sujets` avec les champs : - `consigne` — la situation décrite au candidat (ce qu'il doit faire) - `contexte` — les informations de cadrage (lieu, situation, interlocuteur) - `tache` — valeur `'EO_T2'` - `mode` — valeur `'entrainement'` **Exemple de sujet :** ``` consigne : "Vous avez vu une annonce pour un appartement à louer. Appelez le bailleur pour obtenir les informations nécessaires avant de prendre votre décision." contexte : "Vous cherchez un appartement de 2 pièces dans le centre-ville, votre budget est limité et vous souhaitez emménager le mois prochain." role : "un bailleur qui propose un appartement à louer" ``` > **Note :** Le champ `role` existe dans la table `sujets` et a été > alimenté pour les 9 sujets EO T2 (session 2026-04-26, script SQL > `update_sujets_t2.sql`). --- ## 5. Structure du rapport T2 Le rapport T2 suit **exactement la même structure** que les rapports EO T1 et T3 : 4 critères officiels TCF Canada : | Critère | Pondération | |---|---| | Cohérence et cohésion | 25 % | | Étendue et maîtrise du lexique | 25 % | | Maîtrise morphosyntaxique | 25 % | | Phonologie | 25 % | **Conséquence :** l'évaluation finale peut réutiliser le prompt de correction EO existant (`POST /corrections/eo`) en passant le transcript de la session comme entrée, avec `tache: 'EO_T2'`. > **Rappel TD-08 (backend) :** la phonologie est temporairement fixée à 0 > pour les tâches EO live car l'évaluation nécessite l'audio brut. > Applicable à T2 également — à résoudre post-MVP. --- ## 6. Flux technique complet Sprint 6 ``` 1. Candidat choisit un sujet T2 dans la liste → clic → page préparation 2. Page préparation : consigne affichée + bouton "Démarrer le dialogue" 3. Frontend ouvre WS : wss://api.expria.app/t2/live?token=&sujet= 4. Backend vérifie JWT + plan oral_t2_live (Premium) 5. Backend lit le sujet depuis Supabase (id sujet passé en query param) 6. Backend ouvre WS vers Gemini Live API avec prompt système construit dynamiquement depuis {role} + {contexte} du sujet 7. Backend → Gemini : setup frame (modèle + prompt + responseModalities: AUDIO + VAD : endOfSpeechSensitivity LOW, silenceDurationMs 2000) 8. L'IA attend en silence — c'est le CANDIDAT qui prend la parole en premier (conforme à l'examen réel TCF Canada) 9. Frontend → Backend → Gemini : audio candidat (PCM 16kHz base64) en continu + accumulation dans le buffer d'enregistrement chronologique (rééchantillonné 24kHz) 10. Gemini → Backend → Frontend : réponses audio (PCM 24kHz base64) en continu + accumulation dans le buffer d'enregistrement 11. Candidat clique "Terminer" → Frontend envoie signal de fin 12. Backend ferme WS Gemini, récupère transcript complet (inputTranscription + outputTranscription accumulés pendant la session) 13. Backend POST /corrections/eo avec transcript + tache='EO_T2' → rapport généré (même pipeline que T1/T3) 14. Backend sauvegarde production en base (tache='EO_T2_LIVE') 15. Backend envoie rapport au Frontend via WS (close code 1000 + payload rapport) 16. Frontend → state machine 'ended' → affichage rapport 17. Frontend propose bouton "Télécharger l'audio" (WAV mono 24kHz assemblé depuis le buffer chronologique) ``` --- ## 7. Spécifications audio | Direction | Format | Sample rate | Encoding | |---|---|---|---| | Frontend → Gemini | PCM brut | 16kHz | 16 bits, little-endian, mono | | Gemini → Frontend | PCM brut | 24kHz | 16 bits, little-endian, mono | **MIME type à envoyer à Gemini :** `audio/pcm;rate=16000` **Côté frontend :** - Capture via `AudioContext` + `AudioWorklet` (ou `ScriptProcessorNode` provisoire) - Rééchantillonnage obligatoire : le navigateur capture à 44.1kHz ou 48kHz → downsampler à 16kHz - Conversion Float32 → Int16 PCM avant envoi - Lecture de l'audio reçu : `AudioContext` à 24kHz + `AudioBufferSourceNode` par chunk --- ## 8. Gestion des erreurs WebSocket | Close code | Cause | Action frontend | |---|---|---| | 1000 | Fin normale + rapport prêt | State → 'ended', afficher rapport | | 4001 | AUTH_REQUIRED | State → 'error', redirect /login | | 4003 | PLAN_INSUFFICIENT | State → 'error', PaywallModal Premium | | 4004 | SUJET_NOT_FOUND | State → 'error', retour liste sujets | | Autre | Erreur réseau / Gemini | State → 'error', bouton "Réessayer" | --- ## 9. Questions ouvertes à trancher au Sprint 6 | # | Question | Impact | |---|---|---| | Q1 | Le champ `role` existe-t-il dans la table `sujets` ou faut-il le dériver du `contexte` ? | Migration SQL ou prompt engineering | | Q2 | L'id du sujet est-il passé en query param WS (`?token=jwt&sujet=uuid`) ou via le premier message WS ? | Protocole de connexion | | Q3 | Le transcript est-il accumulé côté backend pendant la session ou demandé à Gemini en fin de session ? | Architecture geminiLive.ts | --- ## 10. Ce qui existe déjà (à ne pas recoder) - `src/routes/t2live.ts` — 101 lignes, route WS + auth + gating ✅ - `src/lib/geminiLive.ts` — 154 lignes, proxy bidirectionnel + setup frame ✅ - Pipeline correction EO (`POST /corrections/eo`) — réutilisable pour évaluation finale ✅ - Modèle `gemini-live-2.5-flash-native-audio` — accès confirmé ✅ **À modifier :** - `src/lib/geminiLive.ts` — remplacer le prompt agent immobilier par le prompt dynamique §3, brancher la récupération du sujet depuis Supabase, accumuler le transcript, déclencher l'évaluation finale.