From 610e50ed54962768babdf71af3e5b5ea625e0c33 Mon Sep 17 00:00:00 2001 From: yuance <182865460@qq.com> Date: Tue, 2 Dec 2025 15:48:05 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=94=9F=E6=88=90=E5=86=B3?= =?UTF-8?q?=E7=AD=96=E6=94=AF=E5=87=BA=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AuditContent1ExpenseConstants.java | 69 +++ .../controller/AuditContent1Controller.java | 49 +++ .../ai/dto/export/ExpenseExportEntity.java | 38 ++ .../service/AuditContent1ExpenseService.java | 21 + .../impl/AuditContent1ExpenseServiceImpl.java | 412 ++++++++++++++++++ 5 files changed, 589 insertions(+) create mode 100644 src/main/java/com/gxwebsoft/ai/constants/AuditContent1ExpenseConstants.java create mode 100644 src/main/java/com/gxwebsoft/ai/dto/export/ExpenseExportEntity.java create mode 100644 src/main/java/com/gxwebsoft/ai/service/AuditContent1ExpenseService.java create mode 100644 src/main/java/com/gxwebsoft/ai/service/impl/AuditContent1ExpenseServiceImpl.java diff --git a/src/main/java/com/gxwebsoft/ai/constants/AuditContent1ExpenseConstants.java b/src/main/java/com/gxwebsoft/ai/constants/AuditContent1ExpenseConstants.java new file mode 100644 index 0000000..c3c07d3 --- /dev/null +++ b/src/main/java/com/gxwebsoft/ai/constants/AuditContent1ExpenseConstants.java @@ -0,0 +1,69 @@ +package com.gxwebsoft.ai.constants; + +import java.util.HashMap; +import java.util.Map; + +/** + * 支出情况表常量类 + */ +public class AuditContent1ExpenseConstants { + + // 支出类型分类 + public static final String EXPENSE_TYPE_RECEPTION = "公务接待"; + public static final String EXPENSE_TYPE_OVERSEAS = "出国"; + public static final String EXPENSE_TYPE_VEHICLE = "公车运行维护"; + public static final String EXPENSE_TYPE_MEETING = "会议培训费"; + + // 年度范围 + public static final int[] YEAR_RANGE = {2020, 2021, 2022, 2023}; + + // 分类描述 + public static final Map EXPENSE_DESCRIPTIONS = new HashMap<>(); + static { + EXPENSE_DESCRIPTIONS.put(EXPENSE_TYPE_RECEPTION, "公务接待费用支出情况"); + EXPENSE_DESCRIPTIONS.put(EXPENSE_TYPE_OVERSEAS, "出国(出境)费用支出情况"); + EXPENSE_DESCRIPTIONS.put(EXPENSE_TYPE_VEHICLE, "公车运行维护费用支出情况"); + EXPENSE_DESCRIPTIONS.put(EXPENSE_TYPE_MEETING, "会议、培训费用支出情况"); + } + + // 数据格式要求 + public static final String DATA_FORMAT_REQUIREMENT = + "每条记录应包含以下字段:\n" + + "- expenseType:支出类型(公务接待/出国/公车运行维护/会议培训费)\n" + + "- year:年份(2020-2023)\n" + + "- finalStatementAmount:决算报表数(单位:元)\n" + + "- initialBudgetAmount:年初预算数(单位:元)\n" + + "- changePercentage:增减情况(%)\n" + + "- budgetRatio:占年初预算比例(%)\n" + + "- remark:备注信息\n" + + "- dataSource:数据来源文件\n" + + "- workPaperIndex:相关文件索引"; + + // 关键词权重 + public static final Map KEYWORD_WEIGHTS = new HashMap<>(); + static { + KEYWORD_WEIGHTS.put("决算", 10); + KEYWORD_WEIGHTS.put("预算", 10); + KEYWORD_WEIGHTS.put("公务接待", 9); + KEYWORD_WEIGHTS.put("出国", 9); + KEYWORD_WEIGHTS.put("公车", 9); + KEYWORD_WEIGHTS.put("会议", 8); + KEYWORD_WEIGHTS.put("培训", 8); + KEYWORD_WEIGHTS.put("支出", 8); + KEYWORD_WEIGHTS.put("费用", 7); + KEYWORD_WEIGHTS.put("财务报表", 9); + KEYWORD_WEIGHTS.put("年度报告", 8); + KEYWORD_WEIGHTS.put("预算执行", 8); + KEYWORD_WEIGHTS.put("财务分析", 7); + } + + // 数据来源关键词 + public static final String[] DATA_SOURCE_KEYWORDS = { + "决算报表", "预算报表", "财务报告", "年度报告", + "预算执行情况", "经费使用情况", "支出明细", "费用分析" + }; + + private AuditContent1ExpenseConstants() { + // 防止实例化 + } +} \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/ai/controller/AuditContent1Controller.java b/src/main/java/com/gxwebsoft/ai/controller/AuditContent1Controller.java index dc4e404..72afd8f 100644 --- a/src/main/java/com/gxwebsoft/ai/controller/AuditContent1Controller.java +++ b/src/main/java/com/gxwebsoft/ai/controller/AuditContent1Controller.java @@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.gxwebsoft.ai.dto.AuditContentRequest; import com.gxwebsoft.ai.dto.export.EightRegExportEntity; +import com.gxwebsoft.ai.dto.export.ExpenseExportEntity; import com.gxwebsoft.ai.dto.export.LeaderListExportEntity; import com.gxwebsoft.ai.entity.AiCloudDoc; import com.gxwebsoft.ai.entity.AiCloudFile; @@ -17,6 +18,7 @@ import com.gxwebsoft.pwl.service.PwlProjectLibraryService; import com.gxwebsoft.ai.service.AiCloudDocService; import com.gxwebsoft.ai.service.AiCloudFileService; import com.gxwebsoft.ai.service.AuditContent1EightRegService; +import com.gxwebsoft.ai.service.AuditContent1ExpenseService; import com.gxwebsoft.ai.service.AuditContent1LeaderListService; import com.gxwebsoft.ai.service.KnowledgeBaseService; import io.swagger.v3.oas.annotations.Operation; @@ -44,6 +46,9 @@ public class AuditContent1Controller extends BaseController { @Autowired private AuditContent1LeaderListService auditContent1LeaderListService; + + @Autowired + private AuditContent1ExpenseService auditContent1ExpenseService; @Autowired private AuditContent1EightRegService auditContent1EightRegService; @@ -78,6 +83,19 @@ public class AuditContent1Controller extends BaseController { params.username, params.history, params.suggestion )); } + + /** + * 生成支出情况表数据 + */ + @Operation(summary = "生成支出情况表") + @PostMapping("/generateExpenseTable") + public ApiResult generateExpenseTable(@RequestBody AuditContentRequest request, HttpServletRequest servletRequest) { + return generateTableData(request, servletRequest.getRequestURI(), + (params) -> auditContent1ExpenseService.generateExpenseTableData( + params.knowledgeBaseId, params.libraryKbIds, params.projectLibrary, + params.username, params.history, params.suggestion + )); + } /** * 生成八项规定对比分析表数据 @@ -339,4 +357,35 @@ public class AuditContent1Controller extends BaseController { entity.setWorkPaperIndex(formatWorkPaperIndex(item.get("workPaperIndex"))); return entity; } + + + /** + * 导出支出情况表到Excel + */ + @Operation(summary = "导出支出情况表到Excel") + @PostMapping("/exportExpenseTable") + public void exportExpenseTable(@RequestBody Map request, HttpServletResponse response) { + exportToExcel(request, response, "支出情况表", + this::convertToExpenseEntityList, ExpenseExportEntity.class); + } + + // ========== 数据转换方法 ========== + + private List convertToExpenseEntityList(List> originalData) { + return originalData.stream().map(this::convertToExpenseEntity).collect(Collectors.toList()); + } + + private ExpenseExportEntity convertToExpenseEntity(Map item) { + ExpenseExportEntity entity = new ExpenseExportEntity(); + entity.setExpenseType(getStringValue(item, "expenseType")); + entity.setYear(getStringValue(item, "year")); + entity.setFinalStatementAmount(getStringValue(item, "finalStatementAmount")); + entity.setInitialBudgetAmount(getStringValue(item, "initialBudgetAmount")); + entity.setChangePercentage(getStringValue(item, "changePercentage")); + entity.setBudgetRatio(getStringValue(item, "budgetRatio")); + entity.setRemark(getStringValue(item, "remark")); + entity.setDataSource(getStringValue(item, "dataSource")); + entity.setWorkPaperIndex(formatWorkPaperIndex(item.get("workPaperIndex"))); + return entity; + } } \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/ai/dto/export/ExpenseExportEntity.java b/src/main/java/com/gxwebsoft/ai/dto/export/ExpenseExportEntity.java new file mode 100644 index 0000000..8dbcdde --- /dev/null +++ b/src/main/java/com/gxwebsoft/ai/dto/export/ExpenseExportEntity.java @@ -0,0 +1,38 @@ +package com.gxwebsoft.ai.dto.export; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +/** + * 支出情况表导出实体类 + */ +@Data +public class ExpenseExportEntity { + + @Excel(name = "支出类型", orderNum = "0", width = 12) + private String expenseType; + + @Excel(name = "年份", orderNum = "1", width = 8) + private String year; + + @Excel(name = "决算报表数(元)", orderNum = "2", width = 15) + private String finalStatementAmount; + + @Excel(name = "年初预算数(元)", orderNum = "3", width = 15) + private String initialBudgetAmount; + + @Excel(name = "增减情况(%)", orderNum = "4", width = 12) + private String changePercentage; + + @Excel(name = "占年初预算比例(%)", orderNum = "5", width = 12) + private String budgetRatio; + + @Excel(name = "备注", orderNum = "6", width = 20) + private String remark; + + @Excel(name = "数据来源", orderNum = "7", width = 20) + private String dataSource; + + @Excel(name = "工作底稿索引", orderNum = "8", width = 25) + private String workPaperIndex; +} \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/ai/service/AuditContent1ExpenseService.java b/src/main/java/com/gxwebsoft/ai/service/AuditContent1ExpenseService.java new file mode 100644 index 0000000..045ceb4 --- /dev/null +++ b/src/main/java/com/gxwebsoft/ai/service/AuditContent1ExpenseService.java @@ -0,0 +1,21 @@ +package com.gxwebsoft.ai.service; + +import com.alibaba.fastjson.JSONObject; + +/** + * 支出情况表服务接口 + */ +public interface AuditContent1ExpenseService { + + /** + * 生成支出情况表数据 + * @param kbIds 知识库ID + * @param libraryKbIds 项目库KB IDs + * @param projectLibrary 项目库ID + * @param userName 用户名 + * @param history 历史记录 + * @param suggestion 建议 + * @return JSON格式的结果 + */ + JSONObject generateExpenseTableData(String kbIds, String libraryKbIds, String projectLibrary, String userName, String history, String suggestion); +} \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent1ExpenseServiceImpl.java b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent1ExpenseServiceImpl.java new file mode 100644 index 0000000..a840a0d --- /dev/null +++ b/src/main/java/com/gxwebsoft/ai/service/impl/AuditContent1ExpenseServiceImpl.java @@ -0,0 +1,412 @@ +package com.gxwebsoft.ai.service.impl; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.ai.constants.AuditContent1ExpenseConstants; +import com.gxwebsoft.ai.service.AuditContent1ExpenseService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import cn.hutool.core.util.StrUtil; + +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class AuditContent1ExpenseServiceImpl extends AbstractAuditContentService implements AuditContent1ExpenseService { + + // 工作流配置 + private static final String DIFY_WORKFLOW_TOKEN = "Bearer app-xwWxGF6hERgdeKB5OPpj9Tq8"; + + @Override + public JSONObject generateExpenseTableData(String kbIds, String libraryKbIds, String projectLibrary, + String userName, String history, String suggestion) { + log.info("开始生成支出情况表数据 - 用户: {}, kbIds: {}, libraryIds: {}, projectLibrary: {}", + userName, kbIds, libraryKbIds, projectLibrary); + + long startTime = System.currentTimeMillis(); + + try { + // 1. 检索相关知识 + Map> knowledgeSources = retrieveKnowledgeForExpense(kbIds, libraryKbIds, projectLibrary); + + // 2. 构建完整的知识上下文 + String knowledgeContext = buildCompleteKnowledgeContext(knowledgeSources, history, suggestion); + + // 3. 调用工作流生成数据 + JSONObject requestBody = buildWorkflowRequest(knowledgeContext, userName); + JSONArray expenseData = callWorkflow(DIFY_WORKFLOW_URL, DIFY_WORKFLOW_TOKEN, requestBody, "支出情况表"); + + // 4. 数据验证和补充 + expenseData = validateAndEnhanceExpenseData(expenseData); + + log.info("支出情况表生成成功 - 记录数: {}, 处理时间: {}ms", + expenseData.size(), (System.currentTimeMillis() - startTime)); + + return buildSuccessResponse(expenseData, startTime, "expense_audit"); + + } catch (Exception e) { + log.error("生成支出情况表失败", e); + return buildErrorResponse("生成支出情况表失败: " + e.getMessage()); + } + } + + /** + * 验证和增强支出情况表数据 + */ + private JSONArray validateAndEnhanceExpenseData(JSONArray originalData) { + if (originalData == null || originalData.isEmpty()) { + log.warn("原始数据为空,返回空数组"); + return new JSONArray(); + } + + JSONArray enhancedData = new JSONArray(); + + for (int i = 0; i < originalData.size(); i++) { + JSONObject item = originalData.getJSONObject(i); + if (item != null) { + // 确保所有必需字段都存在 + enhanceExpenseData(item); + enhancedData.add(item); + } + } + + // 确保数据完整性(至少16条记录) + if (enhancedData.size() < 16) { + enhancedData = supplementMissingExpenseData(enhancedData); + } + + log.info("数据增强完成 - 原始记录数: {}, 增强后记录数: {}", originalData.size(), enhancedData.size()); + return enhancedData; + } + + /** + * 增强单个支出数据 + */ + private void enhanceExpenseData(JSONObject expenseData) { + // 确保支出类型正确 + String expenseType = expenseData.getString("expenseType"); + if (StrUtil.isBlank(expenseType) || !isValidExpenseType(expenseType)) { + expenseData.put("expenseType", AuditContent1ExpenseConstants.EXPENSE_TYPE_RECEPTION); + } + + // 确保年份在2020-2023范围内 + String year = expenseData.getString("year"); + if (StrUtil.isBlank(year) || !isValidYear(year)) { + expenseData.put("year", "2023"); + } + + // 确保金额格式正确 + if (StrUtil.isBlank(expenseData.getString("finalStatementAmount"))) { + expenseData.put("finalStatementAmount", "0.00"); + } + + if (StrUtil.isBlank(expenseData.getString("initialBudgetAmount"))) { + expenseData.put("initialBudgetAmount", "0.00"); + } + + // 计算缺失的百分比字段 + calculateMissingPercentages(expenseData); + + // 确保数据来源 + if (StrUtil.isBlank(expenseData.getString("dataSource"))) { + String yearStr = expenseData.getString("year"); + expenseData.put("dataSource", yearStr + "年度部门决算报表"); + } + + // 确保工作底稿索引是数组格式 + if (!expenseData.containsKey("workPaperIndex") || expenseData.get("workPaperIndex") == null) { + JSONArray workPaperIndex = new JSONArray(); + workPaperIndex.add("《" + expenseData.getString("year") + "年度部门决算报表》"); + workPaperIndex.add("《" + expenseData.getString("year") + "年预算执行情况分析》"); + expenseData.put("workPaperIndex", workPaperIndex); + } + } + + /** + * 补充缺失的支出数据 + */ + private JSONArray supplementMissingExpenseData(JSONArray existingData) { + JSONArray supplementedData = new JSONArray(); + supplementedData.addAll(existingData); + + // 获取已存在的数据组合 + Set existingCombinations = new HashSet<>(); + for (int i = 0; i < existingData.size(); i++) { + JSONObject item = existingData.getJSONObject(i); + String key = item.getString("expenseType") + "_" + item.getString("year"); + existingCombinations.add(key); + } + + // 补充缺失的数据 + String[] expenseTypes = { + AuditContent1ExpenseConstants.EXPENSE_TYPE_RECEPTION, + AuditContent1ExpenseConstants.EXPENSE_TYPE_OVERSEAS, + AuditContent1ExpenseConstants.EXPENSE_TYPE_VEHICLE, + AuditContent1ExpenseConstants.EXPENSE_TYPE_MEETING + }; + + String[] years = {"2020", "2021", "2022", "2023"}; + + for (String expenseType : expenseTypes) { + for (String year : years) { + String key = expenseType + "_" + year; + if (!existingCombinations.contains(key)) { + JSONObject newItem = createDefaultExpenseRecord(expenseType, year); + supplementedData.add(newItem); + } + } + } + + return supplementedData; + } + + /** + * 创建默认的支出记录 + */ + private JSONObject createDefaultExpenseRecord(String expenseType, String year) { + JSONObject record = new JSONObject(); + record.put("expenseType", expenseType); + record.put("year", year); + record.put("finalStatementAmount", "0.00"); + record.put("initialBudgetAmount", "0.00"); + record.put("changePercentage", "0.0%"); + record.put("budgetRatio", "0.0%"); + record.put("remark", "根据年度财务报告数据生成"); + record.put("dataSource", year + "年度部门决算报表"); + + JSONArray workPaperIndex = new JSONArray(); + workPaperIndex.add("《" + year + "年度部门决算报表》"); + workPaperIndex.add("《" + year + "年预算执行情况分析》"); + record.put("workPaperIndex", workPaperIndex); + + return record; + } + + /** + * 计算缺失的百分比字段 + */ + private void calculateMissingPercentages(JSONObject expenseData) { + try { + String finalAmountStr = expenseData.getString("finalStatementAmount").replace(",", ""); + String budgetAmountStr = expenseData.getString("initialBudgetAmount").replace(",", ""); + + double finalAmount = Double.parseDouble(finalAmountStr); + double budgetAmount = Double.parseDouble(budgetAmountStr); + + // 计算增减百分比 + if (budgetAmount > 0) { + double changePercentage = ((finalAmount - budgetAmount) / budgetAmount) * 100; + if (!expenseData.containsKey("changePercentage") || StrUtil.isBlank(expenseData.getString("changePercentage"))) { + expenseData.put("changePercentage", String.format("%.1f%%", changePercentage)); + } + + // 计算预算占比 + double budgetRatio = (finalAmount / budgetAmount) * 100; + if (!expenseData.containsKey("budgetRatio") || StrUtil.isBlank(expenseData.getString("budgetRatio"))) { + expenseData.put("budgetRatio", String.format("%.1f%%", budgetRatio)); + } + } + } catch (Exception e) { + log.warn("计算百分比失败: {}", e.getMessage()); + } + } + + /** + * 检查支出类型是否有效 + */ + private boolean isValidExpenseType(String expenseType) { + return expenseType.equals(AuditContent1ExpenseConstants.EXPENSE_TYPE_RECEPTION) || + expenseType.equals(AuditContent1ExpenseConstants.EXPENSE_TYPE_OVERSEAS) || + expenseType.equals(AuditContent1ExpenseConstants.EXPENSE_TYPE_VEHICLE) || + expenseType.equals(AuditContent1ExpenseConstants.EXPENSE_TYPE_MEETING); + } + + /** + * 检查年份是否有效 + */ + private boolean isValidYear(String year) { + for (int validYear : AuditContent1ExpenseConstants.YEAR_RANGE) { + if (year.equals(String.valueOf(validYear))) { + return true; + } + } + return false; + } + + /** + * 检索支出情况表相关知识 - 优化查询策略 + */ + private Map> retrieveKnowledgeForExpense(String kbIds, String libraryKbIds, String projectLibrary) { + Map> knowledgeSources = new HashMap<>(); + knowledgeSources.put("financial", new ArrayList<>()); + knowledgeSources.put("regulation", new ArrayList<>()); + knowledgeSources.put("auditCase", new ArrayList<>()); + + // 构建更全面的查询词 + List queries = buildEnhancedExpenseQueries(); + + // 财务数据库检索 + if (StrUtil.isNotBlank(kbIds)) { + Arrays.stream(kbIds.split(",")) + .map(String::trim) + .filter(StrUtil::isNotBlank) + .forEach(kbId -> { + List financialKnowledge = queryKnowledgeBase(kbId, queries, 200); + knowledgeSources.get("financial").addAll(financialKnowledge); + log.debug("财务知识库 {} 检索到 {} 条相关知识", kbId, financialKnowledge.size()); + }); + } + + // 公共法律法规库检索 + if (StrUtil.isNotBlank(libraryKbIds)) { + Arrays.stream(libraryKbIds.split(",")) + .map(String::trim) + .filter(StrUtil::isNotBlank) + .forEach(libId -> { + List regulationKnowledge = queryKnowledgeBase(libId, queries, 100); + knowledgeSources.get("regulation").addAll(regulationKnowledge); + }); + } + + // 审计案例库检索 + if (StrUtil.isNotBlank(projectLibrary)) { + List auditCaseKnowledge = queryKnowledgeBase(projectLibrary, queries, 50); + knowledgeSources.get("auditCase").addAll(auditCaseKnowledge); + } + + // 智能去重和排序 + knowledgeSources.forEach((key, list) -> { + List processed = list.stream() + .distinct() + .sorted(this::expenseComparator) + .limit(getLimitBySourceType(key)) + .collect(Collectors.toList()); + knowledgeSources.put(key, processed); + }); + + log.info("支出情况表知识检索完成 - 财务: {}条, 法规: {}条, 案例: {}条", + knowledgeSources.get("financial").size(), + knowledgeSources.get("regulation").size(), + knowledgeSources.get("auditCase").size()); + + return knowledgeSources; + } + + /** + * 构建增强的支出情况表查询词 + */ + private List buildEnhancedExpenseQueries() { + return Arrays.asList( + "决算报表 预算报表 财务报表 年度报告", + "公务接待费 接待费用 招待费用 餐饮费用", + "出国费用 出境费用 国际差旅 境外考察", + "公车运行维护 车辆费用 汽车费用 交通费用", + "会议费 培训费 会务费 培训费用", + "八项规定 三公经费 公务支出", + "预算执行 预算调整 超预算 预算控制", + "2020年 2021年 2022年 2023年", + "支出明细 费用明细 开支情况", + "财务分析 费用分析 支出分析" + ); + } + + /** + * 构建完整的知识上下文 - 优化提示 + */ + private String buildCompleteKnowledgeContext(Map> knowledgeSources, String history, String suggestion) { + StringBuilder context = new StringBuilder(); + + // 1. 支出情况表分析要求 - 增强要求 + context.append("## 支出情况表分析要求\n"); + context.append("请基于以下知识生成完整详细的公务接待/出国/公车运行维护/会议培训费等支出情况表数据:\n\n"); + context.append("1. 必须生成完整的支出情况表数据,覆盖2020-2023四个年度\n"); + context.append("2. 重点关注四类支出:公务接待、出国(出境)、公车运行维护、会议培训费\n"); + context.append("3. 从财务知识库中提取所有实际的支出数据,要求全面完整\n"); + context.append("4. 确保信息的准确性和完整性,包括决算数、预算数、增减情况和占比情况\n"); + context.append("5. 工作底稿索引必须准确对应实际文件名称,可以包含多个相关文件\n"); + context.append("6. 要求生成尽可能多、尽可能完整的支出记录,覆盖所有年份和支出类型\n\n"); + + // 2. 数据格式要求 + context.append("## 数据格式要求\n"); + context.append("需要生成完整详细的支出情况表数据:\n\n"); + context.append(AuditContent1ExpenseConstants.DATA_FORMAT_REQUIREMENT); + context.append("\n\n重要要求:\n"); + context.append("1. 必须根据知识库内容生成尽可能多、尽可能完整的支出信息\n"); + context.append("2. 工作底稿索引必须准确对应实际文件名称,避免使用附表或章节标题\n"); + context.append("3. 金额单位为元,保持两位小数,可以使用逗号分隔千位\n"); + context.append("4. 百分比计算要准确,增减情况正数表示增长,负数表示减少\n"); + context.append("5. 数据来源要具体,如:2023年度部门决算报表\n"); + context.append("6. 备注信息可以包含超支原因、特殊情况说明等\n\n"); + + // 3. 历史内容 + if (StrUtil.isNotBlank(history)) { + context.append("## 历史生成内容\n"); + context.append("以下是之前生成的内容,请基于此进行优化和补充:\n"); + context.append(history).append("\n\n"); + } + + // 4. 用户建议 + if (StrUtil.isNotBlank(suggestion)) { + context.append("## 用户优化建议\n"); + context.append("请根据以下建议对生成内容进行调整:\n"); + context.append(suggestion).append("\n\n"); + } + + // 5. 财务知识 + if (!knowledgeSources.get("financial").isEmpty()) { + context.append("## 财务知识\n"); + context.append("这是财务相关的报表和文件信息,请仔细分析并提取所有支出数据:\n"); + knowledgeSources.get("financial").forEach(knowledge -> + context.append(knowledge).append("\n")); + context.append("\n"); + } + + // 6. 法律法规知识 + if (!knowledgeSources.get("regulation").isEmpty()) { + context.append("## 法律法规知识\n"); + knowledgeSources.get("regulation").forEach(knowledge -> + context.append(knowledge).append("\n")); + context.append("\n"); + } + + // 7. 审计案例知识 + if (!knowledgeSources.get("auditCase").isEmpty()) { + context.append("## 审计案例知识\n"); + knowledgeSources.get("auditCase").forEach(knowledge -> + context.append(knowledge).append("\n")); + } + + log.debug("构建的知识上下文长度: {}", context.length()); + return context.toString(); + } + + /** + * 支出情况表相关性比较器 + */ + private int expenseComparator(String content1, String content2) { + int score1 = calculateExpenseRelevanceScore(content1); + int score2 = calculateExpenseRelevanceScore(content2); + return Integer.compare(score2, score1); + } + + /** + * 计算支出情况表相关性分数 + */ + private int calculateExpenseRelevanceScore(String content) { + return AuditContent1ExpenseConstants.KEYWORD_WEIGHTS.entrySet().stream() + .filter(entry -> content.contains(entry.getKey())) + .mapToInt(Map.Entry::getValue) + .sum(); + } + + private int getLimitBySourceType(String sourceType) { + switch (sourceType) { + case "financial": return 150; + case "regulation": return 80; + case "auditCase": return 40; + default: return 100; + } + } +} \ No newline at end of file