From ae1e150d1c9750db7a47e6e3efde851c86724234 Mon Sep 17 00:00:00 2001 From: yuance <182865460@qq.com> Date: Fri, 16 Jan 2026 17:44:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=A1=E8=AE=A1=E5=86=85=E5=AE=B9=E5=8F=96?= =?UTF-8?q?=E8=AF=81=E5=8D=95=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AuditEvidenceController.java | 53 +++++ .../ai/dto/AuditEvidenceRequest.java | 31 +++ .../ai/service/AuditEvidenceService.java | 11 + .../impl/AuditEvidenceServiceImpl.java | 204 ++++++++++++++++++ 4 files changed, 299 insertions(+) create mode 100644 src/main/java/com/gxwebsoft/ai/controller/AuditEvidenceController.java create mode 100644 src/main/java/com/gxwebsoft/ai/dto/AuditEvidenceRequest.java create mode 100644 src/main/java/com/gxwebsoft/ai/service/AuditEvidenceService.java create mode 100644 src/main/java/com/gxwebsoft/ai/service/impl/AuditEvidenceServiceImpl.java diff --git a/src/main/java/com/gxwebsoft/ai/controller/AuditEvidenceController.java b/src/main/java/com/gxwebsoft/ai/controller/AuditEvidenceController.java new file mode 100644 index 0000000..5c96160 --- /dev/null +++ b/src/main/java/com/gxwebsoft/ai/controller/AuditEvidenceController.java @@ -0,0 +1,53 @@ +package com.gxwebsoft.ai.controller; + +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.ai.dto.AuditEvidenceRequest; +import com.gxwebsoft.ai.service.AuditEvidenceService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.system.entity.User; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 审计取证单控制器 + */ +@Slf4j +@Tag(name = "审计取证单") +@RestController +@RequestMapping("/api/ai/auditEvidence") +public class AuditEvidenceController extends BaseController { + + @Autowired + private AuditEvidenceService auditEvidenceService; + + /** + * 生成审计取证单 + */ + @Operation(summary = "生成审计取证单") + @PostMapping("/generate") + public ApiResult generateAuditEvidence(@RequestBody AuditEvidenceRequest request) { + try { + final User loginUser = getLoginUser(); + request.setUserName(loginUser.getUsername()); + + log.info("接收到审计取证单生成请求 - 用户: {}, 项目: {}", request.getUserName(), request.getProjectName()); + JSONObject result = auditEvidenceService.generateAuditEvidence(request); + if (Boolean.TRUE.equals(result.getBoolean("success"))) { + return success(result); + } else { + return fail(result.getString("error") != null ? result.getString("error") : "生成审计取证单失败"); + } + } catch (Exception e) { + log.error("生成审计取证单异常", e); + return fail("生成审计取证单异常: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/ai/dto/AuditEvidenceRequest.java b/src/main/java/com/gxwebsoft/ai/dto/AuditEvidenceRequest.java new file mode 100644 index 0000000..0839df0 --- /dev/null +++ b/src/main/java/com/gxwebsoft/ai/dto/AuditEvidenceRequest.java @@ -0,0 +1,31 @@ +package com.gxwebsoft.ai.dto; + +import lombok.Data; + +@Data +public class AuditEvidenceRequest { + // 基础信息 + private String caseIndex; // 案引号 + private String projectName; // 项目名称 + private String auditedTarget; // 被审计单位或个人 + private String auditMatter; // 审计事项 + private String summaryTitle; // 标题 + private String auditRecord; // 审计记录 + private String auditFinding; // 审计发现 + private String evidenceBasis; // 定性依据 + private String handling; // 处理 + private String suggestion; // 建议 + private String attachment; // 附件 + private String auditors; // 审计人员 + private String compileDate; // 编制日期 + private String providerOpinion; // 证据提供单位意见 + private String providerDate; // 证据提供日期 + private String attachmentPages; // 附件页数 + private String feedbackDeadline; // 反馈期限 + + // 历史内容(用于工作流生成) + private String history; + + // 用户信息 + private String userName; +} \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/ai/service/AuditEvidenceService.java b/src/main/java/com/gxwebsoft/ai/service/AuditEvidenceService.java new file mode 100644 index 0000000..d711f32 --- /dev/null +++ b/src/main/java/com/gxwebsoft/ai/service/AuditEvidenceService.java @@ -0,0 +1,11 @@ +package com.gxwebsoft.ai.service; + +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.ai.dto.AuditEvidenceRequest; + +public interface AuditEvidenceService { + /** + * 生成审计取证单 + */ + JSONObject generateAuditEvidence(AuditEvidenceRequest request); +} \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditEvidenceServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditEvidenceServiceImpl.java new file mode 100644 index 0000000..6970e07 --- /dev/null +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditEvidenceServiceImpl.java @@ -0,0 +1,204 @@ +package com.gxwebsoft.ai.service.impl; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.ai.dto.AuditEvidenceRequest; +import com.gxwebsoft.ai.service.AuditEvidenceService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; + +import java.util.Date; + +@Slf4j +@Service +public class AuditEvidenceServiceImpl implements AuditEvidenceService { + + // Dify工作流配置 + private static final String DIFY_WORKFLOW_URL = "http://1.14.159.185:8180/v1/workflows/run"; + private static final String DIFY_WORKFLOW_TOKEN = "Bearer app-DEhvF537rQfy6MvH9KeBKUVj"; + + @Override + public JSONObject generateAuditEvidence(AuditEvidenceRequest request) { + log.info("开始生成审计取证单 - 用户: {}, 项目: {}", request.getUserName(), request.getProjectName()); + + long startTime = System.currentTimeMillis(); + + try { + // 1. 构建完整上下文 + String knowledgeContext = buildCompleteContext(request); + + // 2. 构建工作流请求 + JSONObject requestBody = buildWorkflowRequest(knowledgeContext, request.getUserName()); + + // 3. 调用Dify工作流 + JSONObject result = callWorkflow(requestBody, "审计取证单"); + + // 4. 添加处理时间等信息 + result.put("success", true); + result.put("processing_time", (System.currentTimeMillis() - startTime) + "ms"); + result.put("generated_time", new Date().toString()); + + log.info("审计取证单生成成功 - 处理时间: {}ms", (System.currentTimeMillis() - startTime)); + + return result; + + } catch (Exception e) { + log.error("生成审计取证单失败", e); + return buildErrorResponse("生成审计取证单失败: " + e.getMessage()); + } + } + + /** + * 构建完整上下文 + */ + private String buildCompleteContext(AuditEvidenceRequest request) { + StringBuilder context = new StringBuilder(); + + // 1. 审计取证单生成要求 + context.append("## 审计取证单生成要求\n"); + context.append("请基于以下信息生成一份完整的审计取证单。审计取证单是审计工作中的重要文书,用于记录审计发现的问题、事实依据、处理建议等。\n\n"); + + // 2. 输出格式要求 + context.append("## 输出格式要求\n"); + context.append("请严格按照以下JSON格式输出,不要包含任何额外文本:\n"); + context.append("{\n"); + context.append(" \"caseIndex\": \"案件编号,如审计-[2024]-001\",\n"); + context.append(" \"projectName\": \"具体项目名称\",\n"); + context.append(" \"auditedTarget\": \"被审计单位或个人\",\n"); + context.append(" \"auditMatter\": \"审计事项描述\",\n"); + context.append(" \"summaryTitle\": \"核心问题标题\",\n"); + context.append(" \"auditRecord\": \"客观的审计核查事实记录,包括时间、地点、主体、行为、数据等\",\n"); + context.append(" \"auditFinding\": \"审计发现的具体问题、性质及影响\",\n"); + context.append(" \"evidenceBasis\": \"定性依据,引用法规、制度或合同条款\",\n"); + context.append(" \"handling\": \"拟采取的处理措施\",\n"); + context.append(" \"suggestion\": \"改进或整改建议\",\n"); + context.append(" \"attachment\": \"列示随附的证明材料(只出现材料中文名称,不要出现FileId,不要出现网站链接)\",\n"); + context.append(" \"auditors\": \"审计人员姓名\",\n"); + context.append(" \"compileDate\": \"编制日期,格式:YYYY-MM-DD\",\n"); + context.append(" \"providerOpinion\": \"证据提供单位或个人意见\",\n"); + context.append(" \"providerDate\": \"证据提供日期,格式:YYYY-MM-DD\",\n"); + context.append(" \"attachmentPages\": \"附件页数,如:2\",\n"); + context.append(" \"feedbackDeadline\": \"反馈期限,如:5个工作日内\"\n"); + context.append("}\n"); + + // 3. 字段内容要求 + context.append("## 字段内容具体要求\n"); + context.append("1. **审计记录**:客观记录审计核查的具体事实,包括时间、地点、主体、行为、数据等,避免主观评价。\n"); + context.append("2. **审计发现**:基于审计记录提出具体问题性质,先事实后定性,避免夸大。\n"); + context.append("3. **定性依据**:必须引用具体的法规、制度或合同条款,格式如:根据《XX法》第XX条规定...\n"); + context.append("4. **处理措施**:针对发现的问题提出具体的处理措施,要有可操作性。\n"); + context.append("5. **建议**:针对问题根源提出改进或整改建议,要具体可行。\n"); + context.append("6. **日期**:所有日期必须使用YYYY-MM-DD格式。\n\n"); + + // 4. 用户提供的基础信息 + if (StrUtil.isNotBlank(request.getProjectName()) || + StrUtil.isNotBlank(request.getAuditedTarget()) || + StrUtil.isNotBlank(request.getAuditMatter())) { + + context.append("## 用户提供的基础信息\n"); + + if (StrUtil.isNotBlank(request.getProjectName())) { + context.append("- 项目名称:").append(request.getProjectName()).append("\n"); + } + if (StrUtil.isNotBlank(request.getAuditedTarget())) { + context.append("- 被审计单位/个人:").append(request.getAuditedTarget()).append("\n"); + } + if (StrUtil.isNotBlank(request.getAuditMatter())) { + context.append("- 审计事项:").append(request.getAuditMatter()).append("\n"); + } + if (StrUtil.isNotBlank(request.getSummaryTitle())) { + context.append("- 标题:").append(request.getSummaryTitle()).append("\n"); + } + context.append("\n"); + } + + // 5. 历史内容(如果存在) + if (StrUtil.isNotBlank(request.getHistory())) { + context.append("## 历史内容参考\n"); + context.append("以下是与本次审计相关的历史内容,请参考但不完全照搬:\n"); + context.append(request.getHistory()).append("\n\n"); + } + + // 6. 额外要求 + context.append("## 额外要求\n"); + context.append("1. 内容必须真实、准确、完整,符合审计文书规范\n"); + context.append("2. 语言表述要严谨、客观、规范\n"); + context.append("3. 各字段内容要相互衔接,逻辑清晰\n"); + context.append("4. 如果某些信息不明确,请根据审计常规进行合理补充\n"); + + log.debug("构建的上下文长度: {}", context.length()); + return context.toString(); + } + + /** + * 构建工作流请求 + */ + private JSONObject buildWorkflowRequest(String knowledge, String userName) { + JSONObject requestBody = new JSONObject(); + JSONObject inputs = new JSONObject(); + + inputs.put("knowledge", knowledge); + + requestBody.put("inputs", inputs); + requestBody.put("response_mode", "blocking"); + requestBody.put("user", userName); + requestBody.put("timeout", 300); // 5分钟超时 + + return requestBody; + } + + /** + * 调用工作流 + */ + private JSONObject callWorkflow(JSONObject requestBody, String workflowName) { + try { + log.info("调用{}工作流,请求体长度: {}", workflowName, requestBody.toString().length()); + + String result = HttpUtil.createPost(DIFY_WORKFLOW_URL) + .header("Authorization", DIFY_WORKFLOW_TOKEN) + .header("Content-Type", "application/json") + .body(requestBody.toString()) + .timeout(5 * 60 * 1000) // 5分钟 + .execute() + .body(); + + log.info("{}工作流返回结果长度: {}", workflowName, result.length()); + + JSONObject jsonResponse = JSONObject.parseObject(result); + + // 提取输出文本 + String outputText = jsonResponse.getJSONObject("data") + .getJSONObject("outputs") + .getString("result"); + + if (StrUtil.isBlank(outputText)) { + log.warn("{}工作流返回结果为空", workflowName); + return new JSONObject(); + } + + // 解析为JSON对象 + JSONObject auditEvidence = JSONObject.parseObject(outputText); + + log.info("成功解析{}工作流返回数据", workflowName); + return auditEvidence; + + } catch (Exception e) { + log.error("调用{}工作流失败", workflowName, e); + throw new RuntimeException("调用" + workflowName + "工作流失败: " + e.getMessage(), e); + } + } + + /** + * 构建错误响应 + */ + private JSONObject buildErrorResponse(String errorMessage) { + JSONObject result = new JSONObject(); + result.put("success", false); + result.put("error", errorMessage); + result.put("timestamp", System.currentTimeMillis()); + return result; + } +} \ No newline at end of file