expria-frontend/src/entities/report/api.ts
Hermann_Kitio 72795e924e feat(t2-live): archi audio Voie A + Bugs 4/5/6 + indicateur de prise de parole (Sprint 6e)
- Voie A WAV : AudioContext unique au rate natif, tap AudioWorklet sur mixGain, uplink rate-aware 16k, alignement par horloge unique (fin offset/resample/concat). Anti-echo candidat. Cycle start=ws.onopen / stop=Terminer / cancel=aucun WAV.
- Bug 4 : 'Voir le rapport' route vers le rapport (navigatingAwayRef).
- Bug 5 : 'Annuler' (cancelDialogue) - arret sans evaluation, sans WAV, sans production.
- Bug 6 : 'Nouvelle simulation' route selon le type via champ tache propage (Report).
- Indicateur de prise de parole : state machine USER_SPEAKING/USER_SILENT (RMS + hysteresis).
- Cleanup : retrait instrumentation [BISECT] ; ref VAD renomme lastAiChunkTsRef.
- Removed : code mort mixTracksToInt16, resample16kTo24k + tests.
2026-06-29 14:31:38 +03:00

97 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Appels API du domaine `report`.
*
* Toutes les requêtes passent par `apiFetch` (Règle J / Règle F).
* Timeout 30 s : DeepSeek (EE) et Gemini (EO) peuvent mettre jusqu'à 20-25 s.
* Retry désactivé : POST non-idempotent — une double soumission créerait
* deux corrections facturées sur le quota Free.
*
* Erreurs notables : SIMULATION_NOT_FOUND (404), AUTH_REQUIRED (401),
* QUOTA_REACHED (403 — côté simulation, pas correction).
*/
import { apiFetch } from '@/shared/lib/api-client'
import { getSimulationState } from '@/entities/production/api'
import type { CorrectEePayload, CorrectEoPayload, Report } from './types'
/**
* Récupère un rapport existant. Endpoint : `GET /simulations/:id`.
*
* FTD-21 : depuis l'assouplissement de `getById` côté backend (tolère `rapport=null`
* pour permettre le resume), on unwrap le champ `rapport` du `SimulationState`.
* Si la simulation est encore en cours (`rapport === null`), on lève une erreur
* typée `REPORT_NOT_READY` que RapportPage catche pour rediriger vers /simulation/ee.
*/
export function getReport(id: string): Promise<Report> {
return getSimulationState(id).then((state) => {
if (state.rapport === null) {
throw {
error: true,
code: 'REPORT_NOT_READY',
message: 'Simulation en cours — rédaction pas encore corrigée.',
}
}
// Sprint 3.6b : reconstruit un Report en combinant rapport (correction) +
// exercices / modele (jobs fire-and-forget, portés par SimulationState).
return {
...state.rapport,
simulation_id: state.simulation_id,
tache: state.tache,
erreurs_codes: state.rapport.erreurs_codes as Report['erreurs_codes'],
exercices: state.exercices as Report['exercices'],
exercices_status: state.exercices_status,
modele: state.modele as Report['modele'],
modele_status: state.modele_status,
}
})
}
// Sprint 3.6a — le nouveau prompt maître (taxonomie + revelation + diagnostic +
// criteres×6 champs + conseil_nclc + erreurs_codes) produit un JSON long ;
// DeepSeek met typiquement 25-45 s pour répondre. Backend abort à 55 s.
const CORRECTION_EE_TIMEOUT_MS = 60_000
// Sprint 4b.3 — EO en mode audio enchaîne Gemini transcribe (jusqu'à 60 s,
// 30 s + 1 retry de 30 s) puis DeepSeek correction (55 s côté backend).
// Pire cas serveur ≈ 115 s : on alloue 120 s côté client pour ne pas couper
// avant que la mutation aboutisse (le rapport apparaissait sinon dans
// l'historique sans navigation vers /rapport/:id).
const CORRECTION_EO_TIMEOUT_MS = 120_000
/** Soumet une production écrite pour correction. Endpoint : `POST /corrections/ee`.
* Payload : { simulationId, contenu, tache }
*/
export function correctEe(payload: CorrectEePayload): Promise<Report> {
return apiFetch<Report>('/corrections/ee', {
method: 'POST',
body: payload,
timeoutMs: CORRECTION_EE_TIMEOUT_MS,
})
}
/**
* Soumet une production orale pour correction. Endpoint : `POST /corrections/eo`.
* Payload : { simulationId, transcript, tache } — transcript implémenté Sprint 4.
*/
export function correctEo(payload: CorrectEoPayload): Promise<Report> {
return apiFetch<Report>('/corrections/eo', {
method: 'POST',
body: payload,
timeoutMs: CORRECTION_EO_TIMEOUT_MS,
})
}
const IDEES_TIMEOUT_MS = 15_000
/**
* Récupère 5 suggestions d'idées DeepSeek pour prolonger la rédaction en cours.
* Endpoint : `POST /sujets/idees`. Tâche G5.
* Contraintes backend : sujet_consigne non vide + contenu_partiel ≥ 30 mots.
*/
export function getIdees(consigne: string, contenu: string): Promise<string[]> {
return apiFetch<{ idees: string[] }>('/sujets/idees', {
method: 'POST',
body: { sujet_consigne: consigne, contenu_partiel: contenu },
timeoutMs: IDEES_TIMEOUT_MS,
}).then((res) => res.idees)
}