- 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.
97 lines
3.8 KiB
TypeScript
97 lines
3.8 KiB
TypeScript
/**
|
||
* 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)
|
||
}
|