From c61f44e5edfd11d9a62e661126cd171cd0b6d655 Mon Sep 17 00:00:00 2001 From: WJG Date: Mon, 19 May 2025 22:23:11 +0800 Subject: [PATCH] refactor: silero vad --- .../xiaozhi/services/audio/vad/__init__.py | 28 +++---------------- .../xiaozhi/services/audio/vad/silero.py | 19 +++++++++++-- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/examples/xiaozhi/xiaozhi/services/audio/vad/__init__.py b/examples/xiaozhi/xiaozhi/services/audio/vad/__init__.py index f74747c..8738391 100644 --- a/examples/xiaozhi/xiaozhi/services/audio/vad/__init__.py +++ b/examples/xiaozhi/xiaozhi/services/audio/vad/__init__.py @@ -1,20 +1,16 @@ import threading import time -import numpy as np - from config import APP_CONFIG from xiaozhi.event import EventManager from xiaozhi.ref import set_vad from xiaozhi.services.audio.stream import MyAudio -from xiaozhi.services.audio.vad.silero import VAD_MODEL +from xiaozhi.services.audio.vad.silero import Silero from xiaozhi.services.protocols.typing import AudioConfig from xiaozhi.utils.base import get_env class _VAD: - """基于WebRTC VAD的语音活动检测器,用于检测用户打断""" - def __init__(self): set_vad(self) @@ -33,7 +29,6 @@ class _VAD: self.speech_count = 0 self.silence_count = 0 - # 创建独立的PyAudio实例和流,避免与主音频流冲突 self.audio = None self.stream = None @@ -54,15 +49,10 @@ class _VAD: if not get_env("CLI"): return - if self.thread and self.thread.is_alive(): - return - - self.paused = False - - # 初始化PyAudio和流 self._initialize_audio_stream() # 启动检测线程 + self.paused = False self.thread = threading.Thread(target=self._detection_loop, daemon=True) self.thread.start() @@ -112,17 +102,6 @@ class _VAD: self.pause() EventManager.on_silence() - def _detect_speech(self, frames): - """检测是否是语音""" - try: - audio_int16 = np.frombuffer(frames, dtype=np.int16) - audio_float32 = audio_int16.astype(np.float32) / 32768.0 - speech_prob = VAD_MODEL(audio_float32, 16000).item() - is_speech = speech_prob >= self.threshold - return is_speech - except Exception: - return False - def _initialize_audio_stream(self): """初始化独立的音频流""" try: @@ -171,7 +150,8 @@ class _VAD: continue # 检测是否是语音 - is_speech = self._detect_speech(frames) + speech_prob = Silero.vad(frames, self.sample_rate) or 0 + is_speech = speech_prob >= self.threshold if is_speech: self._handle_speech_frame(frames) else: diff --git a/examples/xiaozhi/xiaozhi/services/audio/vad/silero.py b/examples/xiaozhi/xiaozhi/services/audio/vad/silero.py index 6342f2c..b6de26f 100644 --- a/examples/xiaozhi/xiaozhi/services/audio/vad/silero.py +++ b/examples/xiaozhi/xiaozhi/services/audio/vad/silero.py @@ -84,6 +84,19 @@ class OnnxWrapper: return out -VAD_MODEL = OnnxWrapper( - path=get_model_file_path("silero_vad.onnx"), -) +class _Silero: + def __init__(self) -> None: + self.model = OnnxWrapper( + path=get_model_file_path("silero_vad.onnx"), + ) + + def vad(self, frames, sample_rate): + try: + audio_int16 = np.frombuffer(frames, dtype=np.int16) + audio_float32 = audio_int16.astype(np.float32) / 32768.0 + return self.model(audio_float32, sample_rate).item() + except Exception: + return None + + +Silero = _Silero()