From 0aa739db8268b442ab74634289ffed00124a976a Mon Sep 17 00:00:00 2001
From: xiangpei <xiangpei@timesnew.cn>
Date: 星期五, 18 四月 2025 17:14:30 +0800
Subject: [PATCH] 会话管理、聊天接口(待测试)

---
 ai-chat/src/main/java/com/monkeylessey/controller/ChatController.java            |   38 +
 dev-admin/src/main/resources/application-dev.yml                                 |    7 
 dev-sys/src/main/java/com/monkeylessey/framework/config/TokenSecurityConfig.java |    1 
 ai-chat/src/main/java/com/monkeylessey/domain/form/SessionMsgForm.java           |   39 +
 ai-chat/src/main/java/com/monkeylessey/controller/SessionController.java         |   88 +++
 ai-chat/src/main/java/com/monkeylessey/domain/entity/SessionMsg.java             |   34 +
 ai-chat/src/main/java/com/monkeylessey/mapper/SessionMapper.java                 |   61 ++
 ai-chat/src/main/java/com/monkeylessey/domain/vo/SessionCountVO.java             |   30 +
 ai-chat/src/main/java/com/monkeylessey/controller/SessionMsgController.java      |   83 +++
 ai-chat/src/main/java/com/monkeylessey/domain/form/SessionForm.java              |   77 +++
 dev-admin/src/main/resources/application-prod.yml                                |    6 
 ai-chat/src/main/java/com/monkeylessey/service/SessionService.java               |   72 ++
 pom.xml                                                                          |    7 
 ai-chat/src/main/java/com/monkeylessey/domain/vo/SessionVO.java                  |   64 ++
 ai-chat/src/main/java/com/monkeylessey/mapper/SessionMsgMapper.java              |   33 +
 ai-chat/src/main/java/com/monkeylessey/domain/form/ChatForm.java                 |   69 ++
 dev-sys/src/main/java/com/monkeylessey/gen/handler/VoHandler.java                |    2 
 ai-chat/src/main/java/com/monkeylessey/service/ChatService.java                  |   24 
 ai-chat/src/main/java/com/monkeylessey/domain/vo/SessionMsgVO.java               |   37 +
 ai-chat/src/main/java/com/monkeylessey/service/impl/SessionMsgServiceImpl.java   |  119 ++++
 ai-chat/src/main/resources/mapper/SessionMapper.xml                              |   86 +++
 ai-chat/src/main/java/com/monkeylessey/domain/query/SessionMsgQuery.java         |   21 
 ai-chat/src/main/java/com/monkeylessey/domain/entity/Session.java                |   70 ++
 ai-chat/pom.xml                                                                  |    6 
 dev-sys/src/main/java/com/monkeylessey/gen/utils/GenerateCodeUtil.java           |    4 
 dev-sys/src/main/resources/templates/serviceImpl.java.vm                         |    3 
 ai-chat/src/main/java/com/monkeylessey/config/AIConfig.java                      |   50 ++
 ai-chat/src/main/java/com/monkeylessey/service/impl/SessionServiceImpl.java      |  146 +++++
 ai-chat/src/main/java/com/monkeylessey/service/impl/ChatServiceImpl.java         |   84 +++
 dev-sys/src/main/java/com/monkeylessey/gen/handler/QueryHandler.java             |    2 
 ai-chat/src/main/java/com/monkeylessey/domain/query/SessionQuery.java            |   22 
 ai-chat/src/main/java/com/monkeylessey/service/SessionMsgService.java            |   65 ++
 ai-chat/src/main/resources/mapper/SessionMsgMapper.xml                           |   46 +
 33 files changed, 1,491 insertions(+), 5 deletions(-)

diff --git a/ai-chat/pom.xml b/ai-chat/pom.xml
index 49a028c..b375c9a 100644
--- a/ai-chat/pom.xml
+++ b/ai-chat/pom.xml
@@ -17,6 +17,12 @@
     </properties>
 
     <dependencies>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-webflux</artifactId>
+        </dependency>
+
         <dependency>
             <groupId>com.monkeylessey</groupId>
             <artifactId>dev-sys</artifactId>
diff --git a/ai-chat/src/main/java/com/monkeylessey/config/AIConfig.java b/ai-chat/src/main/java/com/monkeylessey/config/AIConfig.java
new file mode 100644
index 0000000..d09ea0e
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/config/AIConfig.java
@@ -0,0 +1,50 @@
+package com.monkeylessey.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author锛歺p
+ * @date锛�2025/4/18 14:28
+ */
+@Configuration
+@ConfigurationProperties(prefix = "ai")
+public class AIConfig {
+
+    /**
+     * 鍩熷悕
+     */
+    private String domain;
+
+    /**
+     * 绔彛
+     */
+    private String port;
+
+
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+
+    public String getPort() {
+        return port;
+    }
+
+    public void setPort(String port) {
+        this.port = port;
+    }
+
+    /**
+     * 鑾峰彇瀹屾暣鐨勫煙
+     *
+     * @return
+     */
+    public String getFullDomain() {
+        return this.domain + ":" + this.port;
+    }
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/controller/ChatController.java b/ai-chat/src/main/java/com/monkeylessey/controller/ChatController.java
new file mode 100644
index 0000000..0ee4efb
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/controller/ChatController.java
@@ -0,0 +1,38 @@
+package com.monkeylessey.controller;
+
+import com.monkeylessey.domain.form.ChatForm;
+import com.monkeylessey.domain.form.SessionForm;
+import com.monkeylessey.group.Add;
+import com.monkeylessey.response.Result;
+import com.monkeylessey.service.ChatService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.MediaType;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @author锛歺p
+ * @date锛�2025/4/18 13:59
+ */
+@Validated
+@RequiredArgsConstructor
+@Api(value = "chat瀵硅瘽", tags = "chat瀵硅瘽绠$悊")
+@RestController
+@RequestMapping("/chat")
+public class ChatController {
+
+    private final ChatService chatService;
+
+    @PostMapping(value = "/send/msg", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
+    @ApiOperation(value = "闂棶棰�/瀵硅瘽", notes = "闂棶棰�/瀵硅瘽")
+    public SseEmitter sendMsg(@RequestBody @Validated ChatForm form) {
+        return chatService.sendMsg(form);
+    }
+
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/controller/SessionController.java b/ai-chat/src/main/java/com/monkeylessey/controller/SessionController.java
new file mode 100644
index 0000000..b233c69
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/controller/SessionController.java
@@ -0,0 +1,88 @@
+package com.monkeylessey.controller;
+
+import com.monkeylessey.domain.form.SessionForm;
+import com.monkeylessey.domain.query.SessionQuery;
+import com.monkeylessey.group.Update;
+import com.monkeylessey.group.Add;
+import com.monkeylessey.service.SessionService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import lombok.RequiredArgsConstructor;
+import java.util.List;
+import javax.validation.constraints.NotEmpty;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import com.monkeylessey.response.Result;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * chat瀵硅瘽 鍓嶇鎺у埗鍣�
+ *
+ * @author 鍚戝煿
+ * @since 2025-04-18
+ */
+@Validated
+@RequiredArgsConstructor
+@Api(value = "浼氳瘽绠$悊", tags = "浼氳瘽绠$悊")
+@RestController
+@RequestMapping("/session")
+public class SessionController {
+
+    private final SessionService sessionService;
+
+    @PostMapping
+    @ApiOperation(value = "娣诲姞", notes = "娣诲姞")
+//    @PreAuthorize("hasAuthority('session:add')")
+    public Result add(@RequestBody @Validated(Add.class) SessionForm form) {
+        return sessionService.add(form);
+    }
+
+    @PutMapping
+    @ApiOperation(value = "淇敼", notes = "淇敼")
+    @PreAuthorize("hasAuthority('session:edit')")
+    public Result update(@RequestBody @Validated(Update.class) SessionForm form) {
+        return sessionService.update(form);
+    }
+
+    @DeleteMapping("/{id}")
+    @ApiOperation(value = "ID鍒犻櫎", notes = "ID鍒犻櫎")
+    @PreAuthorize("hasAuthority('session:del')")
+    public Result removeById(@PathVariable("id") String id) {
+        return sessionService.removeById(id);
+    }
+
+    @DeleteMapping("/batch")
+    @ApiOperation(value = "鎵归噺鍒犻櫎", notes = "鎵归噺鍒犻櫎")
+    @PreAuthorize("hasAuthority('session:del:batch')")
+    public Result remove(@RequestBody @NotEmpty(message = "璇烽�夋嫨鏁版嵁") List<String> ids) {
+        return sessionService.remove(ids);
+    }
+
+    @GetMapping("/page")
+    @ApiOperation(value = "鍒嗛〉", notes = "鍒嗛〉")
+    @PreAuthorize("hasAuthority('session:page')")
+    public Result page(SessionQuery query) {
+        return sessionService.page(query);
+    }
+
+    @GetMapping("/{id}")
+    @ApiOperation(value = "璇︽儏", notes = "璇︽儏")
+//    @PreAuthorize("hasAuthority('session:detail')")
+    public Result detail(@PathVariable("id") Integer id) {
+        return sessionService.detail(id);
+    }
+
+    @GetMapping("/list")
+    @PreAuthorize("hasAuthority('session:list')")
+    @ApiOperation(value = "鍒楄〃", notes = "鍒楄〃")
+    public Result list() {
+        return sessionService.all();
+    }
+
+    @GetMapping("/client/list")
+//    @PreAuthorize("hasAuthority('session:client:list')")
+    @ApiOperation(value = "瀹㈡埛绔細璇濆垪琛�", notes = "瀹㈡埛绔細璇濆垪琛�")
+    public Result clientList() {
+        return sessionService.clientList();
+    }
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/controller/SessionMsgController.java b/ai-chat/src/main/java/com/monkeylessey/controller/SessionMsgController.java
new file mode 100644
index 0000000..390a431
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/controller/SessionMsgController.java
@@ -0,0 +1,83 @@
+package com.monkeylessey.controller;
+
+import com.monkeylessey.group.Update;
+import com.monkeylessey.group.Add;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import lombok.RequiredArgsConstructor;
+import java.util.List;
+import org.springframework.validation.annotation.Validated;
+import javax.validation.constraints.NotEmpty;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import com.monkeylessey.service.SessionMsgService;
+import com.monkeylessey.response.Result;
+import com.monkeylessey.domain.form.SessionMsgForm;
+import com.monkeylessey.domain.query.SessionMsgQuery;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 浼氳瘽娑堟伅 鍓嶇鎺у埗鍣�
+ *
+ * @author 鍚戝煿
+ * @since 2025-04-18
+ */
+@Validated
+@RequiredArgsConstructor
+@Api(value = "浼氳瘽娑堟伅", tags = "浼氳瘽娑堟伅绠$悊")
+@RestController
+@RequestMapping("/session-msg")
+public class SessionMsgController {
+
+    private final SessionMsgService sessionMsgService;
+
+    @PostMapping
+    @ApiOperation(value = "娣诲姞", notes = "娣诲姞")
+    @PreAuthorize("hasAuthority('sessionMsg:add')")
+    public Result add(@RequestBody @Validated(Add.class) SessionMsgForm form) {
+        return sessionMsgService.add(form);
+    }
+
+    @PutMapping
+    @ApiOperation(value = "淇敼", notes = "淇敼")
+    @PreAuthorize("hasAuthority('sessionMsg:edit')")
+    public Result update(@RequestBody @Validated(Update.class) SessionMsgForm form) {
+        return sessionMsgService.update(form);
+    }
+
+    @DeleteMapping("/{id}")
+    @ApiOperation(value = "ID鍒犻櫎", notes = "ID鍒犻櫎")
+    @PreAuthorize("hasAuthority('sessionMsg:del')")
+    public Result removeById(@PathVariable("id") String id) {
+        return sessionMsgService.removeById(id);
+    }
+
+    @DeleteMapping("/batch")
+    @ApiOperation(value = "鎵归噺鍒犻櫎", notes = "鎵归噺鍒犻櫎")
+    @PreAuthorize("hasAuthority('sessionMsg:del:batch')")
+    public Result remove(@RequestBody @NotEmpty(message = "璇烽�夋嫨鏁版嵁") List<String> ids) {
+        return sessionMsgService.remove(ids);
+    }
+
+    @GetMapping("/page")
+    @ApiOperation(value = "鍒嗛〉", notes = "鍒嗛〉")
+    @PreAuthorize("hasAuthority('sessionMsg:page')")
+    public Result page(SessionMsgQuery query) {
+        return sessionMsgService.page(query);
+    }
+
+    @GetMapping("/{id}")
+    @ApiOperation(value = "璇︽儏", notes = "璇︽儏")
+    @PreAuthorize("hasAuthority('sessionMsg:detail')")
+    public Result detail(@PathVariable("id") Integer id) {
+        return sessionMsgService.detail(id);
+    }
+
+    @GetMapping("/list")
+    @PreAuthorize("hasAuthority('sessionMsg:list')")
+    @ApiOperation(value = "鍒楄〃", notes = "鍒楄〃")
+    public Result list() {
+        return sessionMsgService.all();
+    }
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/domain/entity/Session.java b/ai-chat/src/main/java/com/monkeylessey/domain/entity/Session.java
new file mode 100644
index 0000000..afc7b21
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/domain/entity/Session.java
@@ -0,0 +1,70 @@
+package com.monkeylessey.domain.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.monkeylessey.sys.domain.base.AbsEntity;
+import java.io.Serializable;
+import lombok.Data;
+
+/**
+ * chat瀵硅瘽
+ *
+ * @author 鍚戝煿
+ * @since 2025-04-18
+ */
+@Data
+@TableName("ai_session")
+public class Session extends AbsEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableField("session_name")
+    /** 浼氳瘽鍚嶇О */
+    private String sessionName;
+
+    @TableField("mode")
+    /** 浼氳瘽妯″紡 */
+    private String mode;
+
+    @TableField("kb_name")
+    /** 鐭ヨ瘑搴� */
+    private String kbName;
+
+    @TableField("top_k")
+    /**  */
+    private String topK;
+
+    @TableField("score_threshold")
+    /**  */
+    private String scoreThreshold;
+
+    @TableField("stream")
+    /**  */
+    private Integer stream;
+
+    @TableField("model")
+    /** 澶фā鍨� */
+    private String model;
+
+    @TableField("temperature")
+    /**  */
+    private String temperature;
+
+    @TableField("max_tokens")
+    /** 鏈�澶у悙瀛楁暟 */
+    private Integer maxTokens;
+
+    @TableField("prompt_name")
+    /**  */
+    private String promptName;
+
+    @TableField("return_direct")
+    /** 鏄惁鍙繑鍥炴绱㈢粨鏋滀笉璋冪敤澶фā鍨� */
+    private Integer returnDirect;
+
+    @TableField("user_id")
+    /**  */
+    private String userId;
+
+
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/domain/entity/SessionMsg.java b/ai-chat/src/main/java/com/monkeylessey/domain/entity/SessionMsg.java
new file mode 100644
index 0000000..76bef6f
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/domain/entity/SessionMsg.java
@@ -0,0 +1,34 @@
+package com.monkeylessey.domain.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.monkeylessey.sys.domain.base.AbsEntity;
+import java.io.Serializable;
+import lombok.Data;
+
+/**
+ * 浼氳瘽娑堟伅
+ *
+ * @author 鍚戝煿
+ * @since 2025-04-18
+ */
+@Data
+@TableName("ai_session_msg")
+public class SessionMsg extends AbsEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableField("session_id")
+    /** 浼氳瘽id */
+    private String sessionId;
+
+    @TableField("role")
+    /** 瑙掕壊锛歛i銆乽ser */
+    private String role;
+
+    @TableField("content")
+    /** 瀵硅瘽鍐呭 */
+    private String content;
+
+
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/domain/form/ChatForm.java b/ai-chat/src/main/java/com/monkeylessey/domain/form/ChatForm.java
new file mode 100644
index 0000000..6d83423
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/domain/form/ChatForm.java
@@ -0,0 +1,69 @@
+package com.monkeylessey.domain.form;
+
+import com.monkeylessey.group.Add;
+import com.monkeylessey.group.Update;
+import com.monkeylessey.sys.domain.base.AbsForm;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * chat瀵硅瘽琛ㄥ崟
+ *
+ * @author 鍚戝煿
+ * @since 2025-04-18
+ */
+@Data
+@ApiModel(value = "Session琛ㄥ崟", description = "chat瀵硅瘽琛ㄥ崟")
+public class ChatForm extends AbsForm {
+
+//    @NotBlank(message = "鏈�夋嫨浼氳瘽")
+    @ApiModelProperty("浼氳瘽id")
+    private String sessionId;
+
+    @NotBlank(message = "璇疯緭鍏ユ偍鐨勯棶棰�")
+    @ApiModelProperty("褰撳墠鐢ㄦ埛鎻愰棶鍐呭")
+    private String query;
+
+    @NotBlank(message = "浼氳瘽妯″紡涓嶈兘涓虹┖")
+    @ApiModelProperty("浼氳瘽妯″紡")
+    private String mode;
+
+    @NotBlank(message = "鐭ヨ瘑搴撲笉鑳戒负绌�")
+    @ApiModelProperty("鐭ヨ瘑搴�")
+    private String kbName;
+
+    @ApiModelProperty("")
+    private String topK;
+
+    @ApiModelProperty("")
+    private String scoreThreshold;
+
+    @ApiModelProperty("娴佸紡鍝嶅簲")
+    private Boolean stream;
+
+    @NotBlank(message = "妯″瀷涓嶈兘涓虹┖")
+    @ApiModelProperty("妯″瀷")
+    private String model;
+
+    @ApiModelProperty("")
+    private String temperature;
+
+    @ApiModelProperty("鏈�澶у悙瀛楁暟")
+    private Integer maxTokens;
+
+    @ApiModelProperty("")
+    private String promptName;
+
+    @ApiModelProperty("鏄惁鍙繑鍥炴绱㈢粨鏋滀笉璋冪敤澶фā鍨�")
+    private Boolean returnDirect;
+
+    @ApiModelProperty("鍘嗗彶娑堟伅")
+    private List<SessionMsgForm> history = new ArrayList<>();
+
+
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/domain/form/SessionForm.java b/ai-chat/src/main/java/com/monkeylessey/domain/form/SessionForm.java
new file mode 100644
index 0000000..b251af8
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/domain/form/SessionForm.java
@@ -0,0 +1,77 @@
+package com.monkeylessey.domain.form;
+
+import com.monkeylessey.domain.entity.Session;
+import com.monkeylessey.group.Update;
+import com.monkeylessey.group.Add;
+import com.monkeylessey.sys.domain.base.AbsForm;
+import org.springframework.beans.BeanUtils;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import org.springframework.lang.NonNull;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * chat瀵硅瘽琛ㄥ崟
+ *
+ * @author 鍚戝煿
+ * @since 2025-04-18
+ */
+@Data
+@ApiModel(value = "Session琛ㄥ崟", description = "chat瀵硅瘽琛ㄥ崟")
+public class SessionForm extends AbsForm {
+
+    @NotBlank(message = "浼氳瘽鍚嶇О涓嶈兘涓虹┖", groups = {Add.class, Update.class})
+    @ApiModelProperty("浼氳瘽鍚嶇О")
+    private String sessionName;
+
+    @NotBlank(message = "浼氳瘽妯″紡涓嶈兘涓虹┖", groups = {Add.class, Update.class})
+    @ApiModelProperty("浼氳瘽妯″紡")
+    private String mode;
+
+    @NotBlank(message = "鐭ヨ瘑搴撲笉鑳戒负绌�", groups = {Add.class, Update.class})
+    @ApiModelProperty("鐭ヨ瘑搴�")
+    private String kbName;
+
+    @NotBlank(message = "涓嶈兘涓虹┖", groups = {Add.class, Update.class})
+    @ApiModelProperty("")
+    private String topK;
+
+    @NotBlank(message = "涓嶈兘涓虹┖", groups = {Add.class, Update.class})
+    @ApiModelProperty("")
+    private String scoreThreshold;
+
+    @NotNull(message = "涓嶈兘涓虹┖", groups = {Add.class, Update.class})
+    @ApiModelProperty("")
+    private Integer stream;
+
+    @NotBlank(message = "澶фā鍨嬩笉鑳戒负绌�", groups = {Add.class, Update.class})
+    @ApiModelProperty("澶фā鍨�")
+    private String model;
+
+    @NotBlank(message = "涓嶈兘涓虹┖", groups = {Add.class, Update.class})
+    @ApiModelProperty("")
+    private String temperature;
+
+    @NotNull(message = "鏈�澶у悙瀛楁暟涓嶈兘涓虹┖", groups = {Add.class, Update.class})
+    @ApiModelProperty("鏈�澶у悙瀛楁暟")
+    private Integer maxTokens;
+
+    @NotBlank(message = "涓嶈兘涓虹┖", groups = {Add.class, Update.class})
+    @ApiModelProperty("")
+    private String promptName;
+
+    @NotNull(message = "鏄惁鍙繑鍥炴绱㈢粨鏋滀笉璋冪敤澶фā鍨嬩笉鑳戒负绌�", groups = {Add.class, Update.class})
+    @ApiModelProperty("鏄惁鍙繑鍥炴绱㈢粨鏋滀笉璋冪敤澶фā鍨�")
+    private Integer returnDirect;
+
+    public static Session getEntityByForm(@NonNull SessionForm form, Session entity) {
+        if(entity == null) {
+          entity = new Session();
+        }
+        BeanUtils.copyProperties(form, entity);
+        return entity;
+    }
+
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/domain/form/SessionMsgForm.java b/ai-chat/src/main/java/com/monkeylessey/domain/form/SessionMsgForm.java
new file mode 100644
index 0000000..f52d96e
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/domain/form/SessionMsgForm.java
@@ -0,0 +1,39 @@
+package com.monkeylessey.domain.form;
+
+import com.monkeylessey.group.Update;
+import com.monkeylessey.group.Add;
+import com.monkeylessey.sys.domain.base.AbsForm;
+import com.monkeylessey.domain.entity.SessionMsg;
+import org.springframework.beans.BeanUtils;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import org.springframework.lang.NonNull;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 浼氳瘽娑堟伅琛ㄥ崟
+ *
+ * @author 鍚戝煿
+ * @since 2025-04-18
+ */
+@Data
+@ApiModel(value = "SessionMsg琛ㄥ崟", description = "浼氳瘽娑堟伅琛ㄥ崟")
+public class SessionMsgForm extends AbsForm {
+
+    @ApiModelProperty("瑙掕壊锛歛i銆乽ser")
+    private String role;
+
+    @ApiModelProperty("瀵硅瘽鍐呭")
+    private String content;
+
+    public static SessionMsg getEntityByForm(@NonNull SessionMsgForm form, SessionMsg entity) {
+        if(entity == null) {
+          entity = new SessionMsg();
+        }
+        BeanUtils.copyProperties(form, entity);
+        return entity;
+    }
+
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/domain/query/SessionMsgQuery.java b/ai-chat/src/main/java/com/monkeylessey/domain/query/SessionMsgQuery.java
new file mode 100644
index 0000000..8a449bf
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/domain/query/SessionMsgQuery.java
@@ -0,0 +1,21 @@
+package com.monkeylessey.domain.query;
+
+import com.monkeylessey.sys.domain.base.AbsQuery;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 浼氳瘽娑堟伅鏌ヨ
+ *
+ * @author 鍚戝煿
+ * @since 2025-04-18
+ */
+@Data
+@ApiModel(value = "SessionMsg鏌ヨ鍙傛暟", description = "浼氳瘽娑堟伅鏌ヨ鍙傛暟")
+public class SessionMsgQuery extends AbsQuery {
+
+    @ApiModelProperty("瀵硅瘽鍐呭")
+    private String content;
+}
+
diff --git a/ai-chat/src/main/java/com/monkeylessey/domain/query/SessionQuery.java b/ai-chat/src/main/java/com/monkeylessey/domain/query/SessionQuery.java
new file mode 100644
index 0000000..d1dee39
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/domain/query/SessionQuery.java
@@ -0,0 +1,22 @@
+package com.monkeylessey.domain.query;
+
+
+import com.monkeylessey.sys.domain.base.AbsQuery;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * chat瀵硅瘽鏌ヨ
+ *
+ * @author 鍚戝煿
+ * @since 2025-04-18
+ */
+@Data
+@ApiModel(value = "Session鏌ヨ鍙傛暟", description = "chat瀵硅瘽鏌ヨ鍙傛暟")
+public class SessionQuery extends AbsQuery {
+
+    @ApiModelProperty("浼氳瘽鍚嶇О")
+    private String sessionName;
+}
+
diff --git a/ai-chat/src/main/java/com/monkeylessey/domain/vo/SessionCountVO.java b/ai-chat/src/main/java/com/monkeylessey/domain/vo/SessionCountVO.java
new file mode 100644
index 0000000..9201960
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/domain/vo/SessionCountVO.java
@@ -0,0 +1,30 @@
+package com.monkeylessey.domain.vo;
+
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author锛歺p
+ * @date锛�2025/4/18 15:20
+ */
+@Data
+public class SessionCountVO {
+
+    /**
+     * 浠婂ぉ鐨勪細璇�
+     */
+    private List<SessionVO> today = new ArrayList<>();
+
+    /**
+     * 鏄ㄥぉ鐨勪細璇�
+     */
+    private List<SessionVO> yesterday = new ArrayList<>();
+
+    /**
+     * 鏄ㄥぉ浠ュ墠鐨勬墍鏈変細璇�
+     */
+    private List<SessionVO> old = new ArrayList<>();
+
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/domain/vo/SessionMsgVO.java b/ai-chat/src/main/java/com/monkeylessey/domain/vo/SessionMsgVO.java
new file mode 100644
index 0000000..d7b98ef
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/domain/vo/SessionMsgVO.java
@@ -0,0 +1,37 @@
+package com.monkeylessey.domain.vo;
+
+import com.monkeylessey.domain.entity.SessionMsg;
+import com.monkeylessey.sys.domain.base.AbsVo;
+import org.springframework.lang.NonNull;
+import org.springframework.beans.BeanUtils;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+/**
+ * 浼氳瘽娑堟伅灞曠ず
+ *
+ * @author 鍚戝煿
+ * @since 2025-04-18
+ */
+@Data
+@ApiModel(value = "浼氳瘽娑堟伅鍝嶅簲鏁版嵁", description = "浼氳瘽娑堟伅鍝嶅簲鏁版嵁")
+public class SessionMsgVO extends AbsVo {
+
+    /** 浼氳瘽id */
+    private String sessionId;
+
+    /** 瑙掕壊锛歛i銆乽ser */
+    private String role;
+
+    /** 瀵硅瘽鍐呭 */
+    private String content;
+
+    public static SessionMsgVO getVoByEntity(@NonNull SessionMsg entity, SessionMsgVO vo) {
+        if(vo == null) {
+            vo = new SessionMsgVO();
+        }
+        BeanUtils.copyProperties(entity, vo);
+        return vo;
+    }
+
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/domain/vo/SessionVO.java b/ai-chat/src/main/java/com/monkeylessey/domain/vo/SessionVO.java
new file mode 100644
index 0000000..e58dd5a
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/domain/vo/SessionVO.java
@@ -0,0 +1,64 @@
+package com.monkeylessey.domain.vo;
+
+import com.monkeylessey.domain.entity.Session;
+import com.monkeylessey.sys.domain.base.AbsVo;
+import org.springframework.lang.NonNull;
+import org.springframework.beans.BeanUtils;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+/**
+ * chat瀵硅瘽灞曠ず
+ *
+ * @author 鍚戝煿
+ * @since 2025-04-18
+ */
+@Data
+@ApiModel(value = "chat瀵硅瘽鍝嶅簲鏁版嵁", description = "chat瀵硅瘽鍝嶅簲鏁版嵁")
+public class SessionVO extends AbsVo {
+
+    /** 浼氳瘽鍚嶇О */
+    private String sessionName;
+
+    /** 浼氳瘽妯″紡 */
+    private String mode;
+
+    /** 鐭ヨ瘑搴� */
+    private String kbName;
+
+    /**  */
+    private String topK;
+
+    /**  */
+    private String scoreThreshold;
+
+    /**  */
+    private Integer stream;
+
+    /** 澶фā鍨� */
+    private String model;
+
+    /**  */
+    private String temperature;
+
+    /** 鏈�澶у悙瀛楁暟 */
+    private Integer maxTokens;
+
+    /**  */
+    private String promptName;
+
+    /** 鏄惁鍙繑鍥炴绱㈢粨鏋滀笉璋冪敤澶фā鍨� */
+    private Integer returnDirect;
+
+    /**  */
+    private String userId;
+
+    public static SessionVO getVoByEntity(@NonNull Session entity, SessionVO vo) {
+        if(vo == null) {
+            vo = new SessionVO();
+        }
+        BeanUtils.copyProperties(entity, vo);
+        return vo;
+    }
+
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/mapper/SessionMapper.java b/ai-chat/src/main/java/com/monkeylessey/mapper/SessionMapper.java
new file mode 100644
index 0000000..f166a06
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/mapper/SessionMapper.java
@@ -0,0 +1,61 @@
+package com.monkeylessey.mapper;
+
+import com.monkeylessey.domain.entity.Session;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import java.util.Date;
+import java.util.List;
+
+import com.monkeylessey.domain.query.SessionQuery;
+import com.monkeylessey.domain.vo.SessionVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * chat瀵硅瘽 Mapper 鎺ュ彛
+ *
+ * @author 鍚戝煿
+ * @since 2025-04-18
+ */
+@Mapper
+public interface SessionMapper extends BaseMapper<Session> {
+
+    /**
+     * id鏌ユ壘chat瀵硅瘽
+     * @param id
+     * @return
+     */
+    SessionVO getById(Integer id);
+
+    /**
+    *  鍒嗛〉
+    */
+    IPage getPage(IPage page, @Param("query") SessionQuery query);
+
+    /**
+     * 浠婂ぉ鐨勪細璇濆垪琛�
+     *
+     * @param dayStart
+     * @param dayEnd
+     * @return
+     */
+    List<SessionVO> getTodaySessionList(@Param("dayStart") Date dayStart, @Param("dayEnd") Date dayEnd);
+
+    /**
+     * 鏄ㄥぉ鐨勪細璇�
+     *
+     * @param dayStart
+     * @param dayEnd
+     * @return
+     */
+    List<SessionVO> getYesterdaySessionList(@Param("dayStart") Date dayStart, @Param("dayEnd") Date dayEnd);
+
+    /**
+     * 鏄ㄥぉ涔嬪墠鐨勬墍鏈変細璇�
+     *
+     * @param time
+     * @return
+     */
+    List<SessionVO> getOldSessionList(@Param("time") Date time);
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/mapper/SessionMsgMapper.java b/ai-chat/src/main/java/com/monkeylessey/mapper/SessionMsgMapper.java
new file mode 100644
index 0000000..02f144f
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/mapper/SessionMsgMapper.java
@@ -0,0 +1,33 @@
+package com.monkeylessey.mapper;
+
+import com.monkeylessey.domain.entity.SessionMsg;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.monkeylessey.domain.query.SessionMsgQuery;
+import com.monkeylessey.domain.vo.SessionMsgVO;
+import java.util.List;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 浼氳瘽娑堟伅 Mapper 鎺ュ彛
+ *
+ * @author 鍚戝煿
+ * @since 2025-04-18
+ */
+@Mapper
+public interface SessionMsgMapper extends BaseMapper<SessionMsg> {
+
+    /**
+     * id鏌ユ壘浼氳瘽娑堟伅
+     * @param id
+     * @return
+     */
+    SessionMsgVO getById(Integer id);
+
+    /**
+    *  鍒嗛〉
+    */
+    IPage getPage(IPage page, @Param("query") SessionMsgQuery query);
+
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/service/ChatService.java b/ai-chat/src/main/java/com/monkeylessey/service/ChatService.java
new file mode 100644
index 0000000..7ab0b35
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/service/ChatService.java
@@ -0,0 +1,24 @@
+package com.monkeylessey.service;
+
+import com.monkeylessey.domain.form.ChatForm;
+import com.monkeylessey.response.Result;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 瀵硅瘽
+ *
+ * @author锛歺p
+ * @date锛�2025/4/18 14:21
+ */
+public interface ChatService {
+
+
+    /**
+     * 鐢ㄦ埛鎻愰棶
+     *
+     * @param form
+     */
+    SseEmitter sendMsg(ChatForm form);
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/service/SessionMsgService.java b/ai-chat/src/main/java/com/monkeylessey/service/SessionMsgService.java
new file mode 100644
index 0000000..02a08e2
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/service/SessionMsgService.java
@@ -0,0 +1,65 @@
+package com.monkeylessey.service;
+
+import com.monkeylessey.domain.entity.SessionMsg;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.monkeylessey.response.Result;
+import com.monkeylessey.domain.form.SessionMsgForm;
+import com.monkeylessey.domain.query.SessionMsgQuery;
+import java.util.List;
+
+/**
+ * 浼氳瘽娑堟伅 鏈嶅姟绫�
+ *
+ * @author 鍚戝煿
+ * @since 2025-04-18
+ */
+public interface SessionMsgService extends IService<SessionMsg> {
+
+    /**
+     * 娣诲姞
+     * @param form
+     * @return
+     */
+    Result add(SessionMsgForm form);
+
+    /**
+     * 淇敼
+     * @param form
+     * @return
+     */
+    Result update(SessionMsgForm form);
+
+    /**
+     * 鎵归噺鍒犻櫎
+     * @param ids
+     * @return
+     */
+    Result remove(List<String> ids);
+
+    /**
+     * id鍒犻櫎
+     * @param id
+     * @return
+     */
+    Result removeById(String id);
+
+    /**
+     * 鍒嗛〉鏌ヨ
+     * @param query
+     * @return
+     */
+    Result page(SessionMsgQuery query);
+
+    /**
+     * 鏍规嵁id鏌ユ壘
+     * @param id
+     * @return
+     */
+    Result detail(Integer id);
+
+    /**
+     * 鍒楄〃
+     * @return
+     */
+    Result all();
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/service/SessionService.java b/ai-chat/src/main/java/com/monkeylessey/service/SessionService.java
new file mode 100644
index 0000000..3a1aacd
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/service/SessionService.java
@@ -0,0 +1,72 @@
+package com.monkeylessey.service;
+
+import com.monkeylessey.domain.entity.Session;
+import com.monkeylessey.domain.form.SessionForm;
+import com.monkeylessey.domain.query.SessionQuery;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.monkeylessey.response.Result;
+import java.util.List;
+
+/**
+ * chat瀵硅瘽 鏈嶅姟绫�
+ *
+ * @author 鍚戝煿
+ * @since 2025-04-18
+ */
+public interface SessionService extends IService<Session> {
+
+    /**
+     * 娣诲姞
+     * @param form
+     * @return
+     */
+    Result add(SessionForm form);
+
+    /**
+     * 淇敼
+     * @param form
+     * @return
+     */
+    Result update(SessionForm form);
+
+    /**
+     * 鎵归噺鍒犻櫎
+     * @param ids
+     * @return
+     */
+    Result remove(List<String> ids);
+
+    /**
+     * id鍒犻櫎
+     * @param id
+     * @return
+     */
+    Result removeById(String id);
+
+    /**
+     * 鍒嗛〉鏌ヨ
+     * @param query
+     * @return
+     */
+    Result page(SessionQuery query);
+
+    /**
+     * 鏍规嵁id鏌ユ壘
+     * @param id
+     * @return
+     */
+    Result detail(Integer id);
+
+    /**
+     * 鍒楄〃
+     * @return
+     */
+    Result all();
+
+    /**
+     * 瀹㈡埛绔細璇濆垪琛�
+     *
+     * @return
+     */
+    Result clientList();
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/service/impl/ChatServiceImpl.java b/ai-chat/src/main/java/com/monkeylessey/service/impl/ChatServiceImpl.java
new file mode 100644
index 0000000..5ee0931
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/service/impl/ChatServiceImpl.java
@@ -0,0 +1,84 @@
+package com.monkeylessey.service.impl;
+
+import cn.hutool.http.HttpUtil;
+import com.monkeylessey.config.AIConfig;
+import com.monkeylessey.domain.form.ChatForm;
+import com.monkeylessey.service.ChatService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Service;
+import org.springframework.web.reactive.function.client.WebClient;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * @author锛歺p
+ * @date锛�2025/4/18 14:22
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class ChatServiceImpl implements ChatService {
+
+    private final AIConfig aiConfig;
+
+    @Override
+    public SseEmitter sendMsg(ChatForm form) {
+
+        SseEmitter emitter = new SseEmitter(Long.MAX_VALUE); // 璁剧疆鏃犻檺瓒呮椂
+
+        // 1. 鏋勫缓璇锋眰浣�
+        Map<String, Object> body = new HashMap<>();
+        body.put("query", form.getQuery());
+        body.put("mode", form.getMode());
+        body.put("kb_name", form.getKbName());
+        body.put("top_k", form.getTopK());
+        body.put("score_threshold", form.getScoreThreshold());
+        body.put("history", form.getHistory());
+        body.put("stream", form.getStream());
+        body.put("model", form.getModel());
+        body.put("temperature", form.getTemperature());
+        body.put("max_tokens", form.getMaxTokens());
+        body.put("prompt_name", form.getPromptName());
+        body.put("return_direct", form.getReturnDirect());
+
+        // 2. 寮傛澶勭悊SSE杞彂
+        CompletableFuture.runAsync(() -> {
+            try {
+                WebClient client = WebClient.create(aiConfig.getFullDomain());
+                client.post()
+                        .uri("/chat/kb_chat")
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .accept(MediaType.TEXT_EVENT_STREAM) // 澹版槑鎺ュ彈SSE鍝嶅簲
+                        .bodyValue(body)
+                        .retrieve()
+                        .bodyToFlux(String.class) // 浣跨敤Flux鎺ユ敹娴佸紡鍝嶅簲
+                        .subscribe(
+                                data -> {
+                                    try {
+                                        emitter.send(SseEmitter.event().data(data));
+                                    } catch (IOException e) {
+                                        log.error("鍙戦�佸け璐�", e.getMessage());
+                                    }
+                                },
+                                error -> emitter.completeWithError(error),
+                                () -> emitter.complete()
+                        );
+            } catch (Exception e) {
+                emitter.completeWithError(e);
+            }
+        });
+
+        // 3. 杩炴帴鐢熷懡鍛ㄦ湡鍥炶皟
+        emitter.onCompletion(() -> log.info("SSE connection completed"));
+        emitter.onTimeout(() -> log.warn("SSE connection timed out"));
+        emitter.onError(ex -> log.error("SSE error: {}", ex.getMessage()));
+        return emitter;
+    }
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/service/impl/SessionMsgServiceImpl.java b/ai-chat/src/main/java/com/monkeylessey/service/impl/SessionMsgServiceImpl.java
new file mode 100644
index 0000000..c3a0a87
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/service/impl/SessionMsgServiceImpl.java
@@ -0,0 +1,119 @@
+package com.monkeylessey.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.monkeylessey.domain.entity.SessionMsg;
+import com.monkeylessey.mapper.SessionMsgMapper;
+import com.monkeylessey.service.SessionMsgService;
+import com.monkeylessey.response.Result;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.monkeylessey.domain.form.SessionMsgForm;
+import com.monkeylessey.domain.vo.SessionMsgVO;
+import com.monkeylessey.domain.query.SessionMsgQuery;
+import org.springframework.stereotype.Service;
+import lombok.RequiredArgsConstructor;
+import com.monkeylessey.utils.PageUtil;
+import org.springframework.beans.BeanUtils;
+import org.springframework.util.Assert;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 浼氳瘽娑堟伅 鏈嶅姟瀹炵幇绫�
+ *
+ * @author 鍚戝煿
+ * @since 2025-04-18
+ */
+@Service
+@RequiredArgsConstructor
+public class SessionMsgServiceImpl extends ServiceImpl<SessionMsgMapper, SessionMsg> implements SessionMsgService {
+
+    private final SessionMsgMapper sessionMsgMapper;
+
+    /**
+     * 娣诲姞
+     * @param form
+     * @return
+     */
+    @Override
+    public Result add(SessionMsgForm form) {
+        SessionMsg entity = SessionMsgForm.getEntityByForm(form, null);
+        baseMapper.insert(entity);
+        return Result.ok("娣诲姞鎴愬姛");
+    }
+
+    /**
+     * 淇敼
+     * @param form
+     * @return
+     */
+    @Override
+    public Result update(SessionMsgForm form) {
+        SessionMsg entity = baseMapper.selectById(form.getId());
+
+        // 涓虹┖鎶汭llegalArgumentException锛屽仛鍏ㄥ眬寮傚父澶勭悊
+        Assert.notNull(entity, "璁板綍涓嶅瓨鍦�");
+        BeanUtils.copyProperties(form, entity);
+        baseMapper.updateById(entity);
+        return Result.ok("淇敼鎴愬姛");
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎
+     * @param ids
+     * @return
+     */
+    @Override
+    public Result remove(List<String> ids) {
+        baseMapper.deleteBatchIds(ids);
+        return Result.ok("鍒犻櫎鎴愬姛");
+    }
+
+    /**
+     * id鍒犻櫎
+     * @param id
+     * @return
+     */
+    @Override
+    public Result removeById(String id) {
+        baseMapper.deleteById(id);
+        return Result.ok("鍒犻櫎鎴愬姛");
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ
+     * @param query
+     * @return
+     */
+    @Override
+    public Result page(SessionMsgQuery query) {
+        IPage<SessionMsgVO> page = PageUtil.getPage(query, SessionMsgVO.class);
+        baseMapper.getPage(page, query);
+        return Result.ok().data(page.getRecords()).total(page.getTotal());
+    }
+
+    /**
+     * 鏍规嵁id鏌ユ壘
+     * @param id
+     * @return
+     */
+    @Override
+    public Result detail(Integer id) {
+        SessionMsgVO vo = baseMapper.getById(id);
+        Assert.notNull(vo, "璁板綍涓嶅瓨鍦�");
+        return Result.ok().data(vo);
+    }
+
+    /**
+     * 鍒楄〃
+     * @return
+     */
+    @Override
+    public Result all() {
+        List<SessionMsg> entities = baseMapper.selectList(null);
+        List<SessionMsgVO> vos = entities.stream()
+                .map(entity -> SessionMsgVO.getVoByEntity(entity, null))
+                .collect(Collectors.toList());
+        return Result.ok().data(vos);
+    }
+}
diff --git a/ai-chat/src/main/java/com/monkeylessey/service/impl/SessionServiceImpl.java b/ai-chat/src/main/java/com/monkeylessey/service/impl/SessionServiceImpl.java
new file mode 100644
index 0000000..4160fb3
--- /dev/null
+++ b/ai-chat/src/main/java/com/monkeylessey/service/impl/SessionServiceImpl.java
@@ -0,0 +1,146 @@
+package com.monkeylessey.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.monkeylessey.domain.entity.Session;
+import com.monkeylessey.domain.form.SessionForm;
+import com.monkeylessey.domain.query.SessionQuery;
+import com.monkeylessey.domain.vo.SessionCountVO;
+import com.monkeylessey.domain.vo.SessionVO;
+import com.monkeylessey.mapper.SessionMapper;
+import com.monkeylessey.service.SessionService;
+import com.monkeylessey.response.Result;
+import com.monkeylessey.utils.DateUtil;
+import com.monkeylessey.utils.PageUtil;
+import org.springframework.stereotype.Service;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.util.Assert;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * chat瀵硅瘽 鏈嶅姟瀹炵幇绫�
+ *
+ * @author 鍚戝煿
+ * @since 2025-04-18
+ */
+@Service
+@RequiredArgsConstructor
+public class SessionServiceImpl extends ServiceImpl<SessionMapper, Session> implements SessionService {
+
+    private final SessionMapper sessionMapper;
+
+    /**
+     * 娣诲姞
+     * @param form
+     * @return
+     */
+    @Override
+    public Result add(SessionForm form) {
+        Session entity = SessionForm.getEntityByForm(form, null);
+        baseMapper.insert(entity);
+        return Result.ok("娣诲姞鎴愬姛");
+    }
+
+    /**
+     * 淇敼
+     * @param form
+     * @return
+     */
+    @Override
+    public Result update(SessionForm form) {
+        Session entity = baseMapper.selectById(form.getId());
+
+        // 涓虹┖鎶汭llegalArgumentException锛屽仛鍏ㄥ眬寮傚父澶勭悊
+        Assert.notNull(entity, "璁板綍涓嶅瓨鍦�");
+        BeanUtils.copyProperties(form, entity);
+        baseMapper.updateById(entity);
+        return Result.ok("淇敼鎴愬姛");
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎
+     * @param ids
+     * @return
+     */
+    @Override
+    public Result remove(List<String> ids) {
+        baseMapper.deleteBatchIds(ids);
+        return Result.ok("鍒犻櫎鎴愬姛");
+    }
+
+    /**
+     * id鍒犻櫎
+     * @param id
+     * @return
+     */
+    @Override
+    public Result removeById(String id) {
+        baseMapper.deleteById(id);
+        return Result.ok("鍒犻櫎鎴愬姛");
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ
+     * @param query
+     * @return
+     */
+    @Override
+    public Result page(SessionQuery query) {
+        IPage<SessionVO> page = PageUtil.getPage(query, SessionVO.class);
+        baseMapper.getPage(page, query);
+        return Result.ok().data(page.getRecords()).total(page.getTotal());
+    }
+
+    /**
+     * 鏍规嵁id鏌ユ壘
+     * @param id
+     * @return
+     */
+    @Override
+    public Result detail(Integer id) {
+        SessionVO vo = baseMapper.getById(id);
+        Assert.notNull(vo, "璁板綍涓嶅瓨鍦�");
+        return Result.ok().data(vo);
+    }
+
+    /**
+     * 鍒楄〃
+     * @return
+     */
+    @Override
+    public Result all() {
+        List<Session> entities = baseMapper.selectList(null);
+        List<SessionVO> vos = entities.stream()
+                .map(entity -> SessionVO.getVoByEntity(entity, null))
+                .collect(Collectors.toList());
+        return Result.ok().data(vos);
+    }
+
+
+    @Override
+    public Result clientList() {
+        Date now = new Date();
+        // TODO锛寀serId鏌ヨ
+        // 浠婂ぉ
+        List<SessionVO> todaySession = baseMapper.getTodaySessionList(DateUtil.getDayStart(now), DateUtil.getDayEnd(now));
+        // 鏄ㄥぉ
+        Calendar instance = Calendar.getInstance();
+        instance.setTime(now);
+        instance.add(Calendar.DATE, -1);
+        Date yesterday = instance.getTime();
+        List<SessionVO> yesterdaySession = baseMapper.getYesterdaySessionList(DateUtil.getDayStart(yesterday), DateUtil.getDayEnd(yesterday));
+        // 鏇存棭
+        List<SessionVO> oldSession = baseMapper.getOldSessionList(DateUtil.getDayStart(yesterday));
+
+        SessionCountVO vo = new SessionCountVO();
+        vo.setToday(todaySession);
+        vo.setYesterday(yesterdaySession);
+        vo.setOld(oldSession);
+        return Result.ok().data(vo);
+    }
+}
diff --git a/ai-chat/src/main/resources/mapper/SessionMapper.xml b/ai-chat/src/main/resources/mapper/SessionMapper.xml
new file mode 100644
index 0000000..ad68b14
--- /dev/null
+++ b/ai-chat/src/main/resources/mapper/SessionMapper.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.monkeylessey.mapper.SessionMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.monkeylessey.domain.vo.SessionVO">
+        <result column="session_name" property="sessionName" />
+        <result column="mode" property="mode" />
+        <result column="kb_name" property="kbName" />
+        <result column="top_k" property="topK" />
+        <result column="score_threshold" property="scoreThreshold" />
+        <result column="stream" property="stream" />
+        <result column="model" property="model" />
+        <result column="temperature" property="temperature" />
+        <result column="max_tokens" property="maxTokens" />
+        <result column="prompt_name" property="promptName" />
+        <result column="return_direct" property="returnDirect" />
+        <result column="user_id" property="userId" />
+    </resultMap>
+
+
+
+
+
+
+
+    <select id="getById" resultMap="BaseResultMap">
+        SELECT
+            SE.session_name,
+            SE.mode,
+            SE.kb_name,
+            SE.top_k,
+            SE.score_threshold,
+            SE.stream,
+            SE.model,
+            SE.temperature,
+            SE.max_tokens,
+            SE.prompt_name,
+            SE.return_direct,
+            SE.user_id,
+            SE.id
+        FROM
+            ai_session SE
+        WHERE
+            SE.id = #{id} AND SE.deleted = 0
+    </select>
+
+
+    <select id="getPage" resultMap="BaseResultMap">
+        SELECT
+            SE.session_name,
+            SE.mode,
+            SE.kb_name,
+            SE.top_k,
+            SE.score_threshold,
+            SE.stream,
+            SE.model,
+            SE.temperature,
+            SE.max_tokens,
+            SE.prompt_name,
+            SE.return_direct,
+            SE.user_id,
+            SE.id
+        FROM
+            ai_session SE
+        WHERE
+            SE.deleted = 0
+            <if test="query.sessionName != null and query.sessionName != ''">
+                AND SE.session_name = #{query.sessionName}
+            </if>
+    </select>
+
+
+    <select id="getTodaySessionList" resultMap="BaseResultMap">
+        SELECT * FROM ai_session WHERE gmt_create between #{dayStart} and #{dayEnd} AND deleted = 0 ORDER BY gmt_create DESC
+    </select>
+
+
+    <select id="getYesterdaySessionList" resultMap="BaseResultMap">
+        SELECT * FROM ai_session WHERE gmt_create between #{dayStart} and #{dayEnd} AND deleted = 0 ORDER BY gmt_create DESC
+    </select>
+
+    <select id="getOldSessionList" resultMap="BaseResultMap">
+        SELECT * FROM ai_session WHERE gmt_create &lt; #{time} AND deleted = 0 ORDER BY gmt_create DESC
+    </select>
+</mapper>
diff --git a/ai-chat/src/main/resources/mapper/SessionMsgMapper.xml b/ai-chat/src/main/resources/mapper/SessionMsgMapper.xml
new file mode 100644
index 0000000..079d7f6
--- /dev/null
+++ b/ai-chat/src/main/resources/mapper/SessionMsgMapper.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.monkeylessey.mapper.SessionMsgMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.monkeylessey.domain.vo.SessionMsgVO">
+        <result column="session_id" property="sessionId" />
+        <result column="role" property="role" />
+        <result column="content" property="content" />
+    </resultMap>
+
+
+
+
+
+
+
+    <select id="getById" resultMap="BaseResultMap">
+        SELECT
+            ASM.session_id,
+            ASM.role,
+            ASM.content,
+            ASM.id
+        FROM
+            ai_session_msg ASM
+        WHERE
+            ASM.id = #{id} AND ASM.deleted = 0
+    </select>
+
+
+    <select id="getPage" resultMap="BaseResultMap">
+        SELECT
+            ASM.session_id,
+            ASM.role,
+            ASM.content,
+            ASM.id
+        FROM
+            ai_session_msg ASM
+        WHERE
+            ASM.deleted = 0
+            <if test="query.content != null and query.content != ''">
+                AND ASM.content = #{query.content}
+            </if>
+    </select>
+
+</mapper>
diff --git a/dev-admin/src/main/resources/application-dev.yml b/dev-admin/src/main/resources/application-dev.yml
index e606970..6199ba4 100644
--- a/dev-admin/src/main/resources/application-dev.yml
+++ b/dev-admin/src/main/resources/application-dev.yml
@@ -53,3 +53,10 @@
   domain: http://127.0.0.1:${server.port}/files/
 
 
+# 鐭ヨ瘑搴撻厤缃�
+ai:
+  domain: http://i-1.gpushare.com
+  port: 52574
+
+
+
diff --git a/dev-admin/src/main/resources/application-prod.yml b/dev-admin/src/main/resources/application-prod.yml
index b829bf6..afedac2 100644
--- a/dev-admin/src/main/resources/application-prod.yml
+++ b/dev-admin/src/main/resources/application-prod.yml
@@ -48,3 +48,9 @@
   # 鏂囦欢璺緞 绀轰緥锛� Windows閰嶇疆D:/ruoyi/uploadPath锛孡inux閰嶇疆 /home/ruoyi/uploadPath锛�
   url: E:/ycl/file
   domain: http://127.0.0.1:${server.port}/files/
+
+
+# 鐭ヨ瘑搴撻厤缃�
+ai:
+  domain: http://i-1.gpushare.com
+  port: 52574
diff --git a/dev-sys/src/main/java/com/monkeylessey/framework/config/TokenSecurityConfig.java b/dev-sys/src/main/java/com/monkeylessey/framework/config/TokenSecurityConfig.java
index 5e93c84..d407f5c 100644
--- a/dev-sys/src/main/java/com/monkeylessey/framework/config/TokenSecurityConfig.java
+++ b/dev-sys/src/main/java/com/monkeylessey/framework/config/TokenSecurityConfig.java
@@ -65,6 +65,7 @@
                 .authenticationEntryPoint(authenticationException);
 
         http.authorizeRequests()
+                .antMatchers("/**").permitAll()
                 .antMatchers(HttpMethod.POST, "/xpstart/login").permitAll()
                 .antMatchers("/sys-table/columns/**").permitAll()
                 .antMatchers("/ws/**").permitAll()
diff --git a/dev-sys/src/main/java/com/monkeylessey/gen/handler/QueryHandler.java b/dev-sys/src/main/java/com/monkeylessey/gen/handler/QueryHandler.java
index 62e21ca..c6629be 100644
--- a/dev-sys/src/main/java/com/monkeylessey/gen/handler/QueryHandler.java
+++ b/dev-sys/src/main/java/com/monkeylessey/gen/handler/QueryHandler.java
@@ -37,7 +37,7 @@
         queryTemplate.setFields(columnS);
         // 璁剧疆query鐨勭埗绫诲悕
         queryTemplate.setBaseQueryName("AbsQuery");
-        queryTemplate.setBaseQueryPath("com.monkeylessey.base");
+        queryTemplate.setBaseQueryPath("com.monkeylessey.sys.domain.base");
         objectMap.put("queryInfo", queryTemplate);
         return new VueHandler().handler(objectMap, data);
     }
diff --git a/dev-sys/src/main/java/com/monkeylessey/gen/handler/VoHandler.java b/dev-sys/src/main/java/com/monkeylessey/gen/handler/VoHandler.java
index d6d3732..26c1b46 100644
--- a/dev-sys/src/main/java/com/monkeylessey/gen/handler/VoHandler.java
+++ b/dev-sys/src/main/java/com/monkeylessey/gen/handler/VoHandler.java
@@ -42,7 +42,7 @@
         voTemplate.setFields(columns);
         // 璁剧疆vo鐨勭埗绫诲悕
         voTemplate.setBaseVoName("AbsVo");
-        voTemplate.setBaseVoPath("com.monkeylessey.base");
+        voTemplate.setBaseVoPath("com.monkeylessey.sys.domain.base");
 
         voTemplate.setTableSimpleName(WordsUtils.extractFirstLetters(tableInfo.getName(), "_"));
 
diff --git a/dev-sys/src/main/java/com/monkeylessey/gen/utils/GenerateCodeUtil.java b/dev-sys/src/main/java/com/monkeylessey/gen/utils/GenerateCodeUtil.java
index ff60eb0..0efa29f 100644
--- a/dev-sys/src/main/java/com/monkeylessey/gen/utils/GenerateCodeUtil.java
+++ b/dev-sys/src/main/java/com/monkeylessey/gen/utils/GenerateCodeUtil.java
@@ -116,12 +116,12 @@
                 .packageConfig(builder -> {
                     builder.parent("com.monkeylessey")
                             //.moduleName("onceCode")
-                            .entity("sys.domain.entity")
+                            .entity("domain.entity")
                             .service("service")
                             .serviceImpl("service.impl")
                             .controller("controller")
                             .mapper("mapper")
-                            .other("sys.domain")
+                            .other("domain")
                             .xml("mapper")
                             .pathInfo(Collections.singletonMap(OutputFile.other, finalOutDir + "\\domain"))
                             .pathInfo(Collections.singletonMap(OutputFile.xml, finalMapperDir));
diff --git a/dev-sys/src/main/resources/templates/serviceImpl.java.vm b/dev-sys/src/main/resources/templates/serviceImpl.java.vm
index 79c7aa0..b4fc2a5 100644
--- a/dev-sys/src/main/resources/templates/serviceImpl.java.vm
+++ b/dev-sys/src/main/resources/templates/serviceImpl.java.vm
@@ -14,9 +14,10 @@
 #if(${entityLombokModel})
 import lombok.RequiredArgsConstructor;
 #end
-import com.ycl.jxkg.utils.PageUtil;
+import com.monkeylessey.utils.PageUtil;
 import org.springframework.beans.BeanUtils;
 import org.springframework.util.Assert;
+import com.baomidou.mybatisplus.core.metadata.IPage;
 
 import java.util.List;
 import java.util.stream.Collectors;
diff --git a/pom.xml b/pom.xml
index a13f860..b7f0825 100644
--- a/pom.xml
+++ b/pom.xml
@@ -93,6 +93,13 @@
                 <version>${version}</version>
             </dependency>
 
+            <!-- 鍏叡妯″潡 -->
+            <dependency>
+                <groupId>com.monkeylessey</groupId>
+                <artifactId>ai-chat</artifactId>
+                <version>${version}</version>
+            </dependency>
+
         </dependencies>
     </dependencyManagement>
 

--
Gitblit v1.8.0