文章目录
业务流程
- 用户输入
a. 分析目标
b. 上传原始数据
c. 更精细话地控制图表,比如图表类型,图表名称等
后端校验
a. 校验用户的输入是否合法
b. 成本控制(次数统计和校验,鉴权等)把处理后的数据输入给AI模型(调用AI接口),让AI模型给我们提供图表信息,结论文本
图表信息(是一段json配置,是一段代码),结论文本在前端进行展示
开发接口
easyExcel从excel读取数据,数据过滤并进行数据压缩
不要想复杂啦,读取数据很正常,数据过滤就是过滤掉null的数据,数据压缩转化为csv,其实就是转换格式,用英文逗号分割,节省空间,给个预设语句,可以使得AI回答地更准确
package com.yupi.springbootinit.utils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* excel相关工具类
*/
@Slf4j
public class ExcelUtils {
/**
* 数据压缩为csv,返回字符串
*/
public static String excelToCsv(MultipartFile multipartFile){
//读取数据
List<Map<Integer, String>> list = null;
try {
list = EasyExcel.read(multipartFile.getInputStream())
.excelType(ExcelTypeEnum.XLSX)
.sheet()
.headRowNumber(0)
.doReadSync();
} catch (IOException e) {
log.error("表格处理错误");
}
System.out.println(list);
//如果数据为空
if(CollUtil.isEmpty(list)){
return "";
}
//转换为csv (数据压缩)
StrBuilder strBuilder = new StrBuilder();
//过滤表头数据
//todo 问为什么要用LinkedHashMap呢?
LinkedHashMap<Integer, String> headMap = (LinkedHashMap<Integer, String>) list.get(0);
List<String> headValueList = headMap.values().stream().filter(item -> ObjectUtil.isNotEmpty(item)).collect(Collectors.toList());
String head = StringUtils.join(headValueList, ",");
System.out.println(head);
strBuilder.append(head).append("\n");
//过滤表数据
for (int i = 1; i < list.size(); i ++){
LinkedHashMap<Integer, String> dataListMap = (LinkedHashMap)list.get(i);
List<String> dataList = dataListMap.values().stream().filter(item -> ObjectUtil.isNotEmpty(item)).collect(Collectors.toList());
String data = StringUtils.join(dataList, ",");
System.out.println(data);
strBuilder.append(data).append("\n");
}
return strBuilder.toString();
}
/**
* test
* @param args
*/
public static void main(String[] args) {
excelToCsv(null);
}
}
分析接口
/**
* 上传文件,返回数据
*
* @param multipartFile
* @param genChartByAiRequest
* @param request
* @return
*/
@PostMapping("/gen")
public BaseResponse<String> genChartByAi(@RequestPart("file") MultipartFile multipartFile,
GenChartByAiRequest genChartByAiRequest, HttpServletRequest request) {
String name = genChartByAiRequest.getName();
String goal = genChartByAiRequest.getGoal();
String chartType = genChartByAiRequest.getChartType();
//分析目标为空抛出异常
ThrowUtils.throwIf(StringUtils.isBlank(goal),ErrorCode.PARAMS_ERROR,"分析目标为空");
//名称不为空并且名称>100 提示名称过长
ThrowUtils.throwIf(StringUtils.isNotBlank(name) && name.length() > 100,ErrorCode.PARAMS_ERROR,"图表名称过长");
StrBuilder userInput = new StrBuilder();
userInput.append("你是一个数据分析师,接下来我会给你我的分析目标和原始数据,请告诉我分析结论:").append("\n");
userInput.append("分析目标:").append(goal).append("\n");
String result = ExcelUtils.excelToCsv(multipartFile);
userInput.append("数据:").append(result).append("\n");
return ResultUtils.success(userInput.toString());
}
利用AI生成结论和图表
生成结论
生成图表:
AI无法直接生成现成的图表,但是AI可以生成图表代码,可以把代码利用前端组件库(Echarts)在网页进行展示
预期生成的图表代码
AI提问技巧
如果想让AI更好的理解我们的输入,给我们预期的,精确格式的输出,我们就需要严格控制咱们的提问词
0)使用系统预设
1)控制输入格式(便于AI精确地理解我们的需求和提问)
2)控制输出格式(便于AI返回的内容能够更加方便的为我们所用)
3)指定一个示例问答
调用AI
直接调用AI大模型官网的接口
官方文档:https://platform.openai.com/docs/api-reference
优点:不经封装,最灵活,最原始
缺点:要钱,要魔法
本质上openAI就是提供了Http接口,我们可以用任何语言去调用
1)在请求头中指定OPENAI_API_KEY
2)找到你要使用的接口,比如AI对话接口
3)按照接口文档的示例,构造Http请求,比如用Hutool工具类,或者HttpClient
/**
* AI 对话(需要自己创建请求响应对象)
*
* @param request
* @param openAiApiKey
* @return
*/
public CreateChatCompletionResponse createChatCompletion(CreateChatCompletionRequest request, String openAiApiKey) {
if (StringUtils.isBlank(openAiApiKey)) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "未传 openAiApiKey");
}
String url = "https://api.openai.com/v1/chat/completions";
String json = JSONUtil.toJsonStr(request);
String result = HttpRequest.post(url)
.header("Authorization", "Bearer " + openAiApiKey)
.body(json)
.execute()
.body();
return JSONUtil.toBean(result, CreateChatCompletionResponse.class);
}
使用云服务商提供的,封装后的AI接口
比如:Azure云
优点:不用魔法
缺点:依然要钱,可能比直接调用原始的接口更贵
利用鱼聪明AI提供的开放SDK
优点:有很多现成的模型,可以预设
https://github.com/liyupi/yucongming-java-sdk
智能接口实现
echarts在线调试:https://echarts.apache.org/examples/zh/editor.html?c=line-simple
- 构造用户请求(用户消息,csv,图表类型)
- 调用鱼聪明sdk,得到AI响应结果
- 从AI响应结果中,取出需要的信息
- 保存图表到数据库