update: 优化vad判断逻辑

This commit is contained in:
Sakura-RanChen
2025-10-20 11:45:50 +08:00
parent 2e6aced1bd
commit c06a7b1db6
5 changed files with 20 additions and 23 deletions
+1 -1
View File
@@ -454,7 +454,7 @@ VAD:
threshold: 0.5 threshold: 0.5
threshold_low: 0.3 threshold_low: 0.3
model_dir: models/snakers4_silero-vad model_dir: models/snakers4_silero-vad
min_silence_duration_ms: 200 # 如果说话停顿比较长,可以把这个值设置大一些 min_silence_duration_ms: 200 # 如果说话停顿比较长,可以把这个值设置大一些,实际延迟为:min_silence_duration_ms // 32 * 32ms
LLM: LLM:
# 所有openai类型均可以修改超参,以AliLLM为例 # 所有openai类型均可以修改超参,以AliLLM为例
+1 -1
View File
@@ -117,8 +117,8 @@ class ConnectionHandler:
self.client_have_voice = False self.client_have_voice = False
self.last_activity_time = 0.0 # 统一的活动时间戳(毫秒) self.last_activity_time = 0.0 # 统一的活动时间戳(毫秒)
self.client_voice_stop = False self.client_voice_stop = False
self.client_voice_window = deque(maxlen=5)
self.last_is_voice = False self.last_is_voice = False
self.continuous_false_count = 0
# asr相关变量 # asr相关变量
# 因为实际部署时可能会用到公共的本地ASR,不能把变量暴露给公共ASR # 因为实际部署时可能会用到公共的本地ASR,不能把变量暴露给公共ASR
@@ -33,7 +33,7 @@ async def handleAudioMessage(conn, audio):
async def resume_vad_detection(conn): async def resume_vad_detection(conn):
# 等待2秒后恢复VAD检测 # 等待2秒后恢复VAD检测
await asyncio.sleep(1) await asyncio.sleep(2)
conn.just_woken_up = False conn.just_woken_up = False
@@ -68,7 +68,7 @@ class ASRProviderBase(ABC):
conn.asr_audio.clear() conn.asr_audio.clear()
conn.reset_vad_states() conn.reset_vad_states()
if len(asr_audio_task) > 15: if len(asr_audio_task) > 15 or conn.client_listen_mode == "manual":
await self.handle_voice_stop(conn, asr_audio_task) await self.handle_voice_stop(conn, asr_audio_task)
# 处理语音停止 # 处理语音停止
@@ -1,6 +1,6 @@
import time import time
import numpy as np
import torch import torch
import numpy as np
import opuslib_next import opuslib_next
from config.logger import setup_logging from config.logger import setup_logging
from core.providers.vad.base import VADProviderBase from core.providers.vad.base import VADProviderBase
@@ -26,15 +26,12 @@ class VADProvider(VADProviderBase):
threshold_low = config.get("threshold_low", "0.2") threshold_low = config.get("threshold_low", "0.2")
min_silence_duration_ms = config.get("min_silence_duration_ms", "1000") min_silence_duration_ms = config.get("min_silence_duration_ms", "1000")
# 双阈值判断参数
self.vad_threshold = float(threshold) if threshold else 0.5 self.vad_threshold = float(threshold) if threshold else 0.5
self.vad_threshold_low = float(threshold_low) if threshold_low else 0.2 self.vad_threshold_low = float(threshold_low) if threshold_low else 0.2
self.silence_threshold_ms = ( # 静默阈值,连续多少帧低于最低值才判断为静音
int(min_silence_duration_ms) if min_silence_duration_ms else 1000 self.stop_false_count = int(min_silence_duration_ms) // 32 if min_silence_duration_ms else 31
)
# 至少要多少帧才算有语音
self.frame_window_threshold = 3
def is_vad(self, conn, opus_packet): def is_vad(self, conn, opus_packet):
try: try:
@@ -59,24 +56,24 @@ class VADProvider(VADProviderBase):
# 双阈值判断 # 双阈值判断
if speech_prob >= self.vad_threshold: if speech_prob >= self.vad_threshold:
is_voice = True client_have_voice = True
elif speech_prob <= self.vad_threshold_low: elif speech_prob <= self.vad_threshold_low:
is_voice = False client_have_voice = False
else: else:
is_voice = conn.last_is_voice client_have_voice = conn.last_is_voice
if not client_have_voice:
conn.continuous_false_count += 1
else:
conn.continuous_false_count = 0
# 声音没低于最低值则延续前一个状态,判断为有声音 # 声音没低于最低值则延续前一个状态,判断为有声音
conn.last_is_voice = is_voice conn.last_is_voice = client_have_voice
# 更新滑动窗口 # 如果之前有声音,且连续为静音帧,达到静默阈值要求帧数,则认为已经说完一句话
conn.client_voice_window.append(is_voice) if conn.client_have_voice and conn.continuous_false_count >= self.stop_false_count:
client_have_voice = (conn.client_voice_window.count(True) >= self.frame_window_threshold) conn.client_voice_stop = True
# 如果之前有声音,但本次没有声音,且与上次有声音的时间差已经超过了静默阈值,则认为已经说完一句话
if conn.client_have_voice and not client_have_voice:
stop_duration = time.time() * 1000 - conn.last_activity_time
if stop_duration >= self.silence_threshold_ms:
conn.client_voice_stop = True
if client_have_voice: if client_have_voice:
conn.client_have_voice = True conn.client_have_voice = True
conn.last_activity_time = time.time() * 1000 conn.last_activity_time = time.time() * 1000