fix(voice): preserve pending message intent across reconnects
This commit is contained in:
@@ -176,15 +176,13 @@ async def handle_binary_message(websocket: WebSocket, device_id: str, serial_num
|
||||
return current_active_session, first_audio_received_time
|
||||
session.start_received = True
|
||||
session.voice_target = await device_target_cache.claim_target(device_id, websocket, session_id)
|
||||
if session.voice_target:
|
||||
# Acknowledge START now; the first audio packet selects AI (0) or
|
||||
# message (4). A pending message must not swallow an AI recording.
|
||||
await websocket.send_text("START_ACK")
|
||||
session.start_ack_sent = True
|
||||
return session_key, None
|
||||
current_active_session = await start_ai_recording(
|
||||
websocket, device_id, session_id, session_key, session, current_active_session, sample_rate
|
||||
)
|
||||
# START does not identify AI versus message audio. Decide on the first
|
||||
# audio packet, even without a target, so an invalid message cannot
|
||||
# start ASR and later report an unrelated recognition failure.
|
||||
current_active_session = await handle_start_packet(
|
||||
device_id, session_id, session_key, session, current_active_session)
|
||||
await websocket.send_text("START_ACK")
|
||||
session.start_ack_sent = True
|
||||
return current_active_session, None
|
||||
|
||||
if not session.start_received or session.recording_finished:
|
||||
@@ -209,26 +207,32 @@ async def handle_binary_message(websocket: WebSocket, device_id: str, serial_num
|
||||
session_logger.info(device_id, session_id, f"收到第一个音频数据包时间: {first_audio_received_time}")
|
||||
elif packet_type == 4:
|
||||
target = session.voice_target
|
||||
if target and not session.ai_started:
|
||||
if await handle_target_audio_packet(device_id, audio_data, target, websocket, session_id):
|
||||
session.message_audio_received = True
|
||||
if not session.ai_started:
|
||||
session.message_audio_received = True
|
||||
if target:
|
||||
await handle_target_audio_packet(device_id, audio_data, target, websocket, session_id)
|
||||
else:
|
||||
session_logger.warning(device_id, session_id, "留言录音没有对应目标,将返回留言失败提示")
|
||||
else:
|
||||
session_logger.warning(device_id, session_id, "忽略没有对应留言目标的留言音频包")
|
||||
session_logger.warning(device_id, session_id, "忽略普通对话中混入的留言音频")
|
||||
return current_active_session, first_audio_received_time
|
||||
elif packet_type == 3:
|
||||
if session.voice_target:
|
||||
await device_target_cache.remove_target(device_id, expected=session.voice_target, reason="interrupted")
|
||||
if not session.ai_started:
|
||||
if session.voice_target:
|
||||
await device_target_cache.remove_target(device_id, expected=session.voice_target, reason="interrupted")
|
||||
session.voice_target = None
|
||||
session.recording_finished = True
|
||||
await websocket.send_text("INTERRUPT_ACK")
|
||||
await websocket.send_text("INTERRUPT_PROCESSED")
|
||||
await interrupt_handler.remove_session(session_key)
|
||||
return None if current_active_session == session_key else current_active_session, None
|
||||
current_active_session = await handle_interrupt_packet(
|
||||
device_id, session_id, session_key, session, current_active_session
|
||||
)
|
||||
elif packet_type == 2:
|
||||
if session.voice_target:
|
||||
target = await device_target_cache.take_target(device_id, session.voice_target, websocket, session_id)
|
||||
if session.voice_target or session.message_audio_received:
|
||||
target = (await device_target_cache.take_target(device_id, session.voice_target, websocket, session_id)
|
||||
if session.voice_target else None)
|
||||
session.voice_target = None
|
||||
session.recording_finished = True
|
||||
try:
|
||||
@@ -240,10 +244,19 @@ async def handle_binary_message(websocket: WebSocket, device_id: str, serial_num
|
||||
else:
|
||||
await process_cached_audio(device_id, target.target_device_id, serial_number,
|
||||
audio_cache_key=target.audio_cache_key)
|
||||
elif current_active_session is None or current_active_session == session_key:
|
||||
await websocket.send_text(
|
||||
f"PROMPT_SOUND_URL:http://{settings.server_host}:{settings.server_port}/assets/audio/save_audio_fail.mp3")
|
||||
finally:
|
||||
if target:
|
||||
await target_audio_cache.clear_audio_data(target.audio_cache_key)
|
||||
await interrupt_handler.remove_session(session_key)
|
||||
return None if current_active_session == session_key else current_active_session, None
|
||||
if not session.ai_started:
|
||||
# Preserve the existing silent-recording response for START/END
|
||||
# without audio while keeping unowned messages out of the AI path.
|
||||
current_active_session = await start_ai_recording(
|
||||
websocket, device_id, session_id, session_key, session, current_active_session, sample_rate)
|
||||
if current_active_session == session_key:
|
||||
current_active_session = None
|
||||
|
||||
@@ -254,9 +267,6 @@ async def handle_binary_message(websocket: WebSocket, device_id: str, serial_num
|
||||
|
||||
|
||||
async def start_ai_recording(websocket, device_id, session_id, session_key, session, current_active_session, sample_rate):
|
||||
current_active_session = await handle_start_packet(
|
||||
device_id, session_id, session_key, session, current_active_session
|
||||
)
|
||||
await handle_websocket_data(websocket, session_key, session, 1, b"", sample_rate)
|
||||
session.ai_started = True
|
||||
return current_active_session
|
||||
|
||||
Reference in New Issue
Block a user