360 lines
15 KiB
Java
360 lines
15 KiB
Java
package com.gxwebsoft.ai.service.impl;
|
||
|
||
import com.alibaba.fastjson.JSONArray;
|
||
import com.alibaba.fastjson.JSONObject;
|
||
import com.gxwebsoft.ai.constants.AuditContent9PersonnelConstants;
|
||
import com.gxwebsoft.ai.service.AuditContent9PersonnelService;
|
||
import lombok.extern.slf4j.Slf4j;
|
||
import org.springframework.scheduling.annotation.Async;
|
||
import org.springframework.stereotype.Service;
|
||
import cn.hutool.core.util.StrUtil;
|
||
|
||
import java.util.*;
|
||
import java.util.concurrent.CompletableFuture;
|
||
import java.util.stream.Collectors;
|
||
|
||
@Slf4j
|
||
@Service
|
||
public class AuditContent9PersonnelServiceImpl extends AbstractAuditContentService implements AuditContent9PersonnelService {
|
||
|
||
private static final String DIFY_WORKFLOW_TOKEN = "Bearer app-fmGhYITVQVAHaY3GJYonIGPA";
|
||
|
||
@Override
|
||
public JSONObject generatePersonnelTableData(String kbIds, String libraryKbIds, String projectLibrary,
|
||
String userName, String history, String suggestion) {
|
||
log.info("开始生成人员编制管理审计表数据");
|
||
|
||
long startTime = System.currentTimeMillis();
|
||
|
||
try {
|
||
// 异步并行处理每个审计内容(7个大项)
|
||
Map<String, CompletableFuture<JSONArray>> futures = new HashMap<>();
|
||
|
||
for (String auditContent : AuditContent9PersonnelConstants.AUDIT_CONTENTS) {
|
||
futures.put(auditContent, CompletableFuture.supplyAsync(() ->
|
||
generateAuditContentData(auditContent, kbIds, libraryKbIds, projectLibrary,
|
||
userName, history, suggestion)
|
||
));
|
||
}
|
||
|
||
// 等待所有异步任务完成
|
||
CompletableFuture.allOf(futures.values().toArray(new CompletableFuture[0])).join();
|
||
|
||
// 合并所有结果
|
||
JSONArray allData = new JSONArray();
|
||
int index = 1;
|
||
|
||
for (String auditContent : AuditContent9PersonnelConstants.AUDIT_CONTENTS) {
|
||
JSONArray contentData = futures.get(auditContent).get();
|
||
if (contentData != null) {
|
||
for (int i = 0; i < contentData.size(); i++) {
|
||
JSONObject item = contentData.getJSONObject(i);
|
||
item.put("index", index++);
|
||
allData.add(item);
|
||
}
|
||
}
|
||
}
|
||
|
||
log.info("人员编制管理审计表生成完成 - 记录数: {}, 耗时: {}ms",
|
||
allData.size(), System.currentTimeMillis() - startTime);
|
||
|
||
return buildSuccessResponse(allData, startTime, "personnel_establishment_audit");
|
||
|
||
} catch (Exception e) {
|
||
log.error("生成人员编制管理审计表失败", e);
|
||
return buildErrorResponse("生成失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 生成单个审计内容(大项)下的所有子项数据
|
||
*/
|
||
private JSONArray generateAuditContentData(String auditContent, String kbIds, String libraryKbIds,
|
||
String projectLibrary, String userName,
|
||
String history, String suggestion) {
|
||
|
||
JSONArray results = new JSONArray();
|
||
List<AuditContent9PersonnelConstants.AuditSubContent> subContents =
|
||
AuditContent9PersonnelConstants.AUDIT_SUB_CONTENTS.get(auditContent);
|
||
|
||
if (subContents == null || subContents.isEmpty()) {
|
||
return results;
|
||
}
|
||
|
||
// 为该审计内容检索相关知识
|
||
Map<String, List<String>> knowledgeSources = retrieveKnowledgeForAuditContent(
|
||
auditContent, subContents, kbIds, libraryKbIds, projectLibrary
|
||
);
|
||
|
||
// 处理每个子项
|
||
for (AuditContent9PersonnelConstants.AuditSubContent subContent : subContents) {
|
||
try {
|
||
JSONArray subResult = generateSubItemData(auditContent, subContent, knowledgeSources,
|
||
userName, history, suggestion);
|
||
|
||
if (subResult != null && !subResult.isEmpty()) {
|
||
results.addAll(subResult);
|
||
}
|
||
|
||
} catch (Exception e) {
|
||
log.error("处理子项失败: {} - {}", auditContent, subContent.getAuditTarget(), e);
|
||
}
|
||
}
|
||
|
||
return results;
|
||
}
|
||
|
||
/**
|
||
* 为审计内容检索相关知识
|
||
*/
|
||
private Map<String, List<String>> retrieveKnowledgeForAuditContent(
|
||
String auditContent, List<AuditContent9PersonnelConstants.AuditSubContent> subContents,
|
||
String kbIds, String libraryKbIds, String projectLibrary) {
|
||
|
||
Map<String, List<String>> knowledgeSources = new HashMap<>();
|
||
knowledgeSources.put("enterprise", new ArrayList<>());
|
||
knowledgeSources.put("regulation", new ArrayList<>());
|
||
knowledgeSources.put("auditCase", new ArrayList<>());
|
||
|
||
// 构建该审计内容的关键词
|
||
List<String> keywords = buildAuditContentKeywords(auditContent, subContents);
|
||
|
||
// 检索企业知识库
|
||
if (StrUtil.isNotBlank(kbIds)) {
|
||
String[] kbIdArray = kbIds.split(",");
|
||
for (String kbId : kbIdArray) {
|
||
if (StrUtil.isNotBlank(kbId)) {
|
||
knowledgeSources.get("enterprise").addAll(
|
||
queryKnowledgeBase(kbId.trim(), keywords, 80)
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 检索法规库
|
||
if (StrUtil.isNotBlank(libraryKbIds)) {
|
||
String[] libIdArray = libraryKbIds.split(",");
|
||
for (String libId : libIdArray) {
|
||
if (StrUtil.isNotBlank(libId)) {
|
||
knowledgeSources.get("regulation").addAll(
|
||
queryKnowledgeBase(libId.trim(), keywords, 60)
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 检索案例库
|
||
if (StrUtil.isNotBlank(projectLibrary)) {
|
||
knowledgeSources.get("auditCase").addAll(
|
||
queryKnowledgeBase(projectLibrary, keywords, 40)
|
||
);
|
||
}
|
||
|
||
// 去重和排序
|
||
knowledgeSources.forEach((key, list) -> {
|
||
List<String> processed = list.stream()
|
||
.distinct()
|
||
.sorted(this::keywordRelevanceComparator)
|
||
.limit(getLimitBySourceType(key))
|
||
.collect(Collectors.toList());
|
||
knowledgeSources.put(key, processed);
|
||
});
|
||
|
||
return knowledgeSources;
|
||
}
|
||
|
||
/**
|
||
* 构建审计内容关键词
|
||
*/
|
||
private List<String> buildAuditContentKeywords(String auditContent,
|
||
List<AuditContent9PersonnelConstants.AuditSubContent> subContents) {
|
||
|
||
List<String> keywords = new ArrayList<>();
|
||
keywords.add(auditContent);
|
||
|
||
// 添加审计内容相关的关键词
|
||
if (auditContent.contains("劳务派遣")) {
|
||
keywords.addAll(Arrays.asList("劳务派遣", "派遣工", "同工同酬", "三性标准"));
|
||
} else if (auditContent.contains("外包")) {
|
||
keywords.addAll(Arrays.asList("劳务外包", "外包合同", "假外包真派遣"));
|
||
} else if (auditContent.contains("人员经费")) {
|
||
keywords.addAll(Arrays.asList("工资总额", "福利费", "劳务费"));
|
||
} else if (auditContent.contains("借用人员")) {
|
||
keywords.addAll(Arrays.asList("借调", "借用人员", "借调程序"));
|
||
} else if (auditContent.contains("绩效管理")) {
|
||
keywords.addAll(Arrays.asList("绩效考核", "绩效管理", "绩效体系"));
|
||
} else if (auditContent.contains("机构编制")) {
|
||
keywords.addAll(Arrays.asList("机构编制", "三定方案", "编制审批", "领导职数"));
|
||
} else if (auditContent.contains("预算编制")) {
|
||
keywords.addAll(Arrays.asList("预算编制", "人员经费预算", "预算执行"));
|
||
}
|
||
|
||
// 添加所有子项的审计目标作为关键词
|
||
for (AuditContent9PersonnelConstants.AuditSubContent subContent : subContents) {
|
||
keywords.add(subContent.getAuditTarget());
|
||
}
|
||
|
||
return keywords.stream().distinct().collect(Collectors.toList());
|
||
}
|
||
|
||
/**
|
||
* 生成子项数据
|
||
*/
|
||
private JSONArray generateSubItemData(String auditContent,
|
||
AuditContent9PersonnelConstants.AuditSubContent subContent,
|
||
Map<String, List<String>> knowledgeSources,
|
||
String userName, String history, String suggestion) {
|
||
|
||
try {
|
||
// 构建上下文
|
||
String context = buildSubItemContext(auditContent, subContent, knowledgeSources,
|
||
history, suggestion);
|
||
|
||
// 调用Dify工作流 - 使用正确的请求体格式
|
||
JSONObject requestBody = buildWorkflowRequest(context, userName);
|
||
|
||
JSONArray result = callWorkflow(DIFY_WORKFLOW_URL, DIFY_WORKFLOW_TOKEN,
|
||
requestBody, auditContent + "-" + subContent.getAuditTarget());
|
||
|
||
// 处理返回结果
|
||
return processSubItemResult(result, auditContent, subContent);
|
||
|
||
} catch (Exception e) {
|
||
log.error("生成子项数据失败: {} - {}", auditContent, subContent.getAuditTarget(), e);
|
||
return new JSONArray();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 构建子项上下文
|
||
*/
|
||
private String buildSubItemContext(String auditContent,
|
||
AuditContent9PersonnelConstants.AuditSubContent subContent,
|
||
Map<String, List<String>> knowledgeSources,
|
||
String history, String suggestion) {
|
||
|
||
StringBuilder context = new StringBuilder();
|
||
|
||
context.append("## 审计任务\n");
|
||
context.append("生成人员编制管理审计数据\n\n");
|
||
|
||
context.append("## 审计要求\n");
|
||
context.append("1. 审计内容:").append(auditContent).append("\n");
|
||
context.append("2. 审计目标:").append(subContent.getAuditTarget()).append("\n");
|
||
context.append("3. 审计证据:").append(subContent.getAuditEvidence()).append("\n");
|
||
context.append("4. 审计方法:").append(subContent.getAiTestContent()).append("\n");
|
||
context.append("5. 制度依据:").append(subContent.getRegulationBasis()).append("\n\n");
|
||
|
||
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\n");
|
||
|
||
context.append("## 返回格式\n");
|
||
context.append("返回JSON数组,每条记录包含以下字段:\n");
|
||
context.append("- auditContent:固定为'").append(auditContent).append("'\n");
|
||
context.append("- auditTarget:固定为'").append(subContent.getAuditTarget()).append("'\n");
|
||
context.append("- auditEvidence:固定为'").append(subContent.getAuditEvidence()).append("'\n");
|
||
context.append("- generationResult:审计发现和结论\n");
|
||
context.append("- workPaperIndex:工作底稿索引,具体的文件FileId数组\n\n");
|
||
|
||
context.append("## generationResult格式\n");
|
||
context.append("标题:在审计期间,[具体单位名称]存在[具体问题]\n\n");
|
||
context.append("审计记录:\n经核查[具体文件],发现:[具体事实]\n\n");
|
||
context.append("审计发现:\n上述行为构成[问题性质],违反了[相关规定]\n\n");
|
||
context.append("定性依据:\n① [法规1];② [法规2]\n\n");
|
||
context.append("处理建议:\n1. [建议1];2. [建议2]\n\n");
|
||
context.append("附件:\n- [文件1]\n- [文件2]\n\n");
|
||
|
||
// 添加历史内容
|
||
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");
|
||
}
|
||
|
||
// 添加相关知识
|
||
if (!knowledgeSources.get("enterprise").isEmpty()) {
|
||
context.append("## 企业信息\n");
|
||
knowledgeSources.get("enterprise").forEach(info ->
|
||
context.append(info).append("\n"));
|
||
}
|
||
|
||
if (!knowledgeSources.get("regulation").isEmpty()) {
|
||
context.append("## 法规信息\n");
|
||
knowledgeSources.get("regulation").forEach(info ->
|
||
context.append(info).append("\n"));
|
||
}
|
||
|
||
if (!knowledgeSources.get("auditCase").isEmpty()) {
|
||
context.append("## 案例信息\n");
|
||
knowledgeSources.get("auditCase").forEach(info ->
|
||
context.append(info).append("\n"));
|
||
}
|
||
|
||
return context.toString();
|
||
}
|
||
|
||
/**
|
||
* 处理子项返回结果
|
||
*/
|
||
private JSONArray processSubItemResult(JSONArray result, String auditContent,
|
||
AuditContent9PersonnelConstants.AuditSubContent subContent) {
|
||
|
||
if (result == null || result.isEmpty()) {
|
||
JSONArray defaultResult = new JSONArray();
|
||
JSONObject defaultItem = new JSONObject();
|
||
defaultItem.put("auditContent", auditContent);
|
||
defaultItem.put("auditTarget", subContent.getAuditTarget());
|
||
defaultItem.put("auditEvidence", subContent.getAuditEvidence());
|
||
defaultItem.put("generationResult", "审计数据待生成");
|
||
defaultItem.put("workPaperIndex", new JSONArray());
|
||
defaultResult.add(defaultItem);
|
||
return defaultResult;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 关键词相关性比较器
|
||
*/
|
||
private int keywordRelevanceComparator(String content1, String content2) {
|
||
int score1 = calculateKeywordScore(content1);
|
||
int score2 = calculateKeywordScore(content2);
|
||
return Integer.compare(score2, score1);
|
||
}
|
||
|
||
/**
|
||
* 计算关键词得分
|
||
*/
|
||
private int calculateKeywordScore(String content) {
|
||
int score = 0;
|
||
for (Map.Entry<String, Integer> entry : AuditContent9PersonnelConstants.KEYWORD_WEIGHTS.entrySet()) {
|
||
if (content.contains(entry.getKey())) {
|
||
score += entry.getValue();
|
||
}
|
||
}
|
||
return score;
|
||
}
|
||
|
||
/**
|
||
* 获取不同来源的限制条数
|
||
*/
|
||
private int getLimitBySourceType(String sourceType) {
|
||
switch (sourceType) {
|
||
case "enterprise": return 80;
|
||
case "regulation": return 60;
|
||
case "auditCase": return 40;
|
||
default: return 30;
|
||
}
|
||
}
|
||
} |