审计核查功能初版

This commit is contained in:
2025-10-16 15:56:56 +08:00
parent 750ef188c2
commit fdf46b5153
4 changed files with 501 additions and 6 deletions

View File

@@ -0,0 +1,128 @@
package com.gxwebsoft.ai.controller;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gxwebsoft.ai.service.AuditReportService;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.system.entity.User;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
/**
* 审计报告控制器 - 重构版
*/
@Tag(name = "审计报告")
@RestController
@RequestMapping("/api/ai/auditReport2")
public class AuditReportController2 extends BaseController {
@Autowired
private AuditReportService auditReportService;
/**
* 生成审计核查报告 - 重构版
*/
@Operation(summary = "生成审计核查报告")
@PostMapping("/generate")
public ApiResult<?> generateAuditReport(
@RequestPart("file") MultipartFile file,
@RequestPart(value = "kbId", required = false) String kbId,
@RequestPart(value = "libraryIds", required = false) String libraryIds,
@RequestPart(value = "analysisLibrary", required = false) String analysisLibrary,
@RequestPart(value = "projectLibrary", required = false) String projectLibrary) {
final User loginUser = getLoginUser();
try {
// 1. 解析文件五、六点内容
String auditContent = extractAuditContent(file);
if (StrUtil.isBlank(auditContent)) {
return fail("未能提取到审计内容");
}
// 2. 生成完整审计报告
JSONObject auditReport = auditReportService.generateCompleteAuditReport(
auditContent, file.getOriginalFilename(), kbId, libraryIds,
analysisLibrary, projectLibrary, loginUser.getUsername()
);
return success(auditReport);
} catch (Exception e) {
return fail("生成审计报告失败: " + e.getMessage());
}
}
/**
* 提取审计内容(五、六点)
*/
private String extractAuditContent(MultipartFile file) throws IOException {
StringBuilder content = new StringBuilder();
// 保存原来的最小解压比率
double originalMinInflateRatio = ZipSecureFile.getMinInflateRatio();
// 设置新的最小解压比率
ZipSecureFile.setMinInflateRatio(0.001);
try (InputStream is = file.getInputStream();
XWPFDocument doc = new XWPFDocument(is)) {
boolean inSection5 = false;
boolean inSection6 = false;
for (XWPFParagraph para : doc.getParagraphs()) {
String text = para.getText();
if (StrUtil.isBlank(text)) continue;
// 检测第五部分
if (text.contains("五、") || text.contains("5、")) {
inSection5 = true;
inSection6 = false;
content.append("【第五部分】\n");
continue;
}
// 检测第六部分
if (text.contains("六、") || text.contains("6、")) {
inSection5 = false;
inSection6 = true;
content.append("【第六部分】\n");
continue;
}
// 检测结束
if ((text.contains("七、") || text.contains("7、")) && inSection6) {
break;
}
// 收集内容
if (inSection5 || inSection6) {
content.append(text).append("\n");
}
}
} finally {
// 恢复原来的最小解压比率
ZipSecureFile.setMinInflateRatio(originalMinInflateRatio);
}
return content.toString();
}
}

View File

@@ -12,12 +12,18 @@ public class KnowledgeBaseClientFactory {
@Autowired @Autowired
private KnowledgeBaseConfig config; private KnowledgeBaseConfig config;
private Client client;
public Client createClient() throws Exception { public Client createClient() throws Exception {
com.aliyun.teaopenapi.models.Config authConfig = new com.aliyun.teaopenapi.models.Config() if(client == null) {
.setAccessKeyId(config.getAccessKeyId()) com.aliyun.teaopenapi.models.Config authConfig = new com.aliyun.teaopenapi.models.Config()
.setAccessKeySecret(config.getAccessKeySecret()); .setAccessKeyId(config.getAccessKeyId())
// 下方接入地址以公有云的公网接入地址为例,可按需更换接入地址。 .setAccessKeySecret(config.getAccessKeySecret());
authConfig.endpoint = "bailian.cn-beijing.aliyuncs.com"; // 下方接入地址以公有云的公网接入地址为例,可按需更换接入地址。
return new com.aliyun.bailian20231229.Client(authConfig); authConfig.endpoint = "bailian.cn-beijing.aliyuncs.com";
client = new com.aliyun.bailian20231229.Client(authConfig);
}
return client;
} }
} }

View File

@@ -0,0 +1,14 @@
package com.gxwebsoft.ai.service;
import com.alibaba.fastjson.JSONObject;
public interface AuditReportService {
/**
* 生成完整审计报告
*/
JSONObject generateCompleteAuditReport(String auditContent, String fileName,
String kbId, String libraryIds,
String analysisLibrary, String projectLibrary,
String userName);
}

View File

@@ -0,0 +1,347 @@
package com.gxwebsoft.ai.service.impl;
import com.aliyun.bailian20231229.Client;
import com.aliyun.bailian20231229.models.RetrieveResponse;
import com.aliyun.bailian20231229.models.RetrieveResponseBody.RetrieveResponseBodyDataNodes;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gxwebsoft.ai.config.KnowledgeBaseConfig;
import com.gxwebsoft.ai.factory.KnowledgeBaseClientFactory;
import com.gxwebsoft.ai.service.AuditReportService;
import com.gxwebsoft.ai.util.KnowledgeBaseUtil;
import com.gxwebsoft.pwl.entity.PwlProjectLibrary;
import com.gxwebsoft.pwl.service.PwlProjectLibraryService;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class AuditReportServiceImpl implements AuditReportService {
@Autowired
private KnowledgeBaseClientFactory clientFactory;
@Autowired
private KnowledgeBaseConfig config;
@Autowired
private PwlProjectLibraryService pwlProjectLibraryService;
// 工作流配置
private static final String QUESTION_GENERATION_WORKFLOW_URL = "http://1.14.159.185:8180/v1/workflows/run";
private static final String QUESTION_GENERATION_TOKEN = "Bearer app-vqbecZtTGmpGL5YhQzsy0Ctr";
private static final String QUESTION_ANALYSIS_WORKFLOW_URL = "http://1.14.159.185:8180/v1/workflows/run";
private static final String QUESTION_ANALYSIS_TOKEN = "Bearer app-5CQWPxctsPape0HePWA3cP4Y";
@Override
public JSONObject generateCompleteAuditReport(String auditContent, String fileName,
String kbId, String libraryIds,
String analysisLibrary, String projectLibrary,
String userName) {
List<String> idList = StrUtil.split(libraryIds, ',');
List<PwlProjectLibrary> ret = pwlProjectLibraryService.list(new LambdaQueryWrapper<PwlProjectLibrary>().in(PwlProjectLibrary::getId, idList));
String libraryKbIds = ret.stream().map(PwlProjectLibrary::getKbId).collect(Collectors.joining(","));
JSONObject result = new JSONObject();
// 1. 从知识库召回相关规定
List<String> regulations = retrieveRegulations(auditContent, kbId, libraryKbIds);
// 2. 生成审计问题列表
JSONArray questionList = generateAuditQuestions(auditContent, regulations, userName);
// 3. 分析每个问题
JSONArray findings = analyzeQuestions(questionList, analysisLibrary, projectLibrary, userName);
// 4. 构建返回结果
result.put("source_file", fileName);
result.put("audit_content", auditContent);
result.put("total_questions", questionList.size());
result.put("total_findings", findings.size());
result.put("findings", findings);
result.put("generated_time", new Date().toString());
return result;
}
/**
* 从知识库召回相关规定
*/
private List<String> retrieveRegulations(String auditContent, String kbId, String libraryKbIds) {
List<String> regulations = new ArrayList<>();
String query = buildRegulationQuery(auditContent);
// 主知识库
if (StrUtil.isNotBlank(kbId)) {
regulations.addAll(queryKnowledgeBase(kbId, query, 10));
}
// 多个库
if (StrUtil.isNotBlank(libraryKbIds)) {
for (String libId : libraryKbIds.split(",")) {
if (StrUtil.isNotBlank(libId.trim())) {
regulations.addAll(queryKnowledgeBase(libId.trim(), query, 5));
}
}
}
return regulations.stream().distinct().collect(Collectors.toList());
}
/**
* 生成审计问题列表
*/
private JSONArray generateAuditQuestions(String auditContent, List<String> regulations, String userName) {
// 构建知识上下文
String knowledgeContext = buildKnowledgeContext(auditContent, regulations);
JSONObject requestBody = buildQuestionGenerationRequest(knowledgeContext, userName);
JSONArray response = callQuestionGenerationWorkflow(requestBody);
return response;
}
/**
* 分析每个问题
*/
private JSONArray analyzeQuestions(JSONArray questions, String analysisLib, String projectLib, String userName) {
JSONArray findings = new JSONArray();
for (int i = 0; i < questions.size(); i++) {
JSONObject question = questions.getJSONObject(i);
// 从两个库召回证据
List<String> analysisEvidence = retrieveEvidence(question.toJSONString(), analysisLib);
List<String> projectEvidence = retrieveEvidence(question.toJSONString(), projectLib);
// 调用工作流分析
JSONArray analysisResult = analyzeSingleQuestion(question, analysisEvidence, projectEvidence, userName);
if (analysisResult != null && !analysisResult.isEmpty()) {
JSONObject finding = analysisResult.getJSONObject(0);
// 添加索引
finding.put("index", i + 1);
findings.add(finding);
}
}
return findings;
}
/**
* 召回证据
*/
private List<String> retrieveEvidence(String question, String libraryId) {
if (StrUtil.isBlank(libraryId)) return new ArrayList<>();
return new ArrayList<>(queryKnowledgeBase(libraryId, question, 5));
}
/**
* 分析单个问题
*/
private JSONArray analyzeSingleQuestion(JSONObject question, List<String> analysisEvidence,
List<String> projectEvidence, String userName) {
String evidenceContext = buildEvidenceContext(analysisEvidence, projectEvidence);
String questionText = buildQuestionText(question);
JSONObject requestBody = buildQuestionAnalysisRequest(questionText, evidenceContext, userName);
return callQuestionAnalysisWorkflow(requestBody);
}
/**
* 构建问题文本
*/
private String buildQuestionText(JSONObject question) {
StringBuilder sb = new StringBuilder();
sb.append("问题表述: ").append(question.getString("问题表述")).append("\n");
sb.append("问题明细: ").append(question.getString("问题明细")).append("\n");
sb.append("法规依据: ").append(question.getString("法规依据"));
return sb.toString();
}
/**
* 构建知识上下文
*/
private String buildKnowledgeContext(String auditContent, List<String> regulations) {
StringBuilder context = new StringBuilder();
context.append("审计内容:\n").append(auditContent).append("\n\n");
if (!regulations.isEmpty()) {
context.append("相关规定:\n");
regulations.forEach(reg -> context.append("- ").append(reg).append("\n"));
}
return context.toString();
}
/**
* 构建证据上下文
*/
private String buildEvidenceContext(List<String> analysisEvidence, List<String> projectEvidence) {
StringBuilder context = new StringBuilder();
if (!analysisEvidence.isEmpty()) {
context.append("分析库证据:\n");
analysisEvidence.forEach(ev -> context.append("- ").append(ev).append("\n"));
}
if (!projectEvidence.isEmpty()) {
context.append("项目库证据:\n");
projectEvidence.forEach(ev -> context.append("- ").append(ev).append("\n"));
}
return context.toString().trim();
}
/**
* 调用问题生成工作流
*/
private JSONArray callQuestionGenerationWorkflow(JSONObject requestBody) {
try {
String result = HttpUtil.createPost(QUESTION_GENERATION_WORKFLOW_URL)
.header("Authorization", QUESTION_GENERATION_TOKEN)
.header("Content-Type", "application/json")
.body(requestBody.toString())
.timeout(600000)
.execute()
.body();
JSONObject jsonResponse = JSONObject.parseObject(result);
String outputText = jsonResponse.getJSONObject("data")
.getJSONObject("outputs")
.getString("result");
// 解析JSON数组
return JSONArray.parseArray(outputText);
} catch (Exception e) {
throw new RuntimeException("调用问题生成工作流失败: " + e.getMessage(), e);
}
}
/**
* 调用问题分析工作流
*/
private JSONArray callQuestionAnalysisWorkflow(JSONObject requestBody) {
try {
String result = HttpUtil.createPost(QUESTION_ANALYSIS_WORKFLOW_URL)
.header("Authorization", QUESTION_ANALYSIS_TOKEN)
.header("Content-Type", "application/json")
.body(requestBody.toString())
.timeout(600000)
.execute()
.body();
JSONObject jsonResponse = JSONObject.parseObject(result);
String outputText = jsonResponse.getJSONObject("data")
.getJSONObject("outputs")
.getString("result");
// 解析JSON数组
return JSONArray.parseArray(outputText);
} catch (Exception e) {
System.err.println("分析问题失败: " + e.getMessage());
// 返回默认结构,避免整个流程中断
return createDefaultFinding();
}
}
/**
* 创建默认的发现条目
*/
private JSONArray createDefaultFinding() {
JSONObject finding = new JSONObject();
finding.put("是否存在相关问题", "false");
finding.put("问题表述", "");
finding.put("问题明细", "");
finding.put("法规依据", "");
finding.put("涉及金额(万元)", "/");
finding.put("具体责任界定", "/");
finding.put("整改类型", "/");
finding.put("整改要求", "/");
finding.put("整改时限", "/");
finding.put("审计建议", "/");
JSONArray array = new JSONArray();
array.add(finding);
return array;
}
/**
* 构建问题生成工作流请求
*/
private JSONObject buildQuestionGenerationRequest(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);
return requestBody;
}
/**
* 构建问题分析工作流请求
*/
private JSONObject buildQuestionAnalysisRequest(String query, String knowledge, String userName) {
JSONObject requestBody = new JSONObject();
JSONObject inputs = new JSONObject();
inputs.put("query", query);
inputs.put("knowledge", knowledge);
requestBody.put("inputs", inputs);
requestBody.put("response_mode", "blocking");
requestBody.put("user", userName);
return requestBody;
}
/**
* 查询知识库
*/
private Set<String> queryKnowledgeBase(String kbId, String query, int topK) {
Set<String> results = new LinkedHashSet<>();
String workspaceId = config.getWorkspaceId();
try {
Client client = clientFactory.createClient();
RetrieveResponse resp = KnowledgeBaseUtil.retrieveIndex(client, workspaceId, kbId, query);
if (resp.getBody() != null && resp.getBody().getData() != null
&& resp.getBody().getData().getNodes() != null) {
for (RetrieveResponseBodyDataNodes node : resp.getBody().getData().getNodes()) {
results.add(node.getText());
if (results.size() >= topK) break;
}
}
} catch (Exception e) {
// 记录日志但不中断流程
System.err.println("查询知识库失败: " + e.getMessage());
}
return results;
}
/**
* 构建法规查询
*/
private String buildRegulationQuery(String auditContent) {
String[] keywords = {"制度", "办法", "规定", "流程", "标准", "规范", "要求"};
return String.join(" ", keywords);
}
}