Fiabilité : la diarisation ne peut plus bloquer ni casser la transcription

- Timeout de 5 s sur l'identification du locuteur (asyncio.wait_for) : si le
  modèle ECAPA tarde ou se bloque sur CPU, on ignore le locuteur mais le
  texte est transcrit et affiché quand même
- AGC du segmenteur protégé : une trame problématique renvoie l'audio brut
  au lieu d'interrompre le découpage
Testé : texte transcrit malgré un diariseur qui se bloque indéfiniment.

https://claude.ai/code/session_01YHMp3EKzr4s6o8w1ygxuUe
This commit is contained in:
Claude committed 2026-06-13 15:37:23 +00:00
1 parent 0fa8455f8f
commit 55ccef1340
2 files changed
+19 -11

No files matched your search

+6 -3
View File
@@ -283,13 +283,16 @@ async def ws_transcribe(ws: WebSocket):
f"({len(seg.pcm) / 2 / SAMPLE_RATE:.1f}s d'audio, niveau crête {peak}"
f"{', amplifié' if pcm is not seg.pcm else ''}), transcription...", flush=True)
# Diarisation (~30-80 ms CPU, dans un thread pour ne pas bloquer)
# Diarisation (~30-80 ms CPU). Strictement isolée : ni un blocage
# ni une erreur ne doivent empêcher la transcription qui suit.
speaker = ""
if diarizer is not None:
try:
speaker = await asyncio.to_thread(diarizer.identify, pcm)
speaker = await asyncio.wait_for(
asyncio.to_thread(diarizer.identify, pcm), timeout=5.0
)
except Exception as exc:
print(f"[réunion {meeting_id}] diarisation échouée : {exc}", flush=True)
print(f"[réunion {meeting_id}] diarisation ignorée : {exc}", flush=True)
try:
text = await transcribe(pcm)
+13 -8
View File
@@ -48,14 +48,19 @@ class _AutoGain:
self.gain = 1.0
def process(self, frame: bytes) -> bytes:
peak = audioop.max(frame, 2)
if peak >= AGC_NOISE_FLOOR:
desired = min(AGC_MAX_GAIN, AGC_TARGET_PEAK / peak)
rate = AGC_ATTACK if desired > self.gain else AGC_RELEASE
self.gain += (desired - self.gain) * rate
self.gain = max(1.0, min(AGC_MAX_GAIN, self.gain))
if self.gain > 1.01:
return audioop.mul(frame, 2, self.gain)
# Toute erreur ici ne doit JAMAIS interrompre le découpage : on
# renvoie la trame d'origine en cas de souci.
try:
peak = audioop.max(frame, 2)
if peak >= AGC_NOISE_FLOOR:
desired = min(AGC_MAX_GAIN, AGC_TARGET_PEAK / peak)
rate = AGC_ATTACK if desired > self.gain else AGC_RELEASE
self.gain += (desired - self.gain) * rate
self.gain = max(1.0, min(AGC_MAX_GAIN, self.gain))
if self.gain > 1.01:
return audioop.mul(frame, 2, self.gain) # audioop sature, ne déborde pas
except Exception:
return frame
return frame