feat: 增强审核智能体页目录与一致性能力卡展示
This commit is contained in:
@@ -87,6 +87,7 @@ def detail(request, conversation_id: str):
|
|||||||
workspace_summary = _build_workspace_summary(conversation, batch)
|
workspace_summary = _build_workspace_summary(conversation, batch)
|
||||||
conversation_context = _build_conversation_context(conversation, batch, workspace_summary)
|
conversation_context = _build_conversation_context(conversation, batch, workspace_summary)
|
||||||
prompt_templates = _build_prompt_templates()
|
prompt_templates = _build_prompt_templates()
|
||||||
|
analysis_card = _build_analysis_card(result, conversation)
|
||||||
export_card = _build_export_card(result, conversation)
|
export_card = _build_export_card(result, conversation)
|
||||||
risk_card = _build_risk_card(result, conversation)
|
risk_card = _build_risk_card(result, conversation)
|
||||||
notify_card = _build_notify_card(result, conversation)
|
notify_card = _build_notify_card(result, conversation)
|
||||||
@@ -109,6 +110,7 @@ def detail(request, conversation_id: str):
|
|||||||
"workspace_summary": workspace_summary,
|
"workspace_summary": workspace_summary,
|
||||||
"conversation_context": conversation_context,
|
"conversation_context": conversation_context,
|
||||||
"prompt_templates": prompt_templates,
|
"prompt_templates": prompt_templates,
|
||||||
|
"analysis_card": analysis_card,
|
||||||
"upload_form": upload_form,
|
"upload_form": upload_form,
|
||||||
"export_card": export_card,
|
"export_card": export_card,
|
||||||
"risk_card": risk_card,
|
"risk_card": risk_card,
|
||||||
@@ -274,6 +276,55 @@ def _build_prompt_templates() -> list[str]:
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _build_analysis_card(result: AgentResult | None, conversation: Conversation) -> dict:
|
||||||
|
structured_output = {}
|
||||||
|
if result and result.structured_output:
|
||||||
|
structured_output = result.structured_output
|
||||||
|
else:
|
||||||
|
structured_output = (conversation.latest_summary or {}).get("structured_output") or {}
|
||||||
|
output_type = structured_output.get("output_type")
|
||||||
|
if output_type == "registration_overview_report":
|
||||||
|
return {
|
||||||
|
"kind": "overview",
|
||||||
|
"title": "目录汇总能力卡",
|
||||||
|
"summary": structured_output.get("product_name", ""),
|
||||||
|
"stats": [
|
||||||
|
{"label": "资料文件数", "value": structured_output.get("file_count", 0)},
|
||||||
|
{"label": "总页数", "value": structured_output.get("total_page_count", 0)},
|
||||||
|
],
|
||||||
|
"items": structured_output.get("chapter_summary") or [],
|
||||||
|
"warnings": structured_output.get("warnings") or [],
|
||||||
|
}
|
||||||
|
if output_type == "registration_completeness_report":
|
||||||
|
return {
|
||||||
|
"kind": "completeness",
|
||||||
|
"title": "完整性检查能力卡",
|
||||||
|
"summary": structured_output.get("summary", ""),
|
||||||
|
"stats": [{"label": "风险等级", "value": structured_output.get("risk_level", "-")}],
|
||||||
|
"items": structured_output.get("missing_items") or [],
|
||||||
|
"warnings": structured_output.get("misplaced_items") or [],
|
||||||
|
}
|
||||||
|
if output_type == "registration_field_extraction_report":
|
||||||
|
return {
|
||||||
|
"kind": "field_extraction",
|
||||||
|
"title": "字段抽取能力卡",
|
||||||
|
"summary": structured_output.get("summary", ""),
|
||||||
|
"stats": [{"label": "字段数", "value": len(structured_output.get("field_items") or [])}],
|
||||||
|
"items": structured_output.get("field_items") or [],
|
||||||
|
"warnings": structured_output.get("low_confidence_items") or [],
|
||||||
|
}
|
||||||
|
if output_type == "registration_consistency_report":
|
||||||
|
return {
|
||||||
|
"kind": "consistency",
|
||||||
|
"title": "一致性核查能力卡",
|
||||||
|
"summary": structured_output.get("summary", ""),
|
||||||
|
"stats": [{"label": "风险等级", "value": structured_output.get("risk_level", "-")}],
|
||||||
|
"items": structured_output.get("conflict_items") or [],
|
||||||
|
"warnings": structured_output.get("mixed_document_risks") or [],
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
def _build_export_card(result: AgentResult | None, conversation: Conversation) -> dict:
|
def _build_export_card(result: AgentResult | None, conversation: Conversation) -> dict:
|
||||||
"""
|
"""
|
||||||
统一组装 Word 导出能力卡上下文。
|
统一组装 Word 导出能力卡上下文。
|
||||||
|
|||||||
@@ -115,8 +115,81 @@
|
|||||||
|
|
||||||
<article class="panel">
|
<article class="panel">
|
||||||
<h2 class="section-title">节点式结果</h2>
|
<h2 class="section-title">节点式结果</h2>
|
||||||
{% if export_card or risk_card or notify_card %}
|
{% if analysis_card or export_card or risk_card or notify_card %}
|
||||||
<div class="stack">
|
<div class="stack">
|
||||||
|
{% if analysis_card %}
|
||||||
|
<div class="detail-item">
|
||||||
|
<strong>{{ analysis_card.title }}</strong>
|
||||||
|
{% if analysis_card.summary %}
|
||||||
|
<div>{{ analysis_card.summary }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel" style="padding: 14px;">
|
||||||
|
<h3 class="section-title" style="font-size: 1rem;">摘要指标</h3>
|
||||||
|
<div class="badge-row">
|
||||||
|
{% for item in analysis_card.stats %}
|
||||||
|
<span class="pill pill-accent">{{ item.label }}:{{ item.value }}</span>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel" style="padding: 14px;">
|
||||||
|
<h3 class="section-title" style="font-size: 1rem;">节点结果明细</h3>
|
||||||
|
<ul class="detail-list">
|
||||||
|
{% if analysis_card.kind == "overview" %}
|
||||||
|
{% for item in analysis_card.items %}
|
||||||
|
<li class="detail-item">{{ item.chapter_code }} / {{ item.document_count }} 份</li>
|
||||||
|
{% empty %}
|
||||||
|
<li class="detail-item">当前无目录汇总结果。</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% elif analysis_card.kind == "consistency" %}
|
||||||
|
{% for item in analysis_card.items %}
|
||||||
|
<li class="detail-item">
|
||||||
|
<strong>{{ item.field_name|default:"冲突字段" }}</strong>
|
||||||
|
<div>{{ item.issue|default:item }}</div>
|
||||||
|
</li>
|
||||||
|
{% empty %}
|
||||||
|
<li class="detail-item">当前无一致性冲突。</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% elif analysis_card.kind == "field_extraction" %}
|
||||||
|
{% for item in analysis_card.items %}
|
||||||
|
<li class="detail-item">
|
||||||
|
<strong>{{ item.field_name|default:item.name }}</strong>
|
||||||
|
<div>{{ item.field_value|default:item.value }}</div>
|
||||||
|
</li>
|
||||||
|
{% empty %}
|
||||||
|
<li class="detail-item">当前无抽取字段。</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
{% for item in analysis_card.items %}
|
||||||
|
<li class="detail-item">{{ item }}</li>
|
||||||
|
{% empty %}
|
||||||
|
<li class="detail-item">当前无明细结果。</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel" style="padding: 14px;">
|
||||||
|
<h3 class="section-title" style="font-size: 1rem;">提示与异常</h3>
|
||||||
|
<ul class="detail-list">
|
||||||
|
{% for item in analysis_card.warnings %}
|
||||||
|
<li class="detail-item">
|
||||||
|
{% if analysis_card.kind == "field_extraction" %}
|
||||||
|
<strong>{{ item.field_name|default:item.name|default:"低置信度字段" }}</strong>
|
||||||
|
<div>{{ item.field_value|default:item.value|default:item }}</div>
|
||||||
|
{% else %}
|
||||||
|
{{ item }}
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
{% empty %}
|
||||||
|
<li class="detail-item">当前无额外提示。</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if risk_card %}
|
{% if risk_card %}
|
||||||
<div class="detail-item">
|
<div class="detail-item">
|
||||||
<strong>风险预警能力卡</strong>
|
<strong>风险预警能力卡</strong>
|
||||||
|
|||||||
@@ -406,6 +406,66 @@ def test_chat_page_shows_top_context_and_recommended_prompts(client, db):
|
|||||||
assert "请给出当前资料包的高风险项、责任人和整改建议" in content
|
assert "请给出当前资料包的高风险项、责任人和整改建议" in content
|
||||||
|
|
||||||
|
|
||||||
|
def test_chat_page_shows_overview_card_from_conversation_summary(client, db):
|
||||||
|
batch, conversation = _create_conversation_with_batch()
|
||||||
|
conversation.latest_summary = {
|
||||||
|
"structured_output": {
|
||||||
|
"output_type": "registration_overview_report",
|
||||||
|
"batch_id": batch.batch_id,
|
||||||
|
"product_name": batch.product_name,
|
||||||
|
"file_count": 2,
|
||||||
|
"total_page_count": 12,
|
||||||
|
"chapter_summary": [
|
||||||
|
{"chapter_code": "CH1", "document_count": 2},
|
||||||
|
],
|
||||||
|
"documents": [
|
||||||
|
{
|
||||||
|
"original_name": "说明书.md",
|
||||||
|
"chapter_code": "CH1",
|
||||||
|
"page_count": 12,
|
||||||
|
"document_role": "product_manual",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"warnings": ["Word 页数待复核"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conversation.save(update_fields=["latest_summary", "updated_at"])
|
||||||
|
|
||||||
|
response = client.get(reverse("chat:detail", args=[conversation.conversation_id]))
|
||||||
|
|
||||||
|
content = response.content.decode("utf-8")
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert "目录汇总能力卡" in content
|
||||||
|
assert "资料文件数" in content
|
||||||
|
assert "CH1 / 2 份" in content
|
||||||
|
assert "Word 页数待复核" in content
|
||||||
|
|
||||||
|
|
||||||
|
def test_chat_page_shows_consistency_card_from_conversation_summary(client, db):
|
||||||
|
batch, conversation = _create_conversation_with_batch()
|
||||||
|
conversation.latest_summary = {
|
||||||
|
"structured_output": {
|
||||||
|
"output_type": "registration_consistency_report",
|
||||||
|
"summary": "检测到跨文档字段冲突。",
|
||||||
|
"conflict_items": [
|
||||||
|
{"field_name": "产品名称", "issue": "申请表与说明书不一致"},
|
||||||
|
],
|
||||||
|
"mixed_document_risks": ["疑似混入其他产品资料"],
|
||||||
|
"risk_level": "high",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conversation.save(update_fields=["latest_summary", "updated_at"])
|
||||||
|
|
||||||
|
response = client.get(reverse("chat:detail", args=[conversation.conversation_id]))
|
||||||
|
|
||||||
|
content = response.content.decode("utf-8")
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert "一致性核查能力卡" in content
|
||||||
|
assert "申请表与说明书不一致" in content
|
||||||
|
assert "疑似混入其他产品资料" in content
|
||||||
|
assert "high" in content
|
||||||
|
|
||||||
|
|
||||||
def test_chat_page_blocks_formal_export_when_word_export_node_is_blocked(client, db):
|
def test_chat_page_blocks_formal_export_when_word_export_node_is_blocked(client, db):
|
||||||
batch, conversation = _create_conversation_with_batch()
|
batch, conversation = _create_conversation_with_batch()
|
||||||
conversation.node_results = [
|
conversation.node_results = [
|
||||||
|
|||||||
Reference in New Issue
Block a user