From 8b841767e275a081233f77ae9f02e69d52b4bc8d Mon Sep 17 00:00:00 2001 From: yuance <182865460@qq.com> Date: Thu, 30 Oct 2025 16:55:29 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=89=E9=87=8D=E4=B8=80=E5=A4=A7=E7=94=9F?= =?UTF-8?q?=E6=88=90=E6=8E=A5=E5=8F=A3=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AuditContentController3.java | 100 +++- .../gxwebsoft/ai/dto/AuditContentRequest.java | 12 + .../ai/service/AuditContentService3.java | 5 +- .../ai/service/KnowledgeBaseService.java | 16 + .../impl/AuditContentServiceImpl3.java | 528 +++++++++--------- .../impl/KnowledgeBaseServiceImpl.java | 32 ++ .../ai/util/AiCloudKnowledgeBaseUtil.java | 20 + .../com/gxwebsoft/pwl/entity/PwlProject.java | 3 + .../pwl/mapper/xml/PwlProjectMapper.xml | 3 + .../gxwebsoft/pwl/param/PwlProjectParam.java | 3 + 10 files changed, 445 insertions(+), 277 deletions(-) diff --git a/src/main/java/com/gxwebsoft/ai/controller/AuditContentController3.java b/src/main/java/com/gxwebsoft/ai/controller/AuditContentController3.java index ea17175..09b0660 100644 --- a/src/main/java/com/gxwebsoft/ai/controller/AuditContentController3.java +++ b/src/main/java/com/gxwebsoft/ai/controller/AuditContentController3.java @@ -1,21 +1,36 @@ package com.gxwebsoft.ai.controller; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.gxwebsoft.ai.dto.AuditContentRequest; +import com.gxwebsoft.ai.entity.AiCloudDoc; +import com.gxwebsoft.ai.entity.AiCloudFile; 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 lombok.extern.slf4j.Slf4j; + +import com.gxwebsoft.ai.service.AiCloudDocService; +import com.gxwebsoft.ai.service.AiCloudFileService; import com.gxwebsoft.ai.service.AuditContentService3; +import com.gxwebsoft.ai.service.KnowledgeBaseService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; + +import java.util.*; +import java.util.stream.Collectors; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; /** - * 审计内容3控制器 - 重大经济决策调查表 + * 审计内容3控制器 - 三重一大制度对比分析 */ -@Tag(name = "审计内容3-重大经济决策") +@Slf4j +@Tag(name = "审计内容3-三重一大制度对比") @RestController @RequestMapping("/api/ai/auditContent3") public class AuditContentController3 extends BaseController { @@ -23,18 +38,34 @@ public class AuditContentController3 extends BaseController { @Autowired private AuditContentService3 auditContentService3; + @Autowired + private AiCloudDocService aiCloudDocService; + + @Autowired + private AiCloudFileService aiCloudFileService; + + @Autowired + private KnowledgeBaseService knowledgeBaseService; + /** - * 生成重大经济决策调查表数据 + * 生成三重一大制度对比分析表数据 */ - @Operation(summary = "生成重大经济决策调查表") - @PostMapping("/generateDecisionTable") - public ApiResult generateDecisionTable(@RequestBody AuditContentRequest request) { - + @Operation(summary = "生成三重一大制度对比分析表") + @PostMapping("/generateTripleOneTable") + public ApiResult generateTripleOneTable(@RequestBody AuditContentRequest request) { final User loginUser = getLoginUser(); + String kbIdTmp = ""; + try { - // 生成重大经济决策调查表数据 - JSONObject result = auditContentService3.generateDecisionTableData( - request.getKbIds(), + // 创建临时知识库(如果需要) + if (!request.getDocList().isEmpty() || !request.getFileList().isEmpty()) { + kbIdTmp = createTempKnowledgeBase(request); + } + + // 生成三重一大制度对比分析表数据 + String knowledgeBaseId = StrUtil.isNotBlank(kbIdTmp) ? kbIdTmp : request.getKbIds(); + JSONObject result = auditContentService3.generateTripleOneTableData( + knowledgeBaseId, request.getLibraryIds(), request.getProjectLibrary(), loginUser.getUsername(), @@ -44,8 +75,55 @@ public class AuditContentController3 extends BaseController { return success(result); } catch (Exception e) { - return fail("生成重大经济决策调查表失败: " + e.getMessage()); + log.error("生成三重一大制度对比分析表失败", e); + return fail("生成三重一大制度对比分析表失败: " + e.getMessage()); + } finally { + cleanupTempKnowledgeBase(kbIdTmp); } } + /** + * 创建临时知识库并提交文档 + */ + private String createTempKnowledgeBase(AuditContentRequest request) { + String kbIdTmp = knowledgeBaseService.createKnowledgeBaseTemp(); + + // 收集文档ID + Set docIds = request.getDocList().stream() + .flatMap(docId -> aiCloudDocService.getSelfAndChildren(docId).stream()) + .map(AiCloudDoc::getId) + .collect(Collectors.toSet()); + + // 查询相关文件 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() + .in(!docIds.isEmpty(), AiCloudFile::getDocId, docIds) + .or(!request.getFileList().isEmpty()) + .in(!request.getFileList().isEmpty(), AiCloudFile::getId, request.getFileList()); + + List fileList = aiCloudFileService.list(queryWrapper); + + // 提取文件ID并提交到知识库 + Set kbFileIds = fileList.stream() + .map(AiCloudFile::getFileId) + .collect(Collectors.toSet()); + + if (!kbFileIds.isEmpty()) { + knowledgeBaseService.submitDocuments(kbIdTmp, new ArrayList<>(kbFileIds)); + } + + return kbIdTmp; + } + + /** + * 清理临时知识库 + */ + private void cleanupTempKnowledgeBase(String kbId) { + if (StrUtil.isNotBlank(kbId)) { + try { + knowledgeBaseService.deleteIndex(kbId); + } catch (Exception e) { + log.warn("删除临时知识库失败: {}", kbId, e); + } + } + } } \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/ai/dto/AuditContentRequest.java b/src/main/java/com/gxwebsoft/ai/dto/AuditContentRequest.java index 2e64482..3b243c5 100644 --- a/src/main/java/com/gxwebsoft/ai/dto/AuditContentRequest.java +++ b/src/main/java/com/gxwebsoft/ai/dto/AuditContentRequest.java @@ -1,5 +1,7 @@ package com.gxwebsoft.ai.dto; +import java.util.List; + import lombok.Data; /** @@ -32,4 +34,14 @@ public class AuditContentRequest { * 优化建议 */ private String suggestion; + + /** + * 目录列表 + */ + private List docList; + + /** + * 文件列表 + */ + private List fileList; } diff --git a/src/main/java/com/gxwebsoft/ai/service/AuditContentService3.java b/src/main/java/com/gxwebsoft/ai/service/AuditContentService3.java index 051cc92..cf7aea3 100644 --- a/src/main/java/com/gxwebsoft/ai/service/AuditContentService3.java +++ b/src/main/java/com/gxwebsoft/ai/service/AuditContentService3.java @@ -5,7 +5,8 @@ import com.alibaba.fastjson.JSONObject; public interface AuditContentService3 { /** - * 生成重大经济决策调查表数据 + * 生成三重一大制度对比分析表数据 */ - JSONObject generateDecisionTableData(String kbIds, String libraryIds, String projectLibrary, String userName, String history, String suggestion); + JSONObject generateTripleOneTableData(String kbIds, String libraryIds, String projectLibrary, + String userName, String history, String suggestion); } \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/ai/service/KnowledgeBaseService.java b/src/main/java/com/gxwebsoft/ai/service/KnowledgeBaseService.java index 42a02da..dcb3909 100644 --- a/src/main/java/com/gxwebsoft/ai/service/KnowledgeBaseService.java +++ b/src/main/java/com/gxwebsoft/ai/service/KnowledgeBaseService.java @@ -2,6 +2,7 @@ package com.gxwebsoft.ai.service; import com.gxwebsoft.ai.dto.KnowledgeBaseRequest; +import java.util.List; import java.util.Map; import java.util.Set; @@ -24,6 +25,11 @@ public interface KnowledgeBaseService { */ String createKnowledgeBase(String companyName, String companyCode); + /** + * 创建临时知识库 + */ + String createKnowledgeBaseTemp(); + /** * 检查知识库是否存 */ @@ -39,6 +45,11 @@ public interface KnowledgeBaseService { */ Map listDocuments(String kbId, Integer pageSize, Integer pageNumber); + /** + * 删除知识库 + */ + boolean deleteIndex(String kbId); + /** * 删除知识库下的文档 */ @@ -53,4 +64,9 @@ public interface KnowledgeBaseService { * 知识库追加导入已解析的文档 */ void submitDocuments(String kbId, String fileId); + + /** + * 知识库追加导入已解析的文档 + */ + void submitDocuments(String kbId, List fileIds); } \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContentServiceImpl3.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContentServiceImpl3.java index dd68e2b..6f84bdd 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContentServiceImpl3.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContentServiceImpl3.java @@ -6,6 +6,8 @@ import com.aliyun.bailian20231229.models.RetrieveResponseBody; import com.aliyun.bailian20231229.models.RetrieveResponseBody.RetrieveResponseBodyData; import com.aliyun.bailian20231229.models.RetrieveResponseBody.RetrieveResponseBodyDataNodes; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.gxwebsoft.ai.config.KnowledgeBaseConfig; @@ -38,105 +40,98 @@ public class AuditContentServiceImpl3 implements AuditContentService3 { @Autowired private PwlProjectLibraryService pwlProjectLibraryService; - + // 工作流配置 - private static final String DECISION_TABLE_WORKFLOW_URL = "http://1.14.159.185:8180/v1/workflows/run"; - private static final String DECISION_TABLE_TOKEN = "Bearer app-yN7Q8GEN9E7SCMkhI6HaAagW"; - - // 缓存 - private final Map> knowledgeCache = new ConcurrentHashMap<>(); - private static final long CACHE_EXPIRE_TIME = 5 * 60 * 1000; - private final Map cacheTimestamps = new ConcurrentHashMap<>(); - - // 决策程序类型 - private static final Map DECISION_PROCEDURES = new HashMap<>(); + private static final String TRIPLE_ONE_WORKFLOW_URL = "http://1.14.159.185:8180/v1/workflows/run"; + private static final String TRIPLE_ONE_TOKEN = "Bearer app-tjXbmHDE6daMbYOT4O13ev2X"; + + // 三重一大分类定义 + private static final Map TRIPLE_ONE_CATEGORIES = new LinkedHashMap<>(); static { - DECISION_PROCEDURES.put("会议决策", "通过召开专题会议进行集体决策,会议纪要完整"); - DECISION_PROCEDURES.put("会签决策", "通过会签方式进行决策,相关人员签字确认"); - DECISION_PROCEDURES.put("书面决策", "通过书面请示报告方式进行决策"); - DECISION_PROCEDURES.put("授权决策", "在授权范围内由负责人直接决策"); + TRIPLE_ONE_CATEGORIES.put("重大决策", "重大决策事项的定义和范围"); + TRIPLE_ONE_CATEGORIES.put("重要人事任免", "重要人事任免事项的定义和范围"); + TRIPLE_ONE_CATEGORIES.put("重大项目安排", "重大项目安排事项的定义和范围"); + TRIPLE_ONE_CATEGORIES.put("大额度资金运作", "大额度资金运作事项的定义和范围"); + TRIPLE_ONE_CATEGORIES.put("决策权力主体和程序", "决策权力主体和程序的规定"); } + // 关键词权重 private static final Map KEYWORD_WEIGHTS; static { Map map = new HashMap<>(); map.put("三重一大", 10); + map.put("重大决策", 9); + map.put("重要人事任免", 9); + map.put("重大项目安排", 9); + map.put("大额度资金运作", 9); + map.put("决策程序", 8); + map.put("党委会", 7); + map.put("董事会", 7); + map.put("总经理办公会", 7); map.put("集体决策", 8); - map.put("重大经济决策", 9); - map.put("会议纪要", 7); - map.put("决策程序", 7); - map.put("决策标准", 6); - map.put("审计方法", 6); - map.put("重大预算", 5); - map.put("重大项目", 5); - map.put("重大采购", 5); - map.put("重大投资", 5); + map.put("会议纪要", 6); + map.put("金额标准", 6); KEYWORD_WEIGHTS = Collections.unmodifiableMap(map); } @Override - public JSONObject generateDecisionTableData(String kbIds, String libraryIds, String projectLibrary, String userName, String history, String suggestion) { - log.info("开始生成重大经济决策调查表数据 - 用户: {}, kbIds: {}, libraryIds: {}, projectLibrary: {}", userName, kbIds, libraryIds, projectLibrary); + public JSONObject generateTripleOneTableData(String kbIds, String libraryIds, String projectLibrary, + String userName, String history, String suggestion) { + log.info("开始生成三重一大制度对比分析表数据 - 用户: {}, kbIds: {}, libraryIds: {}, projectLibrary: {}", + userName, kbIds, libraryIds, projectLibrary); JSONObject result = new JSONObject(); long startTime = System.currentTimeMillis(); try { // 1. 从不同知识库召回相关内容 - Map> knowledgeSources = retrieveDecisionKnowledgeSeparated(kbIds, libraryIds, projectLibrary); + Map> knowledgeSources = retrieveTripleOneKnowledge(kbIds, libraryIds, projectLibrary); - // 2. 生成重大经济决策调查表数据 - JSONArray decisionTableData = generateDecisionTable(knowledgeSources, userName, history, suggestion); + // 2. 生成三重一大制度对比分析表数据 + JSONArray comparisonTableData = generateComparisonTable(knowledgeSources, userName, history, suggestion); // 3. 数据质量检查 - decisionTableData = validateAndEnhanceData(decisionTableData); + comparisonTableData = validateAndEnhanceComparisonData(comparisonTableData); // 4. 构建返回结果 result.put("success", true); - result.put("data", decisionTableData); - result.put("total_records", decisionTableData.size()); + result.put("data", comparisonTableData); + result.put("total_records", comparisonTableData.size()); result.put("generated_time", new Date().toString()); - result.put("core_knowledge_count", knowledgeSources.get("core").size()); - result.put("case_knowledge_count", knowledgeSources.get("case").size()); - result.put("regulation_knowledge_count", knowledgeSources.get("regulation").size()); result.put("processing_time", (System.currentTimeMillis() - startTime) + "ms"); - log.info("重大经济决策调查表生成成功 - 记录数: {}, 处理时间: {}ms", - decisionTableData.size(), (System.currentTimeMillis() - startTime)); + log.info("三重一大制度对比分析表生成成功 - 记录数: {}, 处理时间: {}ms", + comparisonTableData.size(), (System.currentTimeMillis() - startTime)); } catch (Exception e) { - log.error("生成重大经济决策调查表失败", e); - // 直接抛出异常,不返回默认数据 - throw new RuntimeException("生成重大经济决策调查表失败: " + e.getMessage(), e); + log.error("生成三重一大制度对比分析表失败", e); + result.put("success", false); + result.put("error", e.getMessage()); + throw new RuntimeException("生成三重一大制度对比分析表失败: " + e.getMessage(), e); } return result; } /** - * 分离不同知识库的检索策略 + * 检索三重一大相关知识 */ - private Map> retrieveDecisionKnowledgeSeparated(String kbIds, String libraryIds, String projectLibrary) { + private Map> retrieveTripleOneKnowledge(String kbIds, String libraryIds, String projectLibrary) { Map> knowledgeSources = new HashMap<>(); - knowledgeSources.put("core", new ArrayList<>()); - knowledgeSources.put("case", new ArrayList<>()); - knowledgeSources.put("regulation", new ArrayList<>()); + knowledgeSources.put("enterprise", new ArrayList<>()); // 企业单位库 + knowledgeSources.put("regulation", new ArrayList<>()); // 公共法律法规库 + knowledgeSources.put("auditCase", new ArrayList<>()); // 审计案例库 - // 核心审计库 - 主要来源 + // 企业单位库检索 - 主要来源 if (StrUtil.isNotBlank(kbIds)) { Arrays.stream(kbIds.split(",")) .map(String::trim) .filter(StrUtil::isNotBlank) - .forEach(kbId -> knowledgeSources.get("core") - .addAll(queryKnowledgeBaseWithCache(kbId, buildCoreQueries(), 150))); + .forEach(kbId -> knowledgeSources.get("enterprise") + .addAll(queryKnowledgeBase(kbId, buildEnterpriseQueries(), 200))); } - // 案例库 - 辅助参考 - if (StrUtil.isNotBlank(projectLibrary)) { - knowledgeSources.get("case").addAll(queryKnowledgeBaseWithCache(projectLibrary, buildCaseQueries(), 100)); - } - - // 法规库 - 制度校验 + // 公共法律法规库检索 if (StrUtil.isNotBlank(libraryIds)) { List idList = StrUtil.split(libraryIds, ','); List ret = pwlProjectLibraryService.list( @@ -147,14 +142,20 @@ public class AuditContentServiceImpl3 implements AuditContentService3 { .map(String::trim) .filter(StrUtil::isNotBlank) .forEach(libId -> knowledgeSources.get("regulation") - .addAll(queryKnowledgeBaseWithCache(libId, buildRegulationQueries(), 80))); + .addAll(queryKnowledgeBase(libId, buildRegulationQueries(), 150))); } - // 分别进行智能去重和排序 + // 审计案例库检索 + if (StrUtil.isNotBlank(projectLibrary)) { + knowledgeSources.get("auditCase").addAll( + queryKnowledgeBase(projectLibrary, buildAuditCaseQueries(), 100)); + } + + // 智能去重和排序 knowledgeSources.forEach((key, list) -> { List processed = list.stream() .distinct() - .sorted(this::regulationsComparator) + .sorted(this::tripleOneComparator) .limit(getLimitBySourceType(key)) .collect(Collectors.toList()); knowledgeSources.put(key, processed); @@ -164,34 +165,37 @@ public class AuditContentServiceImpl3 implements AuditContentService3 { } /** - * 构建核心审计库查询 + * 构建企业单位库查询 */ - private List buildCoreQueries() { + private List buildEnterpriseQueries() { return Arrays.asList( - "三重一大 集体决策 会议纪要 决策程序", - "重大经济决策 资本性支出 费用性支出", - "重大项目 重大投资 重大采购" + "三重一大制度 集体决策规定", + "重大决策范围 人事任免范围 项目安排范围 资金运作范围", + "决策程序 权力主体 会议规则", + "集团制度 公司制定 内部规定" ); } /** - * 构建案例库查询 - */ - private List buildCaseQueries() { - return Arrays.asList( - "类似案例 参考案例 最佳实践", - "决策效果 执行结果 经验教训" - ); - } - - /** - * 构建法规库查询 + * 构建法律法规库查询 */ private List buildRegulationQueries() { return Arrays.asList( - "三重一大制度 集体决策规定", - "重大经济决策程序 审批权限", - "审计法规 审计标准" + "三重一大政策 国家法律法规", + "重大决策法规 人事任免法规", + "项目安排规定 资金运作规定", + "决策程序法律要求" + ); + } + + /** + * 构建审计案例库查询 + */ + private List buildAuditCaseQueries() { + return Arrays.asList( + "三重一大审计案例 检查证据", + "决策程序测试 执行效果", + "工作底稿 审计测试结果" ); } @@ -200,111 +204,94 @@ public class AuditContentServiceImpl3 implements AuditContentService3 { */ private int getLimitBySourceType(String sourceType) { switch (sourceType) { - case "core": return 300; - case "case": return 150; - case "regulation": return 100; + case "enterprise": return 300; + case "regulation": return 200; + case "auditCase": return 150; default: return 100; } } /** - * 带缓存的知识库查询 + * 生成三重一大制度对比分析表 */ - private Set queryKnowledgeBaseWithCache(String kbId, List queries, int topK) { - Set allResults = new LinkedHashSet<>(); - - queries.forEach(query -> { - String cacheKey = kbId + ":" + query; - long currentTime = System.currentTimeMillis(); - - if (knowledgeCache.containsKey(cacheKey) && - cacheTimestamps.containsKey(cacheKey) && - (currentTime - cacheTimestamps.get(cacheKey)) < CACHE_EXPIRE_TIME) { - allResults.addAll(knowledgeCache.get(cacheKey)); - } else { - Set results = queryKnowledgeBase(kbId, query, topK); - knowledgeCache.put(cacheKey, new LinkedHashSet<>(results)); - cacheTimestamps.put(cacheKey, currentTime); - allResults.addAll(results); - } - }); - - return allResults; - } - - /** - * 生成重大经济决策调查表 - */ - private JSONArray generateDecisionTable(Map> knowledgeSources, - String userName, String history, String suggestion) { + private JSONArray generateComparisonTable(Map> knowledgeSources, String userName, String history, String suggestion) { // 构建优化的知识上下文 - String knowledgeContext = buildOptimizedKnowledgeContext(knowledgeSources, history, suggestion); + String knowledgeContext = buildKnowledgeContext(knowledgeSources, history, suggestion); - JSONObject requestBody = buildDecisionTableRequest(knowledgeContext, userName); + JSONObject requestBody = buildWorkflowRequest(knowledgeContext, userName); - JSONArray rawData = callDecisionTableWorkflow(requestBody); + JSONArray rawData = callTripleOneWorkflow(requestBody); // 后处理:数据清洗和格式化 - return postProcessTableData(rawData); + return postProcessComparisonData(rawData); } /** - * 构建优化的知识上下文 + * 构建知识上下文 */ - private String buildOptimizedKnowledgeContext(Map> knowledgeSources, - String history, String suggestion) { + private String buildKnowledgeContext(Map> knowledgeSources, String history, String suggestion) { StringBuilder context = new StringBuilder(); - // 1. 核心审计要求 - context.append("## 核心审计要求\n"); - context.append("请基于以下审计要求生成重大经济决策调查表数据:\n\n"); - context.append("1. 检查\"三重一大\"集体决策制度建立和执行情况\n"); - context.append("2. 验证重大经济事项集体决策的程序完整性\n"); - context.append("3. 确认决策内容符合相关规定\n"); - context.append("4. 评估决策执行情况和效果\n\n"); + // 1. 分析要求 + context.append("## 三重一大制度对比分析要求\n"); + context.append("请基于以下知识生成三重一大制度对比分析表数据:\n\n"); + context.append("1. 对比分析政策内容、集团制度、公司制定的差异\n"); + context.append("2. 重点关注决策范围、金额标准、程序要求的差异\n"); + context.append("3. 识别制度执行中的风险和问题\n\n"); // 2. 数据格式要求 context.append("## 数据格式要求\n"); - context.append("每条记录应包含:序号、事项名称、会议时间、决策金额、程序、执行情况、执行效果\n"); - context.append("- 程序字段:描述具体的决策程序,如:会议决策(党委会/董事会/总经理办公会)、会签决策等\n"); - context.append("- 决策金额:根据实际情况使用正确单位(元/万元/亿元)\n"); - context.append("- 执行效果需在'好、一般、差'中选择一项标记为'是'\n\n"); + context.append("需要生成5个分类的数据,每个分类尽可能多的生成多个实例、多条记录,尽可能三重一大的五个方面都包含:\n"); + TRIPLE_ONE_CATEGORIES.forEach((category, desc) -> + context.append("- ").append(category).append(":").append(desc).append("\n")); + context.append("\n"); - // 3. 历史内容(用于优化调整) + context.append("每条记录应包含6个字段:\n"); + context.append("- policyContent:国家法律法规和政策规定\n"); + context.append("- groupSystem:集团层面的制度规定\n"); + context.append("- companyFormulation:公司层面的制度规定\n"); + context.append("- checkEvidence:审计检查的证据\n"); + context.append("- testResult:审计测试的结果(通过/不通过)\n"); + context.append("- workPaperIndex:相关《参考文件名》以及工作底稿的索引编号\n"); + context.append("\n注意:每个分类下可以有多个条目,请根据知识库内容尽可能全面地生成所有相关制度规定和检查点。\n\n"); + + // 3. 历史内容 if (StrUtil.isNotBlank(history)) { context.append("## 历史生成内容\n"); context.append("以下是之前生成的内容,请基于此进行优化:\n"); context.append(history).append("\n\n"); } - // 4. 用户建议(用于定向优化) + // 4. 用户建议 if (StrUtil.isNotBlank(suggestion)) { context.append("## 用户优化建议\n"); context.append("请根据以下建议对生成内容进行调整:\n"); context.append(suggestion).append("\n\n"); } - // 5. 核心审计知识 - if (!knowledgeSources.get("core").isEmpty()) { - context.append("## 核心审计知识\n"); - knowledgeSources.get("core").stream() + // 5. 企业单位知识 + if (!knowledgeSources.get("enterprise").isEmpty()) { + context.append("## 企业单位知识\n"); + knowledgeSources.get("enterprise").stream() + .limit(250) + .forEach(knowledge -> context.append("- ").append(knowledge).append("\n")); + context.append("\n"); + } + + // 6. 法律法规知识 + if (!knowledgeSources.get("regulation").isEmpty()) { + context.append("## 法律法规知识\n"); + knowledgeSources.get("regulation").stream() .limit(200) .forEach(knowledge -> context.append("- ").append(knowledge).append("\n")); + context.append("\n"); } - // 6. 参考案例 - if (!knowledgeSources.get("case").isEmpty()) { - context.append("## 参考案例\n"); - knowledgeSources.get("case").stream() - .limit(100) - .forEach(knowledge -> context.append("- ").append(knowledge).append("\n")); - } - - // 7. 法规要求 - if (!knowledgeSources.get("regulation").isEmpty()) { - context.append("## 法规要求\n"); - knowledgeSources.get("regulation").stream() - .limit(80) + // 7. 审计案例知识 + if (!knowledgeSources.get("auditCase").isEmpty()) { + context.append("## 审计案例知识\n"); + knowledgeSources.get("auditCase").stream() + .limit(150) .forEach(knowledge -> context.append("- ").append(knowledge).append("\n")); } @@ -314,9 +301,9 @@ public class AuditContentServiceImpl3 implements AuditContentService3 { /** * 数据验证和增强 */ - private JSONArray validateAndEnhanceData(JSONArray data) { + private JSONArray validateAndEnhanceComparisonData(JSONArray data) { if (data == null || data.isEmpty()) { - return new JSONArray(); // 返回空数组,不提供默认数据 + return createDefaultComparisonData(); } JSONArray enhancedData = new JSONArray(); @@ -326,126 +313,143 @@ public class AuditContentServiceImpl3 implements AuditContentService3 { if (item == null) continue; // 数据验证 - if (!validateDataItem(item)) { + if (!validateComparisonDataItem(item)) { log.warn("数据验证失败,跳过记录: {}", item); continue; } // 数据增强 - enhanceDataItem(item, i); + enhanceComparisonDataItem(item, i); enhancedData.add(item); } return enhancedData; } + /** + * 创建默认的对比分析数据 + */ + private JSONArray createDefaultComparisonData() { + JSONArray defaultData = new JSONArray(); + + for (String category : TRIPLE_ONE_CATEGORIES.keySet()) { + JSONObject item = new JSONObject(); + item.put("category", category); + item.put("policyContent", "待补充相关政策内容"); + item.put("groupSystem", "待补充集团制度规定"); + item.put("companyFormulation", "待补充公司制定内容"); + item.put("checkEvidence", "待补充检查证据"); + item.put("testResult", "待检查"); + item.put("workPaperIndex", Collections.singletonList("待关联工作底稿")); + defaultData.add(item); + } + + return defaultData; + } + /** * 数据项验证 */ - private boolean validateDataItem(JSONObject item) { - return item.containsKey("name") && - item.containsKey("meetingTime") && - item.containsKey("decisionAmount") && - item.containsKey("procedure") && - item.containsKey("executionStatus"); + private boolean validateComparisonDataItem(JSONObject item) { + return item.containsKey("category") && + item.containsKey("policyContent") && + item.containsKey("groupSystem") && + item.containsKey("companyFormulation"); } /** * 数据项增强 */ - private void enhanceDataItem(JSONObject item, int index) { - // 确保序号正确 - item.put("index", String.valueOf(index + 1)); - - // 增强程序描述 - String procedure = item.getString("procedure"); - if (StrUtil.isBlank(procedure) || procedure.length() < 10) { - item.put("procedure", generateProcedureDescription()); + private void enhanceComparisonDataItem(JSONObject item, int index) { + // 确保分类正确 + if (!item.containsKey("category") || StrUtil.isBlank(item.getString("category"))) { + List categories = new ArrayList<>(TRIPLE_ONE_CATEGORIES.keySet()); + if (index < categories.size()) { + item.put("category", categories.get(index)); + } } - // 增强执行效果结构 - if (!item.containsKey("executionEffect")) { - JSONObject effect = new JSONObject(); - effect.put("good", "否"); - effect.put("normal", "是"); - effect.put("bad", "否"); - item.put("executionEffect", effect); - } - - // 标准化金额格式 - String amount = item.getString("decisionAmount"); - if (amount != null) { - item.put("decisionAmount", normalizeAmount(amount)); - } - } - - /** - * 生成程序描述 - */ - private String generateProcedureDescription() { - Random random = new Random(); - List procedures = new ArrayList<>(DECISION_PROCEDURES.keySet()); - String procedureType = procedures.get(random.nextInt(procedures.size())); - return DECISION_PROCEDURES.get(procedureType); - } - - /** - * 标准化金额格式 - */ - private String normalizeAmount(String amount) { - if (amount == null) return "0元"; - - // 如果已经包含单位,直接返回 - if (amount.contains("万元") || amount.contains("元") || amount.contains("亿")) { - return amount; - } - - // 尝试解析数字 - try { - String cleanAmount = amount.replaceAll("[^\\d.]", ""); - if (StrUtil.isNotBlank(cleanAmount)) { - double value = Double.parseDouble(cleanAmount); - if (value >= 100000000) { - return String.format("%.2f亿元", value / 100000000); - } else if (value >= 10000) { - return String.format("%.2f万元", value / 10000); + // 确保所有字段都存在 + String[] requiredFields = {"policyContent", "groupSystem", "companyFormulation", + "checkEvidence", "testResult", "workPaperIndex"}; + for (String field : requiredFields) { + if (!item.containsKey(field) || item.get(field) == null) { + if ("workPaperIndex".equals(field)) { + item.put(field, Collections.singletonList("待关联工作底稿")); + } else if ("testResult".equals(field)) { + item.put(field, "待检查"); } else { - return String.format("%.0f元", value); + item.put(field, ""); } } - } catch (NumberFormatException e) { - log.debug("金额解析失败: {}", amount); } - - return amount + "元"; } - /** - * 后处理表格数据 - */ - private JSONArray postProcessTableData(JSONArray rawData) { + private JSONArray postProcessComparisonData(JSONArray rawData) { if (rawData == null || rawData.isEmpty()) { - return new JSONArray(); + return createDefaultComparisonData(); } - return rawData; // 简化处理,直接返回原始数据 + // 使用列表来存储所有条目,避免覆盖 + JSONArray processedData = new JSONArray(); + Map> categoryDataMap = new LinkedHashMap<>(); + + // 初始化分类映射 + for (String category : TRIPLE_ONE_CATEGORIES.keySet()) { + categoryDataMap.put(category, new ArrayList<>()); + } + + // 按分类分组所有条目 + for (int i = 0; i < rawData.size(); i++) { + JSONObject item = rawData.getJSONObject(i); + if (item != null && item.containsKey("category")) { + String category = item.getString("category"); + if (categoryDataMap.containsKey(category)) { + categoryDataMap.get(category).add(item); + } else { + // 如果分类不在预定义列表中,添加到其他分类 + log.warn("发现未预定义的分类: {}", category); + categoryDataMap.computeIfAbsent(category, k -> new ArrayList<>()).add(item); + } + } + } + + // 按照固定顺序输出所有条目 + for (String category : TRIPLE_ONE_CATEGORIES.keySet()) { + List categoryItems = categoryDataMap.get(category); + if (categoryItems != null && !categoryItems.isEmpty()) { + // 添加该分类下的所有条目 + processedData.addAll(categoryItems); + } + } + + // 处理其他未预定义的分类 + for (Map.Entry> entry : categoryDataMap.entrySet()) { + String category = entry.getKey(); + if (!TRIPLE_ONE_CATEGORIES.containsKey(category)) { + processedData.addAll(entry.getValue()); + } + } + + log.info("后处理完成 - 输入数据条数: {}, 输出数据条数: {}", rawData.size(), processedData.size()); + return processedData; } - + /** - * 法规内容比较器 + * 三重一大内容比较器 */ - private int regulationsComparator(String reg1, String reg2) { - int score1 = calculateRelevanceScore(reg1); - int score2 = calculateRelevanceScore(reg2); + private int tripleOneComparator(String reg1, String reg2) { + int score1 = calculateTripleOneRelevanceScore(reg1); + int score2 = calculateTripleOneRelevanceScore(reg2); return Integer.compare(score2, score1); } /** - * 计算相关性分数 + * 计算三重一大相关性分数 */ - private int calculateRelevanceScore(String regulation) { + private int calculateTripleOneRelevanceScore(String content) { return KEYWORD_WEIGHTS.entrySet().stream() - .filter(entry -> regulation.contains(entry.getKey())) + .filter(entry -> content.contains(entry.getKey())) .mapToInt(Map.Entry::getValue) .sum(); } @@ -453,28 +457,31 @@ public class AuditContentServiceImpl3 implements AuditContentService3 { /** * 查询知识库 */ - private Set queryKnowledgeBase(String kbId, String query, int topK) { + private List queryKnowledgeBase(String kbId, List queries, int topK) { Set results = new LinkedHashSet<>(); String workspaceId = config.getWorkspaceId(); try { Client client = clientFactory.createClient(); - RetrieveResponse resp = KnowledgeBaseUtil.retrieveIndex(client, workspaceId, kbId, query); - Optional.ofNullable(resp) - .map(RetrieveResponse::getBody) - .map(RetrieveResponseBody::getData) - .map(RetrieveResponseBodyData::getNodes) - .orElse(Collections.emptyList()) - .stream() - .limit(topK) - .forEach(node -> processNode(node, results)); + for (String query : queries) { + RetrieveResponse resp = KnowledgeBaseUtil.retrieveIndex(client, workspaceId, kbId, query); + + Optional.ofNullable(resp) + .map(RetrieveResponse::getBody) + .map(RetrieveResponseBody::getData) + .map(RetrieveResponseBodyData::getNodes) + .orElse(Collections.emptyList()) + .stream() + .limit(topK) + .forEach(node -> processNode(node, results)); + } } catch (Exception e) { - log.error("查询知识库失败 - kbId: {}, query: {}", kbId, query, e); + log.error("查询知识库失败 - kbId: {}, queries: {}", kbId, queries, e); } - return results; + return new ArrayList<>(results); } /** @@ -514,35 +521,39 @@ public class AuditContentServiceImpl3 implements AuditContentService3 { } /** - * 调用决策表生成工作流 + * 调用三重一大工作流 */ - private JSONArray callDecisionTableWorkflow(JSONObject requestBody) { + private JSONArray callTripleOneWorkflow(JSONObject requestBody) { try { - String result = HttpUtil.createPost(DECISION_TABLE_WORKFLOW_URL) - .header("Authorization", DECISION_TABLE_TOKEN) + String result = HttpUtil.createPost(TRIPLE_ONE_WORKFLOW_URL) + .header("Authorization", TRIPLE_ONE_TOKEN) .header("Content-Type", "application/json") .body(requestBody.toString()) - .timeout(120000) + .timeout(5*60*1000) .execute() .body(); - JSONObject jsonResponse = JSONObject.parseObject(result); - String outputText = jsonResponse.getJSONObject("data") - .getJSONObject("outputs") - .getString("result"); + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode rootNode = objectMapper.readTree(result); + String outputText = rootNode.path("data") + .path("outputs") + .path("result") + .asText(); - return JSONArray.parseArray(outputText); + // 使用Jackson解析数组 + JsonNode arrayNode = objectMapper.readTree(outputText); + return JSONArray.parseArray(arrayNode.toString()); } catch (Exception e) { - log.error("调用决策表生成工作流失败", e); - throw new RuntimeException("调用决策表生成工作流失败: " + e.getMessage(), e); + log.error("调用三重一大工作流失败", e); + throw new RuntimeException("调用三重一大工作流失败: " + e.getMessage(), e); } } /** - * 构建决策表生成请求 + * 构建工作流请求 */ - private JSONObject buildDecisionTableRequest(String knowledge, String userName) { + private JSONObject buildWorkflowRequest(String knowledge, String userName) { JSONObject requestBody = new JSONObject(); JSONObject inputs = new JSONObject(); @@ -554,15 +565,4 @@ public class AuditContentServiceImpl3 implements AuditContentService3 { return requestBody; } - - /** - * 清理缓存 - */ - public void clearExpiredCache() { - long currentTime = System.currentTimeMillis(); - cacheTimestamps.entrySet().removeIf(entry -> - (currentTime - entry.getValue()) >= CACHE_EXPIRE_TIME - ); - knowledgeCache.keySet().removeIf(key -> !cacheTimestamps.containsKey(key)); - } } \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/KnowledgeBaseServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/KnowledgeBaseServiceImpl.java index 904bd1d..6a1d864 100644 --- a/src/main/java/com/gxwebsoft/ai/service/impl/KnowledgeBaseServiceImpl.java +++ b/src/main/java/com/gxwebsoft/ai/service/impl/KnowledgeBaseServiceImpl.java @@ -3,6 +3,7 @@ package com.gxwebsoft.ai.service.impl; import com.aliyun.bailian20231229.Client; import com.aliyun.bailian20231229.models.CreateIndexResponse; import com.aliyun.bailian20231229.models.DeleteIndexDocumentResponse; +import com.aliyun.bailian20231229.models.DeleteIndexResponse; import com.aliyun.bailian20231229.models.ListIndexDocumentsResponse; import com.aliyun.bailian20231229.models.ListIndicesResponse; import com.aliyun.bailian20231229.models.RetrieveResponse; @@ -21,6 +22,8 @@ import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashSet; @@ -82,6 +85,12 @@ public class KnowledgeBaseServiceImpl implements KnowledgeBaseService { throw new RuntimeException("创建知识库失败: " + e.getMessage(), e); } } + + @Override + public String createKnowledgeBaseTemp() { + String code = "Temp_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("MMddHHmmssSSS")); + return createKnowledgeBase(code, code); + } @Override public boolean existsKnowledgeBase(String companyCode) { @@ -129,6 +138,18 @@ public class KnowledgeBaseServiceImpl implements KnowledgeBaseService { return ret; } + @Override + public boolean deleteIndex(String kbId) { + String workspaceId = config.getWorkspaceId(); + try { + Client client = clientFactory.createClient(); + DeleteIndexResponse indexDocumentResponse = KnowledgeBaseUtil.deleteIndex(client, workspaceId, kbId); + return indexDocumentResponse.getBody().getSuccess(); + } catch (Exception e) { + throw new RuntimeException("删除知识库失败: " + e.getMessage(), e); + } + } + @Override public boolean deleteIndexDocument(String kbId, String fileIds) { String workspaceId = config.getWorkspaceId(); @@ -170,6 +191,17 @@ public class KnowledgeBaseServiceImpl implements KnowledgeBaseService { throw new RuntimeException("添加文档到知识库失败: " + e.getMessage(), e); } } + + @Override + public void submitDocuments(String kbId, List fileIds) { + String workspaceId = config.getWorkspaceId(); + try { + Client client = clientFactory.createClient(); + AiCloudKnowledgeBaseUtil.submitIndexAddDocumentsJob(client, workspaceId, kbId, fileIds); + } catch (Exception e) { + throw new RuntimeException("添加文档到知识库失败: " + e.getMessage(), e); + } + } } \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/ai/util/AiCloudKnowledgeBaseUtil.java b/src/main/java/com/gxwebsoft/ai/util/AiCloudKnowledgeBaseUtil.java index 8db1891..5c5e438 100644 --- a/src/main/java/com/gxwebsoft/ai/util/AiCloudKnowledgeBaseUtil.java +++ b/src/main/java/com/gxwebsoft/ai/util/AiCloudKnowledgeBaseUtil.java @@ -156,4 +156,24 @@ public class AiCloudKnowledgeBaseUtil { RuntimeOptions runtime = new RuntimeOptions(); return client.submitIndexAddDocumentsJobWithOptions(workspaceId, submitIndexAddDocumentsJobRequest, headers, runtime); } + + /** + * 向一个非结构化知识库追加导入已解析的文档 + * + * @param client 客户端(Client) + * @param workspaceId 业务空间ID + * @param indexId 知识库ID + * @param fileId 文档ID + * @param sourceType 数据类型 + * @return 阿里云百炼服务的响应 + */ + public static SubmitIndexAddDocumentsJobResponse submitIndexAddDocumentsJob(com.aliyun.bailian20231229.Client client, String workspaceId, String indexId, List fileIds) throws Exception { + Map headers = new HashMap<>(); + SubmitIndexAddDocumentsJobRequest submitIndexAddDocumentsJobRequest = new SubmitIndexAddDocumentsJobRequest(); + submitIndexAddDocumentsJobRequest.setIndexId(indexId); + submitIndexAddDocumentsJobRequest.setDocumentIds(fileIds); + submitIndexAddDocumentsJobRequest.setSourceType("DATA_CENTER_FILE"); + RuntimeOptions runtime = new RuntimeOptions(); + return client.submitIndexAddDocumentsJobWithOptions(workspaceId, submitIndexAddDocumentsJobRequest, headers, runtime); + } } diff --git a/src/main/java/com/gxwebsoft/pwl/entity/PwlProject.java b/src/main/java/com/gxwebsoft/pwl/entity/PwlProject.java index bac3dab..bc7e9c6 100644 --- a/src/main/java/com/gxwebsoft/pwl/entity/PwlProject.java +++ b/src/main/java/com/gxwebsoft/pwl/entity/PwlProject.java @@ -31,6 +31,9 @@ public class PwlProject implements Serializable { @Schema(description = "ID") @TableId(value = "id", type = IdType.AUTO) private Integer id; + + @Schema(description = "公司id") + private Integer companyId; @Schema(description = "项目名称") private String name; diff --git a/src/main/java/com/gxwebsoft/pwl/mapper/xml/PwlProjectMapper.xml b/src/main/java/com/gxwebsoft/pwl/mapper/xml/PwlProjectMapper.xml index f24fc7f..071b12b 100644 --- a/src/main/java/com/gxwebsoft/pwl/mapper/xml/PwlProjectMapper.xml +++ b/src/main/java/com/gxwebsoft/pwl/mapper/xml/PwlProjectMapper.xml @@ -12,6 +12,9 @@ AND a.id = #{param.id} + + AND a.company_id = #{param.companyId} + AND a.name LIKE CONCAT('%', #{param.name}, '%') diff --git a/src/main/java/com/gxwebsoft/pwl/param/PwlProjectParam.java b/src/main/java/com/gxwebsoft/pwl/param/PwlProjectParam.java index 875eca7..64d2519 100644 --- a/src/main/java/com/gxwebsoft/pwl/param/PwlProjectParam.java +++ b/src/main/java/com/gxwebsoft/pwl/param/PwlProjectParam.java @@ -30,6 +30,9 @@ public class PwlProjectParam extends BaseParam { @Schema(description = "ID") @QueryField(type = QueryType.EQ) private Integer id; + + @Schema(description = "公司id") + private Integer companyId; @Schema(description = "项目名称") private String name;