refactor: 下沉 Word 导出执行链到 chat 服务层

This commit is contained in:
2026-06-04 04:44:47 +08:00
parent 47f887647b
commit e701b4502e
3 changed files with 87 additions and 45 deletions

View File

@@ -70,6 +70,51 @@ def execute_conversation_agent(
return result, audit_log 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: def _generate_conversation_id() -> str:
return f"conv-{Conversation.objects.count() + 1:03d}" return f"conv-{Conversation.objects.count() + 1:03d}"

View File

@@ -4,14 +4,12 @@ from django.urls import reverse
from django.views.decorators.http import require_POST from django.views.decorators.http import require_POST
from agent_core.results import AgentResult from agent_core.results import AgentResult
from apps.audit.services import create_audit_log
from apps.documents.models import SubmissionBatch, UploadedDocument from apps.documents.models import SubmissionBatch, UploadedDocument
from apps.documents.services import append_documents_to_batch 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 .forms import ChatForm, ConversationUploadForm
from .models import Conversation from .models import Conversation
from .services import execute_conversation_agent from .services import execute_conversation_agent, execute_conversation_export
RISK_LEVEL_DISPLAY = { RISK_LEVEL_DISPLAY = {
"high": "", "high": "",
@@ -159,53 +157,13 @@ def upload_documents(request, conversation_id: str):
def export_word(request, conversation_id: str): def export_word(request, conversation_id: str):
conversation = get_object_or_404(Conversation, conversation_id=conversation_id) conversation = get_object_or_404(Conversation, conversation_id=conversation_id)
batch = get_object_or_404(SubmissionBatch, batch_id=conversation.batch_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: try:
export_report = generate_registration_export( execute_conversation_export(
batch=batch, batch=batch,
conversation=conversation, 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 导出文件。") messages.success(request, "已生成新的 Word 导出文件。")
except Exception as exc: 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}") messages.error(request, f"Word 导出失败:{exc}")
return redirect("chat:detail", conversation_id=conversation.conversation_id) return redirect("chat:detail", conversation_id=conversation.conversation_id)

View File

@@ -8,7 +8,11 @@ from agent_core.results import AgentResult
from apps.audit.models import AgentAuditLog from apps.audit.models import AgentAuditLog
from apps.audit.models import NotificationRecord from apps.audit.models import NotificationRecord
from apps.chat.models import Conversation 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 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}/" 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): def test_chat_page_shows_upload_entry_and_dynamic_context_cards(client, db):
batch, conversation = _create_conversation_with_batch() batch, conversation = _create_conversation_with_batch()
conversation.node_results = [ conversation.node_results = [