refactor: 下沉 Word 导出执行链到 chat 服务层
This commit is contained in:
@@ -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}"
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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 = [
|
||||||
|
|||||||
Reference in New Issue
Block a user