Code source de mirza.audio.vadDetector

"""
Détection d'activité vocale (VAD) neuronale via Silero VAD ONNX.

Module encapsule le modèle Silero VAD v4 pour segmenter en temps réel
les trames de parole et les silences sans solliciter la mémoire GPU.
"""

import os
import urllib.request

import numpy as np
import onnxruntime


[docs] class SileroVadDetector: """ Detection d'activite vocale par Silero VAD, execute sur CPU en moins d'une milliseconde par tranche de 32 ms et sans occupation de VRAM. Attributes ---------- modelPath : str Chemin du fichier ONNX, telecharge au premier besoin. sampleRate : int Frequence d'echantillonnage attendue. speechThreshold : float Probabilite au-dessus de laquelle la tranche compte comme de la parole. """
[docs] def __init__( self, modelPath: str = "/tmp/silero_vad.onnx", sampleRate: int = 16000, speechThreshold: float = 0.45, ): """ Initialise le modèle Silero VAD ONNX et prépare la session d'inférence. Parameters ---------- modelPath : str, optional Chemin local de stockage du fichier ONNX, default is "/tmp/silero_vad.onnx". sampleRate : int, optional Fréquence d'échantillonnage de l'audio en Hz, default is 16000. speechThreshold : float, optional Seuil de probabilité pour valider la parole, default is 0.45. """ self.modelPath = modelPath self.sampleRate = sampleRate self.speechThreshold = speechThreshold self.session = None self._ensureModel() self.reset()
def _ensureModel(self) -> None: """ Telecharge le fichier ONNX si absent, puis ouvre la session. Returns ------- None """ if not os.path.exists(self.modelPath): url = "https://github.com/snakers4/silero-vad/raw/master/src/silero_vad/data/silero_vad.onnx" urllib.request.urlretrieve(url, self.modelPath) opts = onnxruntime.SessionOptions() opts.inter_op_num_threads = 1 opts.intra_op_num_threads = 1 self.session = onnxruntime.InferenceSession( self.modelPath, sess_options=opts, providers=["CPUExecutionProvider"], )
[docs] def reset(self) -> None: """ Remet a zero l'etat recurrent du reseau. Returns ------- None """ self._state = np.zeros((2, 1, 128), dtype=np.float32)
[docs] def predict(self, audioChunk512: np.ndarray) -> tuple[bool, float]: """ Évalue une tranche audio de 512 échantillons (32 ms à 16 kHz). Parameters ---------- audioChunk512 : np.ndarray Tranche audio mono float32 normalisée entre -1.0 et 1.0. Returns ------- tuple of (bool, float) Tuple (isSpeech, confidenceProbability) où `isSpeech` est True si la probabilité dépasse `speechThreshold`. """ if len(audioChunk512) != 512: if len(audioChunk512) < 512: audioChunk512 = np.pad(audioChunk512, (0, 512 - len(audioChunk512))) else: audioChunk512 = audioChunk512[:512] ortInputs = { "input": np.expand_dims(audioChunk512, axis=0).astype(np.float32), "state": self._state, "sr": np.array(self.sampleRate, dtype=np.int64), } out, self._state = self.session.run(None, ortInputs) prob = float(out[0][0]) return prob > self.speechThreshold, prob