Commit 29bcba0a authored by Kourser's avatar Kourser
Browse files

Trente minutes par piste, écrites en dur, pour un rapport qui varie de vingt

Le délai au bout duquel on renonce à transcrire une piste était une constante.
Il faut un délai — sans lui, un moteur bloqué laisserait l'enregistrement « en
cours de transcription » pour toujours — mais aucune valeur écrite en dur ne
peut être juste : le bon délai dépend du modèle retenu et de la machine, deux
choses que l'éditeur ne connaît pas.

Mesuré sur le même extrait, sur un poste sans carte graphique :

  whisper-large-v2 (français)   12,7 s de parole → 27 s
  faster-whisper-tiny           12,7 s de parole → 1,2 s

Vingt fois. Et une piste dure toute la réunion, silences compris — elle porte
une personne, qui se tait pendant que les autres parlent. Le silence n'est pas
gratuit : le même extrait suivi de 120 s de silence prend 101 s au lieu de 27.
C'est donc la durée de la réunion qui compte, pas le temps de parole, et la
piste de qui n'a rien dit coûte presque autant que celle qui a mené le débat.

Avec le modèle français et trente minutes, une réunion de crise de trois
heures voyait chacune de ses pistes coupée sur un délai dépassé. Pas un défaut
intermittent : jamais transcrite.

TRANSCRIPTION_DELAI_MINUTES, en minutes parce que c'est dans cette unité qu'on
raisonne en le réglant. Éprouvé en marche et non par lecture : un moteur lent
contre un délai court rend la main, le même contre un délai large aboutit — un
contrôle qui lirait la variable dirait qu'elle existe, jamais qu'elle sert.

Le message d'échec disait « en 0 minutes » sous la minute. C'est un message
qu'on lit en cherchant une panne : il donne maintenant minutes, secondes ou
millisecondes selon ce qu'on a réellement attendu.

Co-Authored-By: default avatarClaude Opus 5 <noreply@anthropic.com>
parent 92076ab0
Loading
Loading
Loading
Loading
Loading
+28 −0
Changes for .env.example: 28 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -243,6 +243,34 @@ TRANSCRIPTION_MODEL=Systran/faster-whisper-small
# EN   only reachable from the composition's network.
TRANSCRIPTION_KEY=

# Combien de minutes on laisse au moteur pour rendre UNE piste — une piste par
# personne présente, transcrites l'une après l'autre.
#
# Une piste dure toute la réunion, silences compris : elle porte une personne,
# qui se tait pendant que les autres parlent. Et le silence n'est pas gratuit —
# mesuré sur un poste sans carte graphique, avec whisper-large-v2 :
#
#   12,7 s de parole                        → 27 s   (~2 × le temps réel)
#   12,7 s de parole + 120 s de silence     → 101 s  (~0,6 × pour le silence)
#
# Autrement dit, comptez la DURÉE DE LA RÉUNION, pas le temps de parole : une
# piste de trois heures demande deux à trois heures de calcul à ce modèle,
# quelle que soit la part qu'on y a prise.
#
# Le modèle change tout : faster-whisper-tiny transcrit le même extrait en
# 1,2 s — vingt fois plus vite, contre un texte juste mais sans ponctuation
# soignée.
#
# Réglez-le sur la durée de la plus longue réunion attendue, multipliée par le
# rapport que vous mesurez chez vous, et voyez large : trop court, la
# transcription échoue sur un délai dépassé et vous perdez le texte ; trop
# long, une piste qui ne rendra jamais rien occupe la file d'autant.
#
# EN — How many minutes the engine gets for ONE track — one per person
# EN   present, transcribed one after another. Set it to the longest meeting
# EN   you expect, times the ratio you measure on your own machine.
TRANSCRIPTION_DELAI_MINUTES=30

CLAMAV_HOST=clamav
CLAMAV_PORT=3310

+7 −1
Changes for apps/api/src/adaptateurs/transcription.ts: 7 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -105,9 +105,15 @@ export function transcriptionOpenAI(c: ConfigurationTranscription): Transcriptio
      } catch (e) {
        // Le moteur peut être long à charger son modèle au premier appel : on
        // dit lequel des deux a lâché, parce qu'on ne les répare pas pareil.
        // En minutes au-dessus d'une minute, en secondes en dessous : arrondir
        // sans regarder rendait « en 0 minutes », qui ne dit rien à celui qui
        // cherche à savoir combien de temps on a attendu.
        const attendu = delai >= 60_000 ? `${Math.round(delai / 60_000)} min`
          : delai >= 1_000 ? `${Math.round(delai / 1000)} s`
            : `${delai} ms`;
        throw new TranscriptionIndisponible(
          abandon.aborted
            ? `Le moteur n'a pas répondu en ${Math.round(delai / 60_000)} minutes.`
            ? `Le moteur n'a pas répondu en ${attendu}.`
            : `Moteur de transcription injoignable : ${
              e instanceof Error ? e.message : String(e)}`,
        );
+15 −0
Changes for apps/api/src/env.ts: 15 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -90,6 +90,21 @@ const schema = z.object({
  TRANSCRIPTION_URL: z.string().optional(),
  TRANSCRIPTION_MODEL: z.string().default("whisper-1"),
  TRANSCRIPTION_KEY: z.string().optional(),
  /**
   * Combien de minutes on laisse au moteur pour rendre une piste.
   *
   * Le délai était de trente minutes, en dur. Or la vitesse dépend entièrement
   * du modèle et de la machine : mesuré sur un poste sans carte graphique,
   * « whisper-large-v2 » transcrit à deux fois le temps réel — trente minutes
   * ne couvrent alors qu'un quart d'heure de parole par personne, quand une
   * réunion de crise en dure trois. Un petit modèle sur la même machine va
   * cinq à huit fois plus vite et n'a pas besoin d'attendre autant.
   *
   * Le nombre est en minutes parce que c'est dans cette unité qu'on raisonne
   * quand on le règle : « une réunion de deux heures, à deux fois le temps
   * réel, il faut quatre heures ».
   */
  TRANSCRIPTION_DELAI_MINUTES: z.coerce.number().int().positive().default(30),
  SESSION_SECRET: z.string().min(32),

  /**
+1 −0
Changes for apps/api/src/index.ts: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@ if (env.TRANSCRIPTION_URL) {
  definirTranscription(transcriptionOpenAI({
    url: env.TRANSCRIPTION_URL, modele: env.TRANSCRIPTION_MODEL,
    cle: env.TRANSCRIPTION_KEY,
    delaiMs: env.TRANSCRIPTION_DELAI_MINUTES * 60_000,
  }));
}

+1 −1
Changes for apps/api/src/verification/installateur.ts: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -288,7 +288,7 @@ export async function verifierInstallateur(r: Rapport): Promise<void> {

  // ── Ce que le .env retient ───────────────────────────────────────────────
  for (const cle of ["TRANSCRIPTION_MODE", "TRANSCRIPTION_URL", "TRANSCRIPTION_MODEL",
    "TRANSCRIPTION_KEY"]) {
    "TRANSCRIPTION_KEY", "TRANSCRIPTION_DELAI_MINUTES"]) {
    r.verifie("EF-806", `le .env écrit porte ${cle}`,
      new RegExp(`^${cle}=\\$`, "m").test(script));
  }
Loading