from django.utils import timezone from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse from agent_core.orchestrator import run_agent from agent_core.results import AgentResult from apps.audit.services import create_audit_log, create_notification_record from apps.documents.models import SubmissionBatch, UploadedDocument from apps.scenarios.services import get_scenario from .forms import ChatForm from .models import Conversation def index(request): conversations = Conversation.objects.all() if conversations.exists(): return redirect("chat:detail", conversation_id=conversations.first().conversation_id) return render( request, "chat/index.html", { "conversation": None, "conversations": [], "form": ChatForm(), "documents": [], "result": None, "audit_log": None, "node_results": [], "active_node": None, }, ) def detail(request, conversation_id: str): conversation = get_object_or_404(Conversation, conversation_id=conversation_id) batch = SubmissionBatch.objects.filter(batch_id=conversation.batch_id).first() documents = UploadedDocument.objects.filter(batch=batch) form = ChatForm(request.POST or None, documents=documents) result = None audit_log = None active_node = None task_modes = [ {"name": "目录汇总", "description": "汇总文件、页数、章节点和目录型文档。"}, {"name": "完整性检查", "description": "对照法规模板检查齐套性、缺失项和错放项。"}, {"name": "字段抽取", "description": "抽取产品名称、规格、适用范围、储存条件等核心字段。"}, {"name": "一致性核查", "description": "比较申请表、说明书和产品列表的字段一致性。"}, {"name": "综合风险报告", "description": "形成高优先级问题、建议动作和责任人通知。"}, ] if request.method == "POST" and form.is_valid(): scenario = get_scenario("document_review") message = form.cleaned_data["message"] try: result = run_agent( scenario, message, options={ "conversation_id": conversation.conversation_id, "batch_id": conversation.batch_id, "product_name": conversation.product_name, "document_ids": form.cleaned_data["document_ids"], }, ) except Exception as exc: result = AgentResult(status="failed", error=str(exc), answer="") audit_log = create_audit_log( "document_review", "注册审核智能体", message, result, batch_id=conversation.batch_id, conversation_id=conversation.conversation_id, product_name=conversation.product_name, ) _apply_agent_result_to_conversation(conversation, result) _persist_notification_records( result, web_detail_url=reverse("audit:detail", args=[audit_log.id]), ) active_node = "risk" conversation.refresh_from_db() workspace_summary = _build_workspace_summary(conversation, batch) return render( request, "chat/index.html", { "conversation": conversation, "conversations": Conversation.objects.all(), "batch": batch, "form": form, "documents": documents, "document_count": documents.count(), "result": result, "audit_log": audit_log, "task_modes": task_modes, "node_results": conversation.node_results, "active_node": active_node, "workspace_summary": workspace_summary, }, ) def _persist_notification_records(result: AgentResult, *, web_detail_url: str = "") -> None: payload = result.notification_payload or {} owners = payload.get("owners") or [] if not owners: return for owner in owners: create_notification_record( batch_id=payload.get("batch_id", ""), conversation_id=payload.get("conversation_id", ""), product_name=payload.get("product_name", ""), trigger_source="agent_execution", notify_reason=payload.get("notify_reason", "task_completed"), owner_role=owner.get("owner_role", ""), feishu_user_id=owner.get("feishu_user_id", ""), message_status="sent" if result.status == "success" else "failed", web_detail_url=web_detail_url, receipt={"status": result.status}, ) def _build_workspace_summary(conversation: Conversation, batch: SubmissionBatch | None) -> dict: node_status_map = {node.get("label"): node.get("status", "") for node in conversation.node_results} risk_status = node_status_map.get("风险预警", "待处理") notify_status = node_status_map.get("飞书通知", "待处理") export_status = node_status_map.get("Word 回填导出", "待处理") highest_risk_level = "高" if risk_status in {"已阻断", "待复核"} else "中" export_allowed = "否" if risk_status in {"已阻断", "待复核"} else "是" return { "highest_risk_level": highest_risk_level, "export_allowed": export_allowed, "notify_status": notify_status, "export_status": export_status, "file_count": batch.file_count if batch else 0, "page_count": batch.page_count if batch else 0, } def _apply_agent_result_to_conversation(conversation: Conversation, result: AgentResult) -> None: conversation.task_status = result.status if result.node_results: conversation.node_results = result.node_results conversation.latest_summary = { "answer": result.answer, "status": result.status, "error": result.error, "notification_payload": result.notification_payload, } conversation.last_run_at = timezone.now() conversation.save( update_fields=[ "task_status", "node_results", "latest_summary", "last_run_at", "updated_at", ] )