feat(search): __init__.py 公开 API + 修复 OCR 测试 asyncio 兼容性

This commit is contained in:
2026-07-07 06:13:25 -04:00
parent 4baf92c93f
commit 499c5b8043
2 changed files with 26 additions and 13 deletions
+13
View File
@@ -0,0 +1,13 @@
"""搜索 Agent 装配层 — prompt 管理、skill 注册、工具分发、LLM 摘要、视觉观察。"""
from app.search.prompt import PromptManager
from app.search.skills import SkillRegistry, discover_skills
from app.search.tools import SearchToolDispatcher, get_tool_descriptions
__all__ = [
"PromptManager",
"SkillRegistry",
"SearchToolDispatcher",
"discover_skills",
"get_tool_descriptions",
]
+13 -13
View File
@@ -67,7 +67,7 @@ class TestCheckHealth:
url = "http://10.0.0.1:7866" url = "http://10.0.0.1:7866"
responses.add(responses.GET, f"{url}/health", status=200) responses.add(responses.GET, f"{url}/health", status=200)
client = MonkeyOCRClient(urls=[url]) client = MonkeyOCRClient(urls=[url])
asyncio.get_event_loop().run_until_complete(client.check_health()) asyncio.run(client.check_health())
@responses.activate @responses.activate
def test_unhealthy_endpoint_raises(self) -> None: def test_unhealthy_endpoint_raises(self) -> None:
@@ -76,7 +76,7 @@ class TestCheckHealth:
responses.add(responses.GET, f"{url}/health", status=500) responses.add(responses.GET, f"{url}/health", status=500)
client = MonkeyOCRClient(urls=[url]) client = MonkeyOCRClient(urls=[url])
with pytest.raises(RuntimeError, match="健康检查失败"): with pytest.raises(RuntimeError, match="健康检查失败"):
asyncio.get_event_loop().run_until_complete(client.check_health()) asyncio.run(client.check_health())
@responses.activate @responses.activate
def test_unreachable_endpoint_raises(self) -> None: def test_unreachable_endpoint_raises(self) -> None:
@@ -89,7 +89,7 @@ class TestCheckHealth:
) )
client = MonkeyOCRClient(urls=[url]) client = MonkeyOCRClient(urls=[url])
with pytest.raises(RuntimeError, match="端点不可达"): with pytest.raises(RuntimeError, match="端点不可达"):
asyncio.get_event_loop().run_until_complete(client.check_health()) asyncio.run(client.check_health())
@responses.activate @responses.activate
def test_multiple_endpoints_all_checked(self) -> None: def test_multiple_endpoints_all_checked(self) -> None:
@@ -100,7 +100,7 @@ class TestCheckHealth:
responses.add(responses.GET, f"{url_b}/health", status=503) responses.add(responses.GET, f"{url_b}/health", status=503)
client = MonkeyOCRClient(urls=[url_a, url_b]) client = MonkeyOCRClient(urls=[url_a, url_b])
with pytest.raises(RuntimeError, match="健康检查失败"): with pytest.raises(RuntimeError, match="健康检查失败"):
asyncio.get_event_loop().run_until_complete(client.check_health()) asyncio.run(client.check_health())
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@@ -124,7 +124,7 @@ class TestTranscribeFrames:
frame = tmp_path / "frame_001.jpg" frame = tmp_path / "frame_001.jpg"
frame.write_bytes(b"\xff\xd8\xff\xe0fake") frame.write_bytes(b"\xff\xd8\xff\xe0fake")
client = MonkeyOCRClient(urls=[url]) client = MonkeyOCRClient(urls=[url])
result = asyncio.get_event_loop().run_until_complete(client.transcribe_frames([frame])) result = asyncio.run(client.transcribe_frames([frame]))
assert result == "帧1: Hello World | OCR Test" assert result == "帧1: Hello World | OCR Test"
@responses.activate @responses.activate
@@ -149,7 +149,7 @@ class TestTranscribeFrames:
f.write_bytes(b"\xff\xd8data") f.write_bytes(b"\xff\xd8data")
frames.append(f) frames.append(f)
client = MonkeyOCRClient(urls=[url]) client = MonkeyOCRClient(urls=[url])
result = asyncio.get_event_loop().run_until_complete(client.transcribe_frames(frames)) result = asyncio.run(client.transcribe_frames(frames))
assert "帧1: Line A" in result assert "帧1: Line A" in result
assert "帧2: Line B" in result assert "帧2: Line B" in result
@@ -157,7 +157,7 @@ class TestTranscribeFrames:
def test_empty_frames_returns_empty(self) -> None: def test_empty_frames_returns_empty(self) -> None:
"""空帧列表 → 空串。""" """空帧列表 → 空串。"""
client = MonkeyOCRClient(urls=["http://ocr:7866"]) client = MonkeyOCRClient(urls=["http://ocr:7866"])
result = asyncio.get_event_loop().run_until_complete(client.transcribe_frames([])) result = asyncio.run(client.transcribe_frames([]))
assert result == "" assert result == ""
@@ -177,7 +177,7 @@ class TestFailureDegradation:
frame = tmp_path / "frame.jpg" frame = tmp_path / "frame.jpg"
frame.write_bytes(b"\xff\xd8data") frame.write_bytes(b"\xff\xd8data")
client = MonkeyOCRClient(urls=[url]) client = MonkeyOCRClient(urls=[url])
result = asyncio.get_event_loop().run_until_complete(client.transcribe_frames([frame])) result = asyncio.run(client.transcribe_frames([frame]))
assert result == "" assert result == ""
@responses.activate @responses.activate
@@ -197,7 +197,7 @@ class TestFailureDegradation:
f.write_bytes(b"\xff\xd8data") f.write_bytes(b"\xff\xd8data")
frames.append(f) frames.append(f)
client = MonkeyOCRClient(urls=[url]) client = MonkeyOCRClient(urls=[url])
result = asyncio.get_event_loop().run_until_complete(client.transcribe_frames(frames)) result = asyncio.run(client.transcribe_frames(frames))
# 帧1 失败被跳过,帧2 成功但输出为 "帧2: Good" # 帧1 失败被跳过,帧2 成功但输出为 "帧2: Good"
assert "帧1" not in result assert "帧1" not in result
assert "帧2: Good" in result assert "帧2: Good" in result
@@ -224,7 +224,7 @@ class TestLineDedup:
frame = tmp_path / "frame.jpg" frame = tmp_path / "frame.jpg"
frame.write_bytes(b"\xff\xd8data") frame.write_bytes(b"\xff\xd8data")
client = MonkeyOCRClient(urls=[url]) client = MonkeyOCRClient(urls=[url])
result = asyncio.get_event_loop().run_until_complete(client.transcribe_frames([frame])) result = asyncio.run(client.transcribe_frames([frame]))
assert result == "帧1: 重复行 | 不同行" assert result == "帧1: 重复行 | 不同行"
@responses.activate @responses.activate
@@ -240,7 +240,7 @@ class TestLineDedup:
frame = tmp_path / "frame.jpg" frame = tmp_path / "frame.jpg"
frame.write_bytes(b"\xff\xd8data") frame.write_bytes(b"\xff\xd8data")
client = MonkeyOCRClient(urls=[url]) client = MonkeyOCRClient(urls=[url])
result = asyncio.get_event_loop().run_until_complete(client.transcribe_frames([frame])) result = asyncio.run(client.transcribe_frames([frame]))
# "A" 和 "." 被过滤(长度 <= 1),保留 "AB" 和 "CD" # "A" 和 "." 被过滤(长度 <= 1),保留 "AB" 和 "CD"
assert result == "帧1: AB | CD" assert result == "帧1: AB | CD"
@@ -257,7 +257,7 @@ class TestLineDedup:
frame = tmp_path / "frame.jpg" frame = tmp_path / "frame.jpg"
frame.write_bytes(b"\xff\xd8data") frame.write_bytes(b"\xff\xd8data")
client = MonkeyOCRClient(urls=[url]) client = MonkeyOCRClient(urls=[url])
result = asyncio.get_event_loop().run_until_complete(client.transcribe_frames([frame])) result = asyncio.run(client.transcribe_frames([frame]))
assert result == "" assert result == ""
@@ -293,7 +293,7 @@ class TestRoundRobin:
f.write_bytes(b"\xff\xd8data") f.write_bytes(b"\xff\xd8data")
frames.append(f) frames.append(f)
client = MonkeyOCRClient(urls=[url_a, url_b]) client = MonkeyOCRClient(urls=[url_a, url_b])
result = asyncio.get_event_loop().run_until_complete(client.transcribe_frames(frames)) result = asyncio.run(client.transcribe_frames(frames))
assert "帧1: From A" in result assert "帧1: From A" in result
assert "帧2: From B" in result assert "帧2: From B" in result
# 验证两个端点都被调用 # 验证两个端点都被调用