Răsfoiți Sursa

feature:000.000.002:后端完成图标生成的接口
接口完成对数据的解析和压缩;
构建请对数据调用星火的接口;
对星火返回的数据进行处理,持久化

yang yi 9 luni în urmă
părinte
comite
2e073d0818
21 a modificat fișierele cu 1005 adăugiri și 49 ștergeri
  1. 26 25
      serve/pom.xml
  2. 1 1
      serve/sql/init.sql
  3. 0 1
      serve/src/main/java/space/anyi/BI/BIApplication.java
  4. 30 0
      serve/src/main/java/space/anyi/BI/controller/ChartController.java
  5. 6 19
      serve/src/main/java/space/anyi/BI/entity/ResponseResult.java
  6. 63 0
      serve/src/main/java/space/anyi/BI/entity/dto/ChartDTO.java
  7. 128 0
      serve/src/main/java/space/anyi/BI/entity/vo/ChartVO.java
  8. 37 0
      serve/src/main/java/space/anyi/BI/entity/xinghuo/Choice.java
  9. 132 0
      serve/src/main/java/space/anyi/BI/entity/xinghuo/HttpRequestData.java
  10. 103 0
      serve/src/main/java/space/anyi/BI/entity/xinghuo/HttpRequestMessage.java
  11. 71 0
      serve/src/main/java/space/anyi/BI/entity/xinghuo/HttpResponseData.java
  12. 40 0
      serve/src/main/java/space/anyi/BI/entity/xinghuo/HttpResponseFormat.java
  13. 48 0
      serve/src/main/java/space/anyi/BI/entity/xinghuo/Usage.java
  14. 12 1
      serve/src/main/java/space/anyi/BI/exception/SystemException.java
  15. 6 2
      serve/src/main/java/space/anyi/BI/filter/JWTAuthenticationTokenFilter.java
  16. 4 0
      serve/src/main/java/space/anyi/BI/service/ChartService.java
  17. 59 0
      serve/src/main/java/space/anyi/BI/service/impl/ChartServiceImpl.java
  18. 83 0
      serve/src/main/java/space/anyi/BI/util/AiUtil.java
  19. 57 0
      serve/src/main/java/space/anyi/BI/util/ExcelUtils.java
  20. 64 0
      serve/src/test/java/space/anyi/BI/util/AiUtilTest.java
  21. 35 0
      serve/src/test/java/space/anyi/BI/util/ExcelUtilsTest.java

+ 26 - 25
serve/pom.xml

@@ -35,25 +35,15 @@
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
-        <dependency>
-            <groupId>cn.afterturn</groupId>
-            <artifactId>easypoi-spring-boot-starter</artifactId>
-            <version>4.4.0</version>
-        </dependency>
+        <!--<dependency>-->
+        <!--    <groupId>cn.afterturn</groupId>-->
+        <!--    <artifactId>easypoi-spring-boot-starter</artifactId>-->
+        <!--    <version>4.4.0</version>-->
+        <!--</dependency>-->
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-test</artifactId>
         </dependency>
-        <!--<dependency>-->
-        <!--    <groupId>io.springfox</groupId>-->
-        <!--    <artifactId>springfox-swagger2</artifactId>-->
-        <!--    <version>2.7.0</version>-->
-        <!--</dependency>-->
-        <!--<dependency>-->
-        <!--    <groupId>io.springfox</groupId>-->
-        <!--    <artifactId>springfox-swagger-ui</artifactId>-->
-        <!--    <version>2.7.0</version>-->
-        <!--</dependency>-->
         <dependency>
             <groupId>com.github.xiaoymin</groupId>
             <artifactId>knife4j-spring-boot-starter</artifactId>
@@ -87,18 +77,29 @@
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-validation</artifactId>
         </dependency>
+        <!--<dependency>-->
+        <!--    <groupId>com.alibaba</groupId>-->
+        <!--    <artifactId>easyexcel</artifactId>-->
+        <!--    <version>4.0.3</version>-->
+        <!--</dependency>-->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>3.17</version>
+        </dependency>
+
 
     </dependencies>
 
-    <!--<build>-->
-    <!--    <plugins>-->
-    <!--        <plugin>-->
-    <!--            <groupId>org.springframework.boot</groupId>-->
-    <!--            <artifactId>spring-boot-maven-plugin</artifactId>-->
-    <!--            <configuration>-->
-    <!--            </configuration>-->
-    <!--        </plugin>-->
-    <!--    </plugins>-->
-    <!--</build>-->
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
 
 </project>

+ 1 - 1
serve/sql/init.sql

@@ -18,7 +18,7 @@ CREATE TABLE  if NOT EXISTS `user` (
 
 -- 创建一个名为charts的表,用于存储图表信息
 CREATE TABLE if NOT EXISTS `chart` (
-                          `id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '图表ID',
+                          `id` BIGINT NOT NULL PRIMARY KEY COMMENT '图表ID',
                           `name` varchar(128) NULL COMMENT '图表名称',
                           `analysis_target` TEXT NOT NULL COMMENT '分析目标',
                           `chart_data` TEXT NOT NULL COMMENT '图标数据',

+ 0 - 1
serve/src/main/java/space/anyi/BI/BIApplication.java

@@ -2,7 +2,6 @@ package space.anyi.BI;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.web.bind.annotation.CrossOrigin;
 
 /**
  * @ProjectName: BI

+ 30 - 0
serve/src/main/java/space/anyi/BI/controller/ChartController.java

@@ -1,15 +1,23 @@
 package space.anyi.BI.controller;
 
 import cn.hutool.core.util.IdUtil;
+import cn.hutool.poi.excel.ExcelUtil;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import space.anyi.BI.BIApplication;
 import space.anyi.BI.entity.Chart;
 import space.anyi.BI.entity.ResponseResult;
+import space.anyi.BI.entity.dto.ChartDTO;
+import space.anyi.BI.entity.vo.ChartVO;
 import space.anyi.BI.service.ChartService;
 import space.anyi.BI.util.SecurityUtils;
 
 import javax.annotation.Resource;
+import java.io.IOException;
 
 /**
  * @ProjectName: BI
@@ -21,6 +29,7 @@ import javax.annotation.Resource;
 @Controller()
 @RequestMapping("/chart")
 public class ChartController {
+    private final static Logger log = LoggerFactory.getLogger(ChartController.class);
     @Resource
     private ChartService chartService;
     @GetMapping("/getChartById/{id}")
@@ -57,4 +66,25 @@ public class ChartController {
         Page<Chart> page = chartService.page(new Page<>(current, size));
         return ResponseResult.okResult(page);
     }
+
+    @PostMapping("/generateChartByAI")
+    @ResponseBody
+    public ResponseResult generateChartByAI(ChartDTO chartDTO, MultipartFile file) throws IOException {
+        log.info("分析目标:{},图标名称:{}",chartDTO.getAnalysisTarget(),chartDTO.getName());
+        if (file == null || file.isEmpty()) {
+            return ResponseResult.errorResult(ResponseResult.AppHttpCodeEnum.FILE_NOT_NULL);
+        }
+        //文件类判断
+        if (!file.getContentType().equals("application/vnd.ms-excel") && !file.getContentType().equals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) {
+            return ResponseResult.errorResult(ResponseResult.AppHttpCodeEnum.FILE_TYPE_ERROR);
+        }
+        ChartVO vo = chartService.generateChartByAI(chartDTO,file);
+
+        return ResponseResult.okResult(vo);
+    }
+
+    @ExceptionHandler({IOException.class})
+    private ResponseResult exceptionHandler(){
+        return ResponseResult.errorResult(ResponseResult.AppHttpCodeEnum.FILE_ERROR);
+    }
 }

+ 6 - 19
serve/src/main/java/space/anyi/BI/entity/ResponseResult.java

@@ -132,34 +132,21 @@ public class ResponseResult<T> implements Serializable {
         // 登录
         NEED_LOGIN(401,"需要登录后操作"),
         NO_OPERATOR_AUTH(403,"无权限操作"),
-        BOOK_IS_BORROWED(410, "图书已借出"),
+        FILE_NOT_NULL(410,"文件不能为空"),
+        FILE_TYPE_ERROR(411,"文件类型错误"),
         SYSTEM_ERROR(500,"出现错误"),
         USERNAME_EXIST(501,"用户名已存在"),
-        PHONENUMBER_EXIST(502,"手机号已存在"), EMAIL_EXIST(503, "邮箱已存在"),
-        REQUIRE_USERNAME(504, "必需填写用户名"),
-        LOGIN_ERROR(505,"用户名或密码错误"),
-        ARTICLE_NOT_EXIST(506,"文章不存在"),
-        COMMENT_CONTENT_NOT_NULL(507,"评论不能为空"),
-        FILE_NOT_NULL(508,"文件不能为空"),
-        FILE_TYPE_ERROR(509,"文件类型错误"),
+        REQUIRE_USERNAME(502, "必需填写用户名"),
+        LOGIN_ERROR(503,"用户名或密码错误"),
         USER_NOT_NULL(510,"用户不能为空"),
         PASSWORD_NOT_NULL(511,"密码不能为空"),
-        EMAIL_NOT_NULL(512,"邮箱不能为空"),
-        MENU_HAS_CHILDREN(513, "存在子菜单,不允许删除"),
         PASSWORD_ERROR(514, "密码错误"),
         USER_NOT_EXIST(515, "用户不存在"),
         PASSWORD_SAME(516, "新密码不能与旧密码一样"),
         VERIFY_CODE_ERROR(517, "验证码错误"),
         USER_STATE_ERROR(518, "用户状态值不正确"),
-        User_ID_NOT_NULL(519,"用户id不能为空" ),
-        BOOK_ISBN_EXIST(520, "图书ISBN已存在"),
-        BOOK_EXPORT_ERROR(521,"导出图书失败"),
-        USER_EXPORT_ERROR(522, "导出用户失败"),
-        BORROW_RECORD_EXPORT_ERROR(523,"导出借阅记录失败" ),
-        BOOK_IMPORT_ERROR(524,"导入图书数据失败" ),
-        USER_FACE_INFO_ERROR(525, "更新人脸信息失败"),
-        FACE_LOGIN_ERROR(526, "人脸登陆失败,对比不成功"),
-        USER_NOT_ACTIVE_FACE(527, "未激活人脸登陆");
+        FILE_ERROR(528, "文件读取错误"),
+        FILE_IS_EMPTY_ERROR(529, "文件内容不能为空");
 
         private int code;
         private String msg;

+ 63 - 0
serve/src/main/java/space/anyi/BI/entity/dto/ChartDTO.java

@@ -0,0 +1,63 @@
+package space.anyi.BI.entity.dto;
+
+/**
+ * @ProjectName: serve
+ * @FileName: ChartDTO
+ * @Author: 杨逸
+ * @Data:2024/12/3 21:40
+ * @Description:
+ */
+public class ChartDTO {
+
+    /**
+     * 图标名称
+     */
+    private String name;
+
+    /**
+     * 分析目标
+     */
+    private String analysisTarget;
+
+    /**
+     * 图标数据
+     */
+    private String chartData;
+
+    /**
+     * 图标类型
+     */
+    private String chartType;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getAnalysisTarget() {
+        return analysisTarget;
+    }
+
+    public void setAnalysisTarget(String analysisTarget) {
+        this.analysisTarget = analysisTarget;
+    }
+
+    public String getChartData() {
+        return chartData;
+    }
+
+    public void setChartData(String chartData) {
+        this.chartData = chartData;
+    }
+
+    public String getChartType() {
+        return chartType;
+    }
+
+    public void setChartType(String chartType) {
+        this.chartType = chartType;
+    }
+}

+ 128 - 0
serve/src/main/java/space/anyi/BI/entity/vo/ChartVO.java

@@ -0,0 +1,128 @@
+package space.anyi.BI.entity.vo;
+
+/**
+ * @ProjectName: serve
+ * @FileName: ChartVO
+ * @Author: 杨逸
+ * @Data:2024/12/4 20:23
+ * @Description:
+ */
+public class ChartVO {
+    /**
+     * 图表ID
+     */
+    private Long id;
+
+    /**
+     * 图标名称
+     */
+    private String name;
+
+    /**
+     * 分析目标
+     */
+    private String analysisTarget;
+
+    /**
+     * 图表数据
+     */
+    private String chartData;
+
+    /**
+     * 图标类型
+     */
+    private String chartType;
+
+    /**
+     * 生成的图表数据
+     */
+    private String generatedChartData;
+
+    /**
+     * 生成的分析结论
+     */
+    private String analysisConclusion;
+
+    /**
+     * 创建用户ID
+     */
+    private Long userId;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getAnalysisTarget() {
+        return analysisTarget;
+    }
+
+    public void setAnalysisTarget(String analysisTarget) {
+        this.analysisTarget = analysisTarget;
+    }
+
+    public String getChartData() {
+        return chartData;
+    }
+
+    public void setChartData(String chartData) {
+        this.chartData = chartData;
+    }
+
+    public String getChartType() {
+        return chartType;
+    }
+
+    public void setChartType(String chartType) {
+        this.chartType = chartType;
+    }
+
+    public String getGeneratedChartData() {
+        return generatedChartData;
+    }
+
+    public void setGeneratedChartData(String generatedChartData) {
+        this.generatedChartData = generatedChartData;
+    }
+
+    public String getAnalysisConclusion() {
+        return analysisConclusion;
+    }
+
+    public void setAnalysisConclusion(String analysisConclusion) {
+        this.analysisConclusion = analysisConclusion;
+    }
+
+    public Long getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Long userId) {
+        this.userId = userId;
+    }
+
+    @Override
+    public String toString() {
+        return "ChartVO{" +
+                "id=" + id +
+                ", name='" + name + '\'' +
+                ", analysisTarget='" + analysisTarget + '\'' +
+                ", chartData='" + chartData + '\'' +
+                ", chartType='" + chartType + '\'' +
+                ", generatedChartData='" + generatedChartData + '\'' +
+                ", analysisConclusion='" + analysisConclusion + '\'' +
+                ", userId=" + userId +
+                '}';
+    }
+}

+ 37 - 0
serve/src/main/java/space/anyi/BI/entity/xinghuo/Choice.java

@@ -0,0 +1,37 @@
+package space.anyi.BI.entity.xinghuo;
+
+/**
+ * @ProjectName: serve
+ * @FileName: Choice
+ * @Author: 杨逸
+ * @Data:2024/12/4 20:03
+ * @Description:
+ */
+public class Choice {
+    private HttpRequestMessage message;
+    private Integer index;
+
+    public HttpRequestMessage getMessage() {
+        return message;
+    }
+
+    public void setMessage(HttpRequestMessage message) {
+        this.message = message;
+    }
+
+    public Integer getIndex() {
+        return index;
+    }
+
+    public void setIndex(Integer index) {
+        this.index = index;
+    }
+
+    @Override
+    public String toString() {
+        return "Choice{" +
+                "message=" + message +
+                ", index=" + index +
+                '}';
+    }
+}

+ 132 - 0
serve/src/main/java/space/anyi/BI/entity/xinghuo/HttpRequestData.java

@@ -0,0 +1,132 @@
+package space.anyi.BI.entity.xinghuo;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @ProjectName: serve
+ * @FileName: RequestData
+ * @Author: 杨逸
+ * @Data:2024/12/4 15:48
+ * @Description: 讯飞星火大模型的请求对象
+ */
+
+ public class HttpRequestData implements Serializable {
+    public static final String MODEL_LITE = "Lite";
+    public static final String MODEL_PRO = "Pro";
+    public static final String MODEL_MAX = "Max";
+    public static final String MODEL_PRO_128K = "Pro-128K";
+    public static final String MODEL_MAX_32K = "Max-32K";
+    public static final String MODEL_4_0_ULTRA = "4.0 Ultra";
+    private String model = MODEL_LITE;
+    private String user = "user"+System.currentTimeMillis();
+    private List<HttpRequestMessage> messages;
+    private Double temperature = 1.0;
+    private Integer top_k = 4;
+    private Boolean stream = false;
+    private Integer max_tokens = 4096;
+    private Integer presence_penalty = 0;
+    private Integer frequency_penalty = 0;
+    //private List<Tool> tools;
+    private HttpResponseFormat response_format = HttpResponseFormat.text();
+
+    public String getModel() {
+        return model;
+    }
+
+    public void setModel(String model) {
+        this.model = model;
+    }
+
+    public String getUser() {
+        return user;
+    }
+
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    public List<HttpRequestMessage> getMessages() {
+        return messages;
+    }
+
+    public void setMessages(List<HttpRequestMessage> messages) {
+        this.messages = messages;
+    }
+
+    public Double getTemperature() {
+        return temperature;
+    }
+
+    public void setTemperature(Double temperature) {
+        this.temperature = temperature;
+    }
+
+    public Integer getTop_k() {
+        return top_k;
+    }
+
+    public void setTop_k(Integer top_k) {
+        this.top_k = top_k;
+    }
+
+    public Boolean getStream() {
+        return stream;
+    }
+
+    public void setStream(Boolean stream) {
+        this.stream = stream;
+    }
+
+    public Integer getMax_tokens() {
+        return max_tokens;
+    }
+
+    public void setMax_tokens(Integer max_tokens) {
+        this.max_tokens = max_tokens;
+    }
+
+    public Integer getPresence_penalty() {
+        return presence_penalty;
+    }
+
+    public void setPresence_penalty(Integer presence_penalty) {
+        this.presence_penalty = presence_penalty;
+    }
+
+    public Integer getFrequency_penalty() {
+        return frequency_penalty;
+    }
+
+    public void setFrequency_penalty(Integer frequency_penalty) {
+        this.frequency_penalty = frequency_penalty;
+    }
+
+    public HttpResponseFormat getResponse_format() {
+        return response_format;
+    }
+
+    public void setResponse_format(HttpResponseFormat response_format) {
+        this.response_format = response_format;
+    }
+
+    @Override
+    public String toString() {
+        return "HttpRequestData{" +
+                "model='" + model + '\'' +
+                ", user='" + user + '\'' +
+                ", messages=" + messages +
+                ", temperature=" + temperature +
+                ", top_k=" + top_k +
+                ", stream=" + stream +
+                ", max_tokens=" + max_tokens +
+                ", presence_penalty=" + presence_penalty +
+                ", frequency_penalty=" + frequency_penalty +
+                ", response_format=" + response_format +
+                '}';
+    }
+}
+
+
+
+

+ 103 - 0
serve/src/main/java/space/anyi/BI/entity/xinghuo/HttpRequestMessage.java

@@ -0,0 +1,103 @@
+package space.anyi.BI.entity.xinghuo;
+
+import java.io.Serializable;
+
+/**
+ * 信息对象
+ * @ProjectName: serve
+ * @FileName: HttpRequestMessage
+ * @Author: 杨逸
+ * @Data:2024/12/4 16:41
+ * @Description:
+ */
+public class HttpRequestMessage implements Serializable {
+
+    /**
+     * 系统命令
+     * @see String
+     */
+    public static final String SYSTEM_ROLE = "system";
+    /**
+     * 用户
+     * @see String
+     */
+    public static final String USER_ROLE = "user";
+    /**
+     * AI模型
+     * @see String
+     */
+    public static final String ASSISTANT_ROLE = "assistant";
+    /**
+     * function call执行结果
+     * @see String
+     */
+    public static final String TOOL_ROLE = "tool";
+    private String role = USER_ROLE;
+    private String content = "";
+
+    public HttpRequestMessage(String role, String content) {
+        this.role = role;
+        this.content = content;
+    }
+
+    public HttpRequestMessage(String content) {
+        this.content = content;
+    }
+
+    public HttpRequestMessage() {
+    }
+
+    /**
+     * 获取预设的prompt信息
+     * @return {@code HttpRequestMessage }
+     * @description:
+     * @author: 杨逸
+     * @data:2024/12/04 20:52:46
+     * @since 1.0.0
+     */
+    public static HttpRequestMessage getPromptMessage() {
+        String prompt = "你是一位专业的数据分析师和前端工程师,擅长对数据进行分析并得出明确的结论。你精通使用Echarts进行数据可视化,并能结合可视化的数据图表进行合理的分析。\n" +
+                "\n" +
+                "要求:\n" +
+                "\n" +
+                "- 直接输出两个部分:Echarts图表的配置代码和数据分析结论,不包含其他提示内容。\n" +
+                "- 我将提供原始CSV数据和分析目标,你需根据这些信息生成Echarts图表的配置代码。\n" +
+                "\t- CSV数据以','字符分割,\n" +
+                "- 输出格式为:先输出Echarts的option配置对象的JavaScript代码,然后输出分析结论。\n" +
+                "- 请按照指定的输出格式提供我需要的内容。\n" +
+                "输入格式:\n" +
+                "\n" +
+                "- 原始数据\n" +
+                "- 分析目标\n" +
+                "输出格式:\n" +
+                "\n" +
+                "- Echarts的option配置对象的JavaScript代码\n" +
+                "- 数据分析结论";
+        HttpRequestMessage message = new HttpRequestMessage(HttpRequestMessage.SYSTEM_ROLE,prompt);
+        return message;
+    }
+
+    public String getRole() {
+        return role;
+    }
+
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    @Override
+    public String toString() {
+        return "HttpRequestMessage{" +
+                "role='" + role + '\'' +
+                ", content='" + content + '\'' +
+                '}';
+    }
+}

+ 71 - 0
serve/src/main/java/space/anyi/BI/entity/xinghuo/HttpResponseData.java

@@ -0,0 +1,71 @@
+package space.anyi.BI.entity.xinghuo;
+
+/**
+ * @ProjectName: serve
+ * @FileName: HttpReponseData
+ * @Author: 杨逸
+ * @Data:2024/12/4 19:59
+ * @Description:
+ */
+
+
+import java.util.List;
+
+public class HttpResponseData {
+    private Integer code;
+    private String message;
+    private String sid;
+    private List<Choice> choices;
+    private Usage usage;
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public String getSid() {
+        return sid;
+    }
+
+    public void setSid(String sid) {
+        this.sid = sid;
+    }
+
+    public List<Choice> getChoices() {
+        return choices;
+    }
+
+    public void setChoices(List<Choice> choices) {
+        this.choices = choices;
+    }
+
+    public Usage getUsage() {
+        return usage;
+    }
+
+    public void setUsage(Usage usage) {
+        this.usage = usage;
+    }
+
+    @Override
+    public String toString() {
+        return "HttpResponseData{" +
+                "code=" + code +
+                ", message='" + message + '\'' +
+                ", sid='" + sid + '\'' +
+                ", choices=" + choices +
+                ", usage=" + usage +
+                '}';
+    }
+}

+ 40 - 0
serve/src/main/java/space/anyi/BI/entity/xinghuo/HttpResponseFormat.java

@@ -0,0 +1,40 @@
+package space.anyi.BI.entity.xinghuo;
+
+import java.io.Serializable;
+
+/**
+ * @ProjectName: serve
+ * @FileName: HttpResponseFormat
+ * @Author: 杨逸
+ * @Data:2024/12/4 16:43
+ * @Description:
+ */
+public class HttpResponseFormat implements Serializable {
+    private String type;
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public static HttpResponseFormat json(){
+        HttpResponseFormat format = new HttpResponseFormat();
+        format.type = "json_object";
+        return format;
+    }
+    public static HttpResponseFormat text(){
+        HttpResponseFormat format = new HttpResponseFormat();
+        format.type = "text";
+        return format;
+    }
+
+    @Override
+    public String toString() {
+        return "HttpResponseFormat{" +
+                "type='" + type + '\'' +
+                '}';
+    }
+}

+ 48 - 0
serve/src/main/java/space/anyi/BI/entity/xinghuo/Usage.java

@@ -0,0 +1,48 @@
+package space.anyi.BI.entity.xinghuo;
+
+/**
+ * 接口使用量对象
+ * @ProjectName: serve
+ * @FileName: Usage
+ * @Author: 杨逸
+ * @Data:2024/12/4 20:01
+ * @Description:
+ */
+public class Usage {
+    private Integer total_tokens;
+    private Integer prompt_tokens;
+    private Integer completion_tokens;
+
+    public Integer getTotal_tokens() {
+        return total_tokens;
+    }
+
+    public void setTotal_tokens(Integer total_tokens) {
+        this.total_tokens = total_tokens;
+    }
+
+    public Integer getPrompt_tokens() {
+        return prompt_tokens;
+    }
+
+    public void setPrompt_tokens(Integer prompt_tokens) {
+        this.prompt_tokens = prompt_tokens;
+    }
+
+    public Integer getCompletion_tokens() {
+        return completion_tokens;
+    }
+
+    public void setCompletion_tokens(Integer completion_tokens) {
+        this.completion_tokens = completion_tokens;
+    }
+
+    @Override
+    public String toString() {
+        return "Usage{" +
+                "total_tokens=" + total_tokens +
+                ", prompt_tokens=" + prompt_tokens +
+                ", completion_tokens=" + completion_tokens +
+                '}';
+    }
+}

+ 12 - 1
serve/src/main/java/space/anyi/BI/exception/SystemException.java

@@ -7,13 +7,24 @@ import space.anyi.BI.entity.ResponseResult;
  * @FileName: SystemException
  * @Author: 杨逸
  * @Data:2024/11/28 20:22
- * @Description: TODO
+ * @Description:
  */
 public class SystemException extends RuntimeException {
     private int code;
 
     private String msg;
 
+    public SystemException() {
+        super();
+    }
+    public SystemException(int code, String msg) {
+        super(msg);
+        this.code = code;
+        this.msg = msg;
+    }
+
+
+
     public int getCode() {
         return code;
     }

+ 6 - 2
serve/src/main/java/space/anyi/BI/filter/JWTAuthenticationTokenFilter.java

@@ -2,12 +2,15 @@ package space.anyi.BI.filter;
 
 import com.alibaba.fastjson.JSON;
 import io.jsonwebtoken.Claims;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.stereotype.Component;
 import org.springframework.util.StringUtils;
 import org.springframework.web.filter.OncePerRequestFilter;
+import space.anyi.BI.BIApplication;
 import space.anyi.BI.constant.SystemConstants;
 import space.anyi.BI.entity.LoginUserDetails;
 import space.anyi.BI.entity.ResponseResult;
@@ -32,15 +35,16 @@ import java.util.Objects;
  */
 @Component
 public class JWTAuthenticationTokenFilter extends OncePerRequestFilter {
+    private final static Logger log = LoggerFactory.getLogger(BIApplication.class);
     @Resource
     private RedisCache redisCache;
 
     @Override
     protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
         //获取token
-        System.out.println("httpServletRequest.getRequestURI() = " + httpServletRequest.getRequestURI());
+        String uri = httpServletRequest.getRequestURI();
         String token = httpServletRequest.getHeader("token");
-        System.out.println("token = " + token);
+        log.info("token={},\n请求的uri={}",token,uri);
         if (!StringUtils.hasText(token)) {
             filterChain.doFilter(httpServletRequest, httpServletResponse);
             return;

+ 4 - 0
serve/src/main/java/space/anyi/BI/service/ChartService.java

@@ -1,7 +1,10 @@
 package space.anyi.BI.service;
 
+import org.springframework.web.multipart.MultipartFile;
 import space.anyi.BI.entity.Chart;
 import com.baomidou.mybatisplus.extension.service.IService;
+import space.anyi.BI.entity.dto.ChartDTO;
+import space.anyi.BI.entity.vo.ChartVO;
 
 /**
 * @author 杨逸
@@ -10,4 +13,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
 */
 public interface ChartService extends IService<Chart> {
 
+    ChartVO generateChartByAI(ChartDTO chartDTO, MultipartFile file);
 }

+ 59 - 0
serve/src/main/java/space/anyi/BI/service/impl/ChartServiceImpl.java

@@ -1,10 +1,26 @@
 package space.anyi.BI.service.impl;
 
+import cn.hutool.core.util.IdUtil;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.multipart.MultipartFile;
+import space.anyi.BI.BIApplication;
 import space.anyi.BI.entity.Chart;
+import space.anyi.BI.entity.dto.ChartDTO;
+import space.anyi.BI.entity.vo.ChartVO;
+import space.anyi.BI.entity.xinghuo.HttpRequestData;
+import space.anyi.BI.entity.xinghuo.HttpResponseData;
+import space.anyi.BI.exception.SystemException;
 import space.anyi.BI.service.ChartService;
 import space.anyi.BI.mapper.ChartMapper;
 import org.springframework.stereotype.Service;
+import space.anyi.BI.util.AiUtil;
+import space.anyi.BI.util.BeanCopyUtil;
+import space.anyi.BI.util.ExcelUtils;
+import space.anyi.BI.util.SecurityUtils;
+
+import java.io.IOException;
 
 /**
 * @author 杨逸
@@ -14,7 +30,50 @@ import org.springframework.stereotype.Service;
 @Service
 public class ChartServiceImpl extends ServiceImpl<ChartMapper, Chart>
     implements ChartService{
+    private final static Logger log = LoggerFactory.getLogger(ChartServiceImpl.class);
+    @Override
+    public ChartVO generateChartByAI(ChartDTO chartDTO, MultipartFile file) {
+        //读数据
+        String csvData  = "";
+        try {
+            csvData = ExcelUtils.excel2csv(file.getInputStream());
+            log.info("上传的数据为:\n{}", csvData);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        if (csvData.length()>3000){
+            throw new SystemException(500, "数据量过大,请上传小于3000行的数据");
+        }
+        StringBuilder message = new StringBuilder("原始数据:\n");
+        message.append(csvData);
+        message.append("分析目标:\n");
+        message.append(chartDTO.getAnalysisTarget());
+        //配置prompt向AI发送请求
+        HttpRequestData requestData = AiUtil.createDefaultRequestData(message.toString());
+        HttpResponseData responseData = AiUtil.doChat(requestData);
+        //解析AI返回的数据
+        ChartVO chartVO = BeanCopyUtil.copyBean(chartDTO, ChartVO.class);
+        String content = responseData.getChoices().get(0).getMessage().getContent();
+        log.info("AI返回的数据为:{}", content);
+        int index = content.indexOf("```");
+        int endIndex = content.lastIndexOf("```");
+        if (index == -1){
+            throw new SystemException(500, "AI生成图表失败");
+        }
+        //数据可视化,Echarts的option代码
+        chartVO.setGeneratedChartData(content.substring(index+14, endIndex));
+        index = endIndex;
+        //分析结论
+        chartVO.setAnalysisConclusion(content.substring(index+3));
 
+        Chart chart = BeanCopyUtil.copyBean(chartVO, Chart.class);
+        chart.setUserId(SecurityUtils.getUserId());
+        chart.setChartData(csvData);
+        chart.setId(IdUtil.getSnowflake(1,1).nextId());
+        //保存到数据库
+        save(chart);
+        return chartVO;
+    }
 }
 
 

+ 83 - 0
serve/src/main/java/space/anyi/BI/util/AiUtil.java

@@ -0,0 +1,83 @@
+package space.anyi.BI.util;
+
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.HttpUtil;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import space.anyi.BI.entity.ResponseResult;
+import space.anyi.BI.entity.xinghuo.HttpRequestData;
+import space.anyi.BI.entity.xinghuo.HttpRequestMessage;
+import space.anyi.BI.entity.xinghuo.HttpResponseData;
+import space.anyi.BI.exception.SystemException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @ProjectName: serve
+ * @FileName: AiUtil
+ * @Author: 杨逸
+ * @Data:2024/12/4 15:55
+ * @Description:
+ */
+public class AiUtil {
+    private static final String url = "https://spark-api-open.xf-yun.com/v1/chat/completions";
+    public static ObjectMapper objectMapper = new ObjectMapper();
+
+    /**
+     * 调用星火AI接口
+     * @param requestData
+     * @return {@code HttpResponseData }
+     * @description:
+     * @author: 杨逸
+     * @data:2024/12/04 20:50:06
+     * @since 1.0.0
+     */
+    public static HttpResponseData doChat(HttpRequestData requestData){
+        String json = null;
+        try {
+            json = objectMapper.writeValueAsString(requestData);
+        } catch (JsonProcessingException e) {
+            e.printStackTrace();
+        }
+        HttpResponse httpResponse = HttpUtil.createPost(url)
+                .header("Content-Type", "application/json")
+                .header("Authorization", "Bearer ZtPoELVmjZgFSWQPGQfR:BBhQpywhuazFXpURYVnM")
+                //.header("Authorization", "Bearer JXbEljkrEiJWpKlpBudO:gSIilowunJWNMOIQhwVo")
+                .body(json)
+                .execute();
+        String body = httpResponse.body();
+        int index = body.indexOf('0');
+        HttpResponseData httpResponseData = null;
+        if (index == 8){
+            //调用成功
+            try {
+                httpResponseData = objectMapper.readValue(body, HttpResponseData.class);
+            } catch (JsonProcessingException e) {
+                e.printStackTrace();
+            }
+        }else{
+            System.err.println(body);
+            throw new SystemException(ResponseResult.AppHttpCodeEnum.SYSTEM_ERROR);
+        }
+        return httpResponseData;
+    }
+
+    /**
+     * 创建一个简单的请求体
+     * @param message
+     * @return {@code HttpRequestData }
+     * @description:
+     * @author: 杨逸
+     * @data:2024/12/04 20:54:46
+     * @since 1.0.0
+     */
+    public static HttpRequestData createDefaultRequestData(String message){
+        HttpRequestData httpRequestData = new HttpRequestData();
+        List<HttpRequestMessage> messages = new ArrayList<>();
+        messages.add(HttpRequestMessage.getPromptMessage());
+        messages.add(new HttpRequestMessage(HttpRequestMessage.USER_ROLE, message));
+        httpRequestData.setMessages(messages);
+        return httpRequestData;
+    }
+}

+ 57 - 0
serve/src/main/java/space/anyi/BI/util/ExcelUtils.java

@@ -0,0 +1,57 @@
+package space.anyi.BI.util;
+
+import cn.hutool.poi.excel.ExcelUtil;
+import space.anyi.BI.entity.ResponseResult;
+import space.anyi.BI.exception.SystemException;
+
+import java.io.*;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * @ProjectName: serve
+ * @FileName: ExcelUtils
+ * @Author: 杨逸
+ * @Data:2024/12/3 22:05
+ * @Description:
+ */
+public class ExcelUtils {
+    public static String excel2csv(File file){
+        try {
+            return excel2csv(new FileInputStream(file));
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        }
+        return "";
+    }
+
+    public static String excel2csv(InputStream inputStream) {
+        StringBuilder csv = new StringBuilder();
+        //读数据
+        List<Map> list = null;
+        list = ExcelUtil.getReader(inputStream).readAll(Map.class);
+        //处理数据,压缩数据
+        if (Objects.isNull(list) || list.isEmpty()){
+            throw new SystemException(ResponseResult.AppHttpCodeEnum.FILE_IS_EMPTY_ERROR);
+        }
+        //表头
+        List<String> keyList = (List<String>) list.get(0).keySet().stream().collect(Collectors.toList());
+        for (String key : keyList) {
+            csv.append(key).append(",");
+        }
+        csv.deleteCharAt(csv.length() - 1);
+        csv.append("\n");
+        //数据列
+        for (int i = 1; i < list.size(); i++) {
+            Map map = list.get(i);
+            for (String key : keyList) {
+                csv.append(map.get(key)).append(",");
+            }
+            csv.deleteCharAt(csv.length() - 1);
+            csv.append("\n");
+        }
+        return csv.toString();
+    }
+}

+ 64 - 0
serve/src/test/java/space/anyi/BI/util/AiUtilTest.java

@@ -0,0 +1,64 @@
+package space.anyi.BI.util;
+
+import org.junit.jupiter.api.Test;
+import space.anyi.BI.entity.xinghuo.HttpRequestData;
+import space.anyi.BI.entity.xinghuo.HttpRequestMessage;
+import space.anyi.BI.entity.xinghuo.HttpResponseData;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @ProjectName: serve
+ * @FileName: AiUtilTest
+ * @Author: 杨逸
+ * @Data:2024/12/4 16:03
+ * @Description:
+ */
+class AiUtilTest {
+
+    @Test
+    void doChat() {
+        String prompt = "你是一位专业的数据分析师和前端工程师,擅长对数据进行分析并得出明确的结论。你精通使用Echarts进行数据可视化,并能结合可视化的数据图表进行合理的分析。\n" +
+                "\n" +
+                "要求:\n" +
+                "\n" +
+                "- 直接输出两个部分:Echarts图表的配置代码和数据分析结论,不包含其他提示内容。\n" +
+                "- 我将提供原始CSV数据和分析目标,你需根据这些信息生成Echarts图表的配置代码。\n" +
+                "\t- CSV数据以','字符分割,每一行代表一条数据\n" +
+                "- 输出格式为:先输出Echarts的option配置对象的JavaScript代码,然后输出分析结论。\n" +
+                "- 请按照指定的输出格式提供我需要的内容。\n" +
+                "输入格式:\n" +
+                "\n" +
+                "- 原始数据\n" +
+                "- 分析目标\n" +
+                "输出格式:\n" +
+                "\n" +
+                "- Echarts的option配置对象的JavaScript代码\n" +
+                "- 数据分析结论";
+        List<HttpRequestMessage> messages = new ArrayList<>();
+        HttpRequestMessage message = new HttpRequestMessage(HttpRequestMessage.SYSTEM_ROLE,prompt);
+        messages.add(message);
+
+        message = new HttpRequestMessage();
+        String content = "原始数据:\n" +
+                "日期,人数\n" +
+                "1号,10\n" +
+                "2号,30\n" +
+                "3号,20\n" +
+                "分析目标:\n" +
+                "分析网站的人数增长趋势";
+        message.setContent(content);
+        messages.add(message);
+
+        HttpRequestData requestData = new HttpRequestData();
+        //requestData.setModel(HttpRequestData.MODEL_PRO);
+        requestData.setMessages(messages);
+
+        //System.out.println("requestData = " + requestData);
+        HttpResponseData httpResponseData = AiUtil.doChat(requestData);
+        System.out.println("httpResponseData = " + httpResponseData);
+        String res = httpResponseData.getChoices().get(0).getMessage().getContent();
+        System.out.println("res = " + res);
+    }
+}

+ 35 - 0
serve/src/test/java/space/anyi/BI/util/ExcelUtilsTest.java

@@ -0,0 +1,35 @@
+package space.anyi.BI.util;
+
+import cn.hutool.poi.excel.ExcelReader;
+import cn.hutool.poi.excel.ExcelUtil;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * @ProjectName: serve
+ * @FileName: ExcelUtilsTest
+ * @Author: 杨逸
+ * @Data:2024/12/3 22:16
+ * @Description:
+ */
+class ExcelUtilsTest {
+
+    @Test
+    void readExcel() {
+        String filePath = "E:\\2024\\BI\\serve\\test.xlsx";
+        //List<Map<Integer, String>> maps = ExcelUtils.readExcel(filePath);
+        ExcelReader reader = ExcelUtil.getReader(filePath);
+        List<Map> list = reader.readAll(Map.class);
+        for (Map map : list) {
+            System.out.println("map = " + map);
+        }
+    }
+
+    @Test
+    void testReadExcel() {
+    }
+}