128 lines
5.0 KiB
Python
128 lines
5.0 KiB
Python
"""look_at_image 的问题收敛与兼容兜底测试(不碰网络和数据库)。"""
|
|
from __future__ import annotations
|
|
|
|
import tempfile
|
|
import unittest
|
|
import uuid
|
|
from contextlib import ExitStack
|
|
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
from unittest import mock
|
|
|
|
from core.ark_client import ArkConfig
|
|
from tools.look_at_image import LookAtImageTool, _DEFAULT_QUESTION
|
|
|
|
|
|
class LookAtImageQuestionTests(unittest.TestCase):
|
|
def _tool(self) -> LookAtImageTool:
|
|
return LookAtImageTool(
|
|
ark_cfg=ArkConfig(api_key="test", base_url="https://example.invalid", raw={}),
|
|
vision_variant_cfg={
|
|
"model_id": "vision-test",
|
|
"request_timeout_s": 1,
|
|
"timeout_retries": 0,
|
|
},
|
|
variant_key="test",
|
|
working_dir=Path("."),
|
|
task_id=uuid.uuid4(),
|
|
user_id=uuid.uuid4(),
|
|
base_dir=Path("."),
|
|
user_root=Path("."),
|
|
)
|
|
|
|
def test_native_vision_model_omits_look_tool_but_keeps_document_ocr(self):
|
|
from core.tool_registry import ToolContext, build_tools
|
|
|
|
ark = ArkConfig(
|
|
api_key="test",
|
|
base_url="https://example.invalid",
|
|
raw={"vision": {"test": {"model_id": "vision-test"}}},
|
|
)
|
|
|
|
def build(native_image_input: bool) -> dict:
|
|
with tempfile.TemporaryDirectory() as tmp, ExitStack() as stack:
|
|
root = Path(tmp)
|
|
stack.enter_context(mock.patch(
|
|
"core.tool_registry._external_system_status_available",
|
|
return_value=False,
|
|
))
|
|
stack.enter_context(mock.patch(
|
|
"core.tool_registry._external_systems_available",
|
|
return_value=False,
|
|
))
|
|
stack.enter_context(mock.patch(
|
|
"core.tool_registry.smtp_configured", return_value=False,
|
|
))
|
|
stack.enter_context(mock.patch(
|
|
"core.tool_registry.wechat_push_available", return_value=False,
|
|
))
|
|
stack.enter_context(mock.patch(
|
|
"core.tool_registry.lfasr_configured", return_value=False,
|
|
))
|
|
stack.enter_context(mock.patch(
|
|
"core.tool_registry.BochaConfig.load", return_value=None,
|
|
))
|
|
return build_tools(ToolContext(
|
|
tool_base=root,
|
|
ur_path=root,
|
|
working_dir_path=root,
|
|
task_id=uuid.uuid4(),
|
|
uid=uuid.uuid4(),
|
|
cfg={},
|
|
caps=SimpleNamespace(
|
|
enable_run_python=False,
|
|
native_image_input=native_image_input,
|
|
),
|
|
skills=SimpleNamespace(skills={}),
|
|
cancel_check=None,
|
|
scheduled_run=True,
|
|
deferred_actions=SimpleNamespace(),
|
|
ark_cfg=ark,
|
|
img_provider="",
|
|
img_key="",
|
|
img_cfg=None,
|
|
img_provider_cfg=None,
|
|
video_variant="",
|
|
office_to_pdf_available=False,
|
|
))
|
|
|
|
text_only = build(False)
|
|
native = build(True)
|
|
self.assertIn("look_at_image", text_only)
|
|
self.assertIn("read_document", text_only)
|
|
self.assertNotIn("look_at_image", native)
|
|
self.assertIn("read_document", native)
|
|
|
|
def _execute_and_question(self, question=None) -> str:
|
|
captured = {}
|
|
|
|
def fake_chat(_cfg, _endpoint, body, **_kwargs):
|
|
captured["question"] = body["messages"][0]["content"][0]["text"]
|
|
return {
|
|
"choices": [{"finish_reason": "stop", "message": {"content": "ok"}}],
|
|
"usage": {},
|
|
}, ""
|
|
|
|
with mock.patch(
|
|
"tools.look_at_image.load_image_as_data_url",
|
|
return_value=("data:image/png;base64,AA==", "image.png", ""),
|
|
), mock.patch("tools.look_at_image.ark_chat_with_retry", side_effect=fake_chat), \
|
|
mock.patch("tools.look_at_image.record_usage_safe", return_value=0):
|
|
self._tool().execute("image.png", question=question)
|
|
return captured["question"]
|
|
|
|
def test_specific_question_is_forwarded_unchanged(self):
|
|
question = "只读出仪表盘当前数值,不要描述其他内容。"
|
|
self.assertEqual(self._execute_and_question(question), question)
|
|
|
|
def test_missing_question_uses_concise_compatibility_fallback(self):
|
|
self.assertEqual(self._execute_and_question(), _DEFAULT_QUESTION)
|
|
self.assertIn("简洁", _DEFAULT_QUESTION)
|
|
self.assertIn("不要主动全文 OCR", _DEFAULT_QUESTION)
|
|
self.assertNotIn("完整描述画面内容", _DEFAULT_QUESTION)
|
|
self.assertNotIn("把其中的数据、坐标轴、图例", _DEFAULT_QUESTION)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|