add banbanmini backend

This commit is contained in:
HycJack
2026-03-24 15:04:36 +08:00
parent 0d0f995dc2
commit 7510ca6df1
197 changed files with 13008 additions and 0 deletions

View 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,
)