mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-06-25 17:54:43 +08:00
102 lines
3.8 KiB
Python
102 lines
3.8 KiB
Python
from unittest.mock import AsyncMock, patch
|
|
|
|
from app.agent import MoviePilotAgent
|
|
from app.agent.llm import AgentCapabilityManager, LLMHelper
|
|
from app.chain.message import MessageChain
|
|
from app.core.config import settings
|
|
from app.schemas.types import MessageChannel
|
|
|
|
|
|
def test_llm_supports_image_input_uses_model_catalog_text_only(monkeypatch):
|
|
"""内置目录明确为纯文本模型时,应自动关闭图片输入。"""
|
|
monkeypatch.setattr(settings, "LLM_SUPPORT_IMAGE_INPUT", True)
|
|
|
|
assert not LLMHelper.supports_image_input(
|
|
provider="minimax",
|
|
model="MiniMax-M2.7",
|
|
)
|
|
|
|
|
|
def test_llm_supports_image_input_keeps_known_vision_model(monkeypatch):
|
|
"""内置目录明确为视觉模型时,应允许图片输入。"""
|
|
monkeypatch.setattr(settings, "LLM_SUPPORT_IMAGE_INPUT", True)
|
|
|
|
assert LLMHelper.supports_image_input(
|
|
provider="zhipuai",
|
|
model="glm-5v-turbo",
|
|
)
|
|
|
|
|
|
def test_llm_supports_image_input_keeps_unknown_model_override(monkeypatch):
|
|
"""未知自定义模型保持用户开关语义,避免误伤私有视觉模型。"""
|
|
monkeypatch.setattr(settings, "LLM_SUPPORT_IMAGE_INPUT", True)
|
|
|
|
assert LLMHelper.supports_image_input(
|
|
provider="custom-provider",
|
|
model="custom-vlm-model",
|
|
)
|
|
|
|
|
|
def test_agent_capability_manager_delegates_image_support():
|
|
"""Agent 能力管理器应复用统一的模型图片能力判断。"""
|
|
with patch.object(LLMHelper, "supports_image_input", return_value=False) as supports:
|
|
assert not AgentCapabilityManager.supports_image_input()
|
|
|
|
supports.assert_called_once_with()
|
|
|
|
|
|
def test_handle_ai_message_routes_text_only_model_images_to_files(monkeypatch):
|
|
"""纯文本模型收到图片消息时,应降级为文件附件而非 image_url 内容块。"""
|
|
chain = MessageChain()
|
|
monkeypatch.setattr(settings, "AI_AGENT_ENABLE", True)
|
|
monkeypatch.setattr(settings, "LLM_SUPPORT_IMAGE_INPUT", True)
|
|
monkeypatch.setattr(settings, "LLM_PROVIDER", "minimax")
|
|
monkeypatch.setattr(settings, "LLM_MODEL", "MiniMax-M2.7")
|
|
|
|
with patch.object(
|
|
chain, "_get_or_create_session_id", return_value="session-1"
|
|
), patch.object(
|
|
chain, "_download_attachments_to_data_urls"
|
|
) as download_images, patch.object(
|
|
chain,
|
|
"_prepare_agent_files",
|
|
return_value=[
|
|
{
|
|
"name": "image_1.jpg",
|
|
"mime_type": "image/jpeg",
|
|
"local_path": "/tmp/image_1.jpg",
|
|
"status": "ready",
|
|
}
|
|
],
|
|
) as prepare_files, patch(
|
|
"app.chain.message.agent_manager.process_message", new_callable=AsyncMock
|
|
) as process_message, patch(
|
|
"app.chain.message.asyncio.run_coroutine_threadsafe",
|
|
side_effect=lambda coro, _loop: coro.close(),
|
|
):
|
|
chain._handle_ai_message(
|
|
text="/ai 帮我看看这张图",
|
|
channel=MessageChannel.Telegram,
|
|
source="telegram-test",
|
|
userid="10001",
|
|
username="tester",
|
|
images=["tg://file_id/image-1"],
|
|
)
|
|
|
|
download_images.assert_not_called()
|
|
prepare_files.assert_called_once()
|
|
assert prepare_files.call_args.kwargs["files"][0].ref == "tg://file_id/image-1"
|
|
assert process_message.call_args.kwargs["images"] is None
|
|
assert process_message.call_args.kwargs["files"][0]["local_path"] == "/tmp/image_1.jpg"
|
|
|
|
|
|
def test_unsupported_image_error_recognizes_vlm_text_only_message():
|
|
"""兼容端点返回 not a VLM 时,应识别为图片输入能力错误。"""
|
|
error = Exception(
|
|
"Error code: 400 - {'code': 20041, 'message': "
|
|
"'The model is not a VLM (Vision Language Model). "
|
|
"Please use text-only prompts.'}"
|
|
)
|
|
|
|
assert MoviePilotAgent._is_unsupported_image_input_error(error)
|