expria-backend/docs/Prompt_t2live.md
2026-04-26 03:09:13 +03:00

215 lines
9.2 KiB
Markdown

# 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=<jwt>&sujet=<uuid>
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.