fix(geminiLive): T2 prompt durci + VAD réintégré, retrait SDK @google/genai

- Bug 1: prompt système T2 durci (13 règles absolues, interdiction du "?",
  rôle inerte) pour stopper la relance systématique. Réf TD-22.
- Bug 2: realtimeInputConfig (VAD automaticActivityDetection, 4 champs)
  réintégré dans le setup frame Gemini.
- Bug 8: @google/genai retiré + test-gemini-live.js supprimé (SDK abandonné
  au profit du WebSocket brut).

Tests 292/292 verts. Validé Golden Dataset Groupe D.
This commit is contained in:
Hermann_Kitio 2026-06-28 11:49:37 +03:00
parent eee75b53ca
commit 94387a71db
5 changed files with 39 additions and 588 deletions

View file

@ -1,11 +1,11 @@
/**
* geminiLive.ts Sprint 6d (revert WS brut).
*
* Le SDK `@google/genai` fermait la session sans setupComplete ni raison
* exploitable. On revient au WebSocket brut (package `ws`) qui était utilisé
* par `test-gemini-live.js` et permet de loguer précisément ce que Gemini
* répond. Config setup réduite au strict minimum tant que `setupComplete`
* n'est pas confirmé en prod ; on réintègre champs un par un ensuite.
* Historiquement, le proxy s'appuyait sur un SDK Gemini de haut niveau, mais
* celui-ci fermait la session sans setupComplete ni raison exploitable. On
* utilise désormais le WebSocket brut (package `ws`), qui permet de loguer
* précisément ce que Gemini répond et de maîtriser le contenu exact du setup
* frame (model, systemInstruction, transcriptions, VAD).
*
* Interface publique (consommée par `routes/t2live.ts`) INCHANGÉE :
* - openGeminiLiveSession(clientWs, opts)
@ -22,7 +22,7 @@ export const GEMINI_LIVE_URL =
/**
* Modèle Live cible. `gemini-2.0-flash-live-001` est le modèle Live confirmé
* par la doc Google pour les clés API Developer + Express. Format `models/...`
* dans le setup frame natif (cf. `test-gemini-live.js`).
* requis dans le setup frame natif.
*/
export const GEMINI_LIVE_MODEL = "gemini-3.1-flash-live-preview";
@ -41,22 +41,23 @@ export function buildT2SystemPrompt(input: {
contexte: string;
}): string {
const { role, contexte } = input;
return `Tu es un examinateur du TCF Canada pour l'épreuve d'Expression Orale, Tâche 2 (dialogue interactif).
RÔLE : Tu incarnes ${role}.
return `RÔLE : Tu incarnes ${role}.
CONTEXTE : ${contexte}
RÈGLES ABSOLUES :
1. Tu parles TOUJOURS en français naturel et courant, niveau B2-C1.
2. Tu NE corriges JAMAIS les erreurs du candidat.
2. Tu NE corriges JAMAIS les erreurs du candidat. Tu continues naturellement.
3. Tu attends que le candidat finisse sa question avant de répondre.
4. Tes réponses sont courtes (15 à 25 mots maximum). Pas de monologue.
4. Tes réponses sont courtes (15 à 25 mots maximum) pour laisser la place au dialogue.
5. Ne donne pas toutes les informations d'un coup. Force le candidat à poser des questions précises.
6. Si le candidat est vague, réponds brièvement sans chercher à compléter.
7. Ne pose JAMAIS de question après tes réponses. Tu réponds et tu te tais. La seule exception : si le candidat marque un long silence et semble avoir terminé, tu peux dire une seule fois « Si vous n'avez plus de questions, je vous souhaite une bonne journée » ou équivalent pour clore naturellement.
8. Ne prends jamais d'initiative pour orienter la conversation.
9. Tu peux être légèrement pressé ou hésitant pour rendre l'échange réaliste.
10. JAMAIS de listes ni de structure numérotée dans tes réponses.
11. Ne mentionne jamais que tu es une IA ou un modèle.
12. Tu ne prends PAS la parole en premier. Tu attends que le candidat s'adresse à toi.`;
6. Si le candidat est vague, réponds brièvement sans chercher à compléter c'est à lui de reformuler.
7. STRICTE INTERDICTION DE POSER DES QUESTIONS. Tu n'as pas le droit d'utiliser de point d'interrogation. Tes phrases se terminent par un point.
8. SILENCE TOTAL APRÈS LA RÉPONSE. Réponds de manière factuelle, puis arrête-toi immédiatement. Ne suggère rien, ne relance pas, ne dis pas "et vous ?".
9. RÔLE PASSIF : tu es une source d'information inerte. Tu n'aides pas le candidat à tenir la conversation. S'il ne parle plus, le silence s'installe.
10. AUCUNE FORMULE DE POLITESSE DE FIN : bannis "n'hésitez pas", "j'espère que ça vous aide", "qu'en pensez-vous ?".
11. JAMAIS de listes ni de structure numérotée parle naturellement.
12. Ne mentionne jamais que tu es une IA ou un modèle.
13. Tu ne prends PAS la parole en premier. Tu attends que le candidat s'adresse à toi.`;
}
/**
@ -212,11 +213,10 @@ function tryParseGeminiJson(data: unknown): GeminiServerMessage | null {
}
/**
* Construit le setup frame minimal Gemini Live (équivalent du mode
* `minimal` de `test-gemini-live.js`). Les champs `systemInstruction`,
* `inputAudioTranscription`, `outputAudioTranscription`,
* `realtimeInputConfig.automaticActivityDetection` sont volontairement
* retirés tant que `setupComplete` n'est pas confirmé en prod.
* Construit le setup frame Gemini Live : model + responseModalities AUDIO,
* systemInstruction (prompt T2), input/outputAudioTranscription, et
* realtimeInputConfig.automaticActivityDetection (VAD : START/END_SENSITIVITY_LOW,
* 2 s de silence avant que l'IA réponde cf. IMPLEMENTATION_T2_LIVE.md §3).
*/
function buildSetupFrame(systemPrompt: string): string {
return JSON.stringify({
@ -230,6 +230,14 @@ function buildSetupFrame(systemPrompt: string): string {
},
inputAudioTranscription: {},
outputAudioTranscription: {},
realtimeInputConfig: {
automaticActivityDetection: {
disabled: false,
startOfSpeechSensitivity: "START_SENSITIVITY_LOW",
endOfSpeechSensitivity: "END_SENSITIVITY_LOW",
silenceDurationMs: 2000,
},
},
},
});
}