Files
MoviePilot/tests/test_openai_utils.py
DDSRem 2de976f6b3 Merge pull request #7050 from DDSRem-Dev/codex-comment-migration
docs: 统一全项目中文注释和结构化契约说明
2026-10-17 19:26:29 +08:00

152 lines
4.6 KiB
Python

"""
验证 OpenAI 与 Anthropic 兼容接口的多模态消息转换。
"""
from app.api.protocol import (
build_anthropic_messages,
build_completion_payload,
build_prompt,
build_responses_input,
build_session_id,
extract_text_and_images,
)
def test_extract_text_and_images() -> None:
"""
多模态消息按顺序提取文本并收集图片 URL。
"""
text, images = extract_text_and_images(
[
{"type": "text", "text": "你好"},
{"type": "image_url", "image_url": {"url": "https://example.com/a.png"}},
{"type": "text", "text": "世界"},
]
)
assert text == "你好\n世界"
assert images == ["https://example.com/a.png"]
def test_extract_text_and_images_with_input_image_and_base64_image() -> None:
"""
兼容输入图片与 Base64 图片两种载荷形式。
"""
text, images = extract_text_and_images(
[
{"type": "input_text", "text": "看图"},
{"type": "input_image", "image_url": "https://example.com/b.png"},
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": "YWJj",
},
},
]
)
assert text == "看图"
assert images == ["https://example.com/b.png", "data:image/png;base64,YWJj"]
def test_build_prompt_without_server_session_keeps_recent_history() -> None:
"""
没有服务端会话时在提示词中保留近期历史。
"""
prompt, images = build_prompt(
[
{"role": "system", "content": "回答简短"},
{"role": "user", "content": "第一句"},
{"role": "assistant", "content": "第一答"},
{"role": "user", "content": "第二句"},
],
use_server_session=False,
)
assert "系统要求:\n回答简短" in prompt
assert "对话上下文:\nuser: 第一句\nassistant: 第一答" in prompt
assert "当前用户消息:\n第二句" in prompt
assert images == []
def test_build_prompt_with_server_session_ignores_history_block() -> None:
"""
已有服务端会话时不重复附加历史消息块。
"""
prompt, _ = build_prompt(
[
{"role": "user", "content": "历史问题"},
{"role": "assistant", "content": "历史回答"},
{"role": "user", "content": "当前问题"},
],
use_server_session=True,
)
assert "对话上下文:" not in prompt
assert "当前用户消息:\n当前问题" in prompt
def test_build_prompt_accepts_image_only_user_message() -> None:
"""
只有图片的用户消息仍能构造有效提示词。
"""
prompt, images = build_prompt(
[
{
"role": "user",
"content": [{"type": "image_url", "image_url": {"url": "https://example.com/a.png"}}],
}
],
use_server_session=True,
)
assert "请结合图片内容回复" in prompt
assert images == ["https://example.com/a.png"]
def test_build_session_id_is_stable() -> None:
"""
相同用户和会话信息生成稳定会话标识。
"""
session_id = build_session_id("user-1", "openai:")
assert session_id.startswith("openai:")
assert session_id == build_session_id("user-1", "openai:")
assert session_id != build_session_id("user-2", "openai:")
def test_build_completion_payload() -> None:
"""
补全接口输出包含预期模型、消息和用量字段。
"""
payload = build_completion_payload("你好", "moviepilot-agent")
assert payload["model"] == "moviepilot-agent"
assert payload["choices"][0]["message"]["content"] == "你好"
assert payload["choices"][0]["finish_reason"] == "stop"
def test_build_responses_input() -> None:
"""
Responses 请求正确转换文本和图片输入。
"""
messages = build_responses_input(
[
{
"type": "message",
"role": "user",
"content": [{"type": "input_text", "text": "你好"}],
}
],
instructions="你要简短回答",
)
assert messages[0]["role"] == "system"
assert messages[1]["role"] == "user"
def test_build_anthropic_messages() -> None:
"""
Anthropic 请求正确转换系统指令及用户多模态消息。
"""
messages = build_anthropic_messages(
system=[{"type": "text", "text": "你是助手"}],
messages=[{"role": "user", "content": "你好"}],
)
assert messages[0]["role"] == "system"
assert messages[1]["role"] == "user"