215 lines
9.2 KiB
Markdown
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.
|
|
|