支持设备短按向家长留言

This commit is contained in:
HycJack
2026-05-09 11:49:22 +08:00
parent be4d276557
commit edd1a2c4c2
5 changed files with 131 additions and 30 deletions

View File

@@ -4,7 +4,7 @@ import asyncio
from fastapi import WebSocket
from handlers.audio_packet_parser import parse_packet
from handlers.audio_session_handler import handle_websocket_data
from handlers.audio_file_handler import save_audio_file
from handlers.audio_file_handler import message_audio_storage_service, save_audio_file
from services.audio_session import audio_session_manager
from services.interrupt_handler import interrupt_handler
from services.task_manager import task_manager
@@ -13,6 +13,7 @@ from services.device_target_cache import device_target_cache
from services.offline_audio_cache import offline_audio_cache
from services.target_audio_cache import target_audio_cache
from services.card_service import card_service
from services.device_target_cache import VOICE_TARGET_KIND_PARENT
from utils.logger import session_logger
from handlers.prompt_sound_handler import handle_prompt_sound_request
from handlers.session_cleanup_handler import handle_old_session_cleanup
@@ -147,29 +148,28 @@ async def handle_binary_message(websocket: WebSocket, device_id: str, serial_num
session_id = session_key[1]
if packet_type == 1: # 开始包
target_device_id = await device_target_cache.get_target(device_id)
if target_device_id:
# 清除音频缓存
await target_audio_cache.clear_audio_data(target_device_id)
voice_target = await device_target_cache.get_voice_target(device_id)
if voice_target:
await target_audio_cache.clear_audio_data(voice_target.audio_cache_key)
return None, None
current_active_session = await handle_start_packet(
device_id, session_id, session_key, session, current_active_session
)
elif packet_type == 3: # 中断包
target_device_id = await device_target_cache.get_target(device_id)
if target_device_id:
voice_target = await device_target_cache.get_voice_target(device_id)
if voice_target:
return None, None
current_active_session = await handle_interrupt_packet(
device_id, session_id, session_key, session, current_active_session
)
elif packet_type == 2: # 结束包
target_device_id = await device_target_cache.get_target(device_id)
if target_device_id:
# 处理缓存的音频数据
voice_target = await device_target_cache.get_voice_target(device_id)
if voice_target:
session_logger.info(device_id, session_id, f"收到结束包,开始处理缓存音频数据")
await process_cached_audio(device_id, target_device_id, serial_number)
# 移除目标设备关联
if voice_target.kind == VOICE_TARGET_KIND_PARENT:
await process_parent_leave_message(device_id, voice_target.audio_cache_key)
else:
await process_cached_audio(device_id, voice_target.target_device_id, serial_number)
await device_target_cache.remove_target(device_id)
return None, None
if current_active_session == session_key:
@@ -243,20 +243,65 @@ async def handle_interrupt_packet(device_id, session_id, session_key, session, c
async def handle_target_audio_packet(device_id: str, audio_data: bytes):
"""处理发送给目标设备的音频包"""
try:
target_device_id = await device_target_cache.get_target(device_id)
voice_target = await device_target_cache.get_voice_target(device_id)
if not target_device_id:
if not voice_target:
session_logger.warning(device_id, "target", "未设置目标设备,无法发送音频")
return
# 缓存音频数据
await target_audio_cache.add_audio_data(target_device_id, audio_data)
session_logger.info(device_id, "target", f"已缓存音频数据到目标设备 {target_device_id}")
await target_audio_cache.add_audio_data(voice_target.audio_cache_key, audio_data)
if voice_target.kind == VOICE_TARGET_KIND_PARENT:
session_logger.info(device_id, "target", "已缓存发给家长的留言音频数据")
else:
session_logger.info(device_id, "target", f"已缓存音频数据到目标设备 {voice_target.target_device_id}")
except Exception as e:
session_logger.error(device_id, "target", f"处理目标音频包时出错: {e}", exc_info=True)
async def process_parent_leave_message(device_id: str, audio_cache_key: str):
"""处理设备发给家长的留言音频并写入家长会话。"""
try:
cached_audio = await target_audio_cache.get_audio_data(audio_cache_key)
if not cached_audio:
session_logger.info(device_id, "parent", "发给家长的留言没有缓存音频数据")
return
audio_file_key = await save_audio_file(cached_audio, device_id)
audio_url = f"http://{settings.server_host}:{settings.server_port}/{audio_file_key}"
await im_conversation_service.create_device_parent_leave_message(
device_id=device_id,
media_file_key=audio_url,
media_mime_type="audio/mpeg",
media_size_bytes=len(cached_audio),
ext_json={"source": "device_ws_parent_leave_message"},
)
session_logger.info(device_id, "parent", "发给家长的留言已写入家长会话")
websocket = await connection_manager.get_connection(device_id)
if websocket and websocket.client_state.name == "CONNECTED":
success_audio_url = f"http://{settings.server_host}:{settings.server_port}/assets/audio/message_ok.mp3"
await websocket.send_text(f"PROMPT_SOUND_URL:{success_audio_url}")
session_logger.info(device_id, "device", f"留言成功提示音已发送给设备 {device_id}")
else:
session_logger.warning(device_id, "device", f"设备 {device_id} 不在线,暂不发送留言成功提示音")
except Exception as e:
if isinstance(e, HTTPException):
session_logger.error(device_id, "parent", f"发给家长的留言保存失败返回HTTPException: {e}")
websocket = await connection_manager.get_connection(device_id)
if e.status_code == 404 or e.status_code == 400:
if websocket and websocket.client_state.name == "CONNECTED":
fail_audio_url = f"http://{settings.server_host}:{settings.server_port}/assets/audio/save_audio_fail.mp3"
await websocket.send_text(f"PROMPT_SOUND_URL:{fail_audio_url}")
session_logger.info(device_id, "device", f"留言失败提示音已发送给设备 {device_id}")
else:
session_logger.warning(device_id, "device", f"设备 {device_id} 不在线,暂不发送留言失败提示音")
else:
session_logger.error(device_id, "parent", f"处理家长留言音频时出错: {e}", exc_info=True)
finally:
await target_audio_cache.clear_audio_data(audio_cache_key)
async def process_cached_audio(device_id: str, target_device_id: str, serial_number: str):
"""处理缓存的音频数据并发送音频URL"""
try: