fix(avatar): ground replies in recognized images
This commit is contained in:
@@ -12,6 +12,7 @@ from main import app
|
||||
from models import ChatAttachment
|
||||
from routers.chat import (
|
||||
ChatIn,
|
||||
_answer_denies_available_image,
|
||||
_attachment_contexts,
|
||||
_load_chat_attachments,
|
||||
_resolve_reply,
|
||||
@@ -274,6 +275,47 @@ def test_image_context_keeps_standard_answer_authoritative():
|
||||
assert "标准答题对中的事实优先级高于图片资料" in system
|
||||
|
||||
|
||||
def test_ready_image_context_never_returns_whole_image_access_denial():
|
||||
avatar = SimpleNamespace(
|
||||
id="avatar-vision",
|
||||
name="测试分身",
|
||||
description="产品顾问",
|
||||
config={},
|
||||
)
|
||||
model = Mock(return_value="抱歉,我无法查看或识别图片,请重新上传。")
|
||||
result = _resolve_reply(
|
||||
None,
|
||||
avatar,
|
||||
"请看看这张图片",
|
||||
[],
|
||||
qa_pairs=[],
|
||||
search_fn=Mock(return_value=[]),
|
||||
model_client=model,
|
||||
image_contexts=[{
|
||||
"id": "attachment",
|
||||
"filename": "report.jpg",
|
||||
"category": "medical_document",
|
||||
"summary": "一份耳鼻喉科门诊记录",
|
||||
"extractedText": "主诉:咽痛三天",
|
||||
"structuredData": {"key_facts": ["主诉为咽痛三天"]},
|
||||
"warning": "请核对原始资料",
|
||||
}],
|
||||
)
|
||||
|
||||
assert result["source"] == "vision"
|
||||
assert "一份耳鼻喉科门诊记录" in result["answer"]
|
||||
assert "主诉为咽痛三天" in result["answer"]
|
||||
assert "无法查看" not in result["answer"]
|
||||
system = model.call_args.kwargs["messages"][0]["content"]
|
||||
assert "当前会话图片已经成功读取" in system
|
||||
assert "禁止声称无法查看" in system
|
||||
|
||||
|
||||
def test_image_denial_detector_allows_uncertain_field_in_ready_image():
|
||||
assert _answer_denies_available_image("我无法查看这张图片") is True
|
||||
assert _answer_denies_available_image("图片中患者姓名无法辨认,主诉为咽痛三天。") is False
|
||||
|
||||
|
||||
def test_attachment_context_does_not_expose_internal_fields():
|
||||
row = SimpleNamespace(
|
||||
id="attachment",
|
||||
|
||||
@@ -363,6 +363,54 @@ async def test_followup_text_recovers_recent_image_recorded_without_task(service
|
||||
db.close()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_explicit_followup_reuses_handled_image_within_two_days(service_context):
|
||||
session_factory, service, boxim, clock = service_context
|
||||
await service.poll_and_process_messages()
|
||||
image_message = {
|
||||
"id": 116,
|
||||
"localId": 116,
|
||||
"sendId": 200,
|
||||
"recvId": 100,
|
||||
"sendTime": clock.millis(),
|
||||
"type": 1,
|
||||
"content": json.dumps({"originUrl": "https://cdn.example/handled-case.png"}),
|
||||
}
|
||||
boxim.messages.append(image_message)
|
||||
await service.poll_messages()
|
||||
|
||||
db = session_factory()
|
||||
try:
|
||||
image_task = db.query(TakeoverReplyTask).filter_by(trigger_message_id="116").one()
|
||||
image_task.status = "sent"
|
||||
image_task.sent_at = clock.now()
|
||||
db.commit()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
clock.advance(47 * 60 * 60)
|
||||
boxim.messages.append(
|
||||
{
|
||||
"id": 117,
|
||||
"localId": 117,
|
||||
"sendId": 200,
|
||||
"recvId": 100,
|
||||
"sendTime": clock.millis(),
|
||||
"type": 0,
|
||||
"content": "重新看一下刚才那张病例图片",
|
||||
}
|
||||
)
|
||||
await service.poll_messages()
|
||||
|
||||
db = session_factory()
|
||||
try:
|
||||
task = db.query(TakeoverReplyTask).filter_by(trigger_message_id="117").one()
|
||||
assert task.source_message_ids == ["116", "117"]
|
||||
assert task.prompt == "请看看这张图片。\n重新看一下刚才那张病例图片"
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_invalid_image_message_is_recorded_but_not_scheduled(service_context):
|
||||
session_factory, service, boxim, clock = service_context
|
||||
|
||||
Reference in New Issue
Block a user