mirror of
https://github.com/R0m1k3/LiveFlow.git
synced 2026-10-11 17:27:19 +02:00
Qualité de transcription : audio propre pour le moteur (corrige les erreurs)
L'AGC sur-amplifiait (jusqu'à x60) l'audio envoyé au moteur -> signal déformé/bruité -> mauvaise reconnaissance. Désormais : - Le VAD détecte sur l'audio amplifié, mais le segment stocke l'audio BRUT - Le segment est normalisé proprement (mise à l'échelle linéaire unique vers crête ~22000, sans saturation) juste avant le moteur - Segment max ramené de 25 s à 15 s pour un retour plus rapide Validé bout en bout : micro faible -> détecté -> audio propre -> transcrit. https://claude.ai/code/session_01YHMp3EKzr4s6o8w1ygxuUe
This commit is contained in:
2 files changed
+26
-15
No files matched your search
+10
-8
@@ -22,7 +22,7 @@ PREROLL_FRAMES = 10 # 300 ms conservées avant le déclenchement
|
||||
TRIGGER_RATIO = 0.6 # part de trames "parole" du pré-roll pour démarrer
|
||||
SILENCE_END_MS = 700 # silence qui clôt un segment
|
||||
MIN_SPEECH_MS = 300 # en dessous, le segment est ignoré (bruit)
|
||||
MAX_SEGMENT_S = 25 # coupe forcée pour garder une latence raisonnable
|
||||
MAX_SEGMENT_S = 15 # coupe forcée pour garder une latence raisonnable
|
||||
|
||||
# Contrôle de gain automatique appliqué AVANT la détection de parole : sans lui,
|
||||
# un micro faible (casque...) reste sous le seuil du VAD et aucune phrase n'est
|
||||
@@ -83,10 +83,12 @@ class SpeechSegmenter:
|
||||
self._pending.extend(data)
|
||||
segments = []
|
||||
while len(self._pending) >= FRAME_BYTES:
|
||||
frame = bytes(self._pending[:FRAME_BYTES])
|
||||
raw = bytes(self._pending[:FRAME_BYTES])
|
||||
del self._pending[:FRAME_BYTES]
|
||||
frame = self._agc.process(frame) # amplifie avant le VAD
|
||||
seg = self._process_frame(frame)
|
||||
# Le VAD travaille sur l'audio amplifié (détection fiable même micro
|
||||
# faible) ; le segment stocke l'audio BRUT (transcription propre).
|
||||
amplified = self._agc.process(raw)
|
||||
seg = self._process_frame(raw, amplified)
|
||||
if seg is not None:
|
||||
segments.append(seg)
|
||||
return segments
|
||||
@@ -98,12 +100,12 @@ class SpeechSegmenter:
|
||||
self._pending.clear()
|
||||
return seg
|
||||
|
||||
def _process_frame(self, frame: bytes) -> Segment | None:
|
||||
is_speech = self._vad.is_speech(frame, SAMPLE_RATE)
|
||||
def _process_frame(self, raw: bytes, amplified: bytes) -> Segment | None:
|
||||
is_speech = self._vad.is_speech(amplified, SAMPLE_RATE)
|
||||
self._frame_index += 1
|
||||
|
||||
if not self._triggered:
|
||||
self._ring.append((frame, is_speech))
|
||||
self._ring.append((raw, is_speech))
|
||||
voiced = sum(1 for _, s in self._ring if s)
|
||||
if len(self._ring) == self._ring.maxlen and voiced >= TRIGGER_RATIO * self._ring.maxlen:
|
||||
self._triggered = True
|
||||
@@ -114,7 +116,7 @@ class SpeechSegmenter:
|
||||
self._ring.clear()
|
||||
return None
|
||||
|
||||
self._segment.extend(frame)
|
||||
self._segment.extend(raw)
|
||||
if is_speech:
|
||||
self._speech_frames += 1
|
||||
self._silence_frames = 0
|
||||
|
||||
Reference in new issue
Block a user