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 ] ) ;
}
}