mirror of
https://github.com/R0m1k3/LiveFlow.git
synced 2026-10-11 17:27:19 +02:00
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:
2 files changed
+19
-11
No files matched your search
+6
-3
@@ -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
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user