基于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

实现步骤:

  1. 创建交换机和队列

  2. 将线程池中的执行代码移到消费者类中

  3. 根据消费者的需求来确认消息的格式(chartId)

  4. 将提交线程池改造为发送消息到队列

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/26870.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在 Wed 中应用 MyBatis(同时使用MVC架构模式,以及ThreadLocal 事务控制)

1. 在 Wed 中应用 MyBatis&#xff08;同时使用MVC架构模式&#xff0c;以及ThreadLocal 事务控制&#xff09; 文章目录 1. 在 Wed 中应用 MyBatis&#xff08;同时使用MVC架构模式&#xff0c;以及ThreadLocal 事务控制&#xff09;2. 实现步骤&#xff1a;1. 第一步&#xf…

Vulnhub-DC-1,7

靶机IP:192.168.20.141 kaliIP:192.168.20.128 网络有问题的可以看下搭建Vulnhub靶机网络问题(获取不到IP) 前言 1和7都是Drupal的网站&#xff0c;只写了7&#xff0c;包含1的知识点 信息收集 用nmap扫描端口及版本号 进入主页查看作者给的提示&#xff0c;不是暴力破解的…

nodejs湖北省智慧乡村旅游平台-计算机毕业设计源码00232

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;旅游行业当然也不能排除在外。智慧乡村旅游平台是以实际运用为开发背景&#xff0c;运用软件工程开发方法&#xff0c;采…

Weighted A* 改进型(1):XDP

本文的主要内容来自于文献[1]&#xff0c;总的来说这篇文献给我的感觉就是理论证明非常精妙&#xff0c;最后的实际效果也是提升的非常明显。 在Introduction中作者给出了一般Best first search&#xff08;BFS&#xff0c;常用的包括A *&#xff0c;weighted A * &#xff0c…

TK防关联引流系统:全球多账号运营,一“键”掌控!

在TikTok的生态系统中&#xff0c;高效管理多个账号对于品牌推广的成功起着决定性的作用。TK防关联引流系统&#xff0c;作为一款专门为TikTok用户打造的强大工具&#xff0c;为全球范围内的多账号运营提供了坚实的支持。 TK防关联引流系统的核心优势体现在以下几个方面&#x…

2024.6.13

2024.6.13 【痛苦的&#xff0c;热烈的&#xff0c;误解的&#xff0c;无解的&#xff0c;快乐的&#xff0c;解脱的】 Thursday 五月初八 <theme oi-“game theory”> P4018 Roy&October之取石子 Roy&October之取石子 题目背景 Roy 和 October 两人在玩一个…

anaconda安装pytorch-快速上手99%可以(可以虚拟环境OR不进行虚拟环境)

一、预备工作 先检查自己是否有anaconda 在cmd里面输入conda --version查看 二、在anaconda中创建虚拟环境 1.1 打开Anaconda Prompt 1.2 进行自定义安装python 将其中的自定义地址和版本换成自己想安装的地址和版本 我这里安装的地址是E:\Anaconda\DL,python版本是3.8.3…

uniapp地图自定义文字和图标

这是我的结构&#xff1a; <map classmap id"map" :latitude"latitude" :longitude"longitude" markertap"handleMarkerClick" :show-location"true" :markers"covers" /> 记住别忘了在data中定义变量…

Vue页面生成PDF后调起浏览器打印

一、安装依赖 首先&#xff0c;需要安装 html2canvas 和 jsPDF 库。 npm install html2canvas jspdf二、创建公共方法引入 在utils文件夹下创建两个文件分别为pdfExport.js和printPDF.js&#xff0c;代码如下&#xff1a; pdfExport.js import html2canvas from html2canv…

Python PDF转化wolrd代码怎么写

将PDF文件转换为Word文档的过程通常需要使用一些外部库来实现&#xff0c;因为Python本身并不直接支持这种转换。一个常用的库是pdf2docx&#xff0c;它可以帮助我们将PDF文件转换为Word文档格式。以下是使用pdf2docx库将PDF转换为Word的基本步骤&#xff1a; 首先&#xff0c;…

云顶之弈-测试报告

一. 项目背景 个人博客系统采用前后端分离的方法来实现&#xff0c;同时使用了数据库来存储相关的数据&#xff0c;同时将其部署到云服务器上。前端主要有四个页面构成&#xff1a;登录页、列表页、详情页以及编辑页&#xff0c;以上模拟实现了最简单的个人博客系统。其结合后…

Sqoop学习详细介绍!!

一、Sqoop介绍 Sqoop是一款开源的工具&#xff0c;主要用于在Hadoop(HDFS/Hive/HBase)与传统的数据库(mysql、postgresql...)间进行数据的传递&#xff0c;可以将一个关系型数据库&#xff08;例如 &#xff1a; MySQL ,Oracle ,Postgres等&#xff09;中的数据导进到Hadoop的H…

虚拟声卡实现音频回环

虚拟声卡实现音频回环 一、电脑扬声器播放声音路由到麦克风1. Voicemeeters安装设置2. 音频设备选择 二、回声模拟 一、电脑扬声器播放声音路由到麦克风 1. Voicemeeters安装设置 2. 音频设备选择 以腾讯会议为例 二、回声模拟 选中物理输入设备“Stereo Input 1”和物理输出设…

GlusterFS企业分布式存储

GlusterFS 分布式文件系统代表-nfs常见分布式存储Gluster存储基础梳理GlusterFS 适合大文件还是小文件存储&#xff1f; 应用场景术语Trusted Storage PoolBrickVolumes Glusterfs整体工作流程-数据访问流程GlusterFS客户端访问流程 GlusterFS常用命令部署 GlusterFS 群集准备环…

修改版的VectorDBBench更好用

原版本VectorDBBench的几个问题 在这里就不介绍VectorDBBench是干什么的了&#xff0c;上官网即可。 1.并发数设置的太少 2.测试时长30秒太长 3.连接milvus无用户和密码框&#xff0c;这个是最大的问题 4.修改了一下其它参数 由于很多网友发私信问一些milvus的相关技术问…

【机器学习】支持向量机(个人笔记)

文章目录 SVM 分类器的误差函数分类误差函数距离误差函数C 参数 非线性边界的 SVM 分类器&#xff08;内核方法&#xff09;多项式内核径向基函数&#xff08;RBF&#xff09;内核 源代码文件请点击此处&#xff01; SVM 分类器的误差函数 SVM 使用两条平行线&#xff0c;使用…

基于flask的网站如何使用https加密通信

文章目录 内容简介网站目录示例生成SSL证书单独使用Flask使用WSGI服务器Nginx反向代理参考资料 内容简介 HTTPS 是一种至关重要的网络安全协议&#xff0c;它通过在 HTTP 协议之上添加 SSL/TLS 层来确保数据传输的安全性和完整性。这有助于防止数据在客户端和服务器之间传输时…

高考志愿专业选择:计算机人才需求激增,人工智能领域成热门

随着2024年高考的落幕&#xff0c;数百万高三学生站在了人生新的十字路口&#xff0c;面临着一个重要的抉择&#xff1a;选择大学专业。这一选择不仅关乎未来四年的学习生涯&#xff0c;更可能决定一个人一生的职业方向和人生轨迹。在众多专业中&#xff0c;计算机相关专业因其…

如何用Xinstall CPS结算系统打破传统营销桎梏,实现用户增长?

在互联网流量红利逐渐衰退的今天&#xff0c;App推广和运营面临着前所未有的挑战。如何快速搭建起满足用户需求的运营体系&#xff0c;成为了众多企业急待解决的问题。而在这个关键时刻&#xff0c;Xinstall CPS结算系统应运而生&#xff0c;以其独特的优势帮助企业解决了一系列…

【DPDK学习路径】九、学习分支

第八节给出了如何以轮询的方式从网卡中收取数据报文&#xff0c;目前为止已经学会了一些DPDK的简单用法&#xff0c;接下来的学习路径将有多条&#xff1a;1、开发功能&#xff1b;2、软件架构&#xff1b;3、性能调优。 上述排序依据的是难易程序&#xff0c;对于哪些对网络协…