From 27ca7166457113dea59a39054e468a99b83b79fc Mon Sep 17 00:00:00 2001 From: HuangHai <10402852@qq.com> Date: Sat, 14 Jun 2025 08:29:51 +0800 Subject: [PATCH] 'commit' --- .../base/AI/Controller/AiController.java | 75 +++++++- .../base/AI/Generator/PptGenerator.java | 182 ++++-------------- 2 files changed, 114 insertions(+), 143 deletions(-) diff --git a/src/main/java/com/dsideal/base/AI/Controller/AiController.java b/src/main/java/com/dsideal/base/AI/Controller/AiController.java index e29d7638..324b5062 100644 --- a/src/main/java/com/dsideal/base/AI/Controller/AiController.java +++ b/src/main/java/com/dsideal/base/AI/Controller/AiController.java @@ -2,9 +2,11 @@ package com.dsideal.base.AI.Controller; import com.dsideal.base.AI.Generator.WordGenerator; import com.dsideal.base.AI.Generator.HtmlGenerator; +import com.dsideal.base.AI.Generator.PptGenerator; import com.dsideal.base.AI.Model.YunNanModel; import com.dsideal.base.Util.CallDeepSeek; import com.dsideal.base.Util.CommonUtil; +import com.dsideal.base.Util.PptAIKit; import com.jfinal.aop.Before; import com.jfinal.core.Controller; import com.jfinal.ext.interceptor.GET; @@ -96,7 +98,7 @@ public class AiController extends Controller { // 构建HTML提示词,直接生成HTML报告 String regionName = shiZhouA + "与" + shiZhouB; String htmlPrompt = HtmlGenerator.buildHtmlPrompt(content, regionName); - + // 调用DeepSeek API生成HTML报告 CallDeepSeek.callDeepSeekStream(htmlPrompt, new CallDeepSeek.SSEListener() { @Override @@ -113,7 +115,7 @@ public class AiController extends Controller { String fileName = "/upload/" + shiZhouA + "与" + shiZhouB + "_教育分析报告_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + ".html"; String filePath = PathKit.getWebRootPath() + fileName; - + // 清理并保存HTML内容 HtmlGenerator htmlGenerator = new HtmlGenerator(); htmlGenerator.saveHtmlContent(fullResponse, filePath); @@ -144,4 +146,73 @@ public class AiController extends Controller { sseEmitter.waiting(100); renderNull(); } + + /** + * 对比市州,生成对比报告【PPT】 + * + * @param shiZhouA 市州A + * @param shiZhouB 市州B + * http://10.10.21.20:9200/dsBase/ai/compareShiZhouPpt?shiZhouA=文山州&shiZhouB=楚雄州 + */ + @Before({GET.class}) + public void compareShiZhouPpt(String shiZhouA, String shiZhouB) throws Exception { + // 数据获取 + String content = ym.collectEducationData(new String[]{shiZhouA, shiZhouB}); + //创建sse + final SseEmitter sseEmitter = new SseEmitter(getResponse()); + // 发送开始分析的消息 + sseEmitter.sendMessage("data: 开始数据分析...\n\n"); + + // 构建PPT提示词,直接生成PPT大纲 + String regionName = shiZhouA + "与" + shiZhouB; + String pptPrompt = PptGenerator.buildPptPrompt(content, regionName); + + // 调用DeepSeek API生成PPT大纲,然后直接生成PPT文件 + CallDeepSeek.callDeepSeekStream(pptPrompt, new CallDeepSeek.SSEListener() { + @Override + public void onData(String data) { + // 实时推送PPT大纲生成进度 + sseEmitter.sendMessage("data: " + data + "\n\n"); + } + + @Override + public void onComplete(String fullResponse) { + try { + // PPT大纲生成完成,开始生成PPT文件 + sseEmitter.sendMessage("data: PPT大纲生成完成,正在生成PPT文件...\n\n"); + + // 直接使用生成的大纲调用PPT生成API(不再调用DeepSeek) + String token = PptAIKit.createApiToken("dsideal", 1000); + String pptFileUrl = PptGenerator.generatePptFromMarkdown(fullResponse, token); + + if (pptFileUrl != null && !pptFileUrl.trim().isEmpty()) { + sseEmitter.sendMessage("data: PPT生成完成!文件下载地址:" + pptFileUrl + "\n\n"); + } else { + sseEmitter.sendMessage("data: PPT生成失败,请检查API令牌或网络连接\n\n"); + } + + sseEmitter.sendMessage("data: [DONE]\n\n"); + + // 完成SSE连接 + sseEmitter.complete(); + } catch (Exception e) { + sseEmitter.sendMessage("data: 生成PPT时发生错误:" + e.getMessage() + "\n\n"); + sseEmitter.sendMessage("data: [DONE]\n\n"); + sseEmitter.complete(); + } + } + + @Override + public void onError(String error) { + // 发送错误信息给前端 + sseEmitter.sendMessage("data: 调用DeepSeek API异常:" + error + "\n\n"); + sseEmitter.sendMessage("data: [DONE]\n\n"); + sseEmitter.complete(); + } + }); + + //锁住等待子线程推送完成 + sseEmitter.waiting(100); + renderNull(); + } } diff --git a/src/main/java/com/dsideal/base/AI/Generator/PptGenerator.java b/src/main/java/com/dsideal/base/AI/Generator/PptGenerator.java index 0bf90929..4043fe8f 100644 --- a/src/main/java/com/dsideal/base/AI/Generator/PptGenerator.java +++ b/src/main/java/com/dsideal/base/AI/Generator/PptGenerator.java @@ -4,12 +4,9 @@ import com.alibaba.fastjson.JSONObject; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; -import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.text.SimpleDateFormat; -import java.util.Date; /** * PPT生成器 - 负责生成分析报告的PPT演示文稿 @@ -17,43 +14,47 @@ import java.util.Date; public class PptGenerator { private static final String PPT_API_URL = "https://open.docmee.cn/api/ppt/generatePptx"; - // 指定保存目录 - private static final String SAVE_DIRECTORY = "D:\\dsWork\\YunNanDsBase\\WebRoot\\upload"; - + /** - * 生成PPT演示文稿 - * @param analysisContent 分析内容(与Word文档相同的内容) - * @param regions 对比地区 + * 构建PPT提示词 + * @param dataContent 数据内容 + * @param regionName 地区名称 + * @return PPT生成提示词 + */ + public static String buildPptPrompt(String dataContent, String regionName) { + return String.format( + "请根据以下数据内容,生成一个适合制作PPT的大纲,要求:\n\n" + + "1. 生成标准的Markdown格式大纲,用于PPT制作\n" + + "2. 大纲应该包含清晰的章节结构,每个章节都有明确的标题\n" + + "3. 每个章节下应该有3-5个要点,适合在PPT幻灯片中展示\n" + + "4. 重点突出数据对比和分析结论\n" + + "5. 大纲应该逻辑清晰,便于制作专业的演示文稿\n" + + "6. 包含以下主要部分:\n" + + " - 概述与背景\n" + + " - 数据对比分析\n" + + " - 关键发现\n" + + " - 结论与建议\n\n" + + "地区:%s\n\n" + + "数据内容:\n%s", + regionName, dataContent + ); + } + + /** + * 直接从Markdown内容生成PPT(不调用DeepSeek) + * @param markdownContent PPT大纲的Markdown内容(由DeepSeek生成) * @param token API访问令牌 - * @return 本地PPT文件路径 + * @return PPT文件下载URL */ - public static String generatePptPresentation(String analysisContent, String[] regions, String token) { + public static String generatePptFromMarkdown(String markdownContent, String token) { try { - // 确保保存目录存在 - File saveDir = new File(SAVE_DIRECTORY); - if (!saveDir.exists()) { - saveDir.mkdirs(); - } - - // 将分析内容转换为Markdown格式 - String markdownContent = convertToMarkdown(analysisContent, regions); - - // 调用docmee API生成PPT + // 直接使用传入的markdown内容调用docmee API生成PPT String pptFileUrl = callDocmeeApi(markdownContent, token); if (pptFileUrl != null && !pptFileUrl.trim().isEmpty()) { System.out.println("PPT生成成功!"); System.out.println("PPT文件下载地址: " + pptFileUrl); - - // 下载PPT文件到本地 - String localFilePath = downloadPptFile(pptFileUrl, regions); - if (localFilePath != null) { - System.out.println("PPT文件已下载到: " + localFilePath); - return localFilePath; - } else { - System.err.println("PPT文件下载失败"); - return null; - } + return pptFileUrl; } else { System.err.println("PPT生成失败"); return null; @@ -65,120 +66,19 @@ public class PptGenerator { return null; } } - - /** - * 下载PPT文件到本地 - * @param fileUrl PPT文件下载URL - * @param regions 对比地区 - * @return 本地文件路径 - */ - private static String downloadPptFile(String fileUrl, String[] regions) { - try { - // 生成本地文件名 - String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); - String fileName = generateReportTitle(regions).replace("教育资源配置对比分析报告", "教育资源对比分析报告") + "_" + timestamp + ".pptx"; - String localFilePath = SAVE_DIRECTORY + File.separator + fileName; - - // 下载文件 - URL url = new URL(fileUrl); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("GET"); - connection.setConnectTimeout(30000); // 30秒连接超时 - connection.setReadTimeout(60000); // 60秒读取超时 - - int responseCode = connection.getResponseCode(); - if (responseCode == HttpURLConnection.HTTP_OK) { - try (InputStream inputStream = connection.getInputStream(); - FileOutputStream outputStream = new FileOutputStream(localFilePath)) { - - byte[] buffer = new byte[4096]; - int bytesRead; - long totalBytesRead = 0; - - while ((bytesRead = inputStream.read(buffer)) != -1) { - outputStream.write(buffer, 0, bytesRead); - totalBytesRead += bytesRead; - } - - System.out.println("文件下载完成,大小: " + totalBytesRead + " 字节"); - return localFilePath; - } - } else { - System.err.println("下载失败,HTTP状态码: " + responseCode); - return null; - } - - } catch (Exception e) { - System.err.println("下载PPT文件时出错: " + e.getMessage()); - e.printStackTrace(); - return null; - } - } - + /** - * 将分析内容转换为Markdown格式 - * @param analysisContent 分析内容 + * 生成PPT演示文稿(保留原方法以兼容其他调用) + * @param markdownContent PPT大纲的Markdown内容(由DeepSeek生成) * @param regions 对比地区 - * @return Markdown格式的内容 - */ - private static String convertToMarkdown(String analysisContent, String[] regions) { - StringBuilder markdown = new StringBuilder(); - - // 添加标题 - String title = generateReportTitle(regions); - markdown.append("# ").append(title).append("\n\n"); - - // 处理分析内容 - String[] lines = analysisContent.split("\n"); - - for (String line : lines) { - if (line.trim().isEmpty()) { - markdown.append("\n"); - } else if (isTitle(line)) { - // 根据标题级别添加Markdown标题 - if (line.matches("^\\d+\\..+")) { - markdown.append("## ").append(line).append("\n\n"); - } else if (line.matches("^\\d+\\.\\d+.+")) { - markdown.append("### ").append(line).append("\n\n"); - } else if (line.matches("^\\d+\\.\\d+\\.\\d+.+")) { - markdown.append("#### ").append(line).append("\n\n"); - } else { - markdown.append("## ").append(line).append("\n\n"); - } - } else { - // 普通内容,处理列表项 - if (line.trim().startsWith("-") || line.trim().startsWith("•")) { - markdown.append("- ").append(line.trim().substring(1).trim()).append("\n"); - } else { - markdown.append(line).append("\n\n"); - } - } - } - - return markdown.toString(); - } - - /** - * 生成报告标题 - */ - private static String generateReportTitle(String[] regions) { - if (regions != null && regions.length >= 2) { - return String.join("与", regions) + "教育资源配置对比分析报告"; - } else { - return "教育资源配置对比分析报告"; - } - } - - /** - * 判断是否为标题行 + * @param token API访问令牌 + * @return PPT文件下载URL */ - private static boolean isTitle(String line) { - return line.matches("^\\d+\\..+") || - line.matches("^\\d+\\.\\d+.+") || - line.matches("^\\d+\\.\\d+\\.\\d+.+") || - line.trim().matches("^(执行摘要|数据概览|详细对比分析|问题识别|建议与对策|结论).*"); + public static String generatePptPresentation(String markdownContent, String[] regions, String token) { + return generatePptFromMarkdown(markdownContent, token); } - + + /** * 调用docmee API生成PPT * @param markdownContent Markdown内容