add banbanmini backend
This commit is contained in:
165
talkingq-url/services/audio_sender.py
Normal file
165
talkingq-url/services/audio_sender.py
Normal file
@@ -0,0 +1,165 @@
|
||||
import asyncio
|
||||
from typing import Optional
|
||||
from fastapi import WebSocket
|
||||
from utils.logger import session_logger
|
||||
from services.interrupt_handler import interrupt_handler
|
||||
from services.tts_error_manager import tts_error_manager
|
||||
from config import settings
|
||||
|
||||
|
||||
class AudioSender:
|
||||
|
||||
|
||||
def __init__(
|
||||
self, device_id: str, session_id: str, websocket: Optional[WebSocket] = None
|
||||
):
|
||||
self.device_id = device_id
|
||||
self.session_id = session_id
|
||||
self.session_key = (device_id, session_id)
|
||||
self.websocket = websocket
|
||||
|
||||
def check_interruption(self):
|
||||
|
||||
return interrupt_handler.is_interrupted(self.session_key)
|
||||
|
||||
def is_websocket_connected(self):
|
||||
|
||||
return (
|
||||
self.websocket is not None
|
||||
and self.websocket.client_state.name == "CONNECTED"
|
||||
and not getattr(self.websocket, "_closed", False)
|
||||
)
|
||||
|
||||
async def send_start_notification(self):
|
||||
|
||||
if not self.is_websocket_connected():
|
||||
session_logger.warning(
|
||||
self.device_id,
|
||||
self.session_id,
|
||||
"Session websocket 不存在或会话已中断,无法发送 TTS_START",
|
||||
)
|
||||
await interrupt_handler.set_interrupt_state(self.session_key, True)
|
||||
return False
|
||||
try:
|
||||
await self.websocket.send_text("TTS_START")
|
||||
session_logger.info(
|
||||
self.device_id, self.session_id, "已发送 TTS_START 给客户端"
|
||||
)
|
||||
await tts_error_manager.start_tts_session(self.device_id, self.session_id)
|
||||
return True
|
||||
except Exception as e:
|
||||
session_logger.error(
|
||||
self.device_id,
|
||||
self.session_id,
|
||||
f"发送 TTS_START 时发生异常:{e}",
|
||||
exc_info=True,
|
||||
)
|
||||
await interrupt_handler.set_interrupt_state(self.session_key, True)
|
||||
return False
|
||||
|
||||
async def send_audio_urls(self, url_queue: asyncio.Queue):
|
||||
|
||||
try:
|
||||
if not await self.send_start_notification():
|
||||
return
|
||||
|
||||
first_url_sent = False
|
||||
first_tts_submit_time = getattr(url_queue, "first_tts_submit_time", None)
|
||||
|
||||
while True:
|
||||
if self.check_interruption():
|
||||
session_logger.info(
|
||||
self.device_id,
|
||||
self.session_id,
|
||||
"检测到中断标志,立即停止音频发送任务",
|
||||
)
|
||||
break
|
||||
try:
|
||||
audio_url = await asyncio.wait_for(url_queue.get(), timeout=0.1)
|
||||
except asyncio.TimeoutError:
|
||||
if self.check_interruption():
|
||||
break
|
||||
continue
|
||||
except Exception as e:
|
||||
session_logger.error(
|
||||
self.device_id,
|
||||
self.session_id,
|
||||
f"获取音频URL队列数据时出错: {str(e)}",
|
||||
)
|
||||
break
|
||||
if audio_url is None:
|
||||
break
|
||||
if self.is_websocket_connected() and not self.check_interruption():
|
||||
try:
|
||||
full_url = f"http://{settings.server_host}:{settings.server_port}/{audio_url}" if not audio_url.startswith('http') else audio_url
|
||||
await self.websocket.send_text(f"TTS_URL:{full_url}")
|
||||
|
||||
if not first_url_sent and first_tts_submit_time is not None:
|
||||
first_url_sent = True
|
||||
|
||||
session_logger.info(
|
||||
self.device_id,
|
||||
self.session_id,
|
||||
f"已发送音频URL给客户端: {full_url}",
|
||||
)
|
||||
except Exception as e:
|
||||
session_logger.error(
|
||||
self.device_id,
|
||||
self.session_id,
|
||||
f"发送音频URL时出错: {str(e)}",
|
||||
)
|
||||
await interrupt_handler.set_interrupt_state(
|
||||
self.session_key, True
|
||||
)
|
||||
break
|
||||
else:
|
||||
session_logger.warning(
|
||||
self.device_id,
|
||||
self.session_id,
|
||||
"WebSocket连接已关闭或会话已中断,无法发送音频URL",
|
||||
)
|
||||
break
|
||||
if self.check_interruption():
|
||||
break
|
||||
url_queue.task_done()
|
||||
if not self.check_interruption():
|
||||
try:
|
||||
if self.is_websocket_connected():
|
||||
try:
|
||||
await self.websocket.send_text("TTS_END")
|
||||
session_logger.info(
|
||||
self.device_id,
|
||||
self.session_id,
|
||||
"已发送 TTS_END 给客户端",
|
||||
)
|
||||
await tts_error_manager.end_tts_session(self.device_id, self.session_id)
|
||||
except RuntimeError as e:
|
||||
if "Cannot call" in str(e) and "close message" in str(e):
|
||||
session_logger.warning(
|
||||
self.device_id,
|
||||
self.session_id,
|
||||
f"WebSocket已关闭,无法发送TTS_END: {e}",
|
||||
)
|
||||
else:
|
||||
session_logger.error(
|
||||
self.device_id,
|
||||
self.session_id,
|
||||
f"发送TTSEND时发生运行时错误: {e}",
|
||||
)
|
||||
else:
|
||||
session_logger.warning(
|
||||
self.device_id,
|
||||
self.session_id,
|
||||
"WebSocket连接已关闭或会话已中断,跳过发送 TTS_END",
|
||||
)
|
||||
except Exception as e:
|
||||
session_logger.error(
|
||||
self.device_id, self.session_id, f"检查WebSocket状态时出错: {e}"
|
||||
)
|
||||
except Exception as e:
|
||||
session_logger.error(
|
||||
self.device_id,
|
||||
self.session_id,
|
||||
f"发送音频URL时出错: {e}",
|
||||
exc_info=True,
|
||||
)
|
||||
Reference in New Issue
Block a user