diff --git a/app/main.py b/app/main.py index a74855e..05f5397 100644 --- a/app/main.py +++ b/app/main.py @@ -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) diff --git a/app/segmenter.py b/app/segmenter.py index f52be69..e350279 100644 --- a/app/segmenter.py +++ b/app/segmenter.py @@ -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