Files
java-10561/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent3DecisionServiceImpl.java

719 lines
30 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.gxwebsoft.ai.service.impl;
import com.aliyun.bailian20231229.Client;
import com.aliyun.bailian20231229.models.RetrieveResponse;
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;
import com.gxwebsoft.ai.factory.KnowledgeBaseClientFactory;
import com.gxwebsoft.ai.service.AuditContent3DecisionService;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Service
public class AuditContent3DecisionServiceImpl implements AuditContent3DecisionService {
@Autowired
private KnowledgeBaseClientFactory clientFactory;
@Autowired
private KnowledgeBaseConfig config;
@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";
// Excel Sheet1 中的条件信息
private static final String EXCEL_SHEET1_CONDITIONS =
"## 重大经济决策调查表审计重点\n" +
"重大经济事项的决策、执行和效果情况,具体包括重大预算管理、重大项目实施、重大采购项目、重大投资项目、重大外包业务、重大资产处置、大额资金使用的决策和执行情况等。\n\n" +
"## 重点关注\n" +
"\"三重一大\"集体决策制度是否建立健全。重大经济、经营活动必须进行集体决策的标准和必须参加决策的人员是否制定有规定,规定的集体决策的程序(签到表、决策纪要、最终形成的决策、决策人员的签字确认意见等)是否完整,是否有应集体决策而未集体决策的问题,是否有应参加集体决策的人因不合理理由不得参加集体决策的问题,形成的集体决策意见是否符合国家、自治区规定。\n\n" +
"## 审计方法及步骤\n" +
"1. 查阅单位制度,检查议事制度是否建立,查看重大事项进行集体决策的规定,查阅相关会议记录资料,检查会议签到表、会议纪要、会议决定内容及决策参与人员签字确认意见,以确认会议集体决策程序的完整性;对照重大决策内容,检查相关对应资料,确认集体决策内容是否符合国家、自治区规定。\n" +
"2. 抽查一些重大经济决策事项,比如重大建设项目、维修、大宗物资采购、企业投资运营等,审查其决策的背景、决策的过程、决策的执行和落实情况,决策的效果情况,以此来确定是否符合国家、自治区相关规定,执行是否有效。";
@Override
public JSONObject generateDecisionTableData(String kbIds, String libraryIds, String projectLibrary,
String userName, String history, String suggestion, Object data) {
log.info("开始生成重大经济决策调查表数据 - 用户: {}, kbIds: {}, libraryIds: {}, projectLibrary: {}",
userName, kbIds, libraryIds, projectLibrary);
JSONObject result = new JSONObject();
long startTime = System.currentTimeMillis();
try {
// 1. 解析三重一大数据
JSONArray tripleOneData = parseTripleOneData(data);
if (tripleOneData == null || tripleOneData.isEmpty()) {
log.warn("未传入三重一大数据,无法生成重大经济决策调查表");
result.put("success", false);
result.put("error", "需要三重一大数据作为生成依据");
return result;
}
// 2. 基于三重一大数据同步检索相关知识库内容
Map<String, List<String>> knowledgeSources = retrieveKnowledgeForTripleOne(kbIds, libraryIds, projectLibrary, tripleOneData);
// 3. 构建完整的上下文并调用工作流
String knowledgeContext = buildCompleteContext(tripleOneData, knowledgeSources, history, suggestion);
JSONObject requestBody = buildWorkflowRequest(knowledgeContext, userName);
JSONArray decisionTableData = callDecisionWorkflow(requestBody);
// 4. 构建返回结果
result.put("success", true);
result.put("data", decisionTableData);
result.put("total_records", decisionTableData.size());
result.put("generated_time", new Date().toString());
result.put("processing_time", (System.currentTimeMillis() - startTime) + "ms");
result.put("data_source", "triple_one_primary");
log.info("重大经济决策调查表生成成功 - 记录数: {}, 处理时间: {}ms",
decisionTableData.size(), (System.currentTimeMillis() - startTime));
} catch (Exception e) {
log.error("生成重大经济决策调查表失败", e);
result.put("success", false);
result.put("error", e.getMessage());
throw new RuntimeException("生成重大经济决策调查表失败: " + e.getMessage(), e);
}
return result;
}
/**
* 为三重一大数据同步检索相关知识
*/
private Map<String, List<String>> retrieveKnowledgeForTripleOne(String kbIds, String libraryIds,
String projectLibrary, JSONArray tripleOneData) {
Map<String, List<String>> knowledgeSources = new HashMap<>();
knowledgeSources.put("enterprise", new ArrayList<>());
knowledgeSources.put("regulation", new ArrayList<>());
knowledgeSources.put("auditCase", new ArrayList<>());
// 企业单位知识每个三重一大数据项同步检索前10条
for (int i = 0; i < tripleOneData.size(); i++) {
JSONObject tripleItem = tripleOneData.getJSONObject(i);
if (tripleItem != null) {
List<String> enterpriseKnowledge = retrieveEnterpriseKnowledgeForItem(tripleItem, kbIds);
knowledgeSources.get("enterprise").addAll(enterpriseKnowledge);
}
}
// 法律法规知识全局检索100条所有tripleItem共享
if (StrUtil.isNotBlank(libraryIds)) {
List<String> regulationKnowledge = retrieveGlobalRegulationKnowledge(libraryIds, tripleOneData);
knowledgeSources.get("regulation").addAll(regulationKnowledge);
}
// 审计案例知识全局检索50条所有tripleItem共享
if (StrUtil.isNotBlank(projectLibrary)) {
List<String> auditCaseKnowledge = retrieveGlobalAuditCaseKnowledge(projectLibrary, tripleOneData);
knowledgeSources.get("auditCase").addAll(auditCaseKnowledge);
}
// 去重和限制数量
knowledgeSources.put("enterprise", knowledgeSources.get("enterprise").stream()
.distinct()
.limit(200)
.collect(Collectors.toList()));
knowledgeSources.put("regulation", knowledgeSources.get("regulation").stream()
.distinct()
.limit(100)
.collect(Collectors.toList()));
knowledgeSources.put("auditCase", knowledgeSources.get("auditCase").stream()
.distinct()
.limit(50)
.collect(Collectors.toList()));
log.info("知识库检索完成 - 企业单位: {}条, 法律法规: {}条, 审计案例: {}条",
knowledgeSources.get("enterprise").size(),
knowledgeSources.get("regulation").size(),
knowledgeSources.get("auditCase").size());
return knowledgeSources;
}
/**
* 为单个三重一大项检索企业单位知识限制10条
*/
private List<String> retrieveEnterpriseKnowledgeForItem(JSONObject tripleItem, String kbIds) {
List<String> enterpriseKnowledge = new ArrayList<>();
try {
List<String> queries = buildQueriesForTripleOneItem(tripleItem);
if (StrUtil.isNotBlank(kbIds)) {
Arrays.stream(kbIds.split(","))
.map(String::trim)
.filter(StrUtil::isNotBlank)
.forEach(kbId -> enterpriseKnowledge
.addAll(queryKnowledgeBaseForItem(kbId, queries, tripleItem, 10)));
}
} catch (Exception e) {
log.error("检索企业单位知识失败", e);
}
return enterpriseKnowledge.stream()
.distinct()
.limit(10)
.collect(Collectors.toList());
}
/**
* 全局检索法律法规知识100条
*/
private List<String> retrieveGlobalRegulationKnowledge(String libraryIds, JSONArray tripleOneData) {
List<String> regulationKnowledge = new ArrayList<>();
try {
List<String> globalQueries = buildGlobalRegulationQueries(tripleOneData);
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(","));
Arrays.stream(libraryKbIds.split(","))
.map(String::trim)
.filter(StrUtil::isNotBlank)
.forEach(libId -> regulationKnowledge
.addAll(queryKnowledgeBaseForGlobal(libId, globalQueries, 100)));
} catch (Exception e) {
log.error("全局检索法律法规知识失败", e);
}
return regulationKnowledge;
}
/**
* 全局检索审计案例知识50条
*/
private List<String> retrieveGlobalAuditCaseKnowledge(String projectLibrary, JSONArray tripleOneData) {
List<String> auditCaseKnowledge = new ArrayList<>();
try {
List<String> globalQueries = buildGlobalAuditCaseQueries(tripleOneData);
auditCaseKnowledge.addAll(
queryKnowledgeBaseForGlobal(projectLibrary, globalQueries, 50));
} catch (Exception e) {
log.error("全局检索审计案例知识失败", e);
}
return auditCaseKnowledge;
}
/**
* 构建全局法律法规查询
*/
private List<String> buildGlobalRegulationQueries(JSONArray tripleOneData) {
List<String> queries = new ArrayList<>();
// 从所有tripleItem中提取共性关键词
Set<String> categories = new HashSet<>();
Set<String> policyKeywords = new HashSet<>();
for (int i = 0; i < tripleOneData.size(); i++) {
JSONObject item = tripleOneData.getJSONObject(i);
if (item != null) {
String category = item.getString("category");
String policyContent = item.getString("policyContent");
if (StrUtil.isNotBlank(category)) {
categories.add(category);
}
if (StrUtil.isNotBlank(policyContent)) {
if (policyContent.contains("公司法")) policyKeywords.add("公司法");
if (policyContent.contains("国有资产")) policyKeywords.add("国有资产法");
if (policyContent.contains("党组织")) policyKeywords.add("党组织");
}
}
}
// 构建通用查询
queries.add("重大经济决策 法律法规");
queries.add("三重一大 政策规定");
queries.add("集体决策 制度规定");
// 添加分类相关查询
for (String category : categories) {
queries.add(category + " 法律法规");
}
// 添加政策关键词相关查询
for (String keyword : policyKeywords) {
queries.add(keyword + " 决策规定");
}
return queries;
}
/**
* 构建全局审计案例查询
*/
private List<String> buildGlobalAuditCaseQueries(JSONArray tripleOneData) {
List<String> queries = new ArrayList<>();
// 从所有tripleItem中提取共性信息
Set<String> categories = new HashSet<>();
boolean hasFailedCases = false;
for (int i = 0; i < tripleOneData.size(); i++) {
JSONObject item = tripleOneData.getJSONObject(i);
if (item != null) {
String category = item.getString("category");
String testResult = item.getString("testResult");
if (StrUtil.isNotBlank(category)) {
categories.add(category);
}
if ("不通过".equals(testResult)) {
hasFailedCases = true;
}
}
}
// 构建通用查询
queries.add("重大经济决策 审计案例");
queries.add("三重一大 检查方法");
// 添加分类相关查询
for (String category : categories) {
queries.add(category + " 审计案例");
}
// 如果有不通过的案例,添加相关查询
if (hasFailedCases) {
queries.add("决策程序缺陷 案例");
queries.add("集体决策问题 审计");
}
return queries;
}
/**
* 全局知识库查询不关联特定tripleItem
*/
private List<String> queryKnowledgeBaseForGlobal(String kbId, List<String> queries, int topK) {
Set<String> results = new LinkedHashSet<>();
String workspaceId = config.getWorkspaceId();
try {
Client client = clientFactory.createClient();
for (String query : queries) {
try {
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 -> processNodeForGlobal(node, results));
} catch (Exception e) {
log.warn("全局查询知识库失败 - kbId: {}, query: {}", kbId, query, e);
}
}
} catch (Exception e) {
log.error("创建知识库客户端失败", e);
}
return new ArrayList<>(results);
}
/**
* 处理全局知识库节点
*/
private void processNodeForGlobal(RetrieveResponseBodyDataNodes node, Set<String> results) {
try {
String text = node.getText();
if (StrUtil.isBlank(text) || text.length() < 10) {
return;
}
String docName = extractDocumentName(node);
String formattedText = String.format("《%s》%s", docName, text);
results.add(formattedText);
} catch (Exception e) {
log.warn("处理全局知识库节点失败", e);
}
}
/**
* 解析三重一大数据
*/
private JSONArray parseTripleOneData(Object data) {
if (data == null) {
return null;
}
try {
JSONArray tripleData;
if (data instanceof JSONArray) {
tripleData = (JSONArray) data;
} else if (data instanceof List) {
tripleData = JSONArray.parseArray(JSONObject.toJSONString(data));
} else {
JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(data));
if (jsonObject.containsKey("data") && jsonObject.get("data") instanceof JSONArray) {
tripleData = jsonObject.getJSONArray("data");
} else {
tripleData = new JSONArray();
tripleData.add(jsonObject);
}
}
log.info("解析三重一大数据成功,条数: {}", tripleData.size());
return tripleData;
} catch (Exception e) {
log.error("解析三重一大数据失败", e);
return null;
}
}
/**
* 为单个三重一大项构建查询
*/
private List<String> buildQueriesForTripleOneItem(JSONObject tripleItem) {
List<String> queries = new ArrayList<>();
String category = tripleItem.getString("category");
String policyContent = tripleItem.getString("policyContent");
String checkEvidence = tripleItem.getString("checkEvidence");
String companyFormulation = tripleItem.getString("companyFormulation");
// 基于分类构建查询
if (category != null) {
queries.add(category + " 会议记录 决策事项");
queries.add(category + " 经济决策 程序");
}
// 从政策内容提取关键词
if (policyContent != null) {
if (policyContent.contains("投资")) queries.add("投资项目 决策");
if (policyContent.contains("采购")) queries.add("采购项目 决策");
if (policyContent.contains("资产")) queries.add("资产处置 决策");
if (policyContent.contains("预算")) queries.add("预算管理 决策");
if (policyContent.contains("人事")) queries.add("人事任免 决策");
}
// 从检查证据提取具体事项
if (checkEvidence != null) {
String[] evidenceKeywords = extractKeywordsFromEvidence(checkEvidence);
for (String keyword : evidenceKeywords) {
if (keyword.length() > 2) {
queries.add(keyword + " 会议纪要");
queries.add(keyword + " 决策程序");
}
}
}
// 从公司制度问题提取关键词
if (companyFormulation != null) {
if (companyFormulation.contains("权限")) queries.add("决策权限 授权");
if (companyFormulation.contains("程序")) queries.add("决策程序 流程");
if (companyFormulation.contains("审批")) queries.add("审批流程 决策");
}
return queries;
}
/**
* 从检查证据中提取关键词
*/
private String[] extractKeywordsFromEvidence(String checkEvidence) {
if (checkEvidence == null) return new String[0];
List<String> keywords = new ArrayList<>();
// 提取可能的项目名称(包含《》的文件名)
if (checkEvidence.contains("") && checkEvidence.contains("")) {
int start = checkEvidence.indexOf("");
int end = checkEvidence.indexOf("");
if (start < end) {
String fileName = checkEvidence.substring(start + 1, end);
keywords.add(fileName);
}
}
// 提取可能的金额数字
if (checkEvidence.matches(".*\\d+(\\.\\d+)?万.*")) {
keywords.add("金额");
}
// 提取常见项目类型
String[] projectTypes = {"项目", "投资", "采购", "建设", "改造", "扩建", "维修"};
for (String type : projectTypes) {
if (checkEvidence.contains(type)) {
keywords.add(type);
}
}
return keywords.toArray(new String[0]);
}
/**
* 构建完整的上下文
*/
private String buildCompleteContext(JSONArray tripleOneData, Map<String, List<String>> knowledgeSources,
String history, String suggestion) {
StringBuilder context = new StringBuilder();
// 1. 核心指令
context.append("## 核心生成指令\n");
context.append("请基于以下三重一大制度对比分析数据为主要依据,结合相关知识库内容,生成重大经济决策调查表。\n\n");
context.append("**数据优先级**: 三重一大数据 > 知识库内容 > 通用审计规则\n\n");
// 2. Excel Sheet1 条件信息
context.append(EXCEL_SHEET1_CONDITIONS).append("\n\n");
// 3. 三重一大数据(主要依据)
context.append("## 三重一大制度对比分析数据(主要依据)\n");
context.append("请基于以下三重一大数据生成对应的重大经济决策调查记录,每条三重一大数据都应生成对应的调查表记录:\n\n");
for (int i = 0; i < tripleOneData.size(); i++) {
JSONObject item = tripleOneData.getJSONObject(i);
if (item != null) {
context.append("### 三重一大事项 ").append(i + 1).append("\n");
context.append("```json\n");
context.append(JSONObject.toJSONString(item, true));
context.append("\n```\n\n");
}
}
// 4. 知识库内容(辅助信息)
context.append("## 相关知识库内容(辅助信息)\n");
context.append("以下是从知识库中检索到的相关信息,用于补充决策事项的细节:\n\n");
if (!knowledgeSources.get("enterprise").isEmpty()) {
context.append("### 企业单位知识\n");
knowledgeSources.get("enterprise").forEach(knowledge ->
context.append("- ").append(knowledge).append("\n"));
context.append("\n");
}
if (!knowledgeSources.get("regulation").isEmpty()) {
context.append("### 法律法规知识\n");
knowledgeSources.get("regulation").forEach(knowledge ->
context.append("- ").append(knowledge).append("\n"));
context.append("\n");
}
if (!knowledgeSources.get("auditCase").isEmpty()) {
context.append("### 审计案例知识\n");
knowledgeSources.get("auditCase").forEach(knowledge ->
context.append("- ").append(knowledge).append("\n"));
context.append("\n");
}
// 5. 历史内容和用户建议
if (StrUtil.isNotBlank(history)) {
context.append("## 历史生成内容\n");
context.append(history).append("\n\n");
}
if (StrUtil.isNotBlank(suggestion)) {
context.append("## 用户优化建议\n");
context.append(suggestion).append("\n\n");
}
log.debug("完整上下文长度: {}", context.length());
return context.toString();
}
/**
* 为单个项查询知识库
*/
private List<String> queryKnowledgeBaseForItem(String kbId, List<String> queries, JSONObject tripleItem, int topK) {
Set<String> results = new LinkedHashSet<>();
String workspaceId = config.getWorkspaceId();
try {
Client client = clientFactory.createClient();
for (String query : queries) {
try {
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 -> processNodeForItem(node, results, tripleItem));
} catch (Exception e) {
log.warn("查询知识库失败 - kbId: {}, query: {}", kbId, query, e);
}
}
} catch (Exception e) {
log.error("创建知识库客户端失败", e);
}
return new ArrayList<>(results);
}
/**
* 处理知识库节点(针对特定三重一项)
*/
private void processNodeForItem(RetrieveResponseBodyDataNodes node, Set<String> results, JSONObject tripleItem) {
try {
String text = node.getText();
if (StrUtil.isBlank(text) || text.length() < 10) {
return;
}
// 检查文本是否与当前三重一项相关
if (isTextRelevantToItem(text, tripleItem)) {
String docName = extractDocumentName(node);
String formattedText = String.format("《%s》%s", docName, text);
results.add(formattedText);
}
} catch (Exception e) {
log.warn("处理知识库节点失败", e);
}
}
/**
* 检查文本是否与三重一项相关
*/
private boolean isTextRelevantToItem(String text, JSONObject tripleItem) {
String category = tripleItem.getString("category");
String checkEvidence = tripleItem.getString("checkEvidence");
String policyContent = tripleItem.getString("policyContent");
// 基于分类检查相关性
if (category != null && text.contains(category)) {
return true;
}
// 基于检查证据中的关键词检查相关性
if (checkEvidence != null) {
String[] keywords = extractKeywordsFromEvidence(checkEvidence);
for (String keyword : keywords) {
if (keyword.length() > 2 && text.contains(keyword)) {
return true;
}
}
}
// 基于政策内容中的关键词检查相关性
if (policyContent != null) {
if (policyContent.contains("投资") && text.contains("投资")) return true;
if (policyContent.contains("采购") && text.contains("采购")) return true;
if (policyContent.contains("资产") && text.contains("资产")) return true;
if (policyContent.contains("预算") && text.contains("预算")) return true;
}
return false;
}
/**
* 提取文档名称
*/
private String extractDocumentName(RetrieveResponseBodyDataNodes node) {
try {
Object metadataObj = node.getMetadata();
if (metadataObj instanceof Map) {
Map<?, ?> metadata = (Map<?, ?>) metadataObj;
Object docNameObj = metadata.get("doc_name");
if (docNameObj != null) {
return docNameObj.toString();
}
}
} catch (Exception e) {
log.debug("提取文档名称失败", e);
}
return "相关文档";
}
private JSONArray callDecisionWorkflow(JSONObject requestBody) {
try {
log.info("调用重大经济决策工作流,请求体长度: {}", requestBody.toString().length());
String result = HttpUtil.createPost(DECISION_TABLE_WORKFLOW_URL)
.header("Authorization", DECISION_TABLE_TOKEN)
.header("Content-Type", "application/json")
.body(requestBody.toString())
.timeout(10 * 60 * 1000)
.execute()
.body();
log.info("工作流返回结果长度: {}", result.length());
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = objectMapper.readTree(result);
String outputText = rootNode.path("data")
.path("outputs")
.path("result")
.asText();
if (StrUtil.isBlank(outputText)) {
log.warn("工作流返回结果为空");
return new JSONArray();
}
JsonNode arrayNode = objectMapper.readTree(outputText);
JSONArray jsonArray = JSONArray.parseArray(arrayNode.toString());
log.info("成功解析工作流返回数据,记录数: {}", jsonArray.size());
return jsonArray;
} catch (Exception e) {
log.error("调用重大经济决策工作流失败", e);
throw new RuntimeException("调用重大经济决策工作流失败: " + e.getMessage(), e);
}
}
private JSONObject buildWorkflowRequest(String knowledge, String userName) {
JSONObject requestBody = new JSONObject();
JSONObject inputs = new JSONObject();
inputs.put("knowledge", knowledge);
requestBody.put("inputs", inputs);
requestBody.put("response_mode", "blocking");
requestBody.put("user", userName);
requestBody.put("timeout", 600);
return requestBody;
}
}