基于Spring Boot的智能分析平台
项目介绍:
智能分析平台实现了用户导入需要分析的原始数据集后,利用AI自动生成可视化图表和分析结论,改善了传统BI系统需要用户具备相关数据分析技能的问题。该项目使用到的技术是SSM+Spring Boot、redis、rabbitMq、mysql等。在项目中,使用第三方AI助手平台编写一段系统预设prompt来生成指定的json,全局指定助手的职责、输入内容和回复格式。在项目中,由于AIGC是一个消耗资源和成本的重操作,所以使用了redisson提供的rateLimiter实现对单用户使用AI生成图表功能的限流,以保护系统。在AI生成内容时,处于服务能力的考虑,可能会出现第三方接口处理和返回时长较长,就引入异步化来提高用户体验,使用自定义线程池(JUC并发包中的ThreadPoolExcutor)+任务队列来管理线程、协调任务的执行。最后本项目使用RabbitMq把任务提交改为向消息队列发送消息来解决异步化是通过本地线程池实现带来的限制,实现应用解耦。测试得出,若应用程序中断,消息未确认,还会重发消息用以消费。
界面展示:



需求分析:
1.智能分析:用户输入目标和原始数据,自动生成图表和结论
2.图表管理
3.图表生成的异步化(消息队列)
4.对接AI能力

技术栈:
Spring Boot+Mysql+Mybatis Plus+消息队列(RabbitMQ)+AI能力
数据库表设计
1.用户表
-- 用户表
create table if not exists user
(id bigint auto_increment comment 'id' primary key,userAccount varchar(256) not null comment '账号',userPassword varchar(512) not null comment '密码',userName varchar(256) null comment '用户昵称',userAvatar varchar(1024) null comment '用户头像',userRole varchar(256) default 'user' not null comment '用户角色:user/admin',createTime datetime default CURRENT_TIMESTAMP not null comment '创建时间',updateTime datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',isDelete tinyint default 0 not null comment '是否删除',index idx_userAccount (userAccount)
) comment '用户' collate = utf8mb4_unicode_ci;
2.图表信息表
-- 图表表
create table if not exists chart
(id bigint auto_increment comment 'id' primary key,goal text null comment '分析目标','name' varchar(128) null comment '图表名称',chartData text null comment '图表数据',chartType varchar(128) null comment '图表类型',genChart text null comment '生成的图表数据',genResult text null comment '生成的分析结论',status varchar(128) not null default 'wait' comment 'wait,running,succeed,failed',execMessage text null comment '执行信息',userId bigint null comment '创建用户 id',createTime datetime default CURRENT_TIMESTAMP not null comment '创建时间',updateTime datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',isDelete tinyint default 0 not null comment '是否删除'
) comment '图表信息表' collate = utf8mb4_unicode_ci;
调用AI:
系统预设(提前告诉他职责、功能、回复格式要求)+分析目标+压缩后的数据
系统预设例子:你是一个数据分析师,接下来我会告诉你我的分析目标和原始数据,请帮我分析并告诉我结论。
Prompt 预设:
你是一个数据分析师和前端开发专家,接下来我会按照以下固定格式给你提供内容: 分析需求: {数据分析的需求或者目标} 原始数据: {csv格式的原始数据,用,作为分隔符} 请根据这两部分内容,按照以下指定格式生成内容(此外不要输出任何多余的开头、结尾、注释) 【【【【【 {前端 Echarts V5 的 option 配置对象js代码,合理地将数据进行可视化,不要生成任何多余的内容,比如注释} 【【【【【 {明确的数据分析结论、越详细越好,不要生成多余的注释}
业务流程开发:
生成图表:AI无法直接生成现成的图表、但是AI可以生成图标代码--->可以把代码利用前端的组件库(Echarts)在网页展示
后端接口开发:
根据用户的输入,最后返回图表信息和结论文本
1.构造用户请求:用户消息、csv数据、图表类型
2.调用SDK,得到AI响应结果
3.从AI响应结果中,取出需要的信息
4.保存图表到数据库
项目优化:
1.校验文件传入:解决用户上传一个超大的文件
2.限流:解决用户频繁点击提交,导致服务器资源被占满,其他用户无法使用,控制成本,限制用户调用总次数
限流的相关知识点-CSDN博客
3.异步化:解决调用的服务处理能力有限,或者接口的处理时间较长。当用户要进行耗时很长的操作时,点击提交后,不需要在界面等待,而是把这个任务保存到数据库中记录下来。当任务提交成功时,如果我们的程序还有多余的线程空闲,可以立刻执行这个任务,若没有空闲的,则放入到等待队列中。当任务提交失败时,若没有空闲线程,任务队列满了的情况下,会拒绝这个任务或者保存到数据库中记录失败的任务,并且在程序空闲的时候,可以把这个任务拉出来在执行。
4.自定义线程池:解决线程管理复杂、任务存取复杂问题。使用线程池帮助轻松管理线程、协助调取任务的执行过程。
(1).自定义线程池:
@Configuration
public class ThreadPoolExecutorConfig {@Beanpublic ThreadPoolExecutor threadPoolExecutor() {ThreadFactory threadFactory = new ThreadFactory() {private int count = 1;@Overridepublic Thread newThread(@NotNull Runnable r) {Thread thread = new Thread(r);thread.setName("线程" + count);count++;return thread;}};ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 4, 100, TimeUnit.SECONDS,new ArrayBlockingQueue<>(4), threadFactory);return threadPoolExecutor;}
}
(2).提交任务到线程池:
CompletableFuture.runAsync(() -> {System.out.println("任务执行中:" + name + ",执行人:" + Thread.currentThread().getName());try {Thread.sleep(60000);} catch (InterruptedException e) {e.printStackTrace();}
}, threadPoolExecutor);
5.消息队列:本项目的异步通过本地的线程池实现,可能会出现数据持久化、可扩展行、应用耦合较高情况,使用分布式消息队列可以解决上述问题。使用消息队列后,如果程序中断了,消息没有确认,还会重发
本项目使用的是RabbitMQ
实现步骤:
-
创建交换机和队列
-
将线程池中的执行代码移到消费者类中
-
根据消费者的需求来确认消息的格式(chartId)
-
将提交线程池改造为发送消息到队列
(1).引入依赖:使用的版本需要和自己的springboot版本一致
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-amqp --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId><version>2.7.2</version></dependency>
(2).在yml中引入配置
spring:rabbitmq:host: localhostport: 5672password: guestusername: guest
(3).创建交换机和队列
public class BiInitMain {public static void main(String[] args) {try {ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");Connection connection = factory.newConnection();Channel channel = connection.createChannel();//交换机名称String EXCHANGE_NAME=BiMqConstant.BI_EXCHANGE_NAME;channel.exchangeDeclare(EXCHANGE_NAME, "direct");// 创建队列,随机分配一个队列名称String queueName = BiMqConstant.BI_QUEUE_NAME;channel.queueDeclare(queueName, true, false, false, null);channel.queueBind(queueName, EXCHANGE_NAME, BiMqConstant.BI_ROUTING_KEY);}catch(Exception e){}}
}
(4).生产者代码
@Component
public class BiMessageProducer {/*** 发送消息*/@Resourcepublic RabbitTemplate rabbitTemplate;public void sendMessage(String message){rabbitTemplate.convertAndSend(BiMqConstant.BI_EXCHANGE_NAME,BiMqConstant.BI_ROUTING_KEY,message);}
}
(5).消费者代码:
@Component
@Slf4j
public class BiMessageConsumer {@Resourceprivate ChartService chartService;@Resourceprivate AiManager aiManager;//指定程序监听的消息队列和确认机制@SneakyThrows@RabbitListener(queues = {BiMqConstant.BI_QUEUE_NAME},ackMode = "MANUAL")public void receiveMessage(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) Long deliverTag){if(StringUtils.isBlank(message)){//如果失败,消息拒接channel.basicNack(deliverTag,false,false);throw new BusinessException(ErrorCode.SYSTEM_ERROR,"消息为空");}long chartId=Long.parseLong(message);Chart chart=chartService.getById(chartId);if(chart==null){channel.basicNack(deliverTag,false,false);throw new BusinessException(ErrorCode.NOT_FOUND_ERROR,"图表为空");}// 先修改图表任务状态为 “执行中”。等执行成功后,修改为 “已完成”、保存执行结果;执行失败后,状态修改为 “失败”,记录任务失败信息。Chart updateChart = new Chart();updateChart.setId(chart.getId());updateChart.setStatus("running");boolean b = chartService.updateById(updateChart);if (!b) {channel.basicNack(deliverTag,false,false);handleChartUpdateError(chart.getId(), "更新图表执行中状态失败");return;}// 调用 AIString result = aiManager.doChat(CommonConstant.BI_MODEL_ID, buildUserInput(chart));String[] splits = result.split("【【【【【");if (splits.length < 3) {channel.basicNack(deliverTag,false,false);handleChartUpdateError(chart.getId(), "AI 生成错误");return;}String genChart = splits[1].trim();String genResult = splits[2].trim();Chart updateChartResult = new Chart();updateChartResult.setId(chart.getId());updateChartResult.setGenChart(genChart);updateChartResult.setGenResult(genResult);// todo 建议定义状态为枚举值updateChartResult.setStatus("succeed");boolean updateResult = chartService.updateById(updateChartResult);if (!updateResult) {channel.basicNack(deliverTag,false,false);handleChartUpdateError(chart.getId(), "更新图表成功状态失败");}//消息确认channel.basicAck(deliverTag,false);}/*** 构造用户输入* @param chart* @return*/private String buildUserInput(Chart chart){String goal=chart.getGoal();String chartType= chart.getChartType();String csvData=chart.getChartData();//构造用户输入StringBuilder userInput = new StringBuilder();userInput.append("分析需求:").append("\n");//拼接分析目标String userGoal=goal;if(StringUtils.isNotBlank(chartType)){userGoal+=",请使用"+chartType;}userInput.append(userGoal).append("\n");userInput.append("原始数据:").append("\n");userInput.append(csvData).append("\n");return userInput.toString();}private void handleChartUpdateError(long chartId,String execMessage){Chart updateChartResult=new Chart();updateChartResult.setId(chartId);updateChartResult.setStatus("failed");updateChartResult.setExecMessage("execMessage");boolean updateResult = chartService.updateById(updateChartResult);if(!updateResult){log.error("更新图表失败状态失败" + chartId + "," + execMessage);}}}
相关文章:
基于Spring Boot的智能分析平台
项目介绍: 智能分析平台实现了用户导入需要分析的原始数据集后,利用AI自动生成可视化图表和分析结论,改善了传统BI系统需要用户具备相关数据分析技能的问题。该项目使用到的技术是SSMSpring Boot、redis、rabbitMq、mysql等。在项目中&#…...
HTML(13)——显示模式
目录 显示模式 块级元素 行内元素 行内块元素 转换显示模式 显示模式:标签的显示方式 作用:布局网页时,根据标签的显示模式选择合适的标签摆放内容 显示模式 块级元素 独占一行宽度默认为父级的100%添加宽高属性生效 行内元素 …...
【Spring】Spring Boot 快速入门
📚博客主页:爱敲代码的小杨. ✨专栏:《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 |《MySQL探索之旅》 |《Web世界探险家》 ❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更…...
Go自定义数据的序列化流程
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…...
贪心算法练习题(2024/6/18)
什么是贪心 贪心的本质是选择每一阶段的局部最优,从而达到全局最优。 贪心算法一般分为如下四步: 将问题分解为若干个子问题找出适合的贪心策略求解每一个子问题的最优解将局部最优解堆叠成全局最优解 1分发饼干 假设你是一位很棒的家长,…...
4.1 四个子空间的正交性
一、四个子空间的正交性 如果两个向量的点积为零,则两个向量正交: v ⋅ w v T w 0 \boldsymbol v\cdot\boldsymbol w\boldsymbol v^T\boldsymbol w0 v⋅wvTw0。本章着眼于正交子空间、正交基和正交矩阵。两个子空间的中的向量,一组基中的向…...
RabbitMQ实践——使用WebFlux响应式方式实时返回队列中消息
大纲 Pom.xml监听队列实时返回消息测试完整代码工程代码 在之前的案例中,我们在管理后台收发消息都是通过短连接的形式。本文我们将探索对队列中消息的实时读取,并通过流式数据返回给客户端。 webflux是反应式Web框架,客户端可以通过一个长连…...
SpringBoot前后端传递数据时常用的JSON格式数据是什么?【讲解JSON概念、语法、以及Java对象互转】
SpringBoot前后端传递数据时常用的JSON格式数据是什么? JSON概念JSON语法JSON的两种结构:JSON字符串和Java对象互转:objectMapper.writeValueAsString(person);objectMapper.readValue(jsonStr,Person.class); 在SpringMVC框架中,…...
mysql学习——SQL中的DQL和DCL
SQL中的DQL和DCL DQL基本查询条件查询聚合函数分组查询排序查询分页查询 DCL管理用户权限控制 学习黑马MySQL课程,记录笔记,用于复习。 DQL DQL英文全称是Data Query Language(数据查询语言),数据查询语言,用来查询数据库中表的记…...
windows系统上nginx搭建文件共享
1、下载windows版nginx 下载地址 2、配置nginx 编辑nginx.conf配置文件 在http模块下添加这个参数 underscores_in_headers on;#修改location内容,共享哪个文件夹,就写哪个文件夹,最后一定要跟上/,否则无法访问 location / {…...
星闪指向遥控,做家电交互的破壁人
“面壁者罗辑,我是你的破壁人。” 科幻小说《三体》中,当人类的基础科学被三体人封锁,变得停步不前,人类启动了自救的面壁计划,通过一次又一次破壁,找到战胜三体人的办法。 现实中,有一点已经成…...
SpringBoot使用AutoConfigure实现依赖库自动导入配置
我们知道导入配置有两种,一种是Value,一种是ConfigurationProperties,将对应的类标记为Component即可导入。但是被注解标识的类创建Bean有一个前提,只对启动类所在的包路径下的所有带有Component等注解的类才会创建Bean。如果我们…...
QT中利用动画弄一个侧边栏窗口,以及贴条效果
1、效果 2、关键代码 void Widget::on_sliderBtn_clicked() {m_sliderWidget->show();QPropertyAnimation* animation = new QPropertyAnimation(m...
win10免安装配置MySQL8.4.0
注:此教程基于win10 22H2 版本 1、下载最新版本MySQL压缩包 下载链接:MySQL官网下载地址 点击第二行的 ZIP Archive 后面的Download(当前时间2024-06-19最新版本是8.4.0) 2、解压并添加配置文件 下载完毕后,解压缩…...
VS Code安装及环境配置(超详细)
VS Code简介 Visual Studio Code(简称 VS Code )是 Microsoft 于2015年4月发布的一款代码编辑器,以界面简洁、轻量著称。 它是一款免费开源的现代化轻量级代码编辑器,支持几乎所有主流开发语言的语法高亮、智能代码补全、自定义…...
shell脚本通过解析日志使用串口开关屏知识点整理
#!/bin/bash #logPath 写日志的存放路径 #logPath/home/workspace/tvs/trainborne logPath/home/firefly tmpFile$$ function getLogName() { #echo "$logPath/LCDController_"date "%Y%m%d000000.log" echo "LCDController_20240424000000.log&quo…...
速盾:视频cdn和网站cdn的相同点与不同点
CDN(Content Delivery Network)是一种分布式网络架构,旨在为用户提供高效、高质量的内容传送服务。CDN主要通过将内容分发到全球各地的边缘节点,并根据用户的地理位置选择最近的节点来提供内容,从而加速内容的传输并降…...
37.自定义协议
自定义协议要素 1.魔数:用来第一时间判定是否是无效数据包。 2.版本号:主持协议升级。 3.序列化算法:消息正文到底采用那种序列化方式,可以由此扩展,例如:json,protobuf(google的序列化算法,基于二进制,虽然可读性不好,但是字节数占用更少),hessian(基于二进制)…...
【React Native】measureInWindow在安卓上无法正确获取View在屏幕上的布局信息
问题描述: 在React Native中,我们可以使用measureInWindow的方式去获取一个View在屏幕中的位置信息: 下面这个Demo中,我们写了一个页面HomePage和一个列表项组件ListItemA,我们期望每过5s监测一次列表中每一项在屏幕中…...
C++ 教程 - 04 类的使用
文章目录 类的定义类定义案例构造函数 类的定义 C 在 C 语言的基础上增加面向对象编程,类是用于指定对象的形式,是一种用户自定义的数据类型,封装了数据和函数。类可以被看作是一种模板,可以用来创建具有相同属性和行为的多个对象…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用
中达瑞和自2005年成立以来,一直在光谱成像领域深度钻研和发展,始终致力于研发高性能、高可靠性的光谱成像相机,为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...
DBLP数据库是什么?
DBLP(Digital Bibliography & Library Project)Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高,数据库文献更新速度很快,很好地反映了国际计算机科学学术研…...
医疗AI模型可解释性编程研究:基于SHAP、LIME与Anchor
1 医疗树模型与可解释人工智能基础 医疗领域的人工智能应用正迅速从理论研究转向临床实践,在这一过程中,模型可解释性已成为确保AI系统被医疗专业人员接受和信任的关键因素。基于树模型的集成算法(如RandomForest、XGBoost、LightGBM)因其卓越的预测性能和相对良好的解释性…...
React父子组件通信:Props怎么用?如何从父组件向子组件传递数据?
系列回顾: 在上一篇《React核心概念:State是什么?》中,我们学习了如何使用useState让一个组件拥有自己的内部数据(State),并通过一个计数器案例,实现了组件的自我更新。这很棒&#…...
