You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

594 lines
26 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.dsideal.base.AI;
import com.dsideal.base.AI.Generator.PptGenerator;
import com.dsideal.base.DataEase.Model.DataEaseModel;
import com.dsideal.base.Util.LocalMysqlConnectUtil;
import com.dsideal.base.Util.PptAIKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.dsideal.base.Util.CallDeepSeek;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.LinkedHashSet;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.text.SimpleDateFormat;
import java.util.Date;
import cn.hutool.core.io.FileUtil;
import java.io.File;
import java.util.Scanner;
import com.dsideal.base.AI.Generator.WordGenerator;
public class TestMax32K {
private static final int MAX_CHUNK_SIZE = 8000; // 8000字符限制
private static boolean dataSubmitted = false; // 标记数据是否已提交
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
LocalMysqlConnectUtil.Init();
try {
// 第一步:提交所有数据块
System.out.println("开始提交数据到大模型...");
submitAllDataChunks();
dataSubmitted = true;
System.out.println("\n数据提交完成");
// 第二步:询问用户想生成哪种格式
while (true) {
System.out.println("\n=== 报告生成选项 ===");
System.out.println("现在可以基于上传的数据生成以下格式的报告:");
System.out.println("1. WORD文档 (.docx)");
System.out.println("2. HTML网页 (.html)");
System.out.println("3. PPT演示文稿 (.pptx)");
System.out.println("4. 退出程序");
System.out.print("\n请选择您想生成的报告格式 (1-4): ");
String choice = scanner.nextLine().trim();
switch (choice) {
case "1":
generateWordReport();
break;
case "2":
generateHtmlReport();
break;
case "3":
generatePptReport();
break;
case "4":
System.out.println("程序退出。");
return;
default:
System.out.println("无效选择,请输入 1-4 之间的数字。");
}
}
} catch (Exception e) {
System.err.println("程序执行出错: " + e.getMessage());
e.printStackTrace();
} finally {
scanner.close();
}
}
/**
* 提交所有数据块到大模型
*/
private static void submitAllDataChunks() throws Exception {
if (dataSubmitted) {
System.out.println("数据已经提交过了,无需重复提交。");
return;
}
// 添加获取参数的代码
String[] regions = { "楚雄州","文山州"}; // 或者根据需要设置具体的地区
String sql = "select table_name as TABLE_NAME from core_dataset_table where dataset_group_id in (select id from core_dataset_group where pid='1036317909951057920')";
List<Record> tableList = Db.use(DataEaseModel.DB_NAME).find(sql);
// 修改这一行,传递正确的参数
String[] dataChunks = getDataChunks(regions, tableList);
System.out.println("总共需要提交 " + dataChunks.length + " 个数据块");
CountDownLatch latch = new CountDownLatch(dataChunks.length);
for (int i = 0; i < dataChunks.length; i++) {
final int chunkIndex = i;
final boolean isLastChunk = (i == dataChunks.length - 1);
String prompt;
if (isLastChunk) {
prompt = "这是最后一个数据块(第" + (chunkIndex + 1) + "/" + dataChunks.length + "个)。\n" +
"请确认已接收所有数据块,现在数据提交完成。请回复'数据接收完成'以确认。\n\n" +
"数据内容:\n" + dataChunks[chunkIndex];
} else {
prompt = "这是第" + (chunkIndex + 1) + "/" + dataChunks.length + "个数据块,后续还有更多数据。\n" +
"请接收此数据块,无需分析,等待所有数据提交完成。\n\n" +
"数据内容:\n" + dataChunks[chunkIndex];
}
CallDeepSeek.callDeepSeekStream(prompt, new CallDeepSeek.SSEListener() {
@Override
public void onData(String data) {
if (isLastChunk) {
System.out.println("\n大模型确认: " + data);
}
}
@Override
public void onComplete(String fullResponse) {
System.out.println("数据块 " + (chunkIndex + 1) + "/" + dataChunks.length + " 提交完成");
latch.countDown();
}
@Override
public void onError(String error) {
System.err.println("数据块 " + (chunkIndex + 1) + " 提交失败: " + error);
latch.countDown();
}
});
// 避免请求过于频繁
Thread.sleep(1000);
}
latch.await();
}
/**
* 生成Word报告
*/
private static void generateWordReport() {
if (!dataSubmitted) {
System.out.println("请先提交数据!");
return;
}
System.out.println("\n开始生成Word报告...");
try {
String prompt = "基于之前提交的所有数据请生成一份详细的Word格式分析报告。\n" +
"要求:\n" +
"1. 使用Markdown格式输出\n" +
"2. 包含完整的数据分析和洞察\n" +
"3. 结构清晰,包含标题、摘要、详细分析、结论等部分\n" +
"4. 适合转换为Word文档格式";
StringBuilder wordContent = new StringBuilder();
CountDownLatch latch = new CountDownLatch(1);
CallDeepSeek.callDeepSeekStream(prompt, new CallDeepSeek.SSEListener() {
@Override
public void onData(String data) {
wordContent.append(data);
System.out.print("."); // 显示进度
}
@Override
public void onComplete(String fullResponse) {
System.out.println("\nWord报告生成完成");
// 保存Word文件
try {
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String fileName = "analysis_report_" + timestamp + ".docx";
// 使用WordGenerator生成Word文档
String[] regions = {"云南省"}; // 或者根据实际情况设置地区
WordGenerator.generateWordDocument(wordContent.toString(), fileName, regions);
System.out.println("Word报告已保存至: WebRoot/upload/" + fileName);
} catch (Exception e) {
System.err.println("保存Word文档失败: " + e.getMessage());
}
latch.countDown();
}
@Override
public void onError(String error) {
System.err.println("\n生成Word报告失败: " + error);
latch.countDown();
}
});
latch.await();
} catch (Exception e) {
System.err.println("生成Word报告时出错: " + e.getMessage());
}
}
/**
* 生成HTML报告
*/
private static void generateHtmlReport() {
if (!dataSubmitted) {
System.out.println("请先提交数据!");
return;
}
System.out.println("\n开始生成HTML报告...");
try {
String prompt = "基于之前提交的所有数据请生成一份详细的HTML格式分析报告。\n" +
"要求:\n" +
"1. 生成完整的HTML页面代码\n" +
"2. 包含CSS样式确保页面美观\n" +
"3. 必须包含以下9种图表的完整代码\n" +
" - 人口变化趋势图(折线图)\n" +
" - 教育规模分布图(柱状图)\n" +
" - 城乡人口对比图(饼图)\n" +
" - 学龄人口预测图(面积图)\n" +
" - 教育资源配置图(雷达图)\n" +
" - 区域教育发展对比图(条形图)\n" +
" - 教育投入产出分析图(散点图)\n" +
" - 师资力量分布图(热力图)\n" +
" - 综合发展指数图(仪表盘图)\n" +
"4. 使用ECharts库实现图表\n" +
"5. 页面结构清晰,包含标题、摘要、图表展示、数据分析、结论等部分\n" +
"6. 确保所有图表都有真实的数据和完整的配置";
StringBuilder htmlContent = new StringBuilder();
CountDownLatch latch = new CountDownLatch(1);
CallDeepSeek.callDeepSeekStream(prompt, new CallDeepSeek.SSEListener() {
@Override
public void onData(String data) {
htmlContent.append(data);
System.out.print("."); // 显示进度
}
@Override
public void onComplete(String fullResponse) {
System.out.println("\nHTML报告生成完成");
// 保存HTML文件
try {
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String fileName = "analysis_report_" + timestamp + ".html";
String filePath = "WebRoot/upload/" + fileName;
Files.write(Paths.get(filePath), htmlContent.toString().getBytes("UTF-8"));
System.out.println("HTML报告已保存至: " + filePath);
} catch (Exception e) {
System.err.println("保存HTML文件失败: " + e.getMessage());
}
latch.countDown();
}
@Override
public void onError(String error) {
System.err.println("\n生成HTML报告失败: " + error);
latch.countDown();
}
});
latch.await();
} catch (Exception e) {
System.err.println("生成HTML报告时出错: " + e.getMessage());
}
}
/**
* 生成PPT报告
*/
private static void generatePptReport() {
if (!dataSubmitted) {
System.out.println("请先提交数据!");
return;
}
System.out.println("\n开始生成PPT报告...");
try {
String prompt = "基于之前提交的所有数据请生成一份PPT演示文稿的详细内容大纲。\n" +
"要求:\n" +
"1. 提供完整的PPT结构和每页内容\n" +
"2. 包含标题页、目录、数据分析、图表说明、结论建议等\n" +
"3. 每页PPT都要有明确的标题和要点\n" +
"4. 适合制作成专业的演示文稿\n" +
"5. 内容要简洁明了,重点突出";
StringBuilder pptContent = new StringBuilder();
CountDownLatch latch = new CountDownLatch(1);
CallDeepSeek.callDeepSeekStream(prompt, new CallDeepSeek.SSEListener() {
@Override
public void onData(String data) {
pptContent.append(data);
System.out.print("."); // 显示进度
}
@Override
public void onComplete(String fullResponse) {
System.out.println("\nPPT内容生成完成");
// 调用PptGenerator生成PPT
try {
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String fileName = "analysis_report_" + timestamp + ".pptx";
// 使用PptGenerator生成PPT
String token = PptAIKit.createApiToken("dsideal", 1000);
String pptInfo = PptGenerator.generatePptFromMarkdown(pptContent.toString(), token);
// 保存PPT信息到文本文件
String infoFilePath = "WebRoot/upload/ppt_info_" + timestamp + ".txt";
if (pptInfo != null) {
Files.write(Paths.get(infoFilePath), pptInfo.getBytes("UTF-8"));
System.out.println("PPT生成信息已保存至: " + infoFilePath);
} else {
Files.write(Paths.get(infoFilePath), "PPT生成失败".getBytes("UTF-8"));
System.out.println("PPT生成失败错误信息已保存至: " + infoFilePath);
}
} catch (Exception e) {
System.err.println("生成PPT失败: " + e.getMessage());
}
latch.countDown();
}
@Override
public void onError(String error) {
System.err.println("\n生成PPT报告失败: " + error);
latch.countDown();
}
});
latch.await();
} catch (Exception e) {
System.err.println("生成PPT报告时出错: " + e.getMessage());
}
}
/**
* 分割过大的单表数据
*/
private static List<String> splitLargeTable(Set<String> fieldNames,
List<Record> allTableData, int maxSize) {
List<String> chunks = new ArrayList<>();
StringBuilder currentTableChunk = new StringBuilder();
for (Record dataRecord : allTableData) {
Map<String, Object> columns = dataRecord.getColumns();
StringBuilder rowData = new StringBuilder();
rowData.append("[");
boolean first = true;
for (String fieldName : fieldNames) {
if (!first) rowData.append(",");
Object value = columns.get(fieldName);
if (value instanceof String) {
rowData.append("\"").append(value).append("\"");
} else {
rowData.append(value);
}
first = false;
}
rowData.append("]\n");
// 检查是否超过限制
if (currentTableChunk.length() + rowData.length() > maxSize) {
if (!currentTableChunk.isEmpty()) {
chunks.add(currentTableChunk.toString());
currentTableChunk = new StringBuilder();
}
}
currentTableChunk.append(rowData);
}
if (!currentTableChunk.isEmpty()) {
chunks.add(currentTableChunk.toString());
}
return chunks;
}
public static String generateComprehensiveReport(String[] regions) {
String sql = "select table_name as TABLE_NAME from core_dataset_table where dataset_group_id in (select id from core_dataset_group where pid='1036317909951057920')";
List<Record> tableList = Db.use(DataEaseModel.DB_NAME).find(sql);
// 获取分块数据
String[] dataChunks = getDataChunks(regions, tableList);
System.out.println("开始逐步提交 " + dataChunks.length + " 个数据块...");
final StringBuilder finalReport = new StringBuilder();
final CountDownLatch finalLatch = new CountDownLatch(1);
// 逐步提交数据块
for (int i = 0; i < dataChunks.length; i++) {
final int chunkIndex = i;
final boolean isLastChunk = (i == dataChunks.length - 1);
String prompt;
if (isLastChunk) {
// 最后一个数据块:要求返回完整分析报告
prompt = "这是最后一部分教育数据请基于之前提交的所有数据生成一份完整的综合分析报告3000字以内\n" + dataChunks[i];
} else {
// 中间数据块:只提交数据,不要求返回分析
prompt = "这是第" + (i + 1) + "部分教育数据,共" + dataChunks.length + "部分,请接收并记录,暂不需要分析:\n" + dataChunks[i];
}
System.out.println("\n=== 提交第 " + (i + 1) + "/" + dataChunks.length + " 个数据块 ===");
final CountDownLatch chunkLatch = new CountDownLatch(1);
CallDeepSeek.callDeepSeekStream(prompt, new CallDeepSeek.SSEListener() {
@Override
public void onData(String data) {
if (isLastChunk) {
// 只有最后一个数据块才显示和保存返回内容
System.out.print(data);
finalReport.append(data);
} else {
// 中间数据块的响应不显示(或只显示确认信息)
// System.out.print("."); // 可选:显示进度点
}
}
@Override
public void onComplete(String fullResponse) {
if (isLastChunk) {
System.out.println("\n\n=== 综合分析报告生成完成 ===");
// 保存报告到文件
try {
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String fileName = "教育数据综合分析报告_" + timestamp + ".txt";
String filePath = "WebRoot/upload/" + fileName;
FileUtil.writeString(finalReport.toString(), new File(filePath), "UTF-8");
System.out.println("报告已保存到: " + filePath);
} catch (Exception e) {
System.err.println("保存报告时出错: " + e.getMessage());
}
finalLatch.countDown();
} else {
System.out.println("第 " + (chunkIndex + 1) + " 个数据块已提交");
}
chunkLatch.countDown();
}
@Override
public void onError(String error) {
System.err.println("提交第 " + (chunkIndex + 1) + " 个数据块时出错: " + error);
if (isLastChunk) {
finalReport.append("生成失败: ").append(error);
finalLatch.countDown();
}
chunkLatch.countDown();
}
});
try {
// 等待当前块处理完成
chunkLatch.await();
if (!isLastChunk) {
Thread.sleep(1000); // 中间块之间稍微延迟
}
} catch (InterruptedException e) {
System.err.println("等待数据块处理时被中断: " + e.getMessage());
}
}
try {
finalLatch.await();
} catch (InterruptedException e) {
System.err.println("等待最终报告时被中断: " + e.getMessage());
}
return finalReport.toString();
}
/**
* 提取数据分块逻辑为独立方法
*/
private static String[] getDataChunks(String[] regions, List<Record> tableList) {
List<String> dataChunks = new ArrayList<>();
StringBuilder currentChunk = new StringBuilder();
String header = "数据说明: 以下是云南省教育数据的压缩格式\n" +
"格式: 表名 -> 字段列表 -> 数据行(数组格式)\n" +
"地区范围: " + String.join(",", regions) + "\n\n";
currentChunk.append(header);
// 遍历所有相关数据表
for (Record record : tableList) {
String tableName = record.getStr("TABLE_NAME");
// 为当前表收集所有数据
List<Record> allTableData = new ArrayList<>();
Set<String> fieldNames = new LinkedHashSet<>();
// 为每个地区收集数据
for (String region : regions) {
String sql = "select * from `" + tableName + "` where `行政区划`=?";
List<Record> listContent = Db.use(DataEaseModel.DB_NAME).find(sql, region);
if (!listContent.isEmpty()) {
allTableData.addAll(listContent);
// 收集字段名(使用第一条记录的字段结构)
if (fieldNames.isEmpty()) {
fieldNames.addAll(listContent.get(0).getColumns().keySet());
}
}
}
if (!allTableData.isEmpty()) {
// 构建当前表的完整数据块
StringBuilder tableData = new StringBuilder();
tableData.append("\n表: ").append(tableName).append("\n");
tableData.append("字段: ").append(String.join(",", fieldNames)).append("\n");
// 输出压缩格式的数据
for (Record dataRecord : allTableData) {
Map<String, Object> columns = dataRecord.getColumns();
tableData.append("[");
boolean first = true;
for (String fieldName : fieldNames) {
if (!first) tableData.append(",");
Object value = columns.get(fieldName);
if (value instanceof String) {
tableData.append("\"").append(value).append("\"");
} else {
tableData.append(value);
}
first = false;
}
tableData.append("]\n");
}
// 检查是否需要分块
String tableDataStr = tableData.toString();
if (currentChunk.length() + tableDataStr.length() > MAX_CHUNK_SIZE) {
// 当前块已满,保存并开始新块
if (currentChunk.length() > header.length()) {
dataChunks.add(currentChunk.toString());
currentChunk = new StringBuilder();
currentChunk.append(header);
}
// 如果单个表数据超过限制,需要进一步分割
if (tableDataStr.length() > MAX_CHUNK_SIZE - header.length()) {
List<String> tableChunks = splitLargeTable(fieldNames, allTableData, MAX_CHUNK_SIZE - header.length());
for (int i = 0; i < tableChunks.size(); i++) {
StringBuilder chunkBuilder = new StringBuilder();
chunkBuilder.append(header);
chunkBuilder.append("\n[续] 表: ").append(tableName).append(" (第").append(i + 1).append("部分)\n");
chunkBuilder.append("字段: ").append(String.join(",", fieldNames)).append("\n");
chunkBuilder.append(tableChunks.get(i));
dataChunks.add(chunkBuilder.toString());
}
} else {
currentChunk.append(tableDataStr);
}
} else {
currentChunk.append(tableDataStr);
}
}
}
// 添加最后一个块
if (currentChunk.length() > header.length()) {
dataChunks.add(currentChunk.toString());
}
return dataChunks.toArray(new String[0]);
}
}