|
|
@@ -1,7 +1,10 @@
|
|
|
package com.yuxin.finrep.application.orchestration;
|
|
|
|
|
|
+import com.alibaba.fastjson2.JSON;
|
|
|
import com.alibaba.fastjson2.JSONObject;
|
|
|
+import com.yuxin.finrep.domain.knowledge.KnowledgeUnit;
|
|
|
import com.yuxin.finrep.domain.port.out.DataPackageRepositoryPort;
|
|
|
+import com.yuxin.finrep.domain.port.out.KnowledgeUnitRepositoryPort;
|
|
|
import com.yuxin.finrep.domain.port.out.OutlineRepositoryPort;
|
|
|
import com.yuxin.finrep.domain.port.out.PythonAgentClientPort;
|
|
|
import com.yuxin.finrep.domain.port.out.ReportRepositoryPort;
|
|
|
@@ -12,6 +15,7 @@ import com.yuxin.finrep.common.util.JsonUtil;
|
|
|
import com.yuxin.finrep.domain.dataprep.DataPackage;
|
|
|
import com.yuxin.finrep.domain.generation.Report;
|
|
|
import com.yuxin.finrep.domain.outline.Outline;
|
|
|
+import com.yuxin.finrep.domain.outline.OutlineNode;
|
|
|
import com.yuxin.finrep.domain.outline.OutlineSection;
|
|
|
import com.yuxin.finrep.domain.task.Task;
|
|
|
import com.yuxin.finrep.domain.task.TaskStatus;
|
|
|
@@ -38,24 +42,23 @@ public class ReportGenerationOrchestrator {
|
|
|
private final ReportRepositoryPort reportRepositoryPort;
|
|
|
private final PythonAgentClientPort pythonAgentClientPort;
|
|
|
private final TaskOrchestrator taskOrchestrator;
|
|
|
+ private final KnowledgeUnitRepositoryPort knowledgeUnitRepositoryPort;
|
|
|
|
|
|
private final ExecutorService executorService = Executors.newFixedThreadPool(5);
|
|
|
|
|
|
- public void generateReport(String taskId, Map<String, Object> parameters) {
|
|
|
+ public Report generateReport(String taskId, Map<String, Object> parameters) {
|
|
|
log.info("开始生成报告: taskId={}", taskId);
|
|
|
|
|
|
Task task = taskRepositoryPort.findById(taskId)
|
|
|
.orElseThrow(() -> new BusinessException(ErrorCode.TASK_NOT_FOUND));
|
|
|
|
|
|
try {
|
|
|
- Outline outline = outlineRepositoryPort.findByTaskId(taskId)
|
|
|
- .orElseThrow(() -> new BusinessException(ErrorCode.OUTLINE_NOT_FOUND));
|
|
|
-
|
|
|
+ Outline outline = outlineRepositoryPort.findByTaskIdAndType(taskId,"LEVEL2");
|
|
|
List<DataPackage> dataPackages = dataPackageRepositoryPort.findByTaskId(taskId);
|
|
|
|
|
|
- if (dataPackages.isEmpty()) {
|
|
|
- throw new BusinessException(ErrorCode.DATA_PREPARE_FAILED, "没有找到数据包");
|
|
|
- }
|
|
|
+// if (dataPackages.isEmpty()) {
|
|
|
+// throw new BusinessException(ErrorCode.DATA_PREPARE_FAILED, "没有找到数据包");
|
|
|
+// }
|
|
|
|
|
|
Report report = Report.create(
|
|
|
taskId,
|
|
|
@@ -81,6 +84,7 @@ public class ReportGenerationOrchestrator {
|
|
|
taskRepositoryPort.save(task);
|
|
|
|
|
|
log.info("报告生成成功: taskId={}, reportId={}", taskId, report.getReportId());
|
|
|
+ return report;
|
|
|
|
|
|
} catch (BusinessException e) {
|
|
|
log.error("报告生成失败: taskId={}, error={}", taskId, e.getMessage());
|
|
|
@@ -93,39 +97,142 @@ public class ReportGenerationOrchestrator {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 组装完整文章:将生成的段落与二级大纲结构结合
|
|
|
+ * @param report 生成的报告
|
|
|
+ * @param outline 二级大纲
|
|
|
+ * @return 完整文章内容(JSON格式)
|
|
|
+ */
|
|
|
+ public String assembleFullArticle(Report report, Outline outline) {
|
|
|
+ log.info("开始组装完整文章: reportId={}, outlineId={}", report.getReportId(), outline.getOutlineId());
|
|
|
+
|
|
|
+ try {
|
|
|
+ String sectionsJson = outline.getSections();
|
|
|
+ if (sectionsJson == null || sectionsJson.isEmpty()) {
|
|
|
+ log.warn("二级大纲sections为空");
|
|
|
+ return "[]";
|
|
|
+ }
|
|
|
+
|
|
|
+ com.alibaba.fastjson2.JSONArray sectionsArray = JSON.parseArray(sectionsJson);
|
|
|
+ if (sectionsArray == null || sectionsArray.isEmpty()) {
|
|
|
+ log.warn("二级大纲sections解析为空数组");
|
|
|
+ return "[]";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建node_id到段落内容的映射
|
|
|
+ Map<String, String> contentMap = new java.util.HashMap<>();
|
|
|
+ if (report.getSections() != null) {
|
|
|
+ for (Report.Section section : report.getSections()) {
|
|
|
+ if (section.getContent() != null) {
|
|
|
+ contentMap.put(section.getSectionId(), section.getContent());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 遍历二级大纲结构,组装文章
|
|
|
+ for (int i = 0; i < sectionsArray.size(); i++) {
|
|
|
+ com.alibaba.fastjson2.JSONObject chapter = sectionsArray.getJSONObject(i);
|
|
|
+ if (chapter == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 移除chapter级别的无用字段
|
|
|
+ chapter.remove("presentation_enum");
|
|
|
+ chapter.remove("paragraph_count_enum");
|
|
|
+ chapter.remove("reason");
|
|
|
+
|
|
|
+ // 获取l2字段
|
|
|
+ com.alibaba.fastjson2.JSONObject l2 = chapter.getJSONObject("l2");
|
|
|
+ if (l2 == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ l2.remove("structure_logic");
|
|
|
+ // 获取chapter_structure
|
|
|
+ com.alibaba.fastjson2.JSONArray chapterStructure = l2.getJSONArray("chapter_structure");
|
|
|
+ if (chapterStructure == null || chapterStructure.isEmpty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 遍历章节结构,添加生成的段落内容
|
|
|
+ for (int j = 0; j < chapterStructure.size(); j++) {
|
|
|
+ com.alibaba.fastjson2.JSONObject node = chapterStructure.getJSONObject(j);
|
|
|
+ if (node == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ String nodeId = node.getString("node_id");
|
|
|
+ if (nodeId != null && !nodeId.isEmpty()) {
|
|
|
+ // 添加生成的段落内容到节点
|
|
|
+ String content = contentMap.get(nodeId);
|
|
|
+ node.put("content", content != null ? content : "");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 移除node级别的无用字段
|
|
|
+ node.remove("node_level");
|
|
|
+ node.remove("node_id");
|
|
|
+ node.remove("source_type");
|
|
|
+ node.remove("is_selected");
|
|
|
+ node.remove("source_candidate_name");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("完整文章组装完成: reportId={}", report.getReportId());
|
|
|
+ return sectionsArray.toJSONString();
|
|
|
+ } catch (Exception ekt) {
|
|
|
+ log.error("组装完整文章失败: {}", ekt.getMessage());
|
|
|
+ return "[]";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private void generateReportSections(Task task, Outline outline, List<DataPackage> dataPackages,
|
|
|
Report report, Map<String, Object> parameters) {
|
|
|
log.info("开始生成报告段落: taskId={}, outlineId={}", task.getTaskId(), outline.getOutlineId());
|
|
|
|
|
|
List<Report.Section> sections = new ArrayList<>();
|
|
|
List<CompletableFuture<Report.Section>> futures = new ArrayList<>();
|
|
|
+ String writingLogic = outline.getWritingLogic();
|
|
|
|
|
|
- List<OutlineSection> outlineSections = outline.getSectionList();
|
|
|
+ // 从二级大纲的sections中提取node_id与node_name的映射
|
|
|
+ Map<String, String> nodeNameMap = extractNodeNameMappingFromLevel2Outline(outline);
|
|
|
+ log.info("找到待生成段落的节点数量: {}", nodeNameMap.size());
|
|
|
|
|
|
- for (OutlineSection outlineSection : outlineSections) {
|
|
|
- String knowledgeUnitId = outlineSection.getKnowledgeUnitId();
|
|
|
+ for (Map.Entry<String, String> entry : nodeNameMap.entrySet()) {
|
|
|
+ String nodeId = entry.getKey();
|
|
|
+ String nodeName = entry.getValue();
|
|
|
|
|
|
- if (knowledgeUnitId == null) {
|
|
|
- log.warn("章节缺少知识单元ID: sectionId={}", outlineSection.getSectionId());
|
|
|
+ // 根据node_id获取知识单元
|
|
|
+ KnowledgeUnit knowledgeUnit = knowledgeUnitRepositoryPort.findById(nodeId)
|
|
|
+ .orElse(null);
|
|
|
+
|
|
|
+ if (knowledgeUnit == null) {
|
|
|
+ log.warn("未找到知识单元: nodeId={}", nodeId);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
+ // 查找对应的数据包
|
|
|
DataPackage dataPackage = dataPackages.stream()
|
|
|
- .filter(dp -> dp.getKnowledgeUnitId().equals(knowledgeUnitId))
|
|
|
+ .filter(dp -> dp.getKnowledgeUnitId().equals(nodeId))
|
|
|
.findFirst()
|
|
|
.orElse(null);
|
|
|
|
|
|
if (dataPackage == null) {
|
|
|
- log.warn("未找到知识单元对应的数据包: knowledgeUnitId={}", knowledgeUnitId);
|
|
|
- continue;
|
|
|
+ log.warn("未找到知识单元对应的数据包: knowledgeUnitId={}", nodeId);
|
|
|
+ // 即使没有数据包,也可以生成段落(使用空数据)
|
|
|
+ dataPackage = createEmptyDataPackage(nodeId);
|
|
|
}
|
|
|
|
|
|
+ final String finalNodeId = nodeId;
|
|
|
+ final String finalNodeName = nodeName;
|
|
|
+ final DataPackage finalDataPackage = dataPackage;
|
|
|
+ final KnowledgeUnit finalKnowledgeUnit = knowledgeUnit;
|
|
|
+
|
|
|
CompletableFuture<Report.Section> future = CompletableFuture.supplyAsync(() -> {
|
|
|
try {
|
|
|
- return generateSection(task, outlineSection, dataPackage, parameters);
|
|
|
+ return generateSectionFromKnowledgeUnit(task, finalNodeId, finalNodeName, finalKnowledgeUnit,
|
|
|
+ finalDataPackage, parameters, writingLogic);
|
|
|
} catch (Exception e) {
|
|
|
- log.error("生成段落异常: sectionId={}, error={}",
|
|
|
- outlineSection.getSectionId(), e.getMessage(), e);
|
|
|
+ log.error("生成段落异常: nodeId={}, error={}",
|
|
|
+ finalNodeId, e.getMessage(), e);
|
|
|
throw new BusinessException(ErrorCode.SECTION_GENERATE_FAILED, e);
|
|
|
}
|
|
|
}, executorService);
|
|
|
@@ -142,7 +249,7 @@ public class ReportGenerationOrchestrator {
|
|
|
sections.add(section);
|
|
|
report.addSection(section);
|
|
|
|
|
|
- int progress = 75 + (int) (25.0 * sections.size() / outlineSections.size());
|
|
|
+ int progress = 75 + (int) (25.0 * sections.size() / nodeNameMap.size());
|
|
|
task.updateProgress(Math.min(progress, 95));
|
|
|
taskRepositoryPort.save(task);
|
|
|
}
|
|
|
@@ -154,16 +261,31 @@ public class ReportGenerationOrchestrator {
|
|
|
log.info("报告段落生成完成: taskId={}, sectionCount={}", task.getTaskId(), sections.size());
|
|
|
}
|
|
|
|
|
|
- private Report.Section generateSection(Task task, OutlineSection outlineSection,
|
|
|
- DataPackage dataPackage, Map<String, Object> parameters) {
|
|
|
- log.debug("生成段落: taskId={}, sectionId={}", task.getTaskId(), outlineSection.getSectionId());
|
|
|
+
|
|
|
+
|
|
|
+ private Report.Section generateSection(Task task, OutlineNode outlineNode,
|
|
|
+ DataPackage dataPackage, Map<String, Object> parameters, String writingLogic) {
|
|
|
+ log.debug("生成段落: taskId={}, nodeId={}", task.getTaskId(), outlineNode.getNodeId());
|
|
|
+
|
|
|
+ // 根据知识单元ID查询知识单元
|
|
|
+ KnowledgeUnit knowledgeUnit = knowledgeUnitRepositoryPort.findById(dataPackage.getKnowledgeUnitId())
|
|
|
+ .orElseThrow(() -> new BusinessException(ErrorCode.SECTION_GENERATE_FAILED,
|
|
|
+ "知识单元不存在: " + dataPackage.getKnowledgeUnitId()));
|
|
|
+ // 获取知识单元的template
|
|
|
+ String template = knowledgeUnit.getTemplate();
|
|
|
+ if (template == null || template.isEmpty()) {
|
|
|
+ throw new BusinessException(ErrorCode.SECTION_GENERATE_FAILED,
|
|
|
+ "知识单元模板为空: " + dataPackage.getKnowledgeUnitId());
|
|
|
+ }
|
|
|
|
|
|
JSONObject response = pythonAgentClientPort.generateSection(
|
|
|
task.getTaskId(),
|
|
|
task.getTenantId(),
|
|
|
dataPackage.getKnowledgeUnitId(),
|
|
|
mergeData(dataPackage),
|
|
|
- parameters
|
|
|
+ template,
|
|
|
+ parameters,
|
|
|
+ writingLogic
|
|
|
);
|
|
|
|
|
|
if (response == null || !response.containsKey("success") || !response.getBoolean("success")) {
|
|
|
@@ -172,9 +294,9 @@ public class ReportGenerationOrchestrator {
|
|
|
}
|
|
|
|
|
|
Report.Section section = new Report.Section();
|
|
|
- section.setSectionId(outlineSection.getSectionId());
|
|
|
- section.setSectionNumber(outlineSection.getSortOrder() != null ? String.valueOf(outlineSection.getSortOrder()) : "1");
|
|
|
- section.setTitle(outlineSection.getTitle());
|
|
|
+ section.setSectionId(outlineNode.getNodeId());
|
|
|
+ section.setSectionNumber(outlineNode.getChapterNumber() != null ? outlineNode.getChapterNumber() : "1");
|
|
|
+ section.setTitle(outlineNode.getTitle());
|
|
|
section.setContent(response.getString("content"));
|
|
|
section.setKnowledgeUnitId(dataPackage.getKnowledgeUnitId());
|
|
|
section.setCreateTime(LocalDateTime.now());
|
|
|
@@ -285,4 +407,206 @@ public class ReportGenerationOrchestrator {
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从二级大纲中提取node_id列表
|
|
|
+ * 二级大纲的sections结构示例:
|
|
|
+ * [
|
|
|
+ * {
|
|
|
+ * "chapter_id": "pf-l1-01",
|
|
|
+ * "chapter_name": "企业基本情况分析",
|
|
|
+ * "l2": {
|
|
|
+ * "chapter_structure": [
|
|
|
+ * {"node_id": "pf-01-ku-02", "node_name": "企业基本情况", ...}
|
|
|
+ * ]
|
|
|
+ * }
|
|
|
+' * }
|
|
|
+ * ]
|
|
|
+ */
|
|
|
+ private List<String> extractNodeIdsFromLevel2Outline(Outline outline) {
|
|
|
+ List<String> nodeIds = new ArrayList<>();
|
|
|
+ try {
|
|
|
+ String sectionsJson = outline.getSections();
|
|
|
+ if (sectionsJson == null || sectionsJson.isEmpty()) {
|
|
|
+ log.warn("二级大纲sections为空");
|
|
|
+ return nodeIds;
|
|
|
+ }
|
|
|
+
|
|
|
+ com.alibaba.fastjson2.JSONArray sectionsArray = JSON.parseArray(sectionsJson);
|
|
|
+ if (sectionsArray == null || sectionsArray.isEmpty()) {
|
|
|
+ log.warn("二级大纲sections解析为空数组");
|
|
|
+ return nodeIds;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = 0; i < sectionsArray.size(); i++) {
|
|
|
+ com.alibaba.fastjson2.JSONObject chapter = sectionsArray.getJSONObject(i);
|
|
|
+ if (chapter == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取l2字段
|
|
|
+ com.alibaba.fastjson2.JSONObject l2 = chapter.getJSONObject("l2");
|
|
|
+ if (l2 == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取chapter_structure
|
|
|
+ com.alibaba.fastjson2.JSONArray chapterStructure = l2.getJSONArray("chapter_structure");
|
|
|
+ if (chapterStructure == null || chapterStructure.isEmpty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 提取所有node_id
|
|
|
+ for (int j = 0; j < chapterStructure.size(); j++) {
|
|
|
+ com.alibaba.fastjson2.JSONObject node = chapterStructure.getJSONObject(j);
|
|
|
+ if (node == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ String nodeId = node.getString("node_id");
|
|
|
+ if (nodeId != null && !nodeId.isEmpty()) {
|
|
|
+ nodeIds.add(nodeId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("从二级大纲提取到{}个node_id", nodeIds.size());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("提取node_id失败: {}", e.getMessage(), e);
|
|
|
+ }
|
|
|
+ return nodeIds;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从二级大纲中提取node_id与node_name的映射
|
|
|
+ * 二级大纲的sections结构示例:
|
|
|
+ * [
|
|
|
+ * {
|
|
|
+ * "chapter_id": "pf-l1-01",
|
|
|
+ * "chapter_name": "企业基本情况分析",
|
|
|
+ * "l2": {
|
|
|
+ * "chapter_structure": [
|
|
|
+ * {"node_id": "pf-01-ku-02", "node_name": "企业基本情况", ...}
|
|
|
+ * ]
|
|
|
+ * }
|
|
|
+ * }
|
|
|
+ * ]
|
|
|
+ * @return node_id -> node_name 的映射
|
|
|
+ */
|
|
|
+ private Map<String, String> extractNodeNameMappingFromLevel2Outline(Outline outline) {
|
|
|
+ Map<String, String> nodeNameMap = new java.util.HashMap<>();
|
|
|
+ try {
|
|
|
+ String sectionsJson = outline.getSections();
|
|
|
+ if (sectionsJson == null || sectionsJson.isEmpty()) {
|
|
|
+ log.warn("二级大纲sections为空");
|
|
|
+ return nodeNameMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ com.alibaba.fastjson2.JSONArray sectionsArray = JSON.parseArray(sectionsJson);
|
|
|
+ if (sectionsArray == null || sectionsArray.isEmpty()) {
|
|
|
+ log.warn("二级大纲sections解析为空数组");
|
|
|
+ return nodeNameMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = 0; i < sectionsArray.size(); i++) {
|
|
|
+ com.alibaba.fastjson2.JSONObject chapter = sectionsArray.getJSONObject(i);
|
|
|
+ if (chapter == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取l2字段
|
|
|
+ com.alibaba.fastjson2.JSONObject l2 = chapter.getJSONObject("l2");
|
|
|
+ if (l2 == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取chapter_structure
|
|
|
+ com.alibaba.fastjson2.JSONArray chapterStructure = l2.getJSONArray("chapter_structure");
|
|
|
+ if (chapterStructure == null || chapterStructure.isEmpty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 提取所有node_id和node_name的映射
|
|
|
+ for (int j = 0; j < chapterStructure.size(); j++) {
|
|
|
+ com.alibaba.fastjson2.JSONObject node = chapterStructure.getJSONObject(j);
|
|
|
+ if (node == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ String nodeId = node.getString("node_id");
|
|
|
+ String nodeName = node.getString("node_name");
|
|
|
+ if (nodeId != null && !nodeId.isEmpty()) {
|
|
|
+ // 如果node_name为空,使用node_id作为默认值
|
|
|
+ nodeNameMap.put(nodeId, nodeName != null && !nodeName.isEmpty() ? nodeName : nodeId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("从二级大纲提取到{}个node_id与node_name映射", nodeNameMap.size());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("提取node_id与node_name映射失败: {}", e.getMessage(), e);
|
|
|
+ }
|
|
|
+ return nodeNameMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建空的数据包
|
|
|
+ */
|
|
|
+ private DataPackage createEmptyDataPackage(String knowledgeUnitId) {
|
|
|
+ DataPackage dataPackage = new DataPackage();
|
|
|
+ dataPackage.setKnowledgeUnitId(knowledgeUnitId);
|
|
|
+ dataPackage.setAutoData(new java.util.HashMap<>());
|
|
|
+ dataPackage.setManualData(new java.util.HashMap<>());
|
|
|
+ return dataPackage;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据知识单元生成段落
|
|
|
+ */
|
|
|
+ private Report.Section generateSectionFromKnowledgeUnit(Task task, String nodeId, String nodeName,
|
|
|
+ KnowledgeUnit knowledgeUnit,
|
|
|
+ DataPackage dataPackage,
|
|
|
+ Map<String, Object> parameters,
|
|
|
+ String writingLogic) {
|
|
|
+ log.debug("生成段落: taskId={}, nodeId={}, nodeName={}", task.getTaskId(), nodeId, nodeName);
|
|
|
+
|
|
|
+ // 获取知识单元的template
|
|
|
+ String template = knowledgeUnit.getTemplate();
|
|
|
+ if (template == null || template.isEmpty()) {
|
|
|
+ throw new BusinessException(ErrorCode.SECTION_GENERATE_FAILED,
|
|
|
+ "知识单元模板为空: " + nodeId);
|
|
|
+ }
|
|
|
+
|
|
|
+ JSONObject response = pythonAgentClientPort.generateSection(
|
|
|
+ task.getTaskId(),
|
|
|
+ task.getTenantId(),
|
|
|
+ nodeId,
|
|
|
+ mergeData(dataPackage),
|
|
|
+ template,
|
|
|
+ parameters,
|
|
|
+ writingLogic
|
|
|
+ );
|
|
|
+
|
|
|
+ if (response == null ) {
|
|
|
+ String errorMsg = "Python Agent返回空响应";
|
|
|
+ throw new BusinessException(ErrorCode.SECTION_GENERATE_FAILED, errorMsg);
|
|
|
+ }
|
|
|
+
|
|
|
+ Report.Section section = new Report.Section();
|
|
|
+ section.setSectionId(nodeId);
|
|
|
+ // 使用l2大纲中的node_name作为段落标题,如果为空则使用知识单元名称
|
|
|
+ section.setTitle(nodeName != null && !nodeName.isEmpty() ? nodeName : knowledgeUnit.getName());
|
|
|
+ section.setContent(response.getString("generated_text"));
|
|
|
+ section.setKnowledgeUnitId(nodeId);
|
|
|
+ section.setCreateTime(LocalDateTime.now());
|
|
|
+ section.setUpdateTime(LocalDateTime.now());
|
|
|
+
|
|
|
+ if (response.containsKey("references")) {
|
|
|
+ List<String> references = parseReferences(response.getJSONArray("references"));
|
|
|
+ section.setReferences(references);
|
|
|
+ }
|
|
|
+
|
|
|
+ log.debug("段落生成成功: sectionId={}", section.getSectionId());
|
|
|
+ return section;
|
|
|
+ }
|
|
|
}
|