package com.vincent.rsf.server.ai.service.diagnosis; import com.vincent.rsf.server.system.entity.AiDiagnosisRecord; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @Service public class AiDiagnosisReportService { /** * 基于模型结论和工具摘要回填诊断报告结构化字段与 Markdown 内容。 */ public void fillReport(AiDiagnosisRecord record, String conclusion, String toolSummary) { if (record == null) { return; } Map sections = extractSections(conclusion); String executiveSummary = firstNonBlank( sections.get("问题概述"), sections.get("执行摘要"), safeText(conclusion) ); String evidenceSummary = firstNonBlank( sections.get("关键证据"), sections.get("证据摘要"), safeText(toolSummary) ); String actionSummary = firstNonBlank( sections.get("建议动作"), sections.get("处置建议"), "请结合现场流程继续确认。" ); String riskSummary = firstNonBlank( sections.get("风险评估"), sections.get("潜在风险"), "如未及时处理,可能继续影响当前业务运行。" ); record.setReportTitle(buildTitle(record)); record.setExecutiveSummary(executiveSummary); record.setEvidenceSummary(evidenceSummary); record.setActionSummary(actionSummary); record.setRiskSummary(riskSummary); record.setReportMarkdown(buildMarkdown(record, executiveSummary, evidenceSummary, actionSummary, riskSummary, conclusion)); } /** * 尝试从原始结论文本中提取“问题概述/关键证据/建议动作/风险评估”等章节。 */ private Map extractSections(String conclusion) { Map sections = new LinkedHashMap<>(); if (conclusion == null || conclusion.trim().isEmpty()) { return sections; } String[] lines = conclusion.replace("\r", "").split("\n"); String currentTitle = "问题概述"; StringBuilder currentBody = new StringBuilder(); for (String rawLine : lines) { String line = rawLine == null ? "" : rawLine.trim(); String title = normalizeTitle(line); if (title != null) { saveSection(sections, currentTitle, currentBody); currentTitle = title; currentBody = new StringBuilder(); String remainder = line.substring(line.indexOf(title) + title.length()).trim(); if (remainder.startsWith(":") || remainder.startsWith(":")) { remainder = remainder.substring(1).trim(); } if (!remainder.isEmpty()) { currentBody.append(remainder); } continue; } if (currentBody.length() > 0) { currentBody.append("\n"); } currentBody.append(rawLine == null ? "" : rawLine); } saveSection(sections, currentTitle, currentBody); return sections; } /** * 将当前章节内容写入 section map。 */ private void saveSection(Map sections, String title, StringBuilder body) { String content = body == null ? "" : body.toString().trim(); if (content.isEmpty()) { return; } sections.put(title, content); } /** * 判断一行文本是否可视为报告章节标题。 */ private String normalizeTitle(String line) { if (line == null) { return null; } String normalized = line.replace("#", "").replace(":", "").replace(":", "").trim(); List titles = new ArrayList<>(); titles.add("问题概述"); titles.add("执行摘要"); titles.add("关键证据"); titles.add("证据摘要"); titles.add("可能原因"); titles.add("建议动作"); titles.add("处置建议"); titles.add("风险评估"); titles.add("潜在风险"); for (String title : titles) { if (normalized.startsWith(title)) { return title; } } return null; } /** * 构造诊断报告标题。 */ private String buildTitle(AiDiagnosisRecord record) { String diagnosisNo = record.getDiagnosisNo() == null ? "-" : record.getDiagnosisNo(); return "WMS诊断报告-" + diagnosisNo; } /** * 生成最终报告 Markdown。 */ private String buildMarkdown(AiDiagnosisRecord record, String executiveSummary, String evidenceSummary, String actionSummary, String riskSummary, String conclusion) { List parts = new ArrayList<>(); parts.add("# " + buildTitle(record)); parts.add(""); parts.add("## 问题概述"); parts.add(safeText(executiveSummary)); parts.add(""); parts.add("## 关键证据"); parts.add(safeText(evidenceSummary)); parts.add(""); parts.add("## 建议动作"); parts.add(safeText(actionSummary)); parts.add(""); parts.add("## 风险评估"); parts.add(safeText(riskSummary)); if (conclusion != null && !conclusion.trim().isEmpty()) { parts.add(""); parts.add("## 原始结论"); parts.add(conclusion.trim()); } return String.join("\n", parts); } /** * 返回第一个非空文本。 */ private String firstNonBlank(String... values) { if (values == null) { return ""; } for (String value : values) { if (value != null && !value.trim().isEmpty()) { return value.trim(); } } return ""; } /** * 对展示文本做空值兜底。 */ private String safeText(String value) { return value == null || value.trim().isEmpty() ? "暂无内容" : value.trim(); } }