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_low: 0.3
model_dir: models/snakers4_silero-vad
min_silence_duration_ms: 200 # 如果说话停顿比较长,可以把这个值设置大一些
min_silence_duration_ms: 200 # 如果说话停顿比较长,可以把这个值设置大一些,实际延迟为:min_silence_duration_ms // 32 * 32ms
LLM:
# 所有openai类型均可以修改超参,以AliLLM为例
+1 -1
View File
@@ -117,8 +117,8 @@ class ConnectionHandler:
self.client_have_voice = False
self.last_activity_time = 0.0 # 统一的活动时间戳(毫秒)
self.client_voice_stop = False
self.client_voice_window = deque(maxlen=5)
self.last_is_voice = False
self.continuous_false_count = 0
# asr相关变量
# 因为实际部署时可能会用到公共的本地ASR,不能把变量暴露给公共ASR
@@ -33,7 +33,7 @@ async def handleAudioMessage(conn, audio):
async def resume_vad_detection(conn):
# 等待2秒后恢复VAD检测
await asyncio.sleep(1)
await asyncio.sleep(2)
conn.just_woken_up = False
@@ -68,7 +68,7 @@ class ASRProviderBase(ABC):
conn.asr_audio.clear()
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)
# 处理语音停止
@@ -1,6 +1,6 @@
import time
import numpy as np
import torch
import numpy as np
import opuslib_next
from config.logger import setup_logging
from core.providers.vad.base import VADProviderBase
@@ -26,15 +26,12 @@ class VADProvider(VADProviderBase):
threshold_low = config.get("threshold_low", "0.2")
min_silence_duration_ms = config.get("min_silence_duration_ms", "1000")
# 双阈值判断参数
self.vad_threshold = float(threshold) if threshold else 0.5
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.frame_window_threshold = 3
# 静默阈值,连续多少帧低于最低值才判断为静音
self.stop_false_count = int(min_silence_duration_ms) // 32 if min_silence_duration_ms else 31
def is_vad(self, conn, opus_packet):
try:
@@ -59,24 +56,24 @@ class VADProvider(VADProviderBase):
# 双阈值判断
if speech_prob >= self.vad_threshold:
is_voice = True
client_have_voice = True
elif speech_prob <= self.vad_threshold_low:
is_voice = False
client_have_voice = False
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)
client_have_voice = (conn.client_voice_window.count(True) >= self.frame_window_threshold)
# 如果之前有声音,且连续为静音帧,达到静默阈值要求帧数,则认为已经说完一句话
if conn.client_have_voice and conn.continuous_false_count >= self.stop_false_count:
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:
conn.client_have_voice = True
conn.last_activity_time = time.time() * 1000