mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-28 10:03:54 +08:00
Merge pull request #1640 from xinnan-tech/py_tts_listen
fix: 反复打断任务没有被清除,vad四帧语音识别
This commit is contained in:
@@ -5,7 +5,7 @@ from config.config_loader import load_config
|
|||||||
from config.settings import check_config_file
|
from config.settings import check_config_file
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
SERVER_VERSION = "0.5.7"
|
SERVER_VERSION = "0.5.8"
|
||||||
_logger_initialized = False
|
_logger_initialized = False
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ class ConnectionHandler:
|
|||||||
self.client_have_voice_last_time = 0.0
|
self.client_have_voice_last_time = 0.0
|
||||||
self.client_no_voice_last_time = 0.0
|
self.client_no_voice_last_time = 0.0
|
||||||
self.client_voice_stop = False
|
self.client_voice_stop = False
|
||||||
|
self.client_voice_frame_count = 0
|
||||||
|
|
||||||
# asr相关变量
|
# asr相关变量
|
||||||
# 因为实际部署时可能会用到公共的本地ASR,不能把变量暴露给公共ASR
|
# 因为实际部署时可能会用到公共的本地ASR,不能把变量暴露给公共ASR
|
||||||
@@ -627,8 +628,8 @@ class ConnectionHandler:
|
|||||||
)
|
)
|
||||||
memory_str = future.result()
|
memory_str = future.result()
|
||||||
|
|
||||||
uuid_str = str(uuid.uuid4()).replace("-", "")
|
self.sentence_id = str(uuid.uuid4().hex)
|
||||||
self.sentence_id = uuid_str
|
|
||||||
|
|
||||||
if self.intent_type == "function_call" and functions is not None:
|
if self.intent_type == "function_call" and functions is not None:
|
||||||
# 使用支持functions的streaming接口
|
# 使用支持functions的streaming接口
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ from core.utils.util import check_model_key
|
|||||||
from core.providers.tts.base import TTSProviderBase
|
from core.providers.tts.base import TTSProviderBase
|
||||||
from core.handle.abortHandle import handleAbortMessage
|
from core.handle.abortHandle import handleAbortMessage
|
||||||
from core.providers.tts.dto.dto import SentenceType, ContentType, InterfaceType
|
from core.providers.tts.dto.dto import SentenceType, ContentType, InterfaceType
|
||||||
|
from asyncio import Task
|
||||||
|
|
||||||
|
|
||||||
TAG = __name__
|
TAG = __name__
|
||||||
logger = setup_logging()
|
logger = setup_logging()
|
||||||
@@ -141,6 +143,7 @@ class TTSProvider(TTSProviderBase):
|
|||||||
super().__init__(config, delete_audio_file)
|
super().__init__(config, delete_audio_file)
|
||||||
self.ws = None
|
self.ws = None
|
||||||
self.interface_type = InterfaceType.DUAL_STREAM
|
self.interface_type = InterfaceType.DUAL_STREAM
|
||||||
|
self._monitor_task = None # 监听任务引用
|
||||||
self.appId = config.get("appid")
|
self.appId = config.get("appid")
|
||||||
self.access_token = config.get("access_token")
|
self.access_token = config.get("access_token")
|
||||||
self.cluster = config.get("cluster")
|
self.cluster = config.get("cluster")
|
||||||
@@ -270,8 +273,7 @@ class TTSProvider(TTSProviderBase):
|
|||||||
try:
|
try:
|
||||||
# 建立新连接
|
# 建立新连接
|
||||||
if self.ws is None:
|
if self.ws is None:
|
||||||
await handleAbortMessage(self.conn)
|
logger.bind(tag=TAG).warning(f"WebSocket连接不存在,终止发送文本")
|
||||||
logger.bind(tag=TAG).error(f"WebSocket连接不存在,终止发送文本")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# 过滤Markdown
|
# 过滤Markdown
|
||||||
@@ -293,6 +295,25 @@ class TTSProvider(TTSProviderBase):
|
|||||||
async def start_session(self, session_id):
|
async def start_session(self, session_id):
|
||||||
logger.bind(tag=TAG).info(f"开始会话~~{session_id}")
|
logger.bind(tag=TAG).info(f"开始会话~~{session_id}")
|
||||||
try:
|
try:
|
||||||
|
task = self._monitor_task
|
||||||
|
if (
|
||||||
|
task is not None
|
||||||
|
and isinstance(task, Task)
|
||||||
|
and not task.done()
|
||||||
|
):
|
||||||
|
logger.bind(tag=TAG).info("等待上一个监听任务结束...")
|
||||||
|
if self.ws is not None:
|
||||||
|
logger.bind(tag=TAG).info("强制关闭上一个WebSocket连接以唤醒监听任务...")
|
||||||
|
try:
|
||||||
|
await self.ws.close()
|
||||||
|
except Exception as e:
|
||||||
|
logger.bind(tag=TAG).warning(f"关闭上一个ws异常: {e}")
|
||||||
|
self.ws = None
|
||||||
|
try:
|
||||||
|
await asyncio.wait_for(task, timeout=8)
|
||||||
|
except Exception as e:
|
||||||
|
logger.bind(tag=TAG).warning(f"等待监听任务异常: {e}")
|
||||||
|
self._monitor_task = None
|
||||||
# 建立新连接
|
# 建立新连接
|
||||||
await self._ensure_connection()
|
await self._ensure_connection()
|
||||||
|
|
||||||
@@ -463,6 +484,8 @@ class TTSProvider(TTSProviderBase):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
self.ws = None
|
self.ws = None
|
||||||
|
# 监听任务退出时清理引用
|
||||||
|
self._monitor_task = None
|
||||||
|
|
||||||
async def send_event(
|
async def send_event(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ class VADProvider(VADProviderBase):
|
|||||||
pcm_frame = self.decoder.decode(opus_packet, 960)
|
pcm_frame = self.decoder.decode(opus_packet, 960)
|
||||||
conn.client_audio_buffer.extend(pcm_frame) # 将新数据加入缓冲区
|
conn.client_audio_buffer.extend(pcm_frame) # 将新数据加入缓冲区
|
||||||
|
|
||||||
|
# 初始化帧计数器
|
||||||
|
if not hasattr(conn, "client_voice_frame_count"):
|
||||||
|
conn.client_voice_frame_count = 0
|
||||||
|
|
||||||
# 处理缓冲区中的完整帧(每次处理512采样点)
|
# 处理缓冲区中的完整帧(每次处理512采样点)
|
||||||
client_have_voice = False
|
client_have_voice = False
|
||||||
while len(conn.client_audio_buffer) >= 512 * 2:
|
while len(conn.client_audio_buffer) >= 512 * 2:
|
||||||
@@ -50,7 +54,15 @@ class VADProvider(VADProviderBase):
|
|||||||
# 检测语音活动
|
# 检测语音活动
|
||||||
with torch.no_grad():
|
with torch.no_grad():
|
||||||
speech_prob = self.model(audio_tensor, 16000).item()
|
speech_prob = self.model(audio_tensor, 16000).item()
|
||||||
client_have_voice = speech_prob >= self.vad_threshold
|
is_voice = speech_prob >= self.vad_threshold
|
||||||
|
|
||||||
|
if is_voice:
|
||||||
|
conn.client_voice_frame_count += 1
|
||||||
|
else:
|
||||||
|
conn.client_voice_frame_count = 0
|
||||||
|
|
||||||
|
# 只有连续4帧检测到语音才认为有语音
|
||||||
|
client_have_voice = conn.client_voice_frame_count >= 4
|
||||||
|
|
||||||
# 如果之前有声音,但本次没有声音,且与上次有声音的时间差已经超过了静默阈值,则认为已经说完一句话
|
# 如果之前有声音,但本次没有声音,且与上次有声音的时间差已经超过了静默阈值,则认为已经说完一句话
|
||||||
if conn.client_have_voice and not client_have_voice:
|
if conn.client_have_voice and not client_have_voice:
|
||||||
|
|||||||
Reference in New Issue
Block a user