From e1a130177c436a85640a8d88255c08ed6998c14b Mon Sep 17 00:00:00 2001 From: Nelson <1475262689@qq.com> Date: Thu, 9 Jul 2026 10:44:52 +0800 Subject: [PATCH] Add AI request audit detail drawer --- .../apps/admin-web/src/App.vue | 80 +++++++++++++++---- .../apps/admin-web/src/services/api.ts | 1 + .../apps/admin-web/src/styles.css | 24 ++++++ .../apps/backend/app/api/admin_records.py | 14 +++- 4 files changed, 103 insertions(+), 16 deletions(-) diff --git a/ai_knowledge_base_v2/apps/admin-web/src/App.vue b/ai_knowledge_base_v2/apps/admin-web/src/App.vue index 0ccac4a..6196709 100644 --- a/ai_knowledge_base_v2/apps/admin-web/src/App.vue +++ b/ai_knowledge_base_v2/apps/admin-web/src/App.vue @@ -34,6 +34,8 @@ const operationLogs = ref[]>([]); const promptContent = ref(""); const chatDetail = ref(null); const chatDetailOpen = ref(false); +const selectedAiLog = ref(null); +const aiLogDetailOpen = ref(false); const recordTab = ref("chats"); const editingModelId = ref(null); const editingKnowledgeId = ref(null); @@ -960,6 +962,11 @@ async function openChatDetail(row: ChatRecord) { chatDetailOpen.value = true; } +async function openAiLogDetail(row: AiLogRecord) { + selectedAiLog.value = await api.aiLogDetail(row.id); + aiLogDetailOpen.value = true; +} + async function exportChats() { await api.exportChats(buildChatQuery()); } @@ -1463,29 +1470,24 @@ function buildChatQuery() { - - - + + + + + + @@ -1560,5 +1562,53 @@ function buildChatQuery() { + + + + diff --git a/ai_knowledge_base_v2/apps/admin-web/src/services/api.ts b/ai_knowledge_base_v2/apps/admin-web/src/services/api.ts index ab61707..d6fb76f 100644 --- a/ai_knowledge_base_v2/apps/admin-web/src/services/api.ts +++ b/ai_knowledge_base_v2/apps/admin-web/src/services/api.ts @@ -139,6 +139,7 @@ export const api = { exportChats: (query: ChatRecordQuery = {}) => download(`/admin/chat/export${queryString(query)}`, "chat_records.csv"), aiLogs: (query: { sessionId?: number; userId?: number; status?: string } = {}) => request(`/admin/ai-log/list${queryString(query)}`), + aiLogDetail: (id: number) => request(`/admin/ai-log/${id}`), operationLogs: () => request[]>("/admin/log/list"), clearFeishuCache: () => request<{ cleared: number; message: string }>("/admin/feishu/cache/clear", { method: "POST", body: "{}" }), diff --git a/ai_knowledge_base_v2/apps/admin-web/src/styles.css b/ai_knowledge_base_v2/apps/admin-web/src/styles.css index 135ea72..7d0cfe2 100644 --- a/ai_knowledge_base_v2/apps/admin-web/src/styles.css +++ b/ai_knowledge_base_v2/apps/admin-web/src/styles.css @@ -712,6 +712,19 @@ textarea { font-size: 13px; } +.audit-detail-grid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 10px 14px; + margin: 14px 0; + padding: 12px; + border: 1px solid #dce8e4; + border-radius: 6px; + background: #fbfdfc; + color: #40524b; + font-size: 13px; +} + .retrieval-chunks { display: grid; gap: 12px; @@ -743,6 +756,13 @@ textarea { font-size: 13px; } +.chunk-title { + margin-bottom: 8px; + color: #203832; + font-weight: 600; + line-height: 1.5; +} + .retrieval-chunk pre { max-height: 260px; margin: 0; @@ -775,6 +795,10 @@ textarea { grid-template-columns: 1fr; } + .audit-detail-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .agent-preview-panel { height: 620px; } diff --git a/ai_knowledge_base_v2/apps/backend/app/api/admin_records.py b/ai_knowledge_base_v2/apps/backend/app/api/admin_records.py index 3cae58c..007667f 100644 --- a/ai_knowledge_base_v2/apps/backend/app/api/admin_records.py +++ b/ai_knowledge_base_v2/apps/backend/app/api/admin_records.py @@ -6,7 +6,7 @@ from datetime import datetime from io import StringIO from typing import Any -from fastapi import APIRouter, Depends, Query +from fastapi import APIRouter, Depends, HTTPException, Query, status from fastapi.responses import Response from sqlalchemy import exists, or_, select from sqlalchemy.orm import Session @@ -160,6 +160,18 @@ def ai_logs( return api_success([_ai_log_dict(item) for item in logs]) +@router.get("/ai-log/{log_id}") +def ai_log_detail( + log_id: int, + db: Session = Depends(get_db), + current_admin: Admin = Depends(get_current_admin), +) -> dict: + log = db.get(AiRequestLog, log_id) + if log is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="AI 请求日志不存在") + return api_success(_ai_log_dict(log, include_prompt=True)) + + def _chat_query( *, keyword: str,