基于Spring Boot的智能分析平台

news2024/11/24 16:23:40

项目介绍:

智能分析平台实现了用户导入需要分析的原始数据集后,利用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 {

    @Bean
    public ThreadPoolExecutor threadPoolExecutor() {
        ThreadFactory threadFactory = new ThreadFactory() {
            private int count = 1;

            @Override
            public 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: localhost
        port: 5672
        password: guest
        username: 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 {

    /**
     * 发送消息
     */
    @Resource
    public RabbitTemplate rabbitTemplate;

    public void sendMessage(String message){
        rabbitTemplate.convertAndSend(BiMqConstant.BI_EXCHANGE_NAME,BiMqConstant.BI_ROUTING_KEY,message);

    }
}

(5).消费者代码:


@Component
@Slf4j
public class BiMessageConsumer {

    @Resource
    private ChartService chartService;

    @Resource
    private 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;
        }
        // 调用 AI
        String 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.coloradmin.cn/o/1828821.html

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

相关文章

AMD平台,5600X+6650XT,虚拟机安装macOS 14(2024年6月)

AMD平台安装macOS 14的麻烦&#xff0c;要比Intel平台多的多&#xff0c;由于macOS从13开始&#xff0c;对CPU寄存器的读取进行了改变&#xff0c;导致AMD平台只要安装完macOS 13及以后版本&#xff0c;开机后就报五国语言错误&#xff0c;不断重启。改vmx文件&#xff0c;被证…

基于springboot的学生宿舍管理系统(带 1w+字文档)

基于springboot的学生宿舍管理系统(带 1w字文档) 基于 springbootvue 前后端分离的学生宿舍管理系统&#xff1a;前端 vue2、elementui&#xff0c;后端 maven、springmvc、spring、mybatis&#xff1b; 项目简介 本项目可供学习参考&#xff0c;商业慎用。项目带完整安装部署…

Python基础教程(二十二):XML解析

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; &#x1f49d;&#x1f49…

微服务架构思考

时间&#xff1a;2024年06月16日 作者&#xff1a;小蒋聊技术 邮箱&#xff1a;wei_wei10163.com 微信&#xff1a;wei_wei10 音频地址&#xff1a; https://xima.tv/1_HvQZkj?_sonic0https://xima.tv/1_HvQZkj?_sonic0 大家好&#xff0c;欢迎来到小蒋聊技术&#xff0c…

Vue - 实现登录页面

1、技术框架 1、技术框架Vue-Cli Vue3.0 2、界面推荐大小&#xff1a; 1920 * 1080 3、UI组件&#xff1a;elementui 4、icon: element-plus/icons-vue 5、node版本&#xff1a;v20.14.0 2、效果图 3、源代码部分截图 4、其他 有需要的请联系作者。需要购买&#xff0c;不白…

ABBYY Finereader 15软件安装包下载

软件简介&#xff1a; FineReader PDF提供实用、简易的工具&#xff0c;将纸质文档和PDF结合起来&#xff0c;提高了数字工作场所的效率。 FineReader 15最大特色是采用了ABBYY最新推出的基于AI的OCR技术&#xff0c;可以更轻松地在同一工作流程中 对各种文档进行数字化、检索…

明日周刊-第13期

在这期间发生了很多的事&#xff0c;导致拖更了一周。接下去努力不断更&#xff0c;哈哈哈希望如此。配图是最近上映的一部电影《狗阵》的海报&#xff0c;看完之后感悟颇深&#xff0c;希望大家都能去电影院感受一下。 文章目录 一周热点资源分享言论歌曲推荐 一周热点 最近一…

跨语言翻译的突破:使用强化学习与人类反馈提升机器翻译质量

在人工智能领域&#xff0c;知识问答系统的性能优化一直是研究者们关注的焦点。现有的系统通常面临知识更新频繁、检索成本高、以及用户提问多样性等挑战。尽管采用了如RAG&#xff08;Retrieval-Augmented Generation&#xff09;和微调等技术&#xff0c;但它们各有利弊&…

类Copy方法:BeanUtils.copyProperties

类Copy方法&#xff1a;BeanUtils.copyProperties 需求场景 比如有时候我们想要把数据库里面的数据导出到excel表中&#xff0c;比如想要把数据库中的用户数据导出到excel表格中&#xff1b; 假设我们程序代码中与数据库对接的实体类是User&#xff0c;用于展示到前端的实体类…

aarch64系统中给qt编译的可执行程序加上图标

在qt中编译的可执行程序图标是默认是一种格式 而且无法替换改图标&#xff0c;看起来不够美观&#xff0c;可以使用.desktop的链接文件来链接编译的执行程序&#xff0c;通过点击.desktop图标来去运行可执行程序。 实现步骤&#xff1a; 创建一个以.desktop结尾的文件并记得给…

Es 索引查询排序分析

文章目录 概要一、Es数据存储1.1、_source1.2、stored fields 二、Doc values2.1、FieldCache2.2、DocValues 三、Fielddata四、Index sorting五、小结六、参考 概要 倒排索引 优势在于快速的查找到包含特定关键词的所有文档&#xff0c;但是排序&#xff0c;过滤、聚合等操作…

室内定位技术解析:蓝牙信标在室内导航中的应用

室内定位技术&#xff0c;作为现代导航领域的重要突破&#xff0c;解决了GPS在室内空间定位的局限&#xff0c;为我们提供了一种全新的空间认知和利用方式。本文将以蓝牙技术为例&#xff0c;深入解析室内定位的工作原理、关键技术和系统构成&#xff0c;以及在现代导航中的应用…

库的制作 与 使用 (Linux下)

目录 动静态库的制作 前置知识 库的基本构造 问题 分析 要给什么文件 如何更好的让别人使用 库的生成 静态库的生成 makefile参考 动态库的生成 makefile参考&#xff08;包含动态库和静态库生成&#xff09; 库的使用 法一&#xff1a;放入系统路径 弊端 法二…

【MATLAB】语法

MATLAB 基本语法(%{和%}) 赋值 函数名值&#xff1b;for for i1:10循环语句 end//while x0; sum0; while x<100sumsumx;x; end//if if x > 1f x^2 1; elsef 2 * x endswitch onum input(请输入一个数); switch num case -1 //注意case后面没有冒号disp(I am…

[Linux] TCP协议介绍(3): TCP协议的“四次挥手“过程、状态分析...

TCP协议是面向连接的 上一篇文章简单分析了TCP通信非常重要的建立连接的"三次握手"的过程 本篇文章来分析TCP通信中同样非常重要的断开连接的"四次挥手"的过程 TCP的"四次挥手" TCP协议建立连接 需要"三次握手". "三次挥手&q…

英伟达开源最强通用模型Nemotron-4 340B

英伟达的通用大模型 Nemotron&#xff0c;开源了最新的 3400 亿参数版本。 本周五&#xff0c;英伟达宣布推出 Nemotron-4 340B。它包含一系列开放模型&#xff0c;开发人员可以使用这些模型生成合成数据&#xff0c;用于训练大语言模型&#xff08;LLM&#xff09;&#xff0…

【CICID】GitHub-Actions语法

[TOC] 【CICID】GitHub-Actions语法 1 场景 ​ 当我们开发过程中&#xff0c;经常需要提交代码&#xff0c;打包&#xff0c;部署新代码到对应的环境&#xff0c;整个过程都是人工手动操作&#xff0c;占据开发人员大量时间&#xff0c;并且很繁琐容易出错。所以需要借助一些…

奥特曼谈AI的机遇、挑战与人类自我反思:中国将拥有独特的大语言模型

奥特曼在对话中特别提到&#xff0c;中国将在这个领域扮演重要角色&#xff0c;孕育出具有本土特色的大语言模型。这一预见不仅彰显了中国在全球人工智能领域中日益增长的影响力&#xff0c;也预示着未来技术发展的多元化趋势。 ①奥特曼认为AI在提升生产力方面已显现积极作用&…

蔡崇信“预言”:微软与OpenAI未来极有可能会分道扬镳

近日&#xff0c;在美国投行摩根大通于上海举行的第二十届全球中国峰会上&#xff0c;阿里巴巴集团联合创始人、董事局主席蔡崇信与摩根大通北亚区董事长兼大中华区投资银行业务副主席关金星&#xff08;Kam Shing Kwang&#xff09;进行了一场精彩对话。蔡崇信深入分享了他对公…

【LVGL】Guider 界面分析

文章目录 前言架构创建 UI切换界面空间释放分析创建页面空间变化 前言 分析Gui Guider-1.7.2-GA 生成的 LVGL 界面切换&#xff0c;资源管理等处理 架构 所有控件存放于同一个结构体 lv_ui 内&#xff0c;每个页面都至少包含 screen_xxx 和 screen_xxx_del 两个成员 typede…