feat: 增强审核智能体页目录与一致性能力卡展示

This commit is contained in:
2026-06-04 03:03:37 +08:00
parent a7cee4aa27
commit af36ec460d
3 changed files with 185 additions and 1 deletions

View File

@@ -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 导出能力卡上下文。

View File

@@ -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>

View File

@@ -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 = [