From e701b4502ed2f401eb95c4589c32212452e42175 Mon Sep 17 00:00:00 2001 From: bruce Date: Thu, 4 Jun 2026 04:44:47 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=B8=8B=E6=B2=89=20Word=20?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E6=89=A7=E8=A1=8C=E9=93=BE=E5=88=B0=20chat?= =?UTF-8?q?=20=E6=9C=8D=E5=8A=A1=E5=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat/services.py | 45 ++++++++++++++++++++++++++++++++++++++++++ apps/chat/views.py | 46 ++----------------------------------------- tests/test_chat.py | 41 +++++++++++++++++++++++++++++++++++++- 3 files changed, 87 insertions(+), 45 deletions(-) diff --git a/apps/chat/services.py b/apps/chat/services.py index 4ed86a7..102abc3 100644 --- a/apps/chat/services.py +++ b/apps/chat/services.py @@ -70,6 +70,51 @@ def execute_conversation_agent( return result, audit_log +def execute_conversation_export(*, batch, conversation: Conversation) -> dict: + """ + 在服务层串起 Word 导出、会话摘要更新和审计留痕。 + + View 只负责提示成功/失败消息,不直接承载导出编排细节。 + """ + from .export_service import ( + generate_registration_export, + update_conversation_with_export_report, + ) + + upstream_summary = ( + (conversation.latest_summary or {}).get("upstream_structured_output") + or (conversation.latest_summary or {}).get("structured_output") + or {} + ) + export_report = generate_registration_export( + batch=batch, + conversation=conversation, + upstream_summary=upstream_summary, + ) + update_conversation_with_export_report(conversation, export_report) + audit_log = create_audit_log( + "document_review", + "Word 回填导出", + "生成 Word 导出文件", + AgentResult( + answer=export_report.get("summary", ""), + structured_output=export_report, + status="success", + conversation_id=conversation.conversation_id, + batch_id=conversation.batch_id, + product_name=conversation.product_name, + node_results=conversation.node_results, + ), + batch_id=conversation.batch_id, + conversation_id=conversation.conversation_id, + product_name=conversation.product_name, + ) + return { + "export_report": export_report, + "audit_log": audit_log, + } + + def _generate_conversation_id() -> str: return f"conv-{Conversation.objects.count() + 1:03d}" diff --git a/apps/chat/views.py b/apps/chat/views.py index 62499db..b00a355 100644 --- a/apps/chat/views.py +++ b/apps/chat/views.py @@ -4,14 +4,12 @@ from django.urls import reverse from django.views.decorators.http import require_POST from agent_core.results import AgentResult -from apps.audit.services import create_audit_log from apps.documents.models import SubmissionBatch, UploadedDocument from apps.documents.services import append_documents_to_batch -from .export_service import generate_registration_export, update_conversation_with_export_report from .forms import ChatForm, ConversationUploadForm from .models import Conversation -from .services import execute_conversation_agent +from .services import execute_conversation_agent, execute_conversation_export RISK_LEVEL_DISPLAY = { "high": "高", @@ -159,53 +157,13 @@ def upload_documents(request, conversation_id: str): def export_word(request, conversation_id: str): conversation = get_object_or_404(Conversation, conversation_id=conversation_id) batch = get_object_or_404(SubmissionBatch, batch_id=conversation.batch_id) - upstream_summary = ( - (conversation.latest_summary or {}).get("upstream_structured_output") - or (conversation.latest_summary or {}).get("structured_output") - or {} - ) try: - export_report = generate_registration_export( + execute_conversation_export( batch=batch, conversation=conversation, - upstream_summary=upstream_summary, - ) - update_conversation_with_export_report(conversation, export_report) - create_audit_log( - "document_review", - "Word 回填导出", - "生成 Word 导出文件", - AgentResult( - answer=export_report.get("summary", ""), - structured_output=export_report, - status="success", - conversation_id=conversation.conversation_id, - batch_id=conversation.batch_id, - product_name=conversation.product_name, - node_results=conversation.node_results, - ), - batch_id=conversation.batch_id, - conversation_id=conversation.conversation_id, - product_name=conversation.product_name, ) messages.success(request, "已生成新的 Word 导出文件。") except Exception as exc: - create_audit_log( - "document_review", - "Word 回填导出", - "生成 Word 导出文件", - AgentResult( - answer="", - status="failed", - error=str(exc), - conversation_id=conversation.conversation_id, - batch_id=conversation.batch_id, - product_name=conversation.product_name, - ), - batch_id=conversation.batch_id, - conversation_id=conversation.conversation_id, - product_name=conversation.product_name, - ) messages.error(request, f"Word 导出失败:{exc}") return redirect("chat:detail", conversation_id=conversation.conversation_id) diff --git a/tests/test_chat.py b/tests/test_chat.py index 35daa87..9f39a73 100644 --- a/tests/test_chat.py +++ b/tests/test_chat.py @@ -8,7 +8,11 @@ from agent_core.results import AgentResult from apps.audit.models import AgentAuditLog from apps.audit.models import NotificationRecord from apps.chat.models import Conversation -from apps.chat.services import create_conversation_for_batch, execute_conversation_agent +from apps.chat.services import ( + create_conversation_for_batch, + execute_conversation_agent, + execute_conversation_export, +) from apps.documents.models import ExportedDocument, SubmissionBatch, UploadedDocument @@ -412,6 +416,41 @@ def test_execute_conversation_agent_runs_in_service_layer_and_persists_audit_and assert record.web_detail_url == f"/audit/{audit_log.id}/" +def test_execute_conversation_export_runs_in_service_layer_and_persists_audit(db, monkeypatch): + batch, conversation = _create_conversation_with_batch() + captured = {} + + def fake_generate_registration_export(*, batch, conversation, upstream_summary=None): + captured["batch_id"] = batch.batch_id + captured["conversation_id"] = conversation.conversation_id + captured["upstream_summary"] = upstream_summary or {} + return { + "output_type": "registration_word_export_report", + "summary": "已生成草稿导出文件。", + "template_name": "注册证导出模板", + "template_version": "V1.0", + "export_status": "draft_only", + "download_url": "/media/exports/demo.docx", + "output_file": { + "file_name": "demo.docx", + "relative_path": "exports/demo.docx", + "export_mode": "draft", + }, + } + + monkeypatch.setattr("apps.chat.export_service.generate_registration_export", fake_generate_registration_export) + + result = execute_conversation_export(batch=batch, conversation=conversation) + + conversation.refresh_from_db() + assert captured["batch_id"] == batch.batch_id + assert captured["conversation_id"] == conversation.conversation_id + assert result["export_report"]["output_type"] == "registration_word_export_report" + assert result["audit_log"].scenario_name == "Word 回填导出" + assert conversation.latest_summary["structured_output"]["download_url"] == "/media/exports/demo.docx" + assert AgentAuditLog.objects.filter(conversation_id=conversation.conversation_id).count() == 1 + + def test_chat_page_shows_upload_entry_and_dynamic_context_cards(client, db): batch, conversation = _create_conversation_with_batch() conversation.node_results = [