diff --git a/src/main/java/com/gxwebsoft/ai/controller/AuditReportController.java b/src/main/java/com/gxwebsoft/ai/controller/AuditReportController.java index 681c3ee..5c04a56 100644 --- a/src/main/java/com/gxwebsoft/ai/controller/AuditReportController.java +++ b/src/main/java/com/gxwebsoft/ai/controller/AuditReportController.java @@ -20,8 +20,6 @@ import com.alibaba.fastjson2.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.gxwebsoft.ai.entity.AuditEvidence; import com.gxwebsoft.ai.mapper.AuditEvidenceMapper; -import com.gxwebsoft.ai.service.AiCloudDocService; -import com.gxwebsoft.ai.service.AiCloudFileService; import com.gxwebsoft.ai.service.AuditEvidenceService; import com.gxwebsoft.pwl.entity.PwlProject; import com.gxwebsoft.pwl.service.PwlProjectService; @@ -94,45 +92,48 @@ public class AuditReportController extends BaseController { private final AiHistoryService aiHistoryService; - private final AiCloudFileService aiCloudFileService; + private final static String AUDIT_REPORT_TOKEN = "Bearer app-PlYMOvcUQrW7tromrqCNcX9M"; - private final AiCloudDocService aiCloudDocService; +// private final AiCloudFileService aiCloudFileService; +// +// private final AiCloudDocService aiCloudDocService; - private String invok(String query, String knowledge, String history, String suggestion, String title, String userName) { - // 构建请求体 - JSONObject requestBody = new JSONObject(); - JSONObject inputs = new JSONObject(); - inputs.put("query", query); - inputs.put("knowledge", knowledge); - inputs.put("history", history); - inputs.put("suggestion", suggestion); - inputs.put("title", title); - - requestBody.put("inputs", inputs); - requestBody.put("response_mode", "blocking"); - requestBody.put("user", userName); - - // 发送 POST 请求 - String result = HttpUtil.createPost("http://1.14.159.185:8180/v1/workflows/run") - .header("Authorization", "Bearer app-d7Ok9FECVZG2Ybw9wpg7tGu9") - .header("Content-Type", "application/json") - .body(requestBody.toString()) - .timeout(600000) - .execute() - .body(); - // 解析返回的JSON字符串 - JSONObject jsonResponse = JSONObject.parseObject(result); - // 获取data字段 - JSONObject data = jsonResponse.getJSONObject("data"); - // 获取outputs字段 - JSONObject outputs = data.getJSONObject("outputs"); - // 获取outputs中的result字符串 - return outputs.getString("result"); - } +// private String invok(String query, String knowledge, String history, String suggestion, String title, String userName) { +// // 构建请求体 +// JSONObject requestBody = new JSONObject(); +// JSONObject inputs = new JSONObject(); +// inputs.put("query", query); +// inputs.put("knowledge", knowledge); +// inputs.put("history", history); +// inputs.put("suggestion", suggestion); +// inputs.put("title", title); +// +// requestBody.put("inputs", inputs); +// requestBody.put("response_mode", "blocking"); +// requestBody.put("user", userName); +// +// // 发送 POST 请求 +// String result = HttpUtil.createPost("http://1.14.159.185:8180/v1/workflows/run") +// .header("Authorization", AUDIT_REPORT_TOKEN) +// .header("Content-Type", "application/json") +// .body(requestBody.toString()) +// .timeout(600000) +// .execute() +// .body(); +// // 解析返回的JSON字符串 +// JSONObject jsonResponse = JSONObject.parseObject(result); +// // 获取data字段 +// JSONObject data = jsonResponse.getJSONObject("data"); +// // 获取outputs字段 +// JSONObject outputs = data.getJSONObject("outputs"); +// // 获取outputs中的result字符串 +// return outputs.getString("result"); +// } /** * 生成审计报告-单一模块 */ + @Deprecated @Operation(summary = "生成审计报告-单一模块") @PostMapping("/generate") public ApiResult generateAuditReport(@RequestBody AuditReportRequest req) { @@ -148,13 +149,13 @@ public class AuditReportController extends BaseController { knowledgeBaseRequest.setFormCommit((req.getFormCommit() >= 10) ? req.getFormCommit() / 10 : req.getFormCommit()); kbIdSet.addAll(knowledgeBaseService.queryKnowledgeBase(knowledgeBaseRequest)); } - String knowledge = kbIdSet.toString(); + String knowledge = JSON.toJSONString(kbIdSet); String query = AuditReportEnum.getByCode(req.getFormCommit()).getDesc(); // String ret = this.invok(query, knowledge, AuditReportUtil.generateReportContent(req), req.getSuggestion(), loginUser.getUsername()); - String ret = this.invok(query, knowledge, AuditReportUtil.generateReportContentByFormCommit(req), req.getSuggestion(), req.getFrom00(), loginUser.getUsername()); - - return success(ret); +// String ret = this.invok(query, knowledge, AuditReportUtil.generateReportContentByFormCommit(req), req.getSuggestion(), req.getFrom00(), loginUser.getUsername()); + + return success(invokeAIAnalysis(query, knowledge, loginUser.getUsername())); } /** @@ -324,7 +325,7 @@ public class AuditReportController extends BaseController { addBodyTitle(document, "经济责任审计报告"); // 7. 添加文号(右对齐,蓝色)- 从 pwl_project.case_index 获取 - if (project != null && StrUtil.isNotBlank(project.getCaseIndex())) { + if (StrUtil.isNotBlank(project.getCaseIndex())) { addDocumentNumber(document, project.getCaseIndex()); } else { addDocumentNumber(document, "XX 专字 [202X]4501Z000X 号"); @@ -490,7 +491,7 @@ public class AuditReportController extends BaseController { addBodyTitle(document, "经济责任审计报告"); // 9. 添加文号(右对齐,蓝色)- 从 pwl_project.case_index 获取 - if (project != null && StrUtil.isNotBlank(project.getCaseIndex())) { + if (StrUtil.isNotBlank(project.getCaseIndex())) { addDocumentNumber(document, project.getCaseIndex()); } else { addDocumentNumber(document, "XX 专字 [202X]4501Z000X 号"); @@ -664,7 +665,7 @@ public class AuditReportController extends BaseController { addBodyTitle(document, "经济责任审计报告"); // 9. 添加文号(右对齐,蓝色) - if (project != null && StrUtil.isNotBlank(project.getCaseIndex())) { + if (StrUtil.isNotBlank(project.getCaseIndex())) { addDocumentNumber(document, project.getCaseIndex()); } else { addDocumentNumber(document, "XX 专字 [202X]4501Z000X 号"); @@ -897,123 +898,6 @@ public class AuditReportController extends BaseController { log.info("成功添加尾页(使用代码直接绘制)"); } - /** - * 复制段落内容和样式 - */ - private void copyParagraph(XWPFParagraph src, XWPFParagraph dest) { - // 复制段落属性 - if (src.getAlignment() != null) { - dest.setAlignment(src.getAlignment()); - } - if (src.getIndentationFirstLine() != -1) { - dest.setIndentationFirstLine(src.getIndentationFirstLine()); - } - if (src.getIndentationLeft() != -1) { - dest.setIndentationLeft(src.getIndentationLeft()); - } - if (src.getIndentationRight() != -1) { - dest.setIndentationRight(src.getIndentationRight()); - } - if (src.getSpacingBefore() != -1) { - dest.setSpacingBefore(src.getSpacingBefore()); - } - if (src.getSpacingAfter() != -1) { - dest.setSpacingAfter(src.getSpacingAfter()); - } - - // 复制 Run(文本片段) - for (XWPFRun srcRun : src.getRuns()) { - XWPFRun destRun = dest.createRun(); - String text = srcRun.getText(0); - if (text != null) { - destRun.setText(text); - } - - // 复制所有样式属性 - try { - // 字体相关 - if (srcRun.getFontFamily() != null) { - destRun.setFontFamily(srcRun.getFontFamily()); - } - // 尝试使用 setFontName(某些版本的 POI 支持) - try { - java.lang.reflect.Method setFontNameMethod = destRun.getClass().getMethod("setFontName", String.class); - if (srcRun.getFontName() != null) { - setFontNameMethod.invoke(destRun, srcRun.getFontName()); - } - } catch (Exception e) { - // 忽略,不使用 setFontName - } - - // 字体大小 - if (srcRun.getFontSize() != -1) { - destRun.setFontSize(srcRun.getFontSize()); - } - - // 字体样式 - destRun.setBold(srcRun.isBold()); - destRun.setItalic(srcRun.isItalic()); - - // 下划线 - if (srcRun.getUnderline() != null) { - destRun.setUnderline(srcRun.getUnderline()); - } - - // 删除线 - destRun.setStrike(srcRun.isStrike()); - - // 颜色 - if (srcRun.getColor() != null) { - destRun.setColor(srcRun.getColor()); - } - - // 上标/下标 - if (srcRun.getSubscript() != null) { - destRun.setSubscript(srcRun.getSubscript()); - } - } catch (Exception e) { - log.warn("复制 Run 样式时出错", e); - } - } - } - - /** - * 复制表格结构和内容 - */ - private void copyTable(XWPFTable src, XWPFTable dest) { - for (XWPFTableRow srcRow : src.getRows()) { - // 创建新行并复制高度 - XWPFTableRow destRow = dest.createRow(); - destRow.setHeight(srcRow.getHeight()); - - List srcCells = srcRow.getTableCells(); - - // 先确保目标行有足够数量的单元格 - while (destRow.getTableCells().size() < srcCells.size()) { - destRow.addNewTableCell(); - } - - List destCells = destRow.getTableCells(); - - // 复制每个单元格的内容 - for (int i = 0; i < srcCells.size(); i++) { - XWPFTableCell srcCell = srcCells.get(i); - XWPFTableCell destCell = destCells.get(i); - - // 清空目标单元格的默认段落 - if (destCell.getParagraphs().size() > 0) { - destCell.removeParagraph(0); - } - - // 复制源单元格的所有段落 - for (XWPFParagraph srcPara : srcCell.getParagraphs()) { - XWPFParagraph destPara = destCell.addParagraph(); - copyParagraph(srcPara, destPara); - } - } - } - } - /** * 使用表格方式创建尾页(备用方案) */ @@ -1344,7 +1228,7 @@ public class AuditReportController extends BaseController { // 如果数据库中没有数据,使用默认内容 intro = "我们接受委托,自 20XX 年 XX 月 XX 日至 20XX 年 XX 月 XX 日,对 XX 同志自 20XX 年 XX 月 XX 日至 20XX 年 XX 月 XX 日担任公司董事长(具体职务)期间的经济责任履行情况进行了就地审计。公司及 XX 同志的责任是提供与本次审计相关的全部资料,并保证其真实、完整。我们的责任是在实施审计工作的基础上发表审计意见。审计工作为发表意见提供了合理基础。现将审计情况报告如下:"; }*/ - String intro = "我们接受%s委托,自 20XX 年 XX 月 XX 日至 20XX 年 XX 月 XX 日,对%s自 20XX 年 XX 月 XX 日至 20XX 年 XX 月 XX 日担任公司%s期间的经济责任履行情况进行了就地审计。公司及%s责任是提供与本次审计相关的全部资料,并保证其真实、完整。我们的责任是在实施审计工作的基础上发表审计意见。审计工作为发表意见提供了合理基础。现将审计情况报告如下:"; + String intro = "我们接受%s委托,自 20XX 年 XX 月 XX 日至 20XX 年 XX 月 XX 日,对%s自 20XX 年 XX 月 XX 日至 20XX 年 XX 月 XX 日担任%s %s期间的经济责任履行情况进行了就地审计。%s及%s责任是提供与本次审计相关的全部资料,并保证其真实、完整。我们的责任是在实施审计工作的基础上发表审计意见。审计工作为发表意见提供了合理基础。现将审计情况报告如下:"; // 整段话作为一个段落(仿宋_GB2312,小四) XWPFParagraph para = document.createParagraph(); @@ -1356,15 +1240,14 @@ public class AuditReportController extends BaseController { spacing.setLine(java.math.BigInteger.valueOf(360)); // 1.5 倍行距 XWPFRun run = para.createRun(); - run.setText(String.format(intro, project.getName(), project.getPersonName(), project.getPosition(), project.getPersonName()));; + run.setText(String.format(intro, project.getName(), project.getPersonName(), project.getName(), project.getPosition(), project.getName(), project.getPersonName()));; run.setFontSize(12); // 小四 run.setFontFamily("仿宋_GB2312"); // 设置首行缩进 2 个中文字符(POI 中使用半字符单位,1 中文字符=2 英文字符=480 单位) para.setIndentationFirstLine(480); // 1 个中文字符 - // 添加 2 个空行 - document.createParagraph(); + // 添加 1个空行 document.createParagraph(); } /** @@ -1588,22 +1471,57 @@ public class AuditReportController extends BaseController { public ApiResult generateDefaultText(@RequestBody AuditReportDefaultTextRequest request) { try { final User loginUser = getLoginUser(); - log.info("AI 生成默认话术 - formCommit: {}, chapterTitle: {}", request.getFormCommit(), request.getChapterTitle()); + Integer formCommit = request.getFormCommit(); + log.info("AI 生成默认话术 - formCommit: {}, chapterTitle: {}", formCommit, request.getChapterTitle()); // 获取章节标题 String title = request.getChapterTitle(); if (title == null || title.trim().isEmpty()) { - title = AuditReportEnum.getByCode(request.getFormCommit()) != null - ? AuditReportEnum.getByCode(request.getFormCommit()).getDesc() + title = AuditReportEnum.getByCode(formCommit) != null + ? AuditReportEnum.getByCode(formCommit).getDesc() : "审计内容"; } // 从请求体中获取选中的取证单 ID 列表 - List evidenceIds = new ArrayList<>(); - if (request.getEvidenceIds() != null && !request.getEvidenceIds().isEmpty()) { - evidenceIds = request.getEvidenceIds().stream() - .map(Long::valueOf) - .collect(Collectors.toList()); + List evidenceIds = request.getEvidenceIds(); +// List evidenceIds = new ArrayList<>(); +// if (request.getEvidenceIds() != null && !request.getEvidenceIds().isEmpty()) { +// evidenceIds = request.getEvidenceIds().stream() +// .map(Long::valueOf) +// .collect(Collectors.toList()); +// } + List evidences = auditEvidenceService.listByIds(evidenceIds); + + // 构建取证单数据字符串,用于 prompt + boolean isEvidenceUsed = false; + StringBuilder evidenceDataBuilder = new StringBuilder(); + if (evidences != null && !evidences.isEmpty()) { + evidenceDataBuilder.append("\n【取证单数据】\n"); + for (int i = 0; i < evidences.size(); i++) { + AuditEvidence evidence = evidences.get(i); + evidenceDataBuilder.append(String.format("\n--- 取证单 %d ---\n", i + 1)); + if (evidence.getSummaryTitle() != null && !evidence.getSummaryTitle().trim().isEmpty()) { + evidenceDataBuilder.append("核心问题标题:").append(evidence.getSummaryTitle()).append("\n"); + } + if (evidence.getAuditMatter() != null && !evidence.getAuditMatter().trim().isEmpty()) { + evidenceDataBuilder.append("审计事项描述:").append(evidence.getAuditMatter()).append("\n"); + } + if (evidence.getAuditRecord() != null && !evidence.getAuditRecord().trim().isEmpty()) { + evidenceDataBuilder.append("审计核查事实:").append(evidence.getAuditRecord()).append("\n"); + } + if (evidence.getAuditFinding() != null && !evidence.getAuditFinding().trim().isEmpty()) { + evidenceDataBuilder.append("审计发现问题:").append(evidence.getAuditFinding()).append("\n"); + } + if (evidence.getEvidenceBasis() != null && !evidence.getEvidenceBasis().trim().isEmpty()) { + evidenceDataBuilder.append("定性依据:").append(evidence.getEvidenceBasis()).append("\n"); + } + if (evidence.getHandling() != null && !evidence.getHandling().trim().isEmpty()) { + evidenceDataBuilder.append("处理措施:").append(evidence.getHandling()).append("\n"); + } + if (evidence.getSuggestion() != null && !evidence.getSuggestion().trim().isEmpty()) { + evidenceDataBuilder.append("整改建议:").append(evidence.getSuggestion()).append("\n"); + } + } } // 构建提示词,根据 formCommit 使用不同的默认 prompt @@ -1611,102 +1529,102 @@ public class AuditReportController extends BaseController { if (project == null) { return fail("项目不存在,projectId: " + request.getProjectId(), null); } + String kbId = project.getKbId(); String companyName = project.getName(); String personName = project.getPersonName(); String prompt = ""; - if (request.getFormCommit() == 20) { + StringBuilder promptBuilder = new StringBuilder(); + if (formCommit == 20) { // 二、总体评价的特殊提示词模板 // 查询该项目的所有取证单,判断是否有发现问题 - LambdaQueryWrapper evidenceWrapper = new LambdaQueryWrapper<>(); - evidenceWrapper.eq(AuditEvidence::getProjectId, request.getProjectId()) - .eq(AuditEvidence::getDeleted, 0); - List allEvidences = auditEvidenceMapper.selectList(evidenceWrapper); +// LambdaQueryWrapper evidenceWrapper = new LambdaQueryWrapper<>(); +// evidenceWrapper.eq(AuditEvidence::getProjectId, request.getProjectId()) +// .eq(AuditEvidence::getDeleted, 0); +// List allEvidences = auditEvidenceMapper.selectList(evidenceWrapper); // 判断是否有问题(检查是否存在 auditFinding 不为空或有问题的记录) - boolean hasIssues = allEvidences.stream() - .anyMatch(e -> e.getAuditFinding() != null && !e.getAuditFinding().trim().isEmpty()); - - StringBuilder promptBuilder = new StringBuilder(); + boolean hasIssues = false; + if (evidences != null) { + hasIssues = evidences.stream() + .anyMatch(e -> e.getAuditFinding() != null && !e.getAuditFinding().trim().isEmpty()); + } promptBuilder.append(String.format("综合本次经济责任审计情况,我们对%s 任职期间经济责任履行情况的总体评价如下(本部分应基于审计事实,作出客观、公正的概括;既要肯定成绩,也需指出不足,并与第三、%s 主要业绩、四部分履行经济责任的主要情况及审计发现的问题与责任认定相呼应):\n", personName, personName)); // 如果审计没有问题,添加特定段落 if (!hasIssues) { promptBuilder.append("\n审计期间未收到涉及").append(personName).append("的举报信息;根据现有审计程序与所获证据,也未发现其存在违反党风廉政及廉洁从业规定的明显问题或行为线索。"); } - - prompt = promptBuilder.toString(); - } else if (request.getFormCommit() == 30) { + + isEvidenceUsed = true; + + } else if (formCommit == 30) { // 三、XX 同志主要业绩的特殊提示词模板 - prompt = String.format("请根据传入的取证单及相关资料库的数据,总结%s 任职期间的主要业绩。要求:1.基于审计事实和数据;2.突出重要贡献和成绩;3.内容客观真实;4.条理清晰。", personName); - } else if (request.getFormCommit() == 41) { + isEvidenceUsed = true; + promptBuilder.append(String.format("请根据传入的取证单及相关资料库的数据,总结%s 任职期间的主要业绩。要求:1.基于审计事实和数据;2.突出重要贡献和成绩;3.内容客观真实;4.条理清晰。\n", personName)); + } else if (formCommit == 41) { // (二)XX 公司概况的特殊提示词模板 - prompt = String.format("请生成关于'%s'的详细说明。要求按以下格式返回:\n" + + promptBuilder.append(String.format("请生成关于'%s'的详细说明。要求按以下格式返回:\n" + "%s 为(说明企业性质,如:国有独资/控股公司),成立于 XXXX 年 X 月 X 日,注册资本**元,法定代表人 XX,统一社会信用代码:XXX。\n" + "公司主营业务为……(简述主营业务)。\n" + - "%s 下设……(组织架构)。", title, companyName, companyName); - } else if (request.getFormCommit() == 42) { + "%s 下设……(组织架构)。", title, companyName, companyName)); + } else if (formCommit == 42) { // (三)XX 同志任职及分工情况的特殊提示词模板 - prompt = String.format("请生成关于《%s任职及分工情况》的详细说明。按以下格式返回:\n" + - "%s(同本章节标题人名) 自 XXXX 年 X 月至 XXXX 年 X 月任 XXXX(单位名称)XXX(职务名称),其主要职责是:...(描述主要工作职责)。", personName, personName); - } else if (request.getFormCommit() == 43) { + promptBuilder.append(String.format("请生成关于《%s任职及分工情况》的详细说明。按以下格式返回:\n" + + "%s(同本章节标题人名) 自 XXXX 年 X 月至 XXXX 年 X 月任 XXXX(单位名称)XXX(职务名称),其主要职责是:...(描述主要工作职责)。", personName, personName)); + } else if (formCommit == 43) { // (四)实施审计的基本情况,要求返回两段内容 - prompt = String.format("请生成关于'%s'的详细说明。要求返回两段内容:\n" + + promptBuilder.append(String.format("请生成关于'%s'的详细说明。要求返回两段内容:\n" + "第一段格式:本次审计的时间范围是 20XX 年 XX 月 XX 日至 20XX 年 XX 月 XX 日。本次审计以 %s 会计报表、账簿、凭证及相关经济活动资料为基础,对 %s 任职期间履行经济责任的情况进行审查,主要包括:...(具体内容)。\n" + "第二段格式:%s 及 %s 对所提供的与审计相关的会计资料以及其他证明材料作出了书面承诺,对其真实性和完整性负责。我们按照审计实施方案确定的范围和内容,实施了在当时情况下认为有必要采取的审计程序和方法,包括(具体的程序和方案)等,并对重要事项进行了必要的延伸和追溯。", - title, companyName, personName, companyName, personName); - } else if (request.getFormCommit() >= 51 && request.getFormCommit() <= 57) { - // 四、履行经济责任的主要情况及审计发现的问题与责任认定的所有子章节 - // 要求返回三段:第一段概述和问题列示,第二段原因分析,第三段责任界定 - StringBuilder promptBuilder = new StringBuilder(); - - // 只传递取证单 ID 列表,让 AI 自行从数据库读取 - if (!evidenceIds.isEmpty()) { - // 将 ID 列表转换为逗号分隔的字符串 - String evidenceIdsStr = evidenceIds.stream() - .map(String::valueOf) - .collect(Collectors.joining(",")); - - promptBuilder.append(String.format("取证单编号(仅用于查询数据,不要在输出中显示):%s\n", evidenceIdsStr)); - } - + title, companyName, personName, companyName, personName)); + } else if (formCommit >= 51 && formCommit <= 57) { // 生成指令 - promptBuilder.append(String.format("请根据上述取证单数据,为%s生成审计报告该章节内容。\n", personName)); + promptBuilder.append(String.format("\n请根据上述取证单数据,为%s生成审计报告'%s'章节内容。\n", personName, title)); promptBuilder.append("要求生成三段:\n"); promptBuilder.append("1. 履职情况 + 发现问题及责任认定\n"); promptBuilder.append("2. 原因分析\n"); promptBuilder.append("3. 责任界定\n"); promptBuilder.append("\n注意:输出内容中不要显示取证单编号,直接生成正式的审计报告内容。\n"); - - prompt = promptBuilder.toString(); + isEvidenceUsed = true; } - // 其他章节使用通用 prompt - 查询审计相关法规 - // 注意:AI工作流限制query不能超过512字符,因此提示词必须精简 - // 详细信息通过evidenceIds参数和知识库检索获取 - - StringBuilder promptBuilder = new StringBuilder(); - promptBuilder.append(String.format("请为审计报告章节'%s'生成内容。\n", title)); - promptBuilder.append("数据源:1)取证单(已通过evidenceIds传入) 2)阿里云资料库(自动检索)\n"); - promptBuilder.append("要求:优先用取证单事实,结合资料库制度,不足时生成框架内容,勿编造数据。\n"); - prompt = promptBuilder.toString(); - -// prompt += "\n(重要提示:数据源必须严格来自传入接口的取证单数据,或者在本项目配置的阿里云资料库中的文件,必须保存在ai_cloud_doc和ai_cloud_file表中(根据pwl_project.company_id),不能凭空捏造或者从互联网上获取数据。)"; + +// prompt = String.format("请为审计报告章节'%s'生成内容。\n", title) + +// "数据源:1)取证单(已通过evidenceIds传入) 2)阿里云资料库(自动检索)\n" + +// "要求:优先用取证单事实,结合资料库数据,不足时生成框架内容,勿编造数据。\n"; + + if(isEvidenceUsed && !evidenceIds.isEmpty()){ + // 将 ID 列表转换为逗号分隔的字符串 + String evidenceIdsStr = evidenceIds.stream() + .map(String::valueOf) + .collect(Collectors.joining(",")); + promptBuilder.append(String.format("取证单编号(仅用于查询数据,不要在输出中显示):%s\n", evidenceIdsStr)); + promptBuilder.append(evidenceDataBuilder); + + prompt += "数据源:1)取证单内容 2)阿里云资料库(自动检索)\n" + + "要求:优先用取证单事实,结合资料库数据,勿编造数据。\n" + + "最终的生成内容里面不要说明引用资料来源,不要说基于审计取证单及相关资料\n"; + } + else { + prompt += "\n要求:数据源必须严格使用阿里云资料库(自动检索),不能凭空捏造数据。同时返回信息里面,不必说明基于阿里云资料库xxxx。\n"; + } + log.info("生成审计报告标题:{},AI 提示词:{}", request.getChapterTitle(), prompt); - // 调用 AI 接口,同时传递取证单 ID 列表 - String result = invokeDefaultTextGeneration(prompt, loginUser.getUsername(), evidenceIds); + // TODO 调用 AI 接口 + String result = invokeAIAnalysis(prompt, kbId, loginUser.getUsername()); // 保存历史记录到数据库 try { // 构建请求数据 JSONObject requestData = new JSONObject(); requestData.put("projectId", request.getProjectId()); - requestData.put("formCommit", request.getFormCommit()); + requestData.put("formCommit", formCommit); requestData.put("chapterTitle", request.getChapterTitle()); // 根据 formCommit 生成不同的接口名称 - String interfaceName = "/api/ai/auditReport/generateDefaultText_" + request.getFormCommit(); + String interfaceName = "/api/ai/auditReport/generateDefaultText_" + formCommit; // 生成请求哈希 String requestHash = DigestUtil.md5Hex(interfaceName + ":" + requestData.toJSONString()); @@ -1740,6 +1658,7 @@ public class AuditReportController extends BaseController { @Operation(summary = "AI 分析用户自定义输入") @PostMapping("/analyzeUserInput") public ApiResult analyzeUserInput( + @RequestParam String projectId, @RequestParam Integer formCommit, @RequestParam String userQuestion, @RequestParam(required = false) String chapterContent) { @@ -1760,9 +1679,10 @@ public class AuditReportController extends BaseController { } promptBuilder.append(String.format("用户问题:%s\n\n", userQuestion)); promptBuilder.append("请根据用户的问题,为该审计报告章节提供专业、详细的分析内容。要求:1.回答要针对用户问题;2.使用审计专业术语;3.内容要有实际价值;4.字数在 300-500 字左右。"); - - // 调用 AI 接口 - String result = invokeAIAnalysis(promptBuilder.toString(), loginUser.getUsername()); + + PwlProject project = pwlProjectService.getById(projectId); + // TODO 调用 AI 接口 + String result = invokeAIAnalysis(promptBuilder.toString(), project.getKbId(), loginUser.getUsername()); return success(result); } catch (Exception e) { @@ -1774,7 +1694,7 @@ public class AuditReportController extends BaseController { /** * 调用 AI 生成默认话术 */ - private String invokeDefaultTextGeneration(String prompt, String userName, List evidenceIds) { + /*private String invokeDefaultTextGeneration(String prompt, String userName, List evidenceIds) { // 构建请求体 JSONObject requestBody = new JSONObject(); JSONObject inputs = new JSONObject(); @@ -1800,7 +1720,7 @@ public class AuditReportController extends BaseController { try { // 发送 POST 请求 String result = HttpUtil.createPost("http://1.14.159.185:8180/v1/workflows/run") - .header("Authorization", "Bearer app-d7Ok9FECVZG2Ybw9wpg7tGu9") + .header("Authorization", AUDIT_REPORT_TOKEN) .header("Content-Type", "application/json") .body(requestBody.toString()) .timeout(600000) @@ -1843,19 +1763,19 @@ public class AuditReportController extends BaseController { log.error("调用 AI 工作流失败", e); throw new RuntimeException("调用 AI 工作流失败:" + e.getMessage(), e); } - } + }*/ /** * 调用 AI 分析用户输入 */ - private String invokeAIAnalysis(String prompt, String userName) { + private String invokeAIAnalysis(String prompt, String kbId, String userName) { // 构建请求体 JSONObject requestBody = new JSONObject(); JSONObject inputs = new JSONObject(); + if(StrUtil.isNotBlank(kbId)){ + prompt += "\n\n只能在以下知识库中读取数据,标签编号:" + kbId; + } inputs.put("query", prompt); - inputs.put("knowledge", ""); - inputs.put("history", ""); - inputs.put("suggestion", ""); inputs.put("title", "审计报告 AI 分析"); requestBody.put("inputs", inputs); @@ -1865,7 +1785,7 @@ public class AuditReportController extends BaseController { try { // 发送 POST 请求 String result = HttpUtil.createPost("http://1.14.159.185:8180/v1/workflows/run") - .header("Authorization", "Bearer app-d7Ok9FECVZG2Ybw9wpg7tGu9") + .header("Authorization", AUDIT_REPORT_TOKEN) .header("Content-Type", "application/json") .body(requestBody.toString()) .timeout(600000) @@ -1873,37 +1793,53 @@ public class AuditReportController extends BaseController { .body(); log.info("AI 工作流返回结果:{}", result); - + // 解析返回的 JSON 字符串 JSONObject jsonResponse = JSONObject.parseObject(result); - + // 检查是否有错误 if (jsonResponse.containsKey("error")) { JSONObject error = jsonResponse.getJSONObject("error"); String errorMsg = error != null ? error.getString("message") : "未知错误"; throw new RuntimeException("AI 服务返回错误:" + errorMsg); } - + JSONObject data = jsonResponse.getJSONObject("data"); if (data == null) { log.error("AI 响应中缺少 data 字段,完整响应:{}", result); throw new RuntimeException("AI 服务响应格式异常,缺少 data 字段"); } - + JSONObject outputs = data.getJSONObject("outputs"); if (outputs == null) { log.error("AI 响应中缺少 outputs 字段,完整响应:{}", result); throw new RuntimeException("AI 服务响应格式异常,缺少 outputs 字段"); } - - String resultStr = outputs.getString("result"); - - if (resultStr == null || resultStr.trim().isEmpty()) { + + JSONObject resultJSON = outputs.getJSONObject("result"); + + if (resultJSON == null) { log.warn("AI 返回的结果为空,完整响应:{}", result); return ""; } - - return resultStr; + + JSONArray sectionContents = resultJSON.getJSONArray("sectionContent"); + if (sectionContents == null || sectionContents.isEmpty()) { + log.warn("AI 返回的结果数据为空,完整响应:{}", result); + return ""; + } + + StringBuilder resultStr = new StringBuilder(); + for(int i = 0; i < sectionContents.size(); i++){ + JSONObject sectionContent = sectionContents.getJSONObject(i); + String paragraph = sectionContent.getString("paragraph"); + resultStr.append(paragraph); + if(i < sectionContents.size() - 1){ + resultStr.append("\n"); + } + } + + return resultStr.toString(); } catch (Exception e) { log.error("调用 AI 工作流失败", e); throw new RuntimeException("调用 AI 工作流失败:" + e.getMessage(), e); @@ -1932,8 +1868,6 @@ public class AuditReportController extends BaseController { return fail("项目不存在", null); } - String personName = project.getPersonName(); - // 根据取证单 ID 查询所有取证单数据 List evidences = auditEvidenceMapper.selectBatchIds(evidenceIds); if (evidences == null || evidences.isEmpty()) { @@ -1968,11 +1902,11 @@ public class AuditReportController extends BaseController { "5.字数控制在 800-1500 字。\n\n" + "%s\n\n" + "请根据以上内容,生成审计建议:", - suggestionsBuilder.toString() + suggestionsBuilder ); - // 调用 AI 接口,传递取证单 ID - String result = invokeDefaultTextGeneration(prompt, loginUser.getUsername(), evidenceIds.stream().map(Long::valueOf).collect(Collectors.toList())); + // TODO 调用 AI 接口 + String result = invokeAIAnalysis(prompt, project.getKbId(), loginUser.getUsername()); return success(result); } catch (Exception e) { diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent10PartyConductServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent10PartyConductServiceImpl.java index d52ee28..1933b04 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent10PartyConductServiceImpl.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent10PartyConductServiceImpl.java @@ -261,6 +261,9 @@ public class AuditContent10PartyConductServiceImpl extends AbstractAuditContentS context.append(knowledge).append("\n")); context.append("\n"); } + + context.append("## 重要要求\n"); + context.append("1. 除了本次说明中提供的数据知识等依据,不能从其他地方读取数据,不能凭空捏造数据\n"); return context.toString(); } diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent11HistoryServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent11HistoryServiceImpl.java index 52da3f3..f75466c 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent11HistoryServiceImpl.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent11HistoryServiceImpl.java @@ -169,16 +169,7 @@ public class AuditContent11HistoryServiceImpl extends AbstractAuditContentServic context.append("8. **整改责任人**:负责整改的责任人姓名和职务\n"); context.append("9. **备注**:其他需要说明的情况\n"); context.append("10. **工作底稿索引**:相关审计报告、整改报告等文件名称,必须是实际存在的完整文件名\n\n"); - - context.append("**生成要求:**\n"); - context.append("1. 基于知识库内容,尽可能全面地生成历次审计发现的问题和整改情况\n"); - context.append("2. 每个问题应包含完整的审计年度、类型、问题描述、整改要求、措施、完成情况等\n"); - context.append("3. 重点关注整改措施的落实情况和实际效果\n"); - context.append("4. 工作底稿索引必须准确对应实际文件名称,确保能在文件夹中搜索到\n"); - context.append("5. 整改完成情况需根据实际情况判断,证据充分的才能判定为'已完成'\n"); - context.append("6. 对于历史遗留问题,需特别注明是否为非任期问题\n"); - context.append("7. 对于制度完善情况,需说明审计后是否建立了相关制度机制\n\n"); - + // 3. 历史内容 if (StrUtil.isNotBlank(history)) { context.append("## 历史生成内容\n"); @@ -223,6 +214,16 @@ public class AuditContent11HistoryServiceImpl extends AbstractAuditContentServic knowledgeSources.get("regulations").forEach(knowledge -> context.append(knowledge).append("\n")); } + + context.append("**生成要求:**\n"); + context.append("1. 基于知识库内容,尽可能全面地生成历次审计发现的问题和整改情况\n"); + context.append("2. 每个问题应包含完整的审计年度、类型、问题描述、整改要求、措施、完成情况等\n"); + context.append("3. 重点关注整改措施的落实情况和实际效果\n"); + context.append("4. 工作底稿索引必须准确对应实际文件名称,确保能在文件夹中搜索到\n"); + context.append("5. 整改完成情况需根据实际情况判断,证据充分的才能判定为'已完成'\n"); + context.append("6. 对于历史遗留问题,需特别注明是否为非任期问题\n"); + context.append("7. 对于制度完善情况,需说明审计后是否建立了相关制度机制\n\n"); + context.append("8. 除了本次说明中提供的数据知识等依据,不能从其他地方读取数据,不能凭空捏造数据\n"); return context.toString(); } diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent1EightRegServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent1EightRegServiceImpl.java index ec85d98..1190192 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent1EightRegServiceImpl.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent1EightRegServiceImpl.java @@ -253,6 +253,56 @@ public class AuditContent1EightRegServiceImpl extends AbstractAuditContentServic context.append("4. **不得合并计算**:不得将多笔凭证、多次活动合并计算平均值\n"); context.append("5. **逐笔描述**:每笔凭证的检查结果应作为独立记录\n"); } + + // 3. 参考数据(从常量类中获取) + context.append("## 参考数据\n"); + context.append("### 政策内容\n").append(AuditContent1EightRegConstants.POLICY_CONTENTS.get(category)).append("\n\n"); + context.append("### 实施细则\n").append(AuditContent1EightRegConstants.IMPLEMENTATION_DETAILS.get(category)).append("\n\n"); + + // 4. 审计建议 - 新增部分 + String auditSuggestion = AuditContent1EightRegConstants.AUDIT_SUGGESTIONS.get(category); + if (StrUtil.isNotBlank(auditSuggestion)) { + context.append("## 审计建议\n"); + context.append("如发现被审计单位在").append(category).append("方面存在不符合中央八项规定的情况,可参考以下审计建议:\n\n"); + context.append(auditSuggestion).append("\n\n"); + } + + // 4. 历史内容 + if (StrUtil.isNotBlank(history)) { + context.append("## 历史生成内容\n"); + context.append("以下是之前生成的内容,请基于此进行优化:\n"); + context.append(history).append("\n\n"); + } + + // 5. 用户建议 + if (StrUtil.isNotBlank(suggestion)) { + context.append("## 用户优化建议\n"); + context.append("请根据以下建议对生成内容进行调整:\n"); + context.append(suggestion).append("\n\n"); + } + + // 6. 企业单位知识 + if (!knowledgeSources.get("enterprise").isEmpty()) { + context.append("## 企业单位知识\n"); + knowledgeSources.get("enterprise").forEach(knowledge -> + context.append(knowledge).append("\n")); + context.append("\n"); + } + + // 7. 法律法规知识 + if (!knowledgeSources.get("regulation").isEmpty()) { + context.append("## 法律法规知识\n"); + knowledgeSources.get("regulation").forEach(knowledge -> + context.append(knowledge).append("\n")); + context.append("\n"); + } + + // 8. 审计案例知识 + if (!knowledgeSources.get("auditCase").isEmpty()) { + context.append("## 审计案例知识\n"); + knowledgeSources.get("auditCase").forEach(knowledge -> + context.append(knowledge).append("\n")); + } // 2. 数据格式要求 context.append("\n## 数据格式要求\n"); @@ -274,56 +324,7 @@ public class AuditContent1EightRegServiceImpl extends AbstractAuditContentServic context.append("3. 测试结果判定需严格,对于制度不一致、执行不到位、证据不充分的情况必须判定为不通过\n"); // context.append("4. title字段必须按照八项规定顺序输出:一、二、三...八\n\n"); context.append("4. **title字段必须为\"").append(POLICY_TITLE_MAP.get(category)).append("\",不得生成其他标题**\n\n"); - - // 3. 参考数据(从常量类中获取) - context.append("## 参考数据\n"); - context.append("### 政策内容\n").append(AuditContent1EightRegConstants.POLICY_CONTENTS.get(category)).append("\n\n"); - context.append("### 实施细则\n").append(AuditContent1EightRegConstants.IMPLEMENTATION_DETAILS.get(category)).append("\n\n"); - - // 4. 审计建议 - 新增部分 - String auditSuggestion = AuditContent1EightRegConstants.AUDIT_SUGGESTIONS.get(category); - if (StrUtil.isNotBlank(auditSuggestion)) { - context.append("## 审计建议\n"); - context.append("如发现被审计单位在").append(category).append("方面存在不符合中央八项规定的情况,可参考以下审计建议:\n\n"); - context.append(auditSuggestion).append("\n\n"); - } - - // 4. 历史内容 - if (StrUtil.isNotBlank(history)) { - context.append("## 历史生成内容\n"); - context.append("以下是之前生成的内容,请基于此进行优化:\n"); - context.append(history).append("\n\n"); - } - - // 5. 用户建议 - if (StrUtil.isNotBlank(suggestion)) { - context.append("## 用户优化建议\n"); - context.append("请根据以下建议对生成内容进行调整:\n"); - context.append(suggestion).append("\n\n"); - } - - // 6. 企业单位知识 - if (!knowledgeSources.get("enterprise").isEmpty()) { - context.append("## 企业单位知识\n"); - knowledgeSources.get("enterprise").forEach(knowledge -> - context.append(knowledge).append("\n")); - context.append("\n"); - } - - // 7. 法律法规知识 - if (!knowledgeSources.get("regulation").isEmpty()) { - context.append("## 法律法规知识\n"); - knowledgeSources.get("regulation").forEach(knowledge -> - context.append(knowledge).append("\n")); - context.append("\n"); - } - - // 8. 审计案例知识 - if (!knowledgeSources.get("auditCase").isEmpty()) { - context.append("## 审计案例知识\n"); - knowledgeSources.get("auditCase").forEach(knowledge -> - context.append(knowledge).append("\n")); - } + context.append("5. 除了本次说明中提供的数据知识等依据,不能从其他地方读取数据,不能凭空捏造数据\n"); return context.toString(); } diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent1ExpenseServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent1ExpenseServiceImpl.java index ddda567..a14323c 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent1ExpenseServiceImpl.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent1ExpenseServiceImpl.java @@ -213,13 +213,6 @@ public class AuditContent1ExpenseServiceImpl extends AbstractAuditContentService context.append("3. 关注是否存在未经预算批准变相公款消费的情况\n"); context.append("4. 检查报销手续是否完善,是否存在超支使用\n\n"); - // 2. 特别提醒 - context.append("## 特别提醒\n"); - context.append("1. 必须准确识别支出类型:只提取\"公务接待\"、\"出国\"、\"公车运行维护\"、\"会议培训费\"四类支出\n"); - context.append("2. 不要将《工程造价和概(预)算执行情况表》等工程类报表误识别为\"三公经费\"报表\n"); -// context.append("3. 工作底稿索引必须使用实际存在的完整文件名称作为FileId\n\n"); - context.append("3. 工作底稿索引必须使用实际存在的完整文件名||FileUrl\n\n"); - // 3. 历史内容 if (StrUtil.isNotBlank(history)) { context.append("## 历史生成内容参考\n"); @@ -255,6 +248,14 @@ public class AuditContent1ExpenseServiceImpl extends AbstractAuditContentService knowledgeSources.get("auditCase").forEach(knowledge -> context.append(knowledge).append("\n")); } + + // 2. 特别提醒 + context.append("## 特别提醒\n"); + context.append("1. 必须准确识别支出类型:只提取\"公务接待\"、\"出国\"、\"公车运行维护\"、\"会议培训费\"四类支出\n"); + context.append("2. 不要将《工程造价和概(预)算执行情况表》等工程类报表误识别为\"三公经费\"报表\n"); +// context.append("3. 工作底稿索引必须使用实际存在的完整文件名称作为FileId\n\n"); + context.append("3. 工作底稿索引必须使用实际存在的完整文件名||FileUrl\n\n"); + context.append("4. 除了本次说明中提供的数据知识等依据,不能从其他地方读取数据,不能凭空捏造数据\n"); log.debug("构建的知识上下文长度: {}", context.length()); return context.toString(); diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent1LeaderListServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent1LeaderListServiceImpl.java index 14ef58f..d245bb5 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent1LeaderListServiceImpl.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent1LeaderListServiceImpl.java @@ -216,13 +216,6 @@ public class AuditContent1LeaderListServiceImpl extends AbstractAuditContentServ context.append("## 数据格式要求\n"); context.append("需要生成完整详细的领导班子名单数据:\n\n"); context.append(AuditContent1LeaderListConstants.DATA_FORMAT_REQUIREMENT); - context.append("\n\n重要要求:\n"); - context.append("1. 必须根据知识库内容生成尽可能多、尽可能完整的领导班子成员信息\n"); - context.append("2. 工作底稿索引必须准确对应实际文件名称,避免使用附表或章节标题\n"); - context.append("3. 任职期间格式统一为:YYYY.MM-YYYY.MM 或 YYYY.MM-至今\n"); - context.append("4. 主要工作责任要具体明确,不能笼统描述\n"); - context.append("5. 部门信息要具体,如:董事会、经理层、财务部、生产部等\n"); - context.append("6. 备注信息可以包含任命方式、试用期等特殊说明\n\n"); // 3. 历史内容 if (StrUtil.isNotBlank(history)) { @@ -261,6 +254,15 @@ public class AuditContent1LeaderListServiceImpl extends AbstractAuditContentServ knowledgeSources.get("auditCase").forEach(knowledge -> context.append(knowledge).append("\n")); } + + context.append("\n\n重要要求:\n"); + context.append("1. 必须根据知识库内容生成尽可能多、尽可能完整的领导班子成员信息\n"); + context.append("2. 工作底稿索引必须准确对应实际文件名称,避免使用附表或章节标题\n"); + context.append("3. 任职期间格式统一为:YYYY.MM-YYYY.MM 或 YYYY.MM-至今\n"); + context.append("4. 主要工作责任要具体明确,不能笼统描述\n"); + context.append("5. 部门信息要具体,如:董事会、经理层、财务部、生产部等\n"); + context.append("6. 备注信息可以包含任命方式、试用期等特殊说明\n\n"); + context.append("7. 除了本次说明中提供的数据知识等依据,不能从其他地方读取数据,不能凭空捏造数据\n"); log.debug("构建的知识上下文长度: {}", context.length()); return context.toString(); diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent2StrategyServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent2StrategyServiceImpl.java index dbd65b1..91c9607 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent2StrategyServiceImpl.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent2StrategyServiceImpl.java @@ -230,6 +230,9 @@ public class AuditContent2StrategyServiceImpl extends AbstractAuditContentServic context.append("## 用户建议\n"); context.append(suggestion).append("\n"); } + + context.append("\n\n重要要求:\n"); + context.append("1. 除了本次说明中提供的数据知识等依据,不能从其他地方读取数据,不能凭空捏造数据\n"); // 记录上下文长度用于监控 log.debug("分类 {} 构建的知识上下文长度: {} 字符", category, context.length()); diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent3DecisionServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent3DecisionServiceImpl.java index a817bc5..9364e75 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent3DecisionServiceImpl.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent3DecisionServiceImpl.java @@ -235,6 +235,9 @@ public class AuditContent3DecisionServiceImpl extends AbstractAuditContentServic if (StrUtil.isNotBlank(suggestion)) { context.append("## 用户优化建议\n").append(suggestion).append("\n"); } + + context.append("\n\n重要要求:\n"); + context.append("1. 除了本次说明中提供的数据知识等依据,不能从其他地方读取数据,不能凭空捏造数据\n"); return context.toString(); } diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent3TripleServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent3TripleServiceImpl.java index 30b537e..a07c062 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent3TripleServiceImpl.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent3TripleServiceImpl.java @@ -196,17 +196,6 @@ public class AuditContent3TripleServiceImpl extends AbstractAuditContentService context.append("- testResult:审计测试的结果(通过/不通过),严格判断,从严掌握通过标准\n"); // context.append("- workPaperIndex:相关《参考文件名FileId》,必须是实际存在的完整文件FileId,不能使用附表标题,确保能在文件夹中搜索到\n"); context.append("- workPaperIndex:相关[\"实际存在的完整文件名||FileUrl\"],必须是实际存在的完整文件名,不能使用附表标题,确保能在文件夹中搜索到\n"); - context.append("\n注意:\n"); - context.append("1. 请根据知识库内容尽可能全面地生成所有相关制度规定和检查点\n"); - context.append("2. 公司执行情况分析需包含:查阅了哪些文件、发现了什么内容、与制度的差异点、分析判断过程\n"); - context.append("3. 工作底稿索引必须准确对应实际文件名称,避免使用附表或章节标题\n"); - context.append("4. 测试结果判定需严格,对于制度不一致、执行不到位、证据不充分的情况必须判定为不通过\n"); - context.append("5. 审计检查的证据主要按公司制度为主,政策内容和集团制度为次要\n"); - context.append("6. 审计检查的证据增加判断公司制度是否与政策内容和集团制度相符\n"); - context.append("7. 历史问题整改分析:需核查历史问题是否已整改,结合最新时间材料(如最新会议纪要)分析当前是否存在相同问题\n"); - context.append("8. 项目上会核查:涉及三重一大的项目必须核查是否按规定上会,检查有无会议纪要作为证据\n"); - context.append("9. 制度权限关系:明确分析公司制度与集团制度的关联关系,权限设置必须遵循公司权限≤集团权限的原则\n"); - context.append("10. 层级关系识别:注意识别文件中的上级单位信息,分析制度执行是否符合层级管理要求\n\n"); // 3. 参考数据(从常量类中获取) context.append("## 参考数据\n"); @@ -250,7 +239,19 @@ public class AuditContent3TripleServiceImpl extends AbstractAuditContentService knowledgeSources.get("auditCase").forEach(knowledge -> context.append(knowledge).append("\n")); } - + + context.append("\n注意:\n"); + context.append("1. 请根据知识库内容尽可能全面地生成所有相关制度规定和检查点\n"); + context.append("2. 公司执行情况分析需包含:查阅了哪些文件、发现了什么内容、与制度的差异点、分析判断过程\n"); + context.append("3. 工作底稿索引必须准确对应实际文件名称,避免使用附表或章节标题\n"); + context.append("4. 测试结果判定需严格,对于制度不一致、执行不到位、证据不充分的情况必须判定为不通过\n"); + context.append("5. 审计检查的证据主要按公司制度为主,政策内容和集团制度为次要\n"); + context.append("6. 审计检查的证据增加判断公司制度是否与政策内容和集团制度相符\n"); + context.append("7. 历史问题整改分析:需核查历史问题是否已整改,结合最新时间材料(如最新会议纪要)分析当前是否存在相同问题\n"); + context.append("8. 项目上会核查:涉及三重一大的项目必须核查是否按规定上会,检查有无会议纪要作为证据\n"); + context.append("9. 制度权限关系:明确分析公司制度与集团制度的关联关系,权限设置必须遵循公司权限≤集团权限的原则\n"); + context.append("10. 层级关系识别:注意识别文件中的上级单位信息,分析制度执行是否符合层级管理要求\n\n"); + context.append("11. 除了本次说明中提供的数据知识等依据,不能从其他地方读取数据,不能凭空捏造数据\n"); return context.toString(); } diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent4TargetServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent4TargetServiceImpl.java index d3689c6..b48eb5a 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent4TargetServiceImpl.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent4TargetServiceImpl.java @@ -173,23 +173,7 @@ public class AuditContent4TargetServiceImpl extends AbstractAuditContentService // 8. 审计证据要求 context.append("## 审计证据要求\n"); context.append(AuditContent4TargetConstants.AUDIT_EVIDENCE_REQUIREMENTS).append("\n\n"); - - // 9. 特别提醒(新增关键优化点) - context.append("## 特别提醒\n"); - context.append("1. 审计证据必须包含具体的查阅过程:查阅了哪些文件、文件中发现了什么内容\n"); -// context.append("2. workPaperIndex必须填写实际存在的完整文件FileId,确保能在文件夹中搜索到\n"); - context.append("2. workPaperIndex必须填写实际存在的完整文件名||FileUrl,确保能在文件夹中搜索到\n"); - context.append("3. 完成情况判定必须基于充分证据:只有证据充分且完全符合要求才能判定为已完成\n"); - context.append("4. 对于执行不到位、效果不佳、证据不充分的情况必须在备注中说明\n"); - context.append("5. 尽可能识别知识库中所有相关年度,生成对应的审计记录\n"); - context.append("6. 如果知识库中没有单位自定目标文件,请根据企业职责和上级目标合理推断单位自定计划内容\n"); - context.append("7. 不能填写简单的\"无\",要提供有意义的描述\n"); - context.append("8. 对于正在进行的年度,完成情况应填写\"年度未结束无法评估\"\n"); - context.append("9. 如果知识库中有多个目标责任文件,每个文件都应生成独立的审计记录\n"); - context.append("10. 同一年度可能有不同类型的多个目标责任,应尽可能多地生成审计记录\n"); - context.append("11. 不能填写简单的\"无\",要提供有意义的描述\n"); - context.append("12. 对于正在进行的年度,完成情况应填写\"无法评估\"\n\n"); - + // 10. 法规和案例参考 if (!knowledgeSources.get("regulation").isEmpty()) { context.append("## 法律法规参考\n"); @@ -216,7 +200,25 @@ public class AuditContent4TargetServiceImpl extends AbstractAuditContentService context.append("## 用户建议\n"); context.append(suggestion).append("\n\n"); } - + + // 9. 特别提醒(新增关键优化点) + context.append("## 特别提醒\n"); + context.append("1. 审计证据必须包含具体的查阅过程:查阅了哪些文件、文件中发现了什么内容\n"); +// context.append("2. workPaperIndex必须填写实际存在的完整文件FileId,确保能在文件夹中搜索到\n"); + context.append("2. workPaperIndex必须填写实际存在的完整文件名||FileUrl,确保能在文件夹中搜索到\n"); + context.append("3. 完成情况判定必须基于充分证据:只有证据充分且完全符合要求才能判定为已完成\n"); + context.append("4. 对于执行不到位、效果不佳、证据不充分的情况必须在备注中说明\n"); + context.append("5. 尽可能识别知识库中所有相关年度,生成对应的审计记录\n"); +// context.append("6. 如果知识库中没有单位自定目标文件,请根据企业职责和上级目标合理推断单位自定计划内容\n"); + context.append("6. 不能填写简单的\"无\",要提供有意义的描述\n"); + context.append("7. 对于正在进行的年度,完成情况应填写\"年度未结束无法评估\"\n"); + context.append("8. 如果知识库中有多个目标责任文件,每个文件都应生成独立的审计记录\n"); + context.append("9. 同一年度可能有不同类型的多个目标责任,应尽可能多地生成审计记录\n"); + context.append("10. 除了本次说明中提供的数据知识等依据,不能从其他地方读取数据,不能凭空捏造数据\n"); +// context.append("11. 不能填写简单的\"无\",要提供有意义的描述\n"); +// context.append("12. 对于正在进行的年度,完成情况应填写\"无法评估\"\n\n"); + + log.debug("目标责任制审计知识上下文长度: {} 字符", context.length()); return context.toString(); diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent5BudgetExecutionServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent5BudgetExecutionServiceImpl.java index b4b93da..dd7f0a9 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent5BudgetExecutionServiceImpl.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent5BudgetExecutionServiceImpl.java @@ -232,18 +232,6 @@ public class AuditContent5BudgetExecutionServiceImpl extends AbstractAuditConten context.append("## 审计证据要求\n"); context.append(AuditContent5BudgetExecutionConstants.AUDIT_EVIDENCE_REQUIREMENTS).append("\n\n"); - // 10. 特别提醒 - 强调全面识别 - context.append("## 特别提醒\n"); - context.append("1. 必须全面分析预算执行全过程,包括执行进度、执行效果、执行合规性\n"); - context.append("2. 重点关注预算执行率、资金到位率、预算执行偏差等关键指标\n"); - context.append("3. 金额字段应填写具体数值,如\"1,000,000.00\",不能填写简单的\"有\"或\"无\"\n"); -// context.append("4. workPaperIndex必须填写实际存在的完整文件FileId\n"); - context.append("4. workPaperIndex必须填写实际存在的完整文件名||FileUrl\n"); - context.append("5. 对于无数据的字段,可填写\"-\"或留空,但不能填写\"无\"\n"); - context.append("6. 基于预算执行全流程进行审计分析,包括月度、季度、年度执行情况\n"); - context.append("7. 重点关注预算执行偏差原因分析和整改措施\n"); - context.append("8. 尽可能多地生成审计记录,覆盖所有预算项目和执行环节\n\n"); - // 11. 审计项目参考 context.append("## 审计项目参考(常见类型)\n"); AuditContent5BudgetExecutionConstants.AUDIT_PROJECT_TYPES.forEach(project -> @@ -276,6 +264,19 @@ public class AuditContent5BudgetExecutionServiceImpl extends AbstractAuditConten context.append("## 用户建议\n"); context.append(suggestion).append("\n\n"); } + + // 10. 特别提醒 - 强调全面识别 + context.append("## 特别提醒\n"); + context.append("1. 必须全面分析预算执行全过程,包括执行进度、执行效果、执行合规性\n"); + context.append("2. 重点关注预算执行率、资金到位率、预算执行偏差等关键指标\n"); + context.append("3. 金额字段应填写具体数值,如\"1,000,000.00\",不能填写简单的\"有\"或\"无\"\n"); +// context.append("4. workPaperIndex必须填写实际存在的完整文件FileId\n"); + context.append("4. workPaperIndex必须填写实际存在的完整文件名||FileUrl\n"); + context.append("5. 对于无数据的字段,可填写\"-\"或留空,但不能填写\"无\"\n"); + context.append("6. 基于预算执行全流程进行审计分析,包括月度、季度、年度执行情况\n"); + context.append("7. 重点关注预算执行偏差原因分析和整改措施\n"); + context.append("8. 尽可能多地生成审计记录,覆盖所有预算项目和执行环节\n\n"); + context.append("9. 除了本次说明中提供的数据知识等依据,不能从其他地方读取数据,不能凭空捏造数据\n"); log.debug("预算执行情况审计知识上下文长度: {} 字符", context.length()); diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent5BudgetManageServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent5BudgetManageServiceImpl.java index 927712a..9f59ba9 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent5BudgetManageServiceImpl.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent5BudgetManageServiceImpl.java @@ -232,17 +232,6 @@ public class AuditContent5BudgetManageServiceImpl extends AbstractAuditContentSe context.append("## 审计证据要求\n"); context.append(AuditContent5BudgetManageConstants.AUDIT_EVIDENCE_REQUIREMENTS).append("\n\n"); - // 10. 特别提醒 - 强调全面识别 - context.append("## 特别提醒\n"); - context.append("1. 必须全面识别知识库中所有预算科目,包括:基本支出、项目支出、人员经费、公用经费等\n"); - context.append("2. 每个独立的预算科目都要生成独立的审计记录,不限制数量,尽可能多地生成\n"); - context.append("3. 金额字段应填写具体数值,如\"1,000,000.00\",不能填写简单的\"有\"或\"无\"\n"); -// context.append("4. workPaperIndex必须填写实际存在的完整文件FileId\n"); - context.append("4. workPaperIndex必须填写实际存在的完整文件名||FileUrl\n"); - context.append("5. 对于无数据的字段,可填写\"-\"或留空,但不能填写\"无\"\n"); - context.append("6. 基于预算编制、调整、执行的全流程进行审计分析\n"); - context.append("7. 重点关注预算调整的合规性和预算执行的真实性\n\n"); - // 11. 预算科目参考 context.append("## 预算科目参考(常见类型)\n"); AuditContent5BudgetManageConstants.BUDGET_SUBJECT_TYPES.forEach(subject -> @@ -275,6 +264,18 @@ public class AuditContent5BudgetManageServiceImpl extends AbstractAuditContentSe context.append("## 用户建议\n"); context.append(suggestion).append("\n\n"); } + + // 10. 特别提醒 - 强调全面识别 + context.append("## 特别提醒\n"); + context.append("1. 必须全面识别知识库中所有预算科目,包括:基本支出、项目支出、人员经费、公用经费等\n"); + context.append("2. 每个独立的预算科目都要生成独立的审计记录,不限制数量,尽可能多地生成\n"); + context.append("3. 金额字段应填写具体数值,如\"1,000,000.00\",不能填写简单的\"有\"或\"无\"\n"); +// context.append("4. workPaperIndex必须填写实际存在的完整文件FileId\n"); + context.append("4. workPaperIndex必须填写实际存在的完整文件名||FileUrl\n"); + context.append("5. 对于无数据的字段,可填写\"-\"或留空,但不能填写\"无\"\n"); + context.append("6. 基于预算编制、调整、执行的全流程进行审计分析\n"); + context.append("7. 重点关注预算调整的合规性和预算执行的真实性\n\n"); + context.append("8. 除了本次说明中提供的数据知识等依据,不能从其他地方读取数据,不能凭空捏造数据\n"); log.debug("预算管理审计知识上下文长度: {} 字符", context.length()); diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent6StateAssetsServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent6StateAssetsServiceImpl.java index d08ca0b..e223d91 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent6StateAssetsServiceImpl.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent6StateAssetsServiceImpl.java @@ -187,17 +187,6 @@ public class AuditContent6StateAssetsServiceImpl extends AbstractAuditContentSer context.append("## 审计证据要求\n"); context.append(AuditContent6StateAssetsConstants.AUDIT_EVIDENCE_REQUIREMENTS).append("\n\n"); - // 9. 特别提醒 - 强调全面识别 - context.append("## 特别提醒\n"); - context.append("1. 必须全面识别知识库中所有国有资产,包括:房屋、土地、车辆、机械设备、办公设备、电子设备、家具、无形资产等\n"); - context.append("2. 每个独立的资产都要生成独立的审计记录,不限制数量,尽可能多地生成\n"); - context.append("3. 即使资产信息不完整,也要基于现有信息生成审计记录\n"); -// context.append("4. workPaperIndex必须填写实际存在的完整文件FileId\n"); - context.append("4. workPaperIndex必须填写实际存在的完整文件名||FileUrl\n"); - context.append("5. 对于未出租资产,承租方、合同金额等字段填写\"未出租\"\n"); - context.append("6. 备注中应详细说明资产状况、使用情况、合规性评价\n"); - context.append("7. 不能填写简单的\"无\",要提供有意义的描述\n\n"); - // 10. 法规和案例参考 if (!knowledgeSources.get("regulation").isEmpty()) { context.append("## 法律法规参考\n"); @@ -224,6 +213,18 @@ public class AuditContent6StateAssetsServiceImpl extends AbstractAuditContentSer context.append("## 用户建议\n"); context.append(suggestion).append("\n\n"); } + + // 9. 特别提醒 - 强调全面识别 + context.append("## 特别提醒\n"); + context.append("1. 必须全面识别知识库中所有国有资产,包括:房屋、土地、车辆、机械设备、办公设备、电子设备、家具、无形资产等\n"); + context.append("2. 每个独立的资产都要生成独立的审计记录,不限制数量,尽可能多地生成\n"); + context.append("3. 即使资产信息不完整,也要基于现有信息生成审计记录\n"); +// context.append("4. workPaperIndex必须填写实际存在的完整文件FileId\n"); + context.append("4. workPaperIndex必须填写实际存在的完整文件名||FileUrl\n"); + context.append("5. 对于未出租资产,承租方、合同金额等字段填写\"未出租\"\n"); + context.append("6. 备注中应详细说明资产状况、使用情况、合规性评价\n"); + context.append("7. 不能填写简单的\"无\",要提供有意义的描述\n\n"); + context.append("8. 除了本次说明中提供的数据知识等依据,不能从其他地方读取数据,不能凭空捏造数据\n"); log.debug("国资管理审计知识上下文长度: {} 字符", context.length()); diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent7InvestmentServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent7InvestmentServiceImpl.java index e86e411..d7b9ef9 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent7InvestmentServiceImpl.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent7InvestmentServiceImpl.java @@ -293,7 +293,9 @@ public class AuditContent7InvestmentServiceImpl extends AbstractAuditContentServ knowledgeSources.get("financial").forEach(knowledge -> context.append(knowledge).append("\n")); } - + + context.append("## 特别提醒\n"); + context.append("1. 除了本次说明中提供的数据知识等依据,不能从其他地方读取数据,不能凭空捏造数据\n"); return context.toString(); } diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent8InternalControlServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent8InternalControlServiceImpl.java index d272313..f5fab89 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent8InternalControlServiceImpl.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent8InternalControlServiceImpl.java @@ -243,13 +243,6 @@ public class AuditContent8InternalControlServiceImpl extends AbstractAuditConten context.append("4. 每条记录的测试结果必须基于该步骤的检查证据独立判断\n"); context.append("5. 控制环节、控制要求、控制活动描述、控制职责岗位字段在所有相关记录中保持相同\n\n"); - context.append("**注意:**\n"); - context.append("1. 检查证据必须详细描述:针对当前测试步骤查阅了哪些制度文件、检查了哪些业务凭证、访谈了哪些人员、发现了什么问题\n"); - context.append("2. 测试结果判定必须严格,对于制度不健全、执行不到位、证据不充分的情况必须判定为\"不通过\"\n"); - context.append("3. 工作底稿索引必须准确对应实际审计工作底稿文件名称,不能使用章节标题\n"); - context.append("4. 审计检查可采用:符合性测试、穿行测试、抽样测试、观察询问、文档查阅等方法\n"); - context.append("5. 重点关注内部控制制度的建立健全性和执行的有效性\n\n"); - // 3. 审计测试方法参考 context.append("## 审计测试方法参考\n"); context.append("审计时可采用的测试方法:\n"); @@ -292,7 +285,14 @@ public class AuditContent8InternalControlServiceImpl extends AbstractAuditConten knowledgeSources.get("auditCase").forEach(knowledge -> context.append(knowledge).append("\n")); } - + + context.append("**注意:**\n"); + context.append("1. 检查证据必须详细描述:针对当前测试步骤查阅了哪些制度文件、检查了哪些业务凭证、访谈了哪些人员、发现了什么问题\n"); + context.append("2. 测试结果判定必须严格,对于制度不健全、执行不到位、证据不充分的情况必须判定为\"不通过\"\n"); + context.append("3. 工作底稿索引必须准确对应实际审计工作底稿文件名称,不能使用章节标题\n"); + context.append("4. 审计检查可采用:符合性测试、穿行测试、抽样测试、观察询问、文档查阅等方法\n"); + context.append("5. 重点关注内部控制制度的建立健全性和执行的有效性\n\n"); + context.append("6. 除了本次说明中提供的数据知识等依据,不能从其他地方读取数据,不能凭空捏造数据\n"); return context.toString(); } diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent9PersonnelServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent9PersonnelServiceImpl.java index d5d82cf..cf5412e 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent9PersonnelServiceImpl.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent9PersonnelServiceImpl.java @@ -269,14 +269,6 @@ public class AuditContent9PersonnelServiceImpl extends AbstractAuditContentServi context.append("## 生成结果要求\n"); context.append(subContent.getGenerationResult()).append("\n\n"); - context.append("## 重要要求\n"); - context.append("1. 必须使用具体单位名称,禁止使用'XX单位'等模糊词汇\n"); - context.append("2. 审计记录必须具体,包含文件名称、数据、人员等详细信息\n"); - context.append("3. 重点关注问题发现,提供具体证据和建议\n"); - context.append("4. **如果在上传资料中找不到相应证据/凭证,不要直接判定违反规定,应说明'未找到相关材料,无法判定'**\n"); - context.append("5. **除了审计证据中列出的资料清单,还需主动查找上传材料中其他涉及审计内容和目标的材料**\n"); - context.append("6. **合同与主体公司不相关时,不应判定在主体公司责任范围内,需明确区分责任主体**\n\n"); - context.append("## 审计判断原则\n"); context.append("1. **证据不足原则**:当缺乏关键证据时,不做出违规判定\n"); context.append("2. **主动查找原则**:不局限于给定清单,主动识别所有相关材料\n"); @@ -346,6 +338,15 @@ public class AuditContent9PersonnelServiceImpl extends AbstractAuditContentServi knowledgeSources.get("auditCase").forEach(info -> context.append(info).append("\n")); } + + context.append("## 重要要求\n"); + context.append("1. 必须使用具体单位名称,禁止使用'XX单位'等模糊词汇\n"); + context.append("2. 审计记录必须具体,包含文件名称、数据、人员等详细信息\n"); + context.append("3. 重点关注问题发现,提供具体证据和建议\n"); + context.append("4. **如果在上传资料中找不到相应证据/凭证,不要直接判定违反规定,应说明'未找到相关材料,无法判定'**\n"); + context.append("5. **除了审计证据中列出的资料清单,还需主动查找上传材料中其他涉及审计内容和目标的材料**\n"); + context.append("6. **合同与主体公司不相关时,不应判定在主体公司责任范围内,需明确区分责任主体**\n\n"); + context.append("7. 除了本次说明中提供的数据知识等依据,不能从其他地方读取数据,不能凭空捏造数据\n"); return context.toString(); } diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditReportServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditReportServiceImpl.java index f97fed8..ebce5b6 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/AuditReportServiceImpl.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditReportServiceImpl.java @@ -624,9 +624,9 @@ public class AuditReportServiceImpl extends ServiceImpl