mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 23:47:41 +08:00
fix: 避免 Web Agent 语音转写阻塞事件循环 (#6389)
This commit is contained in:
@@ -8,7 +8,8 @@ from unittest.mock import AsyncMock, Mock, patch
|
||||
import pytest
|
||||
|
||||
from app import schemas
|
||||
from app.agent import ReplyMode, agent_manager
|
||||
from app.agent.contracts import ReplyMode
|
||||
from app.agent.orchestrator import agent_manager
|
||||
from app.api.endpoints.agent import (
|
||||
_WebAgentEventPublisher,
|
||||
_WEB_AGENT_FILE_REGISTRY,
|
||||
@@ -26,7 +27,8 @@ from app.api.endpoints.agent import (
|
||||
_get_web_agent_type,
|
||||
_has_web_agent_traditional_interaction,
|
||||
_prepare_web_agent_audio_attachment_path,
|
||||
_transcribe_web_agent_audio_refs,
|
||||
_resolve_web_agent_audio_refs,
|
||||
_transcribe_web_agent_audio_files,
|
||||
web_agent_stream,
|
||||
_resolve_web_agent_choice_payload,
|
||||
_split_web_agent_output,
|
||||
@@ -638,7 +640,7 @@ def test_prepare_web_agent_audio_attachment_converts_unsupported_audio(tmp_path)
|
||||
assert output_path.read_bytes() == b"wav-bytes"
|
||||
|
||||
|
||||
def test_transcribe_web_agent_audio_refs_reads_registered_upload(tmp_path):
|
||||
def test_transcribe_web_agent_audio_files_reads_registered_upload(tmp_path):
|
||||
"""WebAgent 上传录音应从临时附件登记表读取并转写为文本。"""
|
||||
voice_path = tmp_path / "recording.webm"
|
||||
voice_path.write_bytes(b"webm-bytes")
|
||||
@@ -657,7 +659,11 @@ def test_transcribe_web_agent_audio_refs_reads_registered_upload(tmp_path):
|
||||
"app.api.endpoints.agent.AgentCapabilityManager.transcribe_audio",
|
||||
return_value="帮我推荐一部电影",
|
||||
) as transcribe_audio:
|
||||
transcript = _transcribe_web_agent_audio_refs(["message/agent/file/audio-test"])
|
||||
audio_files = _resolve_web_agent_audio_refs(
|
||||
["message/agent/file/audio-test"]
|
||||
)
|
||||
_WEB_AGENT_FILE_REGISTRY.pop("audio-test", None)
|
||||
transcript = _transcribe_web_agent_audio_files(audio_files)
|
||||
finally:
|
||||
_WEB_AGENT_FILE_REGISTRY.pop("audio-test", None)
|
||||
|
||||
@@ -679,16 +685,58 @@ def test_web_agent_stream_returns_error_when_voice_transcription_fails():
|
||||
user = SimpleNamespace(id=1, name="admin")
|
||||
|
||||
with patch("app.api.endpoints.agent.settings.AI_AGENT_ENABLE", True), patch(
|
||||
"app.api.endpoints.agent._transcribe_web_agent_audio_refs",
|
||||
"app.api.endpoints.agent._transcribe_web_agent_audio_files",
|
||||
return_value=None,
|
||||
):
|
||||
) as transcribe_audio:
|
||||
response = asyncio.run(web_agent_stream(payload, request, user))
|
||||
body = "".join(asyncio.run(_collect_streaming_response(response)))
|
||||
|
||||
transcribe_audio.assert_not_called()
|
||||
assert "error" in body
|
||||
assert "语音识别失败" in body
|
||||
|
||||
|
||||
def test_web_agent_stream_does_not_block_event_loop_during_transcription():
|
||||
"""同步音频 provider 等待时,事件循环仍应让其他任务获得执行机会。"""
|
||||
payload = schemas.AgentWebChatRequest(
|
||||
text="",
|
||||
session_id="browser-session",
|
||||
audio_refs=["message/agent/file/audio-test"],
|
||||
)
|
||||
request = SimpleNamespace(headers={})
|
||||
user = SimpleNamespace(id=1, name="admin")
|
||||
|
||||
transcription_started = ThreadEvent()
|
||||
transcription_release = ThreadEvent()
|
||||
|
||||
def blocking_transcription(_audio_refs):
|
||||
transcription_started.set()
|
||||
assert transcription_release.wait(timeout=2)
|
||||
return None
|
||||
|
||||
async def scenario():
|
||||
stream_task = asyncio.create_task(web_agent_stream(payload, request, user))
|
||||
assert await asyncio.to_thread(transcription_started.wait, 1)
|
||||
assert stream_task.done() is False
|
||||
transcription_release.set()
|
||||
return await stream_task
|
||||
|
||||
try:
|
||||
with patch("app.api.endpoints.agent.settings.AI_AGENT_ENABLE", True), patch(
|
||||
"app.api.endpoints.agent._resolve_web_agent_audio_refs",
|
||||
return_value=[Mock()],
|
||||
), patch(
|
||||
"app.api.endpoints.agent._transcribe_web_agent_audio_files",
|
||||
side_effect=blocking_transcription,
|
||||
):
|
||||
response = asyncio.run(scenario())
|
||||
finally:
|
||||
transcription_release.set()
|
||||
|
||||
body = "".join(asyncio.run(_collect_streaming_response(response)))
|
||||
assert "语音识别失败" in body
|
||||
|
||||
|
||||
def test_web_agent_stream_binds_session_to_agent_manager():
|
||||
"""WebAgent 普通对话应统一进入 AgentManager 并绑定远程命令会话。"""
|
||||
payload = schemas.AgentWebChatRequest(
|
||||
|
||||
Reference in New Issue
Block a user