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

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



}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

工业 UI 风格,展现独特魅力

工业 UI 风格&#xff0c;展现独特魅力

Facebook:数字时代的文化交流平台

在当今信息爆炸的数字时代&#xff0c;Facebook已经成为了一个不可或缺的社交媒体平台&#xff0c;不仅在个人生活中起到了联系社交的作用&#xff0c;更在全球范围内促进了文化交流和理解。本文将深入探讨Facebook作为文化交流平台的重要性&#xff0c;并分析其在数字时代如何…

C++面向对象程序设计 - 命名空间

命名空间是ANSI C引入的可以由用户命名的作用域&#xff0c;用来处理程序中常见的同名冲突。 在C语言中定义了三个层次的作用域&#xff0c;即文件&#xff08;编译单元&#xff09;、函数和复合语句。C又引入了类作用域&#xff0c;类是出现在文件内的。在不同的作用域中可以定…

vue代办事件案例实战练习,配有答案解析

代办事件案例 该案例&#xff0c;综合了前面所学的知识&#xff0c;列入点击事件绑定&#xff0c;双向绑定&#xff0c;v-for循环语句&#xff0c;v-model双向绑定&#xff0c;以及input标签的不同type形式。 演示代码如下&#xff1a; <template > <div id"ku…

腾讯云对象存储不绑定自定义备案域名不给下载应该如何处理?

从2024年1月1日起&#xff0c;腾讯云对象存储&#xff08;COS&#xff09;将实施新政策&#xff1a;新创建的存储桶不再支持使用path-style域名&#xff08;即存储桶绝对路径&#xff09;。此外&#xff0c;使用默认域名访问的新存储桶将不再支持任意类型文件的预览&#xff0c…

刷题记录(240613)

aliyun0512 1. 小红定义一个数组是好数组&#xff0c;当且仅当所有奇数出现了奇数次&#xff0c;所有偶数出现了偶数次。现在小红拿到了一个数组&#xff0c;她希望取一个该数组的非空子序列(可以不连续)&#xff0c;使得子序列是好数组。你能帮小红求出子序列的方案数吗?由于…

C++面向对象:多态性

多态性 1.概念 多态性是面向对象的程序设计的一个重要特征。在面向对象的方法中一般是这样表述多态的&#xff1a;向不同的对象发送同一个信息&#xff0c;不同的对象在接收时会产生不同的行为。也就是说&#xff0c;每个对象用自己的方式去响应共同的消息。 2.典例 下面这…

MFC动态创建按钮

void CMFCApplication1Dlg::OnBnClickedOk() {for (int i 0; i < 100; i){for (int j 0; j < 100; j){CButton* pButton3 new CButton;pButton[i][j] pButton3;}}CRect rect;GetClientRect(&rect); // 获取对话框客户区的大小rect.top 10; // 设置按钮的位置rec…

Elastic 索引结构-倒排索引

前言 Elastic 在数据库分类中一般被分为全文检索的数据库&#xff0c;那为什么这么区分呢&#xff1f;主要是因为其独特的索引结构 即倒排索引。 倒排索引 倒排索引先将文档中包含的关键字全部提取出来&#xff0c;然后再将关键字与文档的对应关系保存起来&#xff0c;最后再…

19、24年--信息系统工程——安全工程

1、工程概述 信息安全系统工程就是要建造一个信息安全系统,它是整个信息系统工程的一部分,而且最好是业务应用信息系统工程同步进行,主要围绕信息安全内容。 2、安全系统 1)X轴是”安全机制“。安全机制可以理解为提供某些安全服务,利用各种安全技术和技巧,所形成的一个…

06 SpringBoot 配置文件详解-application.yaml

Spring Boot 提供了大量的自动配置&#xff0c;极大地简化了spring 应用的开发过程&#xff0c;当用户创建了一个 Spring Boot 项目后&#xff0c;即使不进行任何配置&#xff0c;该项目也能顺利的运行起来。当然&#xff0c;用户也可以根据自身的需要使用配置文件修改 Spring …

电脑技巧:认识全能绘画软件Krita

目录 一、软件简介 二、软件功能 2.1 强大的画笔引擎 2.2专业色彩管理 2.3 多层编辑与管理 2.4 动画制作 三、软件特点 四、安装说明 五、使用技巧 六、快捷键大全 对于喜欢绘画的朋友来说&#xff0c;Krita 是一款不可多得的绘画工具&#xff0c;它具有开源、免费、…

查分易发成绩教程

马上就要期末考试了&#xff0c;老师们是不是正为家长咨询成绩倍感头痛&#xff1f;在以前老师们发布成绩都是私发给家长或者写在一张小纸条上让学生带回家&#xff0c;麻烦还容易出错&#xff0c;给老师的工作带来不小的压力。不过现在的年轻教师都在使用——查分易小程序&…

开源项目QAnything:全能型本地知识库问答系统

在当今信息爆炸的时代&#xff0c;如何高效地管理和检索大量数据成为了一个重要课题。网易有道推出的开源项目QAnything&#xff0c;正是为了解决这一问题而生。QAnything是一个本地知识库问答系统&#xff0c;支持多种文件格式和数据库&#xff0c;允许用户在离线状态下进行安…

Linux:线程概念 线程控制

Linux&#xff1a;线程概念 & 线程控制 线程概念轻量级进程 LWP页表 线程控制POSIX 线程库 - ptherad线程创建pthread_createpthread_self 线程退出pthread_exitpthread_cancelpthread_joinpthread_detach 线程架构线程与地址空间线程与pthread动态库 线程的优缺点 线程概念…

复分析——第2章——Cauchy定理及其应用(E.M. Stein R. Shakarchi)

第2章 Cauchy定理及其应用 The solution of a large number of problems can be reduced, in the last analysis, to the evaluation of definite integrals; thus mathematicians have been much occupied with this task... However, among many results obtained, a n…

【RabbitMQ】初识 RabbitMQ

初识 RabbitMQ 1.认识 RabbitMQ1.1 介绍1. 2.使用场景1.2.1 推送通知1.2.2 异步任务1.2.3 多平台应用的通信1.2.4 消息延迟1.2.5 远程过程调用 1.3 特性 2.基本概念2.1 生产者、消费者和代理2.2 消息队列2.3 交换机2.3.1 direct2.3.2 topic2.3.3 headers2.3.4 fanout 2.4 绑定2…

基于SpringBoot+VueBBS论坛系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝1W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f; 感兴趣的可以先收藏起来&#xff0c;还…

蓝牙模块的工作原理与电路设计

蓝牙技术是一种短距离无线通信技术&#xff0c;广泛应用于各种智能设备中&#xff0c;如手机、耳机、智能手表等。蓝牙模块作为实现蓝牙通信的核心部件&#xff0c;其工作原理和电路设计对于蓝牙设备的性能和稳定性至关重要。本文将深入解析蓝牙模块的工作原理&#xff0c;包括…

Docker(一)-认识Docker

1.docker理念 Docker是基于Go语言实现的云开源项目。 Docker的主要目标是“Build,Ship and Run Any App,Anywhere”&#xff0c;也就是通过对应用组件的封装&#xff0c;分发&#xff0c;部署&#xff0c;运行等生命周期的管理&#xff0c;使用户的应用及其运行环境能够做到”…