Переглянути джерело

删掉多余代码(等待spring完成api)

zhenghao 4 місяців тому
батько
коміт
319f02d3d7
74 змінених файлів з 430 додано та 975 видалено
  1. 3 3
      pom.xml
  2. 4 6
      sql/pg.sql
  3. 4 5
      src/main/java/cn/jlsxwkj/RagChatApplication.java
  4. 2 0
      src/main/java/cn/jlsxwkj/common/R/Response.java
  5. 3 1
      src/main/java/cn/jlsxwkj/common/R/ResponseError.java
  6. 3 0
      src/main/java/cn/jlsxwkj/common/R/ResponseSucceed.java
  7. 0 4
      src/main/java/cn/jlsxwkj/common/R/package-info.java
  8. 16 6
      src/main/java/cn/jlsxwkj/common/config/FunctionCallConfig.java
  9. 7 10
      src/main/java/cn/jlsxwkj/common/config/RateLimiterConfig.java
  10. 4 3
      src/main/java/cn/jlsxwkj/common/config/SaTokenConfig.java
  11. 2 8
      src/main/java/cn/jlsxwkj/common/config/UserConfig.java
  12. 0 4
      src/main/java/cn/jlsxwkj/common/config/package-info.java
  13. 2 0
      src/main/java/cn/jlsxwkj/common/dao/Dao.java
  14. 0 4
      src/main/java/cn/jlsxwkj/common/dao/package-info.java
  15. 2 1
      src/main/java/cn/jlsxwkj/common/exception/AccountAuthFailException.java
  16. 2 1
      src/main/java/cn/jlsxwkj/common/exception/AccountPasswordCheckFailException.java
  17. 2 1
      src/main/java/cn/jlsxwkj/common/exception/CustomException.java
  18. 2 1
      src/main/java/cn/jlsxwkj/common/exception/FileDeleteFailException.java
  19. 2 1
      src/main/java/cn/jlsxwkj/common/exception/FileTypeDoesNotSupportException.java
  20. 2 1
      src/main/java/cn/jlsxwkj/common/exception/InsertFailException.java
  21. 2 1
      src/main/java/cn/jlsxwkj/common/exception/LoginAccountAlreadyLoginException.java
  22. 2 1
      src/main/java/cn/jlsxwkj/common/exception/LoginWrongPasswordException.java
  23. 2 1
      src/main/java/cn/jlsxwkj/common/exception/NotContentInFileException.java
  24. 2 0
      src/main/java/cn/jlsxwkj/common/exception/OpenFileFailException.java
  25. 2 1
      src/main/java/cn/jlsxwkj/common/exception/TooManyRequestsException.java
  26. 2 1
      src/main/java/cn/jlsxwkj/common/exception/UnknownException.java
  27. 0 4
      src/main/java/cn/jlsxwkj/common/exception/package-info.java
  28. 13 9
      src/main/java/cn/jlsxwkj/common/filter/ExecTimeFilter.java
  29. 15 10
      src/main/java/cn/jlsxwkj/common/filter/RateLimiterFilter.java
  30. 0 4
      src/main/java/cn/jlsxwkj/common/filter/package-info.java
  31. 10 20
      src/main/java/cn/jlsxwkj/common/handler/GlobalRestExceptionHandler.java
  32. 10 9
      src/main/java/cn/jlsxwkj/common/handler/ResultResponseHandler.java
  33. 0 4
      src/main/java/cn/jlsxwkj/common/handler/package-info.java
  34. 10 16
      src/main/java/cn/jlsxwkj/common/reader/ParagraphDocReader.java
  35. 9 13
      src/main/java/cn/jlsxwkj/common/reader/ParagraphOcrReader.java
  36. 3 5
      src/main/java/cn/jlsxwkj/common/reader/ParagraphTextReader.java
  37. 0 4
      src/main/java/cn/jlsxwkj/common/reader/package-info.java
  38. 4 2
      src/main/java/cn/jlsxwkj/common/utils/CheckPassword.java
  39. 5 6
      src/main/java/cn/jlsxwkj/common/utils/FileType.java
  40. 3 3
      src/main/java/cn/jlsxwkj/common/utils/Log.java
  41. 12 29
      src/main/java/cn/jlsxwkj/common/utils/MergeDocuments.java
  42. 9 20
      src/main/java/cn/jlsxwkj/common/utils/SplitDocument.java
  43. 0 4
      src/main/java/cn/jlsxwkj/common/utils/package-info.java
  44. 10 14
      src/main/java/cn/jlsxwkj/moudles/chat/ChatController.java
  45. 0 30
      src/main/java/cn/jlsxwkj/moudles/chat/ChatRequest.java
  46. 0 27
      src/main/java/cn/jlsxwkj/moudles/chat/ChatResponse.java
  47. 73 204
      src/main/java/cn/jlsxwkj/moudles/chat/ChatService.java
  48. 0 113
      src/main/java/cn/jlsxwkj/moudles/chat/ChatUtil.java
  49. 0 23
      src/main/java/cn/jlsxwkj/moudles/chat/message/AssistantMessage.java
  50. 0 19
      src/main/java/cn/jlsxwkj/moudles/chat/message/Message.java
  51. 0 22
      src/main/java/cn/jlsxwkj/moudles/chat/message/SystemMessage.java
  52. 0 21
      src/main/java/cn/jlsxwkj/moudles/chat/message/UserMessage.java
  53. 0 23
      src/main/java/cn/jlsxwkj/moudles/chat/message/UserRole.java
  54. 0 4
      src/main/java/cn/jlsxwkj/moudles/chat/message/package-info.java
  55. 0 4
      src/main/java/cn/jlsxwkj/moudles/chat/package-info.java
  56. 1 0
      src/main/java/cn/jlsxwkj/moudles/chat_history/ChatHistoryController.java
  57. 2 36
      src/main/java/cn/jlsxwkj/moudles/chat_history/ChatHistoryMapper.java
  58. 13 2
      src/main/java/cn/jlsxwkj/moudles/chat_history/ChatHistoryService.java
  59. 31 9
      src/main/java/cn/jlsxwkj/moudles/chat_history/ChatHistoryVO.java
  60. 0 4
      src/main/java/cn/jlsxwkj/moudles/chat_history/package-info.java
  61. 0 17
      src/main/java/cn/jlsxwkj/moudles/log_error/LogError.java
  62. 2 23
      src/main/java/cn/jlsxwkj/moudles/log_error/LogErrorMapper.java
  63. 9 3
      src/main/java/cn/jlsxwkj/moudles/log_error/LogErrorService.java
  64. 0 4
      src/main/java/cn/jlsxwkj/moudles/log_error/package-info.java
  65. 7 3
      src/main/java/cn/jlsxwkj/moudles/user_list/UserListController.java
  66. 2 37
      src/main/java/cn/jlsxwkj/moudles/user_list/UserListMapper.java
  67. 15 23
      src/main/java/cn/jlsxwkj/moudles/user_list/UserListService.java
  68. 33 9
      src/main/java/cn/jlsxwkj/moudles/user_list/UserVO.java
  69. 0 4
      src/main/java/cn/jlsxwkj/moudles/user_list/package-info.java
  70. 7 7
      src/main/java/cn/jlsxwkj/moudles/weather_demo/Request.java
  71. 27 0
      src/main/java/cn/jlsxwkj/moudles/weather_demo/Response.java
  72. 16 49
      src/main/java/cn/jlsxwkj/moudles/weather_demo/WeatherService.java
  73. 0 4
      src/main/java/cn/jlsxwkj/moudles/weather_demo/package-info.java
  74. 5 10
      src/main/resources/application-dev.yml

+ 3 - 3
pom.xml

@@ -82,9 +82,9 @@
         </dependency>
         <!--mybatis-->
         <dependency>
-            <groupId>org.mybatis.spring.boot</groupId>
-            <artifactId>mybatis-spring-boot-starter</artifactId>
-            <version>3.0.3</version>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
+            <version>3.5.7</version>
         </dependency>
         <!--spring doc-->
         <dependency>

+ 4 - 6
sql/pg.sql

@@ -13,30 +13,28 @@ CREATE TABLE IF NOT EXISTS log_error (
     id bigserial PRIMARY KEY, -- 主键
     "exception" text NULL, -- 异常
     message text NULL, -- 异常消息
-    error_info text NULL, -- 异常详细消息
     error_stack_trace text NULL, -- 异常堆栈
     create_time timestamp(0) DEFAULT now() NULL -- 创建时间
 );
 COMMENT ON COLUMN log_error.id IS '主键';
 COMMENT ON COLUMN log_error."exception" IS '异常';
 COMMENT ON COLUMN log_error.message IS '异常消息';
-COMMENT ON COLUMN log_error.error_info IS '异常详细消息';
 COMMENT ON COLUMN log_error.error_stack_trace IS '异常堆栈';
 COMMENT ON COLUMN log_error.create_time IS '创建时间';
 
 CREATE TABLE IF NOT EXISTS chat_history (
     id bigserial PRIMARY KEY, -- 主键
     user_id text NULL, -- 用户id
-    "user_Q" text NULL, -- 用户提问
-    "chat_A" text NULL, -- chat回答
+    user_q text NULL, -- 用户提问
+    chat_a text NULL, -- chat回答
     create_time timestamp(0) DEFAULT now() NULL, -- 创建时间
     update_time timestamp(0) DEFAULT now() NULL, -- 更改时间
     is_deleted int2 DEFAULT 0 NULL -- 是否删除
 );
 COMMENT ON COLUMN chat_history.id IS '主键';
 COMMENT ON COLUMN chat_history.user_id IS '用户id';
-COMMENT ON COLUMN chat_history."user_Q" IS '用户提问';
-COMMENT ON COLUMN chat_history."chat_A" IS 'chat回答';
+COMMENT ON COLUMN chat_history."user_q" IS '用户提问';
+COMMENT ON COLUMN chat_history."chat_a" IS 'chat回答';
 COMMENT ON COLUMN chat_history.create_time IS '创建时间';
 COMMENT ON COLUMN chat_history.update_time IS '更改时间';
 COMMENT ON COLUMN chat_history.is_deleted IS '是否删除';

+ 4 - 5
src/main/java/cn/jlsxwkj/RagChatApplication.java

@@ -12,9 +12,8 @@ import org.springframework.scheduling.annotation.EnableAsync;
 @EnableAsync
 public class RagChatApplication {
 
-	public static void main(String[] args) {
-		SpringApplication.run(RagChatApplication.class, args);
-		Log.warn(RagChatApplication.class, "Started Application");
-	}
-
+    public static void main(String[] args) {
+        SpringApplication.run(RagChatApplication.class, args);
+        Log.warn(RagChatApplication.class, "Started Application");
+    }
 }

+ 2 - 0
src/main/java/cn/jlsxwkj/common/R/Response.java

@@ -3,6 +3,8 @@ package cn.jlsxwkj.common.R;
 import lombok.Data;
 
 /**
+ * 响应封装父类.
+ *
  * @author zh
  */
 @Data

+ 3 - 1
src/main/java/cn/jlsxwkj/common/R/ResponseError.java

@@ -4,8 +4,9 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 
 /**
+ * 响应异常封装.
+ *
  * @author zh
- * 异常封装类
  */
 @EqualsAndHashCode(callSuper = true)
 @Data
@@ -23,6 +24,7 @@ public class ResponseError extends Response {
 
     /**
      * response error.
+     *
      * @param exception 异常名称
      * @return 封装后的异常对象
      */

+ 3 - 0
src/main/java/cn/jlsxwkj/common/R/ResponseSucceed.java

@@ -5,6 +5,8 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 
 /**
+ * 响应成功封装.
+ *
  * @author zh
  */
 @EqualsAndHashCode(callSuper = true)
@@ -18,6 +20,7 @@ public class ResponseSucceed extends Response {
 
     /**
      * response success.
+     *
      * @param data 数据
      * @return 返回响应成功对象
      */

+ 0 - 4
src/main/java/cn/jlsxwkj/common/R/package-info.java

@@ -1,4 +0,0 @@
-/**
- * 数据封装包.
- */
-package cn.jlsxwkj.common.R;

+ 16 - 6
src/main/java/cn/jlsxwkj/common/config/FunctionCallConfig.java

@@ -8,10 +8,13 @@ import org.springframework.ai.model.function.FunctionCallbackWrapper;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
-import java.io.IOException;
 import java.net.InetAddress;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
+ * 函数回调.
+ *
  * @author zh
  */
 @Configuration
@@ -24,24 +27,31 @@ public class FunctionCallConfig {
     private WeatherService weatherService;
 
     /**
+     * 函数回调集合.
+     */
+    public static final Set<String> TOOLS_FUNCTION = new HashSet<>();
+
+    /**
      * 获取天气.
+     *
      * @return 返回回调函数
      */
     @Bean
     public FunctionCallback getWeather() {
         try {
             InetAddress byName = InetAddress.getByName("www.baidu.com");
+            TOOLS_FUNCTION.add("getWeather");
             int timeOut = 1000;
             if (byName.isReachable(timeOut)) {
                 Log.info(this.getClass(), "互联网畅通");
                 return FunctionCallbackWrapper.builder(weatherService)
-                        .withName("getWeather")
-                        .withDescription("获取提供位置天气信息")
-                        .build();
+                    .withName("getWeather")
+                    .withDescription("获取提供位置天气信息")
+                    .build();
             }
+            Log.info(this.getClass(), "互联网阻塞");
+        } catch (Exception e) {
             Log.info(this.getClass(), "未连接互联网");
-        } catch (IOException e) {
-            e.printStackTrace();
         }
         return null;
     }

+ 7 - 10
src/main/java/cn/jlsxwkj/common/config/RateLimiterConfig.java

@@ -10,8 +10,9 @@ import org.springframework.context.annotation.Configuration;
 import java.time.Duration;
 
 /**
+ * 限流.
+ *
  * @author zh
- * 限流
  */
 @Configuration
 public class RateLimiterConfig {
@@ -24,19 +25,15 @@ public class RateLimiterConfig {
 
     /**
      * 桶.
+     *
      * @return 返回桶
      */
     @Bean
     public Bucket bucket() {
-        Bandwidth limit = Bandwidth.classic(
-                userConfig.getGenTokens(),
-                Refill.greedy(
-                        userConfig.getGenTokens(),
-                        Duration.ofSeconds(userConfig.getRateLimitSec())
-                )
-        );
         return Bucket.builder()
-                .addLimit(limit)
-                .build();
+            .addLimit(Bandwidth.classic(
+                userConfig.getGenTokens(),
+                Refill.greedy(userConfig.getGenTokens(), Duration.ofSeconds(userConfig.getRateLimitSec()))
+            )).build();
     }
 }

+ 4 - 3
src/main/java/cn/jlsxwkj/common/config/SaTokenConfig.java

@@ -7,6 +7,8 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
 /**
+ * 登录认证.
+ *
  * @author zh
  */
 @Configuration
@@ -19,8 +21,7 @@ public class SaTokenConfig implements WebMvcConfigurer {
      */
     @Override
     public void addInterceptors(final InterceptorRegistry registry) {
-        registry.addInterceptor(
-                new SaInterceptor(handler -> StpUtil.checkLogin()))
-                .addPathPatterns("/**");
+        registry.addInterceptor(new SaInterceptor(handler -> StpUtil.checkLogin()))
+            .addPathPatterns("/**");
     }
 }

+ 2 - 8
src/main/java/cn/jlsxwkj/common/config/UserConfig.java

@@ -5,6 +5,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.stereotype.Component;
 
 /**
+ * 自定义配置类.
+ *
  * @author zh
  */
 @Data
@@ -25,14 +27,6 @@ public class UserConfig {
      */
     private String sysMessage = "Always say you're an ai or 大模型";
     /**
-     * 消息列表最大长度.
-     */
-    private Integer maxListMessageLength = 10;
-    /**
-     * 机器人每条消息最大长度, 超过会截取.
-     */
-    private Integer maxMessageLength = 512;
-    /**
      * 打印 api 大于指定执行时间.
      */
     private Integer execTime = 100;

+ 0 - 4
src/main/java/cn/jlsxwkj/common/config/package-info.java

@@ -1,4 +0,0 @@
-/**
- * 配置包.
- */
-package cn.jlsxwkj.common.config;

+ 2 - 0
src/main/java/cn/jlsxwkj/common/dao/Dao.java

@@ -3,6 +3,8 @@ package cn.jlsxwkj.common.dao;
 import lombok.Data;
 
 /**
+ * 实体父类.
+ *
  * @author zh
  */
 @Data

+ 0 - 4
src/main/java/cn/jlsxwkj/common/dao/package-info.java

@@ -1,4 +0,0 @@
-/**
- * 实体包.
- */
-package cn.jlsxwkj.common.dao;

+ 2 - 1
src/main/java/cn/jlsxwkj/common/exception/AccountAuthFailException.java

@@ -1,8 +1,9 @@
 package cn.jlsxwkj.common.exception;
 
 /**
+ * 用户注册失败异常.
+ *
  * @author zh
- * 用户注册失败异常
  */
 public class AccountAuthFailException extends CustomException {
 

+ 2 - 1
src/main/java/cn/jlsxwkj/common/exception/AccountPasswordCheckFailException.java

@@ -1,8 +1,9 @@
 package cn.jlsxwkj.common.exception;
 
 /**
+ * 用户密码检查未通过.
+ *
  * @author zh
- * 用户密码检查未通过
  */
 public class AccountPasswordCheckFailException extends CustomException {
 

+ 2 - 1
src/main/java/cn/jlsxwkj/common/exception/CustomException.java

@@ -1,8 +1,9 @@
 package cn.jlsxwkj.common.exception;
 
 /**
+ * 抽象自定义异常类, 用于统一捕捉异常.
+ *
  * @author zh
- * 抽象自定义异常类, 用于统一捕捉异常
  */
 public abstract class CustomException extends Exception {
 

+ 2 - 1
src/main/java/cn/jlsxwkj/common/exception/FileDeleteFailException.java

@@ -1,8 +1,9 @@
 package cn.jlsxwkj.common.exception;
 
 /**
+ * 文件删除失败.
+ *
  * @author zh
- * 文件删除失败
  */
 @SuppressWarnings("unused")
 public class FileDeleteFailException extends CustomException {

+ 2 - 1
src/main/java/cn/jlsxwkj/common/exception/FileTypeDoesNotSupportException.java

@@ -1,8 +1,9 @@
 package cn.jlsxwkj.common.exception;
 
 /**
+ * 文件类型不支持.
+ *
  * @author zh
- * 文件类型不支持
  */
 public class FileTypeDoesNotSupportException extends CustomException {
 

+ 2 - 1
src/main/java/cn/jlsxwkj/common/exception/InsertFailException.java

@@ -1,8 +1,9 @@
 package cn.jlsxwkj.common.exception;
 
 /**
+ * 插入失败.
+ *
  * @author zh
- * 插入失败
  */
 public class InsertFailException extends CustomException {
     /**

+ 2 - 1
src/main/java/cn/jlsxwkj/common/exception/LoginAccountAlreadyLoginException.java

@@ -1,8 +1,9 @@
 package cn.jlsxwkj.common.exception;
 
 /**
+ * 重复登录.
+ *
  * @author zh
- * 重复登录
  */
 public class LoginAccountAlreadyLoginException extends CustomException {
 

+ 2 - 1
src/main/java/cn/jlsxwkj/common/exception/LoginWrongPasswordException.java

@@ -1,8 +1,9 @@
 package cn.jlsxwkj.common.exception;
 
 /**
+ * 登录密码错误.
+ *
  * @author zh
- * 登录密码错误
  */
 public class LoginWrongPasswordException extends CustomException {
 

+ 2 - 1
src/main/java/cn/jlsxwkj/common/exception/NotContentInFileException.java

@@ -1,8 +1,9 @@
 package cn.jlsxwkj.common.exception;
 
 /**
+ * 文件中没有内容.
+ *
  * @author zh
- * 文件中没有内容
  */
 @SuppressWarnings("unused")
 public class NotContentInFileException extends CustomException {

+ 2 - 0
src/main/java/cn/jlsxwkj/common/exception/OpenFileFailException.java

@@ -1,6 +1,8 @@
 package cn.jlsxwkj.common.exception;
 
 /**
+ * 打开文件失败.
+ *
  * @author zh
  */
 public class OpenFileFailException extends CustomException {

+ 2 - 1
src/main/java/cn/jlsxwkj/common/exception/TooManyRequestsException.java

@@ -1,8 +1,9 @@
 package cn.jlsxwkj.common.exception;
 
 /**
+ * 太多请求.
+ *
  * @author zh
- * 太多请求
  */
 public class TooManyRequestsException extends CustomException {
 

+ 2 - 1
src/main/java/cn/jlsxwkj/common/exception/UnknownException.java

@@ -1,8 +1,9 @@
 package cn.jlsxwkj.common.exception;
 
 /**
+ * 未知错误.
+ *
  * @author zh
- * 未知错误
  */
 public class UnknownException extends CustomException {
 

+ 0 - 4
src/main/java/cn/jlsxwkj/common/exception/package-info.java

@@ -1,4 +0,0 @@
-/**
- * 异常包.
- */
-package cn.jlsxwkj.common.exception;

+ 13 - 9
src/main/java/cn/jlsxwkj/common/filter/ExecTimeFilter.java

@@ -3,13 +3,19 @@ package cn.jlsxwkj.common.filter;
 import cn.jlsxwkj.common.config.UserConfig;
 import cn.jlsxwkj.common.utils.Log;
 import jakarta.annotation.Resource;
-import jakarta.servlet.*;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
 import jakarta.servlet.http.HttpServletRequest;
 import org.springframework.stereotype.Component;
 
 import java.io.IOException;
 
 /**
+ * 打印超时 api.
+ *
  * @author zh
  */
 @Component
@@ -30,18 +36,16 @@ public class ExecTimeFilter implements Filter {
      */
     @Override
     public void doFilter(
-            final ServletRequest servletRequest,
-            final ServletResponse servletResponse,
-            final FilterChain filterChain)
-            throws IOException, ServletException {
+        final ServletRequest servletRequest,
+        final ServletResponse servletResponse,
+        final FilterChain filterChain)
+        throws IOException, ServletException {
         long startTime = System.currentTimeMillis();
-        String url = ((HttpServletRequest) servletRequest)
-                .getRequestURL().toString();
+        String url = ((HttpServletRequest) servletRequest).getRequestURL().toString();
         filterChain.doFilter(servletRequest, servletResponse);
         long execTime = System.currentTimeMillis() - startTime;
         if (execTime > userConfig.getExecTime()) {
-            Log.warn(this.getClass(),
-                    "api: {}, exec_time ====> {}ms", url, execTime);
+            Log.warn(this.getClass(), "api: {}, exec_time ====> {}ms", url, execTime);
         }
     }
 

+ 15 - 10
src/main/java/cn/jlsxwkj/common/filter/RateLimiterFilter.java

@@ -5,7 +5,11 @@ import cn.jlsxwkj.common.R.ResponseError;
 import cn.jlsxwkj.common.exception.TooManyRequestsException;
 import io.github.bucket4j.Bucket;
 import jakarta.annotation.Resource;
-import jakarta.servlet.*;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
 import jakarta.servlet.http.HttpServletResponse;
 import org.springframework.http.HttpStatus;
 import org.springframework.stereotype.Component;
@@ -13,6 +17,8 @@ import org.springframework.stereotype.Component;
 import java.io.IOException;
 
 /**
+ * 限流.
+ *
  * @author zh
  */
 @Component
@@ -25,23 +31,22 @@ public class RateLimiterFilter implements Filter {
     private Bucket bucket;
 
     /**
-     * @param request ServletRequest
+     * @param request  ServletRequest
      * @param response ServletResponse
-     * @param chain FilterChain
-     * @throws IOException IOException
+     * @param chain    FilterChain
+     * @throws IOException      IOException
      * @throws ServletException ServletException
      */
     @Override
     public void doFilter(
-            final ServletRequest request,
-            final ServletResponse response,
-            final FilterChain chain)
-            throws IOException, ServletException {
+        final ServletRequest request,
+        final ServletResponse response,
+        final FilterChain chain)
+        throws IOException, ServletException {
         if (bucket.tryConsume(1)) {
             chain.doFilter(request, response);
         } else {
-            ResponseError data = ResponseError.data(
-                    TooManyRequestsException.class.getName());
+            ResponseError data = ResponseError.data(TooManyRequestsException.class.getName());
             data.setMessage("请求次数过多, 请稍后再试");
             data.setCode(HttpStatus.TEMPORARY_REDIRECT.value());
 

+ 0 - 4
src/main/java/cn/jlsxwkj/common/filter/package-info.java

@@ -1,4 +0,0 @@
-/**
- * filter.
- */
-package cn.jlsxwkj.common.filter;

+ 10 - 20
src/main/java/cn/jlsxwkj/common/handler/GlobalRestExceptionHandler.java

@@ -5,16 +5,15 @@ import cn.jlsxwkj.common.R.ResponseError;
 import cn.jlsxwkj.common.exception.CustomException;
 import cn.jlsxwkj.common.exception.InsertFailException;
 import cn.jlsxwkj.common.utils.Log;
-import cn.jlsxwkj.moudles.log_error.LogError;
 import cn.jlsxwkj.moudles.log_error.LogErrorService;
 import jakarta.annotation.Resource;
 import org.springframework.web.ErrorResponse;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
 
-import java.util.Arrays;
-
 /**
+ * 全局异常捕捉.
+ *
  * @author zh
  */
 @RestControllerAdvice
@@ -36,7 +35,7 @@ public class GlobalRestExceptionHandler {
     public ResponseError exception(final Throwable e) {
 
         ResponseError responseError =
-                ResponseError.data(e.getClass().getName());
+            ResponseError.data(e.getClass().getName());
 
         if (e instanceof CustomException) {
             responseError.setMessage(e.getMessage());
@@ -50,26 +49,17 @@ public class GlobalRestExceptionHandler {
             responseError.setMessage("账户未登录");
         }
 
-        LogError errorHandlerToLogError =
-                new LogError().castResponseErrorToLogError(responseError);
-        errorHandlerToLogError.setErrorInfo(e.getMessage());
-        errorHandlerToLogError.setErrorStackTrace(
-                Arrays.toString(e.getStackTrace()));
+        Log.error(e.getClass(), "Code       ====> {}", responseError.getCode());
+        Log.error(e.getClass(), "Exception  ====> {}", responseError.getException());
+        Log.error(e.getClass(), "Message    ====> {}", responseError.getMessage());
+        e.printStackTrace();
+
         try {
-            logErrorService.insertOne(errorHandlerToLogError);
+            logErrorService.insertOne(e);
         } catch (InsertFailException insertFailException) {
-            Log.warn(this.getClass(), insertFailException.getMessage());
+            insertFailException.printStackTrace();
         }
 
-        Log.error(e.getClass(),
-                "Code       ====> {}", responseError.getCode());
-        Log.error(e.getClass(),
-                "Exception  ====> {}", responseError.getException());
-        Log.error(e.getClass(),
-                "Message    ====> {}", responseError.getMessage());
-
-        Log.info(this.getClass(), Arrays.toString(e.getStackTrace()));
-
         return responseError;
     }
 }

+ 10 - 9
src/main/java/cn/jlsxwkj/common/handler/ResultResponseHandler.java

@@ -17,8 +17,9 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
 import java.util.Arrays;
 
 /**
+ * ControllerAdvice 绑定的Controller包的权限定名 例如:com.dj.Controller.
+ *
  * @author Joker DJ
- * ControllerAdvice 绑定的Controller包的权限定名 例如:com.dj.Controller
  */
 @ControllerAdvice(basePackages = "cn.jlsxwkj.moudles")
 public class ResultResponseHandler implements ResponseBodyAdvice<Object> {
@@ -32,8 +33,8 @@ public class ResultResponseHandler implements ResponseBodyAdvice<Object> {
      */
     @Override
     public boolean supports(
-            @Nullable final MethodParameter methodParameter,
-            @Nullable final Class<? extends HttpMessageConverter<?>> aClass) {
+        @Nullable final MethodParameter methodParameter,
+        @Nullable final Class<? extends HttpMessageConverter<?>> aClass) {
         return true;
     }
 
@@ -50,12 +51,12 @@ public class ResultResponseHandler implements ResponseBodyAdvice<Object> {
      */
     @Override
     public Object beforeBodyWrite(
-            @Nullable final Object o,
-            @Nullable final MethodParameter methodParameter,
-            @Nullable final MediaType mediaType,
-            @Nullable final Class<? extends HttpMessageConverter<?>> aClass,
-            @Nullable final ServerHttpRequest serverHttpRequest,
-            @Nullable final ServerHttpResponse serverHttpResponse) {
+        @Nullable final Object o,
+        @Nullable final MethodParameter methodParameter,
+        @Nullable final MediaType mediaType,
+        @Nullable final Class<? extends HttpMessageConverter<?>> aClass,
+        @Nullable final ServerHttpRequest serverHttpRequest,
+        @Nullable final ServerHttpResponse serverHttpResponse) {
         // 对请求的结果在这里统一返回和处理
         if (o instanceof ResponseError errorHandler) {
             // 1、如果返回的结果是一个异常的结果,就把异常返回的结构数据倒腾到R.fail里面即可

+ 0 - 4
src/main/java/cn/jlsxwkj/common/handler/package-info.java

@@ -1,4 +0,0 @@
-/**
- * 异常捕获包.
- */
-package cn.jlsxwkj.common.handler;

+ 10 - 16
src/main/java/cn/jlsxwkj/common/reader/ParagraphDocReader.java

@@ -16,8 +16,9 @@ import java.io.InputStream;
 import java.util.List;
 
 /**
+ * 文档读取.
+ *
  * @author zh
- * 文档读取
  */
 @Data
 public class ParagraphDocReader implements DocumentReader {
@@ -59,20 +60,20 @@ public class ParagraphDocReader implements DocumentReader {
      * doc reader.
      *
      * @param bytes 文件数据
-     * @param fn    文件名
-     * @param ws    窗口大小
+     * @param name    文件名
+     * @param size    窗口大小
      */
     public ParagraphDocReader(final byte[] bytes,
-                              final String fn,
-                              final int ws) {
+                              final String name,
+                              final int size) {
         this.textFormatter = ExtractedTextFormatter.defaults();
         this.parser = new AutoDetectParser();
         this.handler = new BodyContentHandler(-1);
         this.metadata = new Metadata();
         this.context = new ParseContext();
         this.inputStream = new ByteArrayInputStream(bytes);
-        this.windowSize = ws;
-        this.fileName = fn;
+        this.windowSize = size;
+        this.fileName = name;
     }
 
     /**
@@ -83,17 +84,10 @@ public class ParagraphDocReader implements DocumentReader {
     @Override
     public List<Document> get() {
         try {
-            this.parser.parse(
-                    this.inputStream,
-                    this.handler,
-                    this.metadata,
-                    this.context);
+            this.parser.parse(this.inputStream, this.handler, this.metadata, this.context);
         } catch (Exception e) {
             e.printStackTrace();
         }
-        return SplitDocument.splitStringToListDocument(
-                this.handler.toString(),
-                this.windowSize,
-                this.fileName);
+        return SplitDocument.splitStringToListDocument(this.handler.toString(), this.windowSize, this.fileName);
     }
 }

+ 9 - 13
src/main/java/cn/jlsxwkj/common/reader/ParagraphOcrReader.java

@@ -13,6 +13,8 @@ import java.nio.charset.StandardCharsets;
 import java.util.List;
 
 /**
+ * 图片读取.
+ *
  * @author zh
  */
 @Data
@@ -41,10 +43,10 @@ public class ParagraphOcrReader implements DocumentReader {
     /**
      * ocr reader.
      *
-     * @param file   文件
-     * @param name  文件名
-     * @param url ocr 地址
-     * @param ws  窗口大小
+     * @param file 文件
+     * @param name 文件名
+     * @param url  ocr 地址
+     * @param ws   窗口大小
      */
     public ParagraphOcrReader(final byte[] file,
                               final String name,
@@ -63,17 +65,11 @@ public class ParagraphOcrReader implements DocumentReader {
      */
     @Override
     public List<Document> get() {
-        String image = HttpRequest.post(cnocrUrl)
-                .form("image", bytes, fileName)
-                .execute()
-                .body();
+        String image = HttpRequest.post(cnocrUrl).form("image", bytes, fileName).execute().body();
         StringBuilder sb = new StringBuilder();
         new JSONArray(new JSONObject(image).get("results")).forEach(x ->
-                sb.append(new JSONObject(x).get("text")).append(" "));
+            sb.append(new JSONObject(x).get("text")).append(" "));
         String document = sb.toString();
-        return SplitDocument.splitStringToListDocument(
-                document,
-                this.windowSize,
-                this.fileName);
+        return SplitDocument.splitStringToListDocument(document, this.windowSize, this.fileName);
     }
 }

+ 3 - 5
src/main/java/cn/jlsxwkj/common/reader/ParagraphTextReader.java

@@ -15,8 +15,9 @@ import java.nio.charset.StandardCharsets;
 import java.util.List;
 
 /**
+ * 文本读取.
+ *
  * @author zh
- * 文本读取
  */
 @Data
 public class ParagraphTextReader implements DocumentReader {
@@ -67,9 +68,6 @@ public class ParagraphTextReader implements DocumentReader {
             e.printStackTrace();
         }
         assert document != null;
-        return SplitDocument.splitStringToListDocument(
-                document,
-                this.windowSize,
-                this.fileName);
+        return SplitDocument.splitStringToListDocument(document, this.windowSize, this.fileName);
     }
 }

+ 0 - 4
src/main/java/cn/jlsxwkj/common/reader/package-info.java

@@ -1,4 +0,0 @@
-/**
- * 文档切割包.
- */
-package cn.jlsxwkj.common.reader;

+ 4 - 2
src/main/java/cn/jlsxwkj/common/utils/CheckPassword.java

@@ -4,6 +4,8 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 /**
+ * 密码校验.
+ *
  * @author LL
  */
 public final class CheckPassword {
@@ -14,12 +16,12 @@ public final class CheckPassword {
      * 密码长度为8到20位,必须包含字母和数字,字母区分大小写.
      */
     private static final String
-            REG_EX1 = "^(?=.*[0-9])(?=.*[a-zA-Z])(.{8,20})$";
+        REG_EX1 = "^(?=.*[0-9])(?=.*[a-zA-Z])(.{8,20})$";
     /**
      * 密码中必须包含字母、数字、特称字符,至少8个字符,最多16个字符.
      */
     private static final String
-            REG_EX2 = "^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9])(.{8,16})$";
+        REG_EX2 = "^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9])(.{8,16})$";
 
     /**
      * 密码长度为8到20位,必须包含字母和数字,字母区分大小写.

+ 5 - 6
src/main/java/cn/jlsxwkj/common/utils/FileType.java

@@ -9,6 +9,8 @@ import java.util.HashMap;
 import java.util.Map;
 
 /**
+ * 校验支持的文件类型并创建 reader.
+ *
  * @author zh
  */
 public class FileType {
@@ -29,12 +31,9 @@ public class FileType {
                     final String fileName,
                     final int winSize,
                     final String cnocrUrl) {
-        TYPE.put("txt", new Tuple("文本",
-                new ParagraphTextReader(bytes, fileName, winSize)));
-        TYPE.put("doc docx", new Tuple("文档",
-                new ParagraphDocReader(bytes, fileName, winSize)));
-        TYPE.put("jpg png", new Tuple("图片",
-                new ParagraphOcrReader(bytes, fileName, cnocrUrl, winSize)));
+        TYPE.put("txt", new Tuple("文本", new ParagraphTextReader(bytes, fileName, winSize)));
+        TYPE.put("doc docx", new Tuple("文档", new ParagraphDocReader(bytes, fileName, winSize)));
+        TYPE.put("jpg png", new Tuple("图片", new ParagraphOcrReader(bytes, fileName, cnocrUrl, winSize)));
     }
 
     /**

+ 3 - 3
src/main/java/cn/jlsxwkj/common/utils/Log.java

@@ -6,8 +6,9 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
+ * 打印日志对象缓存池.
+ *
  * @author zh
- * 打印日志对象缓存池
  */
 public final class Log {
     private Log() {
@@ -16,8 +17,7 @@ public final class Log {
     /**
      * Log 对象池.
      */
-    private static final Map<String, Slf4jLog>
-            CACHE_LOGS = new ConcurrentHashMap<>();
+    private static final Map<String, Slf4jLog> CACHE_LOGS = new ConcurrentHashMap<>();
 
     /**
      * 打印 info 级别的日志.

+ 12 - 29
src/main/java/cn/jlsxwkj/common/utils/MergeDocuments.java

@@ -10,6 +10,8 @@ import java.util.Optional;
 import java.util.stream.Collectors;
 
 /**
+ * 合并文档.
+ *
  * @author jay
  */
 public final class MergeDocuments {
@@ -23,25 +25,16 @@ public final class MergeDocuments {
      * @return 合并后的文档列表
      */
     public static List<Document> mergeDocuments(
-            final List<Document> documentList) {
+        final List<Document> documentList) {
         ArrayList<Document> mergeDocuments = new ArrayList<>();
         //根据文档来源进行分组
-        for (var docListEntry : documentList.stream().collect(
-                Collectors.groupingBy(document -> (String)
-                        document.getMetadata()
-                                .get(SplitDocument.FILE_NAME)
-                )).entrySet()) {
+        for (var docListEntry : documentList.stream().collect(Collectors.groupingBy(document -> (String) document.getMetadata().get(SplitDocument.FILE_NAME))).entrySet()) {
             //获取最大的段落结束编码
-            Optional<Document> documents = docListEntry.getValue().stream().max(
-                    Comparator.comparing(document -> (int)
-                            document.getMetadata()
-                                    .get(SplitDocument.END_PARAGRAPH_NUMBER)
-                    ));
+            Optional<Document> documents = docListEntry.getValue().stream().max(Comparator.comparing(document -> (int) document.getMetadata().get(SplitDocument.END_PARAGRAPH_NUMBER)));
             if (documents.isEmpty()) {
                 continue;
             }
-            int maxParagraphNum = (int) documents.get().getMetadata()
-                    .get(SplitDocument.END_PARAGRAPH_NUMBER);
+            int maxParagraphNum = (int) documents.get().getMetadata().get(SplitDocument.END_PARAGRAPH_NUMBER);
             //根据最大段落结束编码构建一个用于合并段落的空数组
             String[] paragraphs = new String[maxParagraphNum];
             //用于获取最小段落开始编码
@@ -50,31 +43,21 @@ public final class MergeDocuments {
                 //文档内容根据回车进行分段
                 String[] tempPs = document.getContent().split("\n");
                 //获取文档开始段落编码
-                int startParagraphNumber = (int) document.getMetadata()
-                        .get(SplitDocument.START_PARAGRAPH_NUMBER);
+                int startParagraphNumber = (int) document.getMetadata().get(SplitDocument.START_PARAGRAPH_NUMBER);
                 if (minParagraphNum > startParagraphNumber) {
                     minParagraphNum = startParagraphNumber;
                 }
                 //将文档段落列表拷贝到合并段落数组中
-                System.arraycopy(
-                        tempPs,
-                        0,
-                        paragraphs,
-                        startParagraphNumber - 1,
-                        tempPs.length);
+                System.arraycopy(tempPs, 0, paragraphs, startParagraphNumber - 1, tempPs.length);
             }
             //合并段落去除空值,并组成文档内容
-            Document mergeDoc = new Document(
-                    ArrayUtil.join(ArrayUtil.removeNull(paragraphs), "\n"));
+            Document mergeDoc = new Document(ArrayUtil.join(ArrayUtil.removeNull(paragraphs), "\n"));
             //合并元数据
-            mergeDoc.getMetadata().putAll(docListEntry.getValue()
-                    .get(0).getMetadata());
+            mergeDoc.getMetadata().putAll(docListEntry.getValue().get(0).getMetadata());
             //设置元数据:开始段落编码
-            mergeDoc.getMetadata()
-                    .put(SplitDocument.START_PARAGRAPH_NUMBER, minParagraphNum);
+            mergeDoc.getMetadata().put(SplitDocument.START_PARAGRAPH_NUMBER, minParagraphNum);
             //设置元数据:结束段落编码
-            mergeDoc.getMetadata()
-                    .put(SplitDocument.END_PARAGRAPH_NUMBER, maxParagraphNum);
+            mergeDoc.getMetadata().put(SplitDocument.END_PARAGRAPH_NUMBER, maxParagraphNum);
             mergeDocuments.add(mergeDoc);
         }
         return mergeDocuments;

+ 9 - 20
src/main/java/cn/jlsxwkj/common/utils/SplitDocument.java

@@ -9,6 +9,8 @@ import java.util.List;
 import java.util.stream.Collectors;
 
 /**
+ * 分割文档.
+ *
  * @author jay
  */
 public final class SplitDocument {
@@ -37,36 +39,23 @@ public final class SplitDocument {
      * @return 多个文档
      */
     public static List<Document> splitStringToListDocument(
-            final String document,
-            final int windowSize,
-            final String fileName) {
+        final String document,
+        final int windowSize,
+        final String fileName) {
         if (document.isBlank()) {
             return null;
         }
         ArrayList<Document> readDocuments = new ArrayList<>();
-        List<String> paragraphs = Arrays.stream(document.split("\n")).distinct()
-                .dropWhile(""::equals)
-                .collect(Collectors.toList());
+        List<String> paragraphs = Arrays.stream(document.split("\n")).distinct().dropWhile(""::equals).collect(Collectors.toList());
         //采用窗口滑动读取
         int startIndex = 0;
         int endIndex = startIndex + windowSize;
         if (endIndex > paragraphs.size()) {
-            readDocuments.add(toDocument(
-                    paragraphs,
-                    fileName,
-                    startIndex + 1,
-                    paragraphs.size()));
+            readDocuments.add(toDocument(paragraphs, fileName, startIndex + 1, paragraphs.size()));
         } else {
             for (; endIndex <= paragraphs.size(); startIndex++, endIndex++) {
-                List<String> sub = ListUtil.sub(
-                        paragraphs,
-                        startIndex,
-                        endIndex);
-                readDocuments.add(toDocument(
-                        sub,
-                        fileName,
-                        startIndex + 1,
-                        endIndex));
+                List<String> sub = ListUtil.sub(paragraphs, startIndex, endIndex);
+                readDocuments.add(toDocument(sub, fileName, startIndex + 1, endIndex));
             }
         }
         return readDocuments;

+ 0 - 4
src/main/java/cn/jlsxwkj/common/utils/package-info.java

@@ -1,4 +0,0 @@
-/**
- * 工具包.
- */
-package cn.jlsxwkj.common.utils;

+ 10 - 14
src/main/java/cn/jlsxwkj/moudles/chat/ChatController.java

@@ -5,7 +5,11 @@ import cn.jlsxwkj.common.exception.CustomException;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import jakarta.annotation.Resource;
 import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.multipart.MultipartFile;
 import reactor.core.publisher.Flux;
 
@@ -33,7 +37,7 @@ public class ChatController {
     @PostMapping("/upload")
     @SaIgnore
     public String uploadDoc(
-            @RequestBody final MultipartFile file) throws CustomException {
+        @RequestBody final MultipartFile file) throws CustomException {
         return chatService.uploadDocument(file);
     }
 
@@ -55,7 +59,7 @@ public class ChatController {
      * @return 流消息
      */
     @PostMapping(value = "/chatStream",
-            produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
+        produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
     public Flux<String> chatStream(@RequestParam final String message) {
         return chatService.chatStream(message);
     }
@@ -68,18 +72,10 @@ public class ChatController {
      * @return 流消息
      */
     @PostMapping(value = "/chatSummaryStream",
-            produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
+        produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
     public Flux<String> chatSummaryStream(
-            @RequestParam(defaultValue = "帮我总结一下上面内容") final String message,
-            @RequestBody final MultipartFile file) {
+        @RequestParam(defaultValue = "帮我总结一下上面内容") final String message,
+        @RequestBody final MultipartFile file) {
         return chatService.chatSummaryStream(message, file);
     }
-
-    /**
-     * 停止问答.
-     */
-    @GetMapping("/stopChat")
-    public void stopChat() {
-        chatService.stop();
-    }
 }

+ 0 - 30
src/main/java/cn/jlsxwkj/moudles/chat/ChatRequest.java

@@ -1,30 +0,0 @@
-package cn.jlsxwkj.moudles.chat;
-
-import cn.jlsxwkj.moudles.chat.message.Message;
-import lombok.Data;
-import org.springframework.ai.chat.prompt.ChatOptions;
-
-import java.util.List;
-
-/**
- * @author zh
- */
-@Data
-public class ChatRequest {
-    /**
-     * 模型.
-     */
-    private String model;
-    /**
-     * 消息列表.
-     */
-    private List<Message> messages;
-    /**
-     * 是否流.
-     */
-    private Boolean stream;
-    /**
-     * chat 参数.
-     */
-    private ChatOptions options;
-}

+ 0 - 27
src/main/java/cn/jlsxwkj/moudles/chat/ChatResponse.java

@@ -1,27 +0,0 @@
-package cn.jlsxwkj.moudles.chat;
-
-import cn.jlsxwkj.moudles.chat.message.AssistantMessage;
-import lombok.Data;
-
-/**
- * @author zh
- */
-@Data
-public class ChatResponse {
-    /**
-     * 模型.
-     */
-    private String model;
-    /**
-     * 创建时间.
-     */
-    private String createdAt;
-    /**
-     * 机器人消息.
-     */
-    private AssistantMessage message;
-    /**
-     * 是否完成.
-     */
-    private Boolean done;
-}

+ 73 - 204
src/main/java/cn/jlsxwkj/moudles/chat/ChatService.java

@@ -3,14 +3,22 @@ package cn.jlsxwkj.moudles.chat;
 import cn.dev33.satoken.SaManager;
 import cn.hutool.core.lang.Tuple;
 import cn.hutool.crypto.digest.MD5;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
 import cn.jlsxwkj.common.config.UserConfig;
-import cn.jlsxwkj.common.exception.*;
+import cn.jlsxwkj.common.exception.CustomException;
+import cn.jlsxwkj.common.exception.FileTypeDoesNotSupportException;
+import cn.jlsxwkj.common.exception.InsertFailException;
+import cn.jlsxwkj.common.exception.OpenFileFailException;
+import cn.jlsxwkj.common.exception.UnknownException;
 import cn.jlsxwkj.common.utils.FileType;
 import cn.jlsxwkj.common.utils.Log;
 import cn.jlsxwkj.common.utils.MergeDocuments;
-import cn.jlsxwkj.moudles.chat.message.*;
 import cn.jlsxwkj.moudles.chat_history.ChatHistoryService;
 import jakarta.annotation.Resource;
+import org.springframework.ai.chat.messages.Message;
+import org.springframework.ai.chat.messages.SystemMessage;
+import org.springframework.ai.chat.messages.UserMessage;
 import org.springframework.ai.chat.prompt.Prompt;
 import org.springframework.ai.document.Document;
 import org.springframework.ai.document.DocumentReader;
@@ -25,9 +33,13 @@ import reactor.core.publisher.Flux;
 
 import java.io.File;
 import java.io.IOException;
-import java.util.*;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Collectors;
 
+import static cn.jlsxwkj.common.config.FunctionCallConfig.TOOLS_FUNCTION;
 
 /**
  * @author zh
@@ -42,20 +54,7 @@ public class ChatService {
     /**
      * 获取当前项目地址 + /ai_doc.
      */
-    private static final String
-            PATH = System.getProperty("user.dir") + "/ai_doc/";
-    /**
-     * 函数回调集合.
-     */
-    private static final HashSet<String> TOOLS_FUNCTION = new HashSet<>();
-    /**
-     * 历史消息列表.
-     */
-    private List<Message> listMessage;
-    /**
-     * chat 消息.
-     */
-    private StringBuffer chatMessage;
+    private static final String PATH = System.getProperty("user.dir") + "/ai_doc/";
     /**
      * pg 向量对象(将文档转换为向量并保存至数据库).
      */
@@ -72,11 +71,6 @@ public class ChatService {
     @Resource
     private EmbeddingModel embeddingModel;
     /**
-     * 自定义 chat 工具.
-     */
-    @Resource
-    private ChatUtil chatUtil;
-    /**
      * 保存对话对象(将对话保存至数据库).
      */
     @Resource
@@ -87,13 +81,6 @@ public class ChatService {
     @Resource
     private UserConfig userConfig;
 
-    /*
-      初始化回调函数
-     */
-    static {
-        TOOLS_FUNCTION.add("getWeather");
-    }
-
     /**
      * 使用spring ai解析txt文档并保存至 pg.
      *
@@ -101,24 +88,16 @@ public class ChatService {
      * @return 保存状态
      */
     public String uploadDocument(
-            final MultipartFile file) throws CustomException {
-        //检测文件是否支持
+        final MultipartFile file) throws CustomException {
         Tuple supportFile = isSupportFile(file);
-        //需要保存的文件
         File saveFile = supportFile.get(0);
-        //文件名
         String fileName = supportFile.get(1);
-        //分割文档对象
         DocumentReader reader = supportFile.get(3);
-        //判断文件是否存在
         if (!saveFile.exists()) {
             try {
-                //保存文件
                 file.transferTo(saveFile);
-                //保存文档到数据库
                 vectorStore.add(reader.get());
             } catch (Exception e) {
-                //保存文件到数据库失败删除本地缓存文件
                 boolean delete = saveFile.delete();
                 if (!delete) {
                     Log.warn(this.getClass(), "删除文件失败: {}", fileName);
@@ -136,12 +115,8 @@ public class ChatService {
      * @return 文本内容
      */
     public String search(final String keyword) {
-        //设置检索文档关键字相似度至少近似 50% 以上
-        SearchRequest searchRequest =
-                SearchRequest.query(keyword).withSimilarityThreshold(0.5);
-        //检索文档
+        SearchRequest searchRequest = SearchRequest.query(keyword).withSimilarityThreshold(0.5);
         List<Document> documents = vectorStore.similaritySearch(searchRequest);
-        //返回合并的文档
         return mergeDocuments(documents);
     }
 
@@ -152,27 +127,37 @@ public class ChatService {
      * @return 回答内容
      */
     public Flux<String> chatStream(final String message) {
-        //检索知识库
         String context = search(message);
-        //预处理
-        //创建用户消息
-        org.springframework.ai.chat.messages.UserMessage userMessage =
-                new org.springframework.ai.chat.messages.UserMessage(message);
-        //设置提示词以及添加回调函数
-        Prompt prompt = new Prompt(userMessage, OllamaOptions.builder()
-                .withFunctions(TOOLS_FUNCTION).build());
-        //预处理, chat 总结的函数结果
-        String toolMessage = ollamaChatModel.call(prompt)
-                .getResult().getOutput().getContent();
-        //合并知识库结果和函数结果
-        String format = """
+        Prompt prompt = new Prompt(List.of(
+            new SystemMessage(userConfig.getSysMessage()),
+            new UserMessage(message)),
+            OllamaOptions.builder().withFunctions(TOOLS_FUNCTION).build());
+        AtomicBoolean flag = new AtomicBoolean(false);
+        StringBuilder funcCall = new StringBuilder();
+        String funcCallResult = "";
+        Objects.requireNonNull(ollamaChatModel.stream(prompt)
+            .map(response -> {
+                String content = response.getResult().getOutput().getContent();
+                if (content.contains("<tool")) {
+                    flag.set(true);
+                }
+                return content;
+            }).collectList().block())
+            .forEach(funcCall::append);
+        if (flag.get()) {
+            String tool = funcCall.toString().split("\n")[1];
+            JSONObject entries = JSONUtil.parseObj(tool);
+            String funcName = entries.get("name", String.class);
+            String args = entries.get("arguments", String.class);
+            funcCallResult = ollamaChatModel.getFunctionCallbackRegister().get(funcName).call(args);
+        }
+        return stream(new UserMessage(message),
+            new SystemMessage("""
                 %s
                 %s
-                如果以上内容不为空请永远用以上内容回答问题
-                """;
-        //提问 chat 并返回流
-        return stream(message, new SystemMessage(
-                String.format(format, context, toolMessage, message)));
+                根据参考内容回答, 当内容和问题不匹配时不要参考 system context, 请参考 user context 回答
+                """.formatted(context, funcCallResult))
+        );
     }
 
     /**
@@ -184,34 +169,23 @@ public class ChatService {
      */
     public Flux<String> chatSummaryStream(final String message,
                                           final MultipartFile file) {
-        //检测模型是否开启
         embeddingModel.embed("");
-        //检测文件是否支持
         Tuple supportFile;
         try {
             supportFile = isSupportFile(file);
         } catch (CustomException e) {
-            //如果异常则通过流返回异常
             return Flux.just(e.getMessage()).concatWithValues("<{完成}>");
         }
-        //文件名
         String fileName = supportFile.get(1);
-        //文件类型
         String fileTypeCn = supportFile.get(2);
-        //分割文档对象
         DocumentReader reader = supportFile.get(3);
-        //格式化提问格式
-        String format = """
+        String document = mergeDocuments(reader.get());
+        return stream(new UserMessage(message),
+            new UserMessage("""
                 %s :: %s ====> %s
                 ↑ %s
-                """;
-        String context = String.format(format,
-                fileTypeCn, fileName, mergeDocuments(reader.get()), message);
-        //设置用户消息
-        UserMessage userMessage = new UserMessage(context);
-        Log.info(this.getClass(), context);
-        //返回 chat 流
-        return stream(message, userMessage);
+                """.formatted(fileTypeCn, fileName, document, message))
+        );
     }
 
     /**
@@ -222,120 +196,33 @@ public class ChatService {
      */
     private String mergeDocuments(final List<Document> documents) {
         return MergeDocuments.mergeDocuments(documents).stream()
-                .map(Document::getContent)
-                .collect(Collectors.joining("\n"));
+            .map(Document::getContent).collect(Collectors.joining("\n"));
     }
 
-    /**
-     * 停止 chat.
-     */
-    public void stop() {
-        chatUtil.stop();
-    }
-
-    /**
-     * 获取prompt.
-     *
-     * @param message 提问内容
-     * @param context 提示词
-     */
-    private void setChatMessage(final String message,
-                                final Message context) {
-        //初始化消息并设置系统提示词
-        if (listMessage == null) {
-            listMessage = new ArrayList<>();
-            listMessage.add(new SystemMessage(userConfig.getSysMessage()));
-        }
-        //判断消息列表是否大于定义的消息列表长度
-        if (listMessage.size() > userConfig.getMaxListMessageLength()) {
-            //缩减长度到指定列表长度
-            int start =
-                    listMessage.size() - userConfig.getMaxListMessageLength();
-            listMessage = listMessage.subList(start,
-                    listMessage.size()).stream()
-                    //过滤定义的定义的系统消息
-                    .filter(msg -> !msg.getContent()
-                            .equals(userConfig.getSysMessage()))
-                    .map(msg -> {
-                        //判断是否为 chat 消息, 如果是缩减 chat 回答后的长度
-                        if (msg.getRole().equals(UserRole.ASSISTANT)) {
-                            String content = msg.getContent();
-                            if (content.length()
-                                    > userConfig.getMaxMessageLength()) {
-                                return new AssistantMessage(content.substring(
-                                        0,
-                                        userConfig.getMaxMessageLength()));
-                            }
-                        }
-                        return msg;
-                    }).distinct()
-                    .collect(Collectors.toList());
-            //再次将自定义系统提示词添加到列表末尾
-            listMessage.add(new SystemMessage(userConfig.getSysMessage()));
-        }
-        //如果 context 是系统消息则将两个都添加
-        if (context.getRole().equals(UserRole.SYSTEM)) {
-            listMessage.add(new UserMessage(message));
-            //判断系统消息是否为空
-            if (!context.getContent().isBlank()) {
-                listMessage.add(context);
-            }
-        }
-        if (context.getRole().equals(UserRole.USER)) {
-            listMessage.add(context);
-        }
-    }
 
     /**
      * chat stream 封装.
      *
-     * @param message 提问内容
-     * @param context 提示词
+     * @param userMessage 提问内容
+     * @param sysOrUserMessage 用户或系统提示词
      * @return flux
      */
-    private Flux<String> stream(final String message,
-                                final Message context) {
-        //获取用户id
+    private Flux<String> stream(final Message userMessage,
+                                final Message sysOrUserMessage) {
         String userId = SaManager.getStpLogic("").getLoginIdAsString();
-        //初始化
-        chatMessage = new StringBuffer();
-        //设置消息列表
-        setChatMessage(message, context);
-        //返回消息流
-        return chatUtil.chat(listMessage, true).map(response -> {
-            //获取消息主体
-            String str = response.getMessage().getContent();
-            //添加至消息中
-            chatMessage.append(str);
-            //格式化字符串
-            return str.replace(" ", "  ")
-                    .replace("\t", "    ");
-        })
-                //流完成后拼接的字符
-                .concatWithValues("<{完成}>")
-                //取消时返回的调度器
-                .cancelOn(chatUtil.getScheduler())
-                //取消时执行的操作
-                .doOnCancel(() -> {
-                    //上游
-                    this.stop();
-                    Log.info(this.getClass(), "{} ==== 用户停止", userId);
-                })
-                //流完成时的操作
-                .doOnComplete(() -> {
-                    String chatMsg = chatMessage.toString();
-                    listMessage.add(new AssistantMessage(chatMsg));
-                    try {
-                        //将消息添加至数据库
-                        chatHistoryService.insert(userId, message, chatMsg);
-                    } catch (InsertFailException e) {
-                        Log.warn(this.getClass(), e.getMessage());
-                    }
-                    Log.info(this.getClass(),
-                            "{} user message ==> {}", userId, message);
-                    Log.info(this.getClass(),
-                            "{} chat message ==> {}", userId, chatMsg);
-                });
+        StringBuilder chatMessage = new StringBuilder();
+        return ollamaChatModel.stream(sysOrUserMessage, userMessage).map(response -> {
+            chatMessage.append(response);
+            return response.replace(" ", "  ").replace("\t", "    ");
+        }).concatWithValues("<{完成}>")
+            .doOnComplete(() -> {
+                String chatMsg = chatMessage.toString();
+                try {
+                    chatHistoryService.insert(userId, userMessage.getContent(), chatMsg);
+                } catch (InsertFailException e) {
+                    Log.warn(this.getClass(), e.getMessage());
+                }
+            });
     }
 
     /**
@@ -345,48 +232,30 @@ public class ChatService {
      * @return 元组
      */
     private Tuple isSupportFile(
-            final MultipartFile file) throws CustomException {
-        //初始化
+        final MultipartFile file) throws CustomException {
         byte[] bytes;
         try {
-            //读取文件
             bytes = file.getBytes();
         } catch (IOException e) {
             throw new OpenFileFailException("读取文件失败");
         }
-        //对文件名分割
-        String[] split = Objects.requireNonNull(file.getOriginalFilename())
-                .split("\\.");
-        //文件类型
+        String[] split = Objects.requireNonNull(file.getOriginalFilename()).split("\\.");
         String fileType = split[split.length - 1].toLowerCase(Locale.ROOT);
-        //保存文件地址
         File savePath = new File(PATH);
-        //保存文件
         File saveFile = new File(PATH + md5.digestHex(bytes) + "." + fileType);
-        //文件名
         String fileName = saveFile.getName();
-        //判断文件地址是否存在
         if (!savePath.exists()) {
-            //创建文件夹
             if (!savePath.mkdirs()) {
                 Log.warn(this.getClass(), "创建文件夹失败: " + PATH);
             }
         }
-        //获取文件的各参数
-        Tuple fileTypeAndResource = new FileType(
-                bytes,
-                fileName,
-                5,
-                userConfig.getCnocrUrl())
-                .getFileTypeAndResource(fileType);
+        Tuple fileTypeAndResource = new FileType(bytes, fileName, 5, userConfig.getCnocrUrl())
+            .getFileTypeAndResource(fileType);
         if (fileTypeAndResource == null) {
             throw new FileTypeDoesNotSupportException("暂不支持的文件类型: " + fileType);
         }
-        //文件类型(中文)
         String fileTypeCn = fileTypeAndResource.get(0);
-        //分割文档对象
         DocumentReader reader = fileTypeAndResource.get(1);
-        //返回(保存文件对象, 文件名, 文件类型中文名, 分割文档对象)
         return new Tuple(saveFile, fileName, fileTypeCn, reader);
     }
 }

+ 0 - 113
src/main/java/cn/jlsxwkj/moudles/chat/ChatUtil.java

@@ -1,113 +0,0 @@
-package cn.jlsxwkj.moudles.chat;
-
-import cn.hutool.http.HttpRequest;
-import cn.hutool.json.JSONUtil;
-import cn.jlsxwkj.common.config.UserConfig;
-import cn.jlsxwkj.common.utils.Log;
-import cn.jlsxwkj.moudles.chat.message.Message;
-import jakarta.annotation.Resource;
-import org.springframework.ai.autoconfigure.ollama.OllamaConnectionDetails;
-import org.springframework.ai.chat.model.ChatModel;
-import org.springframework.stereotype.Component;
-import reactor.core.publisher.Flux;
-import reactor.core.scheduler.Scheduler;
-import reactor.core.scheduler.Schedulers;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.List;
-
-/**
- * @author zh
- * chat 工具类, 用来请求上游 chat api
- */
-@Component
-public class ChatUtil {
-
-    /**
-     * ChatModel.
-     */
-    @Resource
-    private ChatModel chatModel;
-    /**
-     * model url.
-     */
-    @Resource
-    private OllamaConnectionDetails ollamaConnectionDetails;
-    /**
-     * InputStream.
-     */
-    private InputStream inputStream;
-    /**
-     * InputStreamReader.
-     */
-    private InputStreamReader inputStreamReader;
-    /**
-     * BufferedReader.
-     */
-    private BufferedReader bufferedReader;
-    /**
-     * Scheduler.
-     */
-    private final Scheduler scheduler = Schedulers.single();
-
-    /**
-     * 请求上游 chat api.
-     *
-     * @param messages 消息列表(带历史对话)
-     * @param isStream 是否流式返回
-     * @return 流式返回
-     */
-    public Flux<ChatResponse> chat(
-            final List<Message> messages,
-            final boolean isStream) {
-        ChatRequest chatRequest = new ChatRequest();
-        chatRequest.setModel(chatModel.getDefaultOptions().getModel());
-        chatRequest.setMessages(messages);
-        chatRequest.setStream(isStream);
-        chatRequest.setOptions(chatModel.getDefaultOptions());
-        Log.info(this.getClass(), JSONUtil.toJsonStr(chatRequest));
-        inputStream = HttpRequest.post(
-                ollamaConnectionDetails.getBaseUrl() + "/api/chat")
-                .body(JSONUtil.toJsonStr(chatRequest))
-                .execute(isStream)
-                .bodyStream();
-        inputStreamReader = new InputStreamReader(inputStream);
-        bufferedReader = new BufferedReader(inputStreamReader);
-        return Flux.fromStream(bufferedReader.lines())
-                .map(str -> JSONUtil.parse(str).toBean(ChatResponse.class))
-                .subscribeOn(scheduler, false);
-    }
-
-    /**
-     * 停止流.
-     */
-    public void stop() {
-        try {
-            bufferedReader.close();
-        } catch (IOException e) {
-            Log.error(e.getClass(), e.getMessage());
-        }
-        try {
-            inputStreamReader.close();
-        } catch (IOException e) {
-            Log.error(e.getClass(), e.getMessage());
-        }
-        try {
-            inputStream.close();
-        } catch (IOException e) {
-            Log.error(e.getClass(), e.getMessage());
-        }
-    }
-
-    /**
-     * 获取调度器.
-     *
-     * @return 调度器
-     */
-    public Scheduler getScheduler() {
-        return scheduler;
-    }
-}

+ 0 - 23
src/main/java/cn/jlsxwkj/moudles/chat/message/AssistantMessage.java

@@ -1,23 +0,0 @@
-package cn.jlsxwkj.moudles.chat.message;
-
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-/**
- * @author zh
- */
-@EqualsAndHashCode(callSuper = true)
-@Data
-public class AssistantMessage extends Message {
-
-    /**
-     * 机器人消息.
-     *
-     * @param message 消息
-     */
-    public AssistantMessage(final String message) {
-        this.setRole(UserRole.ASSISTANT);
-        this.setContent(message);
-    }
-
-}

+ 0 - 19
src/main/java/cn/jlsxwkj/moudles/chat/message/Message.java

@@ -1,19 +0,0 @@
-package cn.jlsxwkj.moudles.chat.message;
-
-import lombok.Data;
-
-/**
- * @author zh
- * 消息父类
- */
-@Data
-public abstract class Message {
-    /**
-     * 角色.
-     */
-    private String role;
-    /**
-     * 消息.
-     */
-    private String content;
-}

+ 0 - 22
src/main/java/cn/jlsxwkj/moudles/chat/message/SystemMessage.java

@@ -1,22 +0,0 @@
-package cn.jlsxwkj.moudles.chat.message;
-
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-/**
- * @author zh
- */
-@EqualsAndHashCode(callSuper = true)
-@Data
-public class SystemMessage extends Message {
-
-    /**
-     * 系统消息.
-     * @param message 消息
-     */
-    public SystemMessage(final String message) {
-        this.setRole(UserRole.SYSTEM);
-        this.setContent(message);
-    }
-
-}

+ 0 - 21
src/main/java/cn/jlsxwkj/moudles/chat/message/UserMessage.java

@@ -1,21 +0,0 @@
-package cn.jlsxwkj.moudles.chat.message;
-
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-
-/**
- * @author zh
- */
-@EqualsAndHashCode(callSuper = true)
-@Data
-public class UserMessage extends Message {
-
-    /**
-     * 用户消息.
-     * @param message 消息
-     */
-    public UserMessage(final String message) {
-        this.setRole(UserRole.USER);
-        this.setContent(message);
-    }
-}

+ 0 - 23
src/main/java/cn/jlsxwkj/moudles/chat/message/UserRole.java

@@ -1,23 +0,0 @@
-package cn.jlsxwkj.moudles.chat.message;
-
-/**
- * @author zh
- */
-public final class UserRole {
-    private UserRole() {
-    }
-
-    /**
-     * 用户.
-     */
-    public static final String USER = "user";
-    /**
-     * 系统.
-     */
-    public static final String SYSTEM = "system";
-    /**
-     * 机器人.
-     */
-    public static final String ASSISTANT = "assistant";
-
-}

+ 0 - 4
src/main/java/cn/jlsxwkj/moudles/chat/message/package-info.java

@@ -1,4 +0,0 @@
-/**
- * 消息包.
- */
-package cn.jlsxwkj.moudles.chat.message;

+ 0 - 4
src/main/java/cn/jlsxwkj/moudles/chat/package-info.java

@@ -1,4 +0,0 @@
-/**
- * chat 包.
- */
-package cn.jlsxwkj.moudles.chat;

+ 1 - 0
src/main/java/cn/jlsxwkj/moudles/chat_history/ChatHistoryController.java

@@ -24,6 +24,7 @@ public class ChatHistoryController {
 
     /**
      * 获取历史对话.
+     *
      * @return 返回历史消息列表
      */
     @GetMapping("/getHistory")

+ 2 - 36
src/main/java/cn/jlsxwkj/moudles/chat_history/ChatHistoryMapper.java

@@ -1,45 +1,11 @@
 package cn.jlsxwkj.moudles.chat_history;
 
-import org.apache.ibatis.annotations.Insert;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
-import org.apache.ibatis.annotations.Select;
-
-import java.util.List;
 
 /**
  * @author zh
  */
 @Mapper
-public interface ChatHistoryMapper {
-
-    /**
-     * 插入对话消息.
-     * @param userId 用户id
-     * @param userQ 用户问
-     * @param chatA chat 回答
-     * @return 成功条数
-     */
-    @Insert("""
-            insert into chat_history(user_id, "user_Q", "chat_A")
-            values (#{userId}, #{userQ}, #{chatA})
-            """)
-    Integer insert(@Param("userId") String userId,
-                   @Param("userQ") String userQ,
-                   @Param("chatA") String chatA);
-
-    /**
-     * 查询历史回答.
-     * @param userId 用户id
-     * @return 返回近期 20 条历史回答
-     */
-    @Select("""
-            select *
-            from chat_history
-            where user_id = #{userId}
-            and is_deleted = 0
-            order by create_time desc
-            limit 20
-            """)
-    List<ChatHistoryVO> selectHistoryByUserId(@Param("userId") String userId);
+public interface ChatHistoryMapper extends BaseMapper<ChatHistory> {
 }

+ 13 - 2
src/main/java/cn/jlsxwkj/moudles/chat_history/ChatHistoryService.java

@@ -2,6 +2,7 @@ package cn.jlsxwkj.moudles.chat_history;
 
 import cn.dev33.satoken.SaManager;
 import cn.jlsxwkj.common.exception.InsertFailException;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -30,7 +31,11 @@ public class ChatHistoryService {
     public void insert(final String userId,
                        final String userQ,
                        final String chatA) throws InsertFailException {
-        Integer rows = chatHistoryMapper.insert(userId, userQ, chatA);
+        ChatHistory chatHistory = new ChatHistory();
+        chatHistory.setUserId(userId);
+        chatHistory.setUserQ(userQ);
+        chatHistory.setChatA(chatA);
+        int rows = chatHistoryMapper.insert(chatHistory);
         if (rows < 1) {
             throw new InsertFailException("插入失败");
         }
@@ -41,6 +46,12 @@ public class ChatHistoryService {
      */
     public List<ChatHistoryVO> selectHistoryByUserId() {
         String userId = SaManager.getStpLogic("").getLoginIdAsString();
-        return chatHistoryMapper.selectHistoryByUserId(userId);
+        return chatHistoryMapper.selectList(
+            Wrappers.query(ChatHistory.class)
+                .eq("user_id", userId)
+                .orderByDesc("create_time")
+                .last("limit 10"))
+            .stream().map(ChatHistoryVO::cast)
+            .toList();
     }
 }

+ 31 - 9
src/main/java/cn/jlsxwkj/moudles/chat_history/ChatHistoryVO.java

@@ -1,12 +1,34 @@
 package cn.jlsxwkj.moudles.chat_history;
 
-/**
- * @param userId 用户id
- * @param userQ  用户问
- * @param chatA  chat 回答
- */
-public record ChatHistoryVO(
-        String userId,
-        String userQ,
-        String chatA) {
+import lombok.Data;
+
+@Data
+public class ChatHistoryVO {
+
+    /**
+     * 用户 id.
+     */
+    private String userId;
+    /**
+     * 用户提问.
+     */
+    private String userQ;
+    /**
+     * chat 回答.
+     */
+    private String chatA;
+
+    /**
+     * 转换为 VO.
+     *
+     * @param chatHistory 历史消息
+     * @return VO
+     */
+    public static ChatHistoryVO cast(final ChatHistory chatHistory) {
+        ChatHistoryVO chatHistoryVO = new ChatHistoryVO();
+        chatHistoryVO.setUserId(chatHistory.getUserId());
+        chatHistoryVO.setUserQ(chatHistory.getUserQ());
+        chatHistoryVO.setChatA(chatHistory.getChatA());
+        return chatHistoryVO;
+    }
 }

+ 0 - 4
src/main/java/cn/jlsxwkj/moudles/chat_history/package-info.java

@@ -1,4 +0,0 @@
-/**
- * chat_history 包.
- */
-package cn.jlsxwkj.moudles.chat_history;

+ 0 - 17
src/main/java/cn/jlsxwkj/moudles/log_error/LogError.java

@@ -1,6 +1,5 @@
 package cn.jlsxwkj.moudles.log_error;
 
-import cn.jlsxwkj.common.R.ResponseError;
 import cn.jlsxwkj.common.dao.Dao;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -21,23 +20,7 @@ public class LogError extends Dao {
      */
     private String message;
     /**
-     * 异常信息.
-     */
-    private String errorInfo;
-    /**
      * 异常堆栈.
      */
     private String errorStackTrace;
-
-    /**
-     * 转换异常.
-     * @param errorHandler 异常
-     * @return LogError
-     */
-    public LogError castResponseErrorToLogError(
-            final ResponseError errorHandler) {
-        this.setMessage(errorHandler.getMessage());
-        this.setException(errorHandler.getException());
-        return this;
-    }
 }

+ 2 - 23
src/main/java/cn/jlsxwkj/moudles/log_error/LogErrorMapper.java

@@ -1,32 +1,11 @@
 package cn.jlsxwkj.moudles.log_error;
 
-import org.apache.ibatis.annotations.Insert;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
 
 /**
  * @author zh
  */
 @Mapper
-public interface LogErrorMapper {
-
-    /**
-     * 插入错误日志.
-     *
-     * @param logError log实体
-     * @return 成功条数
-     */
-    @Insert("""
-            insert into log_error(
-                message,
-                exception,
-                error_info,
-                error_stack_trace)
-            values (
-                #{LogError.message},
-                #{LogError.exception},
-                #{LogError.errorInfo},
-                #{LogError.errorStackTrace})
-            """)
-    Integer insertOne(@Param("LogError") LogError logError);
+public interface LogErrorMapper extends BaseMapper<LogError> {
 }

+ 9 - 3
src/main/java/cn/jlsxwkj/moudles/log_error/LogErrorService.java

@@ -5,6 +5,8 @@ import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.util.Arrays;
+
 /**
  * @author zh
  */
@@ -18,12 +20,16 @@ public class LogErrorService {
     private LogErrorMapper logErrorMapper;
 
     /**
-     * @param logError logError
+     * @param e 异常
      * @throws InsertFailException 插入失败
      */
     @Transactional(rollbackFor = InsertFailException.class)
-    public void insertOne(final LogError logError) throws InsertFailException {
-        Integer rows = logErrorMapper.insertOne(logError);
+    public void insertOne(final Throwable e) throws InsertFailException {
+        LogError logError = new LogError();
+        logError.setException(e.getClass().getName());
+        logError.setMessage(e.getMessage());
+        logError.setErrorStackTrace(Arrays.toString(e.getStackTrace()));
+        int rows = logErrorMapper.insert(logError);
         if (rows < 1) {
             throw new InsertFailException("插入失败");
         }

+ 0 - 4
src/main/java/cn/jlsxwkj/moudles/log_error/package-info.java

@@ -1,4 +0,0 @@
-/**
- * log_error 包.
- */
-package cn.jlsxwkj.moudles.log_error;

+ 7 - 3
src/main/java/cn/jlsxwkj/moudles/user_list/UserListController.java

@@ -5,7 +5,11 @@ import cn.dev33.satoken.stp.StpUtil;
 import cn.jlsxwkj.common.exception.CustomException;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import jakarta.annotation.Resource;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 
 /**
  * @author zh
@@ -32,8 +36,8 @@ public class UserListController {
     @PostMapping("/login")
     @SaIgnore
     public UserVO login(
-            @RequestParam final String userName,
-            @RequestParam final String userPassword) throws CustomException {
+        @RequestParam final String userName,
+        @RequestParam final String userPassword) throws CustomException {
         return userListService.checkOrAddUser(userName, userPassword);
     }
 

+ 2 - 37
src/main/java/cn/jlsxwkj/moudles/user_list/UserListMapper.java

@@ -1,46 +1,11 @@
 package cn.jlsxwkj.moudles.user_list;
 
-import org.apache.ibatis.annotations.Insert;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
-import org.apache.ibatis.annotations.Select;
 
 /**
  * @author zh
  */
 @Mapper
-public interface UserListMapper {
-
-    /**
-     * 注册用户.
-     *
-     * @param user 用户实体
-     * @return 插入条数
-     */
-    @Insert("""
-            insert into user_list(
-                user_id,
-                user_name,
-                user_password)
-            values (
-                #{user.userId},
-                #{user.userName},
-                #{user.userPassword})
-            """)
-    Integer authUser(@Param("user") UserList user);
-
-    /**
-     * 查询用户是否存在.
-     *
-     * @param userName 用户名
-     * @return 用户实体
-     */
-    @Select("""
-            select *
-            from user_list
-            where user_name = #{userName}
-            and is_deleted = 0
-            limit 1
-            """)
-    UserList checkUser(@Param("userName") String userName);
+public interface UserListMapper extends BaseMapper<UserList> {
 }

+ 15 - 23
src/main/java/cn/jlsxwkj/moudles/user_list/UserListService.java

@@ -3,8 +3,13 @@ package cn.jlsxwkj.moudles.user_list;
 import cn.dev33.satoken.secure.SaSecureUtil;
 import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.lang.Snowflake;
-import cn.jlsxwkj.common.exception.*;
+import cn.jlsxwkj.common.exception.AccountAuthFailException;
+import cn.jlsxwkj.common.exception.AccountPasswordCheckFailException;
+import cn.jlsxwkj.common.exception.CustomException;
+import cn.jlsxwkj.common.exception.LoginAccountAlreadyLoginException;
+import cn.jlsxwkj.common.exception.LoginWrongPasswordException;
 import cn.jlsxwkj.common.utils.CheckPassword;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -36,28 +41,20 @@ public class UserListService {
      */
     @Transactional(rollbackFor = AccountAuthFailException.class)
     public UserVO checkOrAddUser(
-            final String userName,
-            final String userPassword) throws CustomException {
+        final String userName,
+        final String userPassword) throws CustomException {
         if (!CheckPassword.checkPassword(userPassword)) {
-            throw new AccountPasswordCheckFailException(
-                    "密码长度为8到20位,必须包含字母和数字,字母区分大小写"
-            );
+            throw new AccountPasswordCheckFailException("密码长度为8到20位,必须包含字母和数字,字母区分大小写");
         }
         String sha512pwd = SaSecureUtil.sha512(userPassword);
-        UserList userList = userListMapper.checkUser(userName);
-        String userId;
+        UserList userList = userListMapper.selectOne(Wrappers.query(UserList.class).eq("user_name", userName));
         if (userList != null) {
             if (!userList.getUserPassword().contains(sha512pwd)) {
                 throw new LoginWrongPasswordException("密码错误");
             }
             if (!StpUtil.isLogin()) {
-                userId = userList.getUserId();
-                StpUtil.login(userId, false);
-                return new UserVO(
-                        userId,
-                        userList.getUserName(),
-                        "登录成功"
-                );
+                StpUtil.login(userList.getUserId(), false);
+                return UserVO.cast(userList, "登录成功");
             }
             throw new LoginAccountAlreadyLoginException("请勿重复登录");
         }
@@ -65,15 +62,10 @@ public class UserListService {
         userList.setUserId(snowflake.nextIdStr());
         userList.setUserName(userName);
         userList.setUserPassword(sha512pwd);
-        Integer rows = userListMapper.authUser(userList);
+        int rows = userListMapper.insert(userList);
         if (rows > 0) {
-            userId = userList.getUserId();
-            StpUtil.login(userId, false);
-            return new UserVO(
-                    userId,
-                    userList.getUserName(),
-                    "注册成功"
-            );
+            StpUtil.login(userList.getUserId(), false);
+            return UserVO.cast(userList, "注册成功");
 
         }
         throw new AccountAuthFailException("注册失败");

+ 33 - 9
src/main/java/cn/jlsxwkj/moudles/user_list/UserVO.java

@@ -1,12 +1,36 @@
 package cn.jlsxwkj.moudles.user_list;
 
-/**
- * @param userId   用户id
- * @param userName 用户名
- * @param message  用户消息
- */
-public record UserVO(
-        String userId,
-        String userName,
-        String message) {
+import lombok.Data;
+
+@Data
+public class UserVO {
+
+    /**
+     * 用户 id.
+     */
+    private String userId;
+    /**
+     * 用户名.
+     */
+    private String userName;
+    /**
+     * 消息.
+     */
+    private String message;
+
+    /**
+     * 转换实体为 VO.
+     *
+     * @param userList 实体
+     * @param message  消息
+     * @return VO
+     */
+    public static UserVO cast(final UserList userList,
+                              final String message) {
+        UserVO userVO = new UserVO();
+        userVO.setUserId(userList.getUserId());
+        userVO.setUserName(userList.getUserName());
+        userVO.setMessage(message);
+        return userVO;
+    }
 }

+ 0 - 4
src/main/java/cn/jlsxwkj/moudles/user_list/package-info.java

@@ -1,4 +0,0 @@
-/**
- * user_list 包.
- */
-package cn.jlsxwkj.moudles.user_list;

+ 7 - 7
src/main/java/cn/jlsxwkj/moudles/weather_demo/Request.java

@@ -1,12 +1,12 @@
 package cn.jlsxwkj.moudles.weather_demo;
 
 import com.fasterxml.jackson.annotation.JsonPropertyDescription;
+import lombok.Data;
 
-/**
- * @param sheng 省
- * @param place 地区
- */
-public record Request(
-        @JsonPropertyDescription("省") String sheng,
-        @JsonPropertyDescription("地区") String place) {
+@Data
+public class Request {
+    @JsonPropertyDescription("省, 如: 吉林省")
+    private String sheng;
+    @JsonPropertyDescription("地区, 如: 长春")
+    private String place;
 }

+ 27 - 0
src/main/java/cn/jlsxwkj/moudles/weather_demo/Response.java

@@ -0,0 +1,27 @@
+package cn.jlsxwkj.moudles.weather_demo;
+
+import lombok.Data;
+
+@Data
+public class Response {
+
+    private String precipitation;
+    private String temperature;
+    private String pressure;
+    private String humidity;
+    private String windDirection;
+    private String windDirectionDegree;
+    private String windSpeed;
+    private String windScale;
+    private String place;
+    private String weather1;
+    private String weather2;
+
+
+    @Override
+    public String toString() {
+        return """
+            降水: %s, 温度: %s, 气压: %s, 湿度: %s, 风向: %s, 风向度: %s, 风速: %s, 风力等级: %s, 地区: %s, 天气: %s - %s
+            """.formatted(precipitation, temperature, pressure, humidity, windDirection, windDirectionDegree, windSpeed, windScale, place, weather1, weather2);
+    }
+}

+ 16 - 49
src/main/java/cn/jlsxwkj/moudles/weather_demo/WeatherService.java

@@ -1,65 +1,32 @@
 package cn.jlsxwkj.moudles.weather_demo;
 
 import cn.hutool.http.HttpRequest;
+import cn.hutool.json.JSONUtil;
 import cn.jlsxwkj.common.utils.Log;
 import org.springframework.stereotype.Service;
 
 import java.util.HashMap;
+import java.util.Map;
 import java.util.function.Function;
 
-/**
- * @author zh
- */
 @Service
 public class WeatherService implements Function<Request, String> {
 
-    /**
-     * @param request Request
-     * @return 天气
-     */
     @Override
-    public String apply(Request request) {
-        Log.info(this.getClass(),
-                "省 : {},  地区 {}", request.sheng(), request.place());
-        HashMap<String, Object> kv = new HashMap<>();
-        kv.put("id", 88888888);
-        kv.put("key", 88888888);
-        kv.put("sheng", request.sheng());
-        kv.put("place", request.place());
-        String body = HttpRequest.get(
-                "https://cn.apihz.cn/api/tianqi/tqyb.php?")
-                .form(kv).execute().body();
-        Log.info(this.getClass(), body);
-        return body;
-        /*
-        JSONObject weather = new JSONObject(body)
-            .setDateFormat("yyyy-mm-dd HH:MM:ss");
-        String format = """
-                降水: %s
-                温度: %s
-                气压: %s
-                湿度: %s
-                风向: %s
-                风向度: %s
-                风速: %s
-                风力等级: %s
-                地区: %s
-                天气: %s - %s
-                """;
-
-        return String.format(format,
-                weather.get("precipitation"),
-                weather.get("temperature"),
-                weather.get("pressure"),
-                weather.get("humidity"),
-                weather.get("windDirection"),
-                weather.get("windDirectionDegree"),
-                weather.get("windSpeed"),
-                weather.get("windScale"),
-                weather.get("place"),
-                weather.get("weather1"),
-                weather.get("weather2"));
-        */
+    public String apply(final Request request) {
+        Log.info(this.getClass(), "省 : {},  地区 {}", request.getSheng(), request.getPlace());
+        Map<String, Object> kv = new HashMap<>();
+        kv.put("id", "88888888");
+        kv.put("key", "88888888");
+        kv.put("sheng", request.getSheng());
+        kv.put("place", request.getPlace());
+        String body = HttpRequest.get("https://cn.apihz.cn/api/tianqi/tqyb.php")
+            .form(kv)
+            .execute()
+            .body();
+        String response = JSONUtil.parse(body).toBean(Response.class).toString();
+        Log.info(this.getClass(), response);
+        return response;
     }
 }
 

+ 0 - 4
src/main/java/cn/jlsxwkj/moudles/weather_demo/package-info.java

@@ -1,4 +0,0 @@
-/**
- * 天气包.
- */
-package cn.jlsxwkj.moudles.weather_demo;

+ 5 - 10
src/main/resources/application-dev.yml

@@ -1,8 +1,8 @@
 spring:
   datasource:
-      url: jdbc:postgresql://localhost:5433/postgres
-      username: postgres
-      password: postgres
+    url: jdbc:postgresql://localhost:5433/postgres
+    username: postgres
+    password: postgres
   ai:
     vectorstore:
       pgvector:
@@ -19,18 +19,13 @@ spring:
           keep-alive: 24h
           # 是否开启 gpu 1 代表开启
           num-g-p-u: 0
-          temperature: 0.5
       embedding:
         model: shaw/dmeta-embedding-zh
 customer:
-  cnocr-url: "http://www.jlsxwkj.cn:8501/ocr"
+  cnocr-url: "http://localhost:8501/ocr"
   sys-message: "Always say you're an ai or 大模型 from 玄武科技"
-  # 历史消息最大长度
-  max-list-message-length: 12
-  # 每条消息最大长度
-  max-message-length: 512
   # api 执行时间, 超过打印在控制台
   exec-time: 100
   # 限流, 每 5 秒 可以请求 2 次
-  rate-limit-sec: 5
+  rate-limit-sec: 1
   gen-tokens: 2