feat(asr): switch to Qwen streaming and close interrupted providers
This commit is contained in:
@@ -4,9 +4,34 @@ from services.task_manager import task_manager
|
||||
from utils.logger import session_logger
|
||||
from services.interrupt_handler import interrupt_handler
|
||||
import time
|
||||
from config import settings
|
||||
|
||||
|
||||
async def _connect_with_interrupt_cleanup(service, session_key):
|
||||
"""Own warmup connections even when interruption races with connect()."""
|
||||
if interrupt_handler.is_interrupted(session_key):
|
||||
return False
|
||||
await interrupt_handler.register_cleanup_handler(
|
||||
session_key, service.close,
|
||||
priority=interrupt_handler.PRIORITY["NETWORK_CONNECTION"],
|
||||
)
|
||||
try:
|
||||
await service.connect()
|
||||
if interrupt_handler.is_interrupted(session_key):
|
||||
await service.close()
|
||||
return False
|
||||
return True
|
||||
except asyncio.CancelledError:
|
||||
await service.close()
|
||||
raise
|
||||
except Exception:
|
||||
await service.close()
|
||||
raise
|
||||
|
||||
|
||||
async def prepare_asr_service(session, device_id, session_id):
|
||||
session.asr_error = None
|
||||
session.asr_service.sample_rate = session.sample_rate
|
||||
if hasattr(session.asr_service, "device_id"):
|
||||
session.asr_service.device_id = device_id
|
||||
if hasattr(session.asr_service, "session_id"):
|
||||
@@ -20,7 +45,8 @@ async def prepare_llm_service(session, device_id, session_id, selected_role):
|
||||
if hasattr(session.llm_service, "session_id"):
|
||||
session.llm_service.session_id = session_id
|
||||
if hasattr(session.llm_service, "connect"):
|
||||
await session.llm_service.connect()
|
||||
if not await _connect_with_interrupt_cleanup(session.llm_service, (device_id, session_id)):
|
||||
return
|
||||
|
||||
from services.conversation_history import conversation_history_manager
|
||||
from config import settings
|
||||
@@ -58,12 +84,29 @@ async def establish_asr_connection(session: AudioSession):
|
||||
)
|
||||
await session.asr_service.connect()
|
||||
if not session.asr_service.connected:
|
||||
session_logger.error("unknown", "unknown", "语音识别 WebSocket 连接未建立")
|
||||
return
|
||||
raise RuntimeError("语音识别 WebSocket 连接未建立")
|
||||
if session.device_id and session.session_id:
|
||||
if interrupt_handler.is_interrupted((session.device_id, session.session_id)):
|
||||
raise RuntimeError("连接期间会话已中断")
|
||||
await interrupt_handler.register_cleanup_handler(
|
||||
(session.device_id, session.session_id), session.asr_service.close,
|
||||
priority=interrupt_handler.PRIORITY["NETWORK_CONNECTION"],
|
||||
)
|
||||
await interrupt_handler.register_cleanup_handler(
|
||||
(session.device_id, session.session_id), session.cancel_send_task,
|
||||
priority=interrupt_handler.PRIORITY["TASK_CANCELLATION"],
|
||||
)
|
||||
session_logger.info(
|
||||
"unknown", "unknown", f"语音识别连接已建立,采样率: {session.sample_rate}Hz"
|
||||
)
|
||||
except asyncio.CancelledError:
|
||||
await session.cancel_send_task()
|
||||
await session.asr_service.close()
|
||||
raise
|
||||
except Exception as e:
|
||||
session.asr_error = f"{type(e).__name__}: {e}"
|
||||
await session.cancel_send_task()
|
||||
await session.asr_service.close()
|
||||
session_logger.error(
|
||||
"unknown", "unknown", f"建立语音识别 WebSocket 连接失败: {e}", exc_info=True
|
||||
)
|
||||
@@ -80,7 +123,10 @@ async def establish_tts_connection(session: AudioSession):
|
||||
)
|
||||
return
|
||||
|
||||
await session.tts_service.connect()
|
||||
if not await _connect_with_interrupt_cleanup(
|
||||
session.tts_service, (session.device_id, session.session_id)
|
||||
):
|
||||
return
|
||||
|
||||
if not session.tts_service.connected:
|
||||
session_logger.error(
|
||||
@@ -113,19 +159,24 @@ async def send_audio_task(session: AudioSession):
|
||||
session.device_id, session.session_id, "发送音频任务被中断"
|
||||
)
|
||||
break
|
||||
audio_data = await session.send_queue.get()
|
||||
if audio_data is None: # 结束信号
|
||||
break
|
||||
|
||||
await session.asr_service.send_audio(audio_data)
|
||||
queue = session.send_queue
|
||||
audio_data = await queue.get()
|
||||
try:
|
||||
if audio_data is None: # Drain all preceding audio before finish-task.
|
||||
break
|
||||
await session.asr_service.send_audio(audio_data)
|
||||
finally:
|
||||
queue.task_done()
|
||||
|
||||
except asyncio.CancelledError:
|
||||
session.asr_error = session.asr_error or "发送音频任务被取消"
|
||||
session_logger.info(
|
||||
session.device_id or "unknown",
|
||||
session.session_id or "unknown",
|
||||
"发送音频数据任务被取消",
|
||||
)
|
||||
except Exception as e:
|
||||
session.asr_error = str(e)
|
||||
session_logger.error(
|
||||
session.device_id or "unknown",
|
||||
session.session_id or "unknown",
|
||||
@@ -135,51 +186,51 @@ async def send_audio_task(session: AudioSession):
|
||||
|
||||
|
||||
async def end_asr_session(session: AudioSession):
|
||||
|
||||
if session.asr_service.connected:
|
||||
try:
|
||||
asr_end_start_time = time.perf_counter()
|
||||
await session.asr_service.send_end()
|
||||
await session.asr_service.receive_results()
|
||||
session.transcript = session.asr_service.transcript
|
||||
asr_end_elapsed = time.perf_counter() - asr_end_start_time
|
||||
session_logger.info(
|
||||
session.device_id or "unknown",
|
||||
session.session_id or "unknown",
|
||||
f"ASR结束延迟: 从发送结束包到获取最终结果耗时 {asr_end_elapsed:.2f} 秒",
|
||||
"""Drain device audio, collect the complete transcript, always release ASR."""
|
||||
session.transcript = ""
|
||||
try:
|
||||
session_key = (session.device_id, session.session_id)
|
||||
if interrupt_handler.is_interrupted(session_key):
|
||||
raise RuntimeError("识别会话已中断")
|
||||
if session.send_task and not session.send_task.done():
|
||||
await session.send_queue.put(None)
|
||||
await asyncio.wait_for(
|
||||
asyncio.shield(session.send_task),
|
||||
timeout=settings.asr_queue_drain_timeout_seconds,
|
||||
)
|
||||
except Exception as e:
|
||||
session_logger.error(
|
||||
session.device_id or "unknown",
|
||||
session.session_id or "unknown",
|
||||
f"ASR结束处理出错: {e}",
|
||||
exc_info=True,
|
||||
)
|
||||
finally:
|
||||
if session.send_task:
|
||||
session.send_task.cancel()
|
||||
try:
|
||||
await asyncio.wait_for(session.send_task, timeout=2.0)
|
||||
except (asyncio.CancelledError, asyncio.TimeoutError):
|
||||
pass
|
||||
except Exception as e:
|
||||
session_logger.error(
|
||||
session.device_id or "unknown",
|
||||
session.session_id or "unknown",
|
||||
f"取消发送任务时出错: {e}",
|
||||
)
|
||||
finally:
|
||||
session.send_task = None
|
||||
|
||||
await session.asr_service.close()
|
||||
session_logger.info(
|
||||
session.device_id or "unknown",
|
||||
session.session_id or "unknown",
|
||||
"语音识别 WebSocket 连接和 ClientSession 已关闭",
|
||||
)
|
||||
else:
|
||||
if session.asr_error:
|
||||
raise RuntimeError(session.asr_error)
|
||||
if session.send_queue and not session.send_queue.empty():
|
||||
raise RuntimeError("发送任务提前退出,音频未完整发送")
|
||||
if interrupt_handler.is_interrupted(session_key):
|
||||
raise RuntimeError("识别会话已中断")
|
||||
asr_end_start_time = time.perf_counter()
|
||||
await session.asr_service.send_end()
|
||||
if interrupt_handler.is_interrupted(session_key):
|
||||
raise RuntimeError("识别会话已中断")
|
||||
session.transcript = await session.asr_service.receive_results()
|
||||
session_logger.info(
|
||||
session.device_id or "unknown", session.session_id or "unknown",
|
||||
f"ASR结束延迟: {time.perf_counter() - asr_end_start_time:.2f} 秒",
|
||||
)
|
||||
except Exception as e:
|
||||
session.asr_error = f"{type(e).__name__}: {e}"
|
||||
session.transcript = ""
|
||||
session_logger.error(
|
||||
session.device_id or "unknown",
|
||||
session.session_id or "unknown",
|
||||
"语音识别 WebSocket 连接未建立",
|
||||
session.device_id or "unknown", session.session_id or "unknown",
|
||||
f"ASR结束处理出错: {session.asr_error}",
|
||||
)
|
||||
finally:
|
||||
if session.send_task:
|
||||
session.send_task.cancel()
|
||||
try:
|
||||
await asyncio.wait_for(session.send_task, timeout=2.0)
|
||||
except (asyncio.CancelledError, asyncio.TimeoutError):
|
||||
pass
|
||||
finally:
|
||||
session.send_task = None
|
||||
await session.asr_service.close()
|
||||
session_logger.info(
|
||||
session.device_id or "unknown", session.session_id or "unknown",
|
||||
"语音识别 WebSocket 连接和 ClientSession 已关闭",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user