Преглед изворни кода

Merge remote-tracking branch 'origin/master-jdk21-ai' into master-jdk21-ai

cherishsince пре 11 месеци
родитељ
комит
1fa799f6a9
19 измењених фајлова са 240 додато и 231 уклоњено
  1. 9 8
      yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/ErrorCodeConstants.java
  2. 25 26
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatConversationController.java
  3. 13 0
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationCreateMyReqVO.java
  4. 0 17
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationCreateReqVO.java
  5. 0 13
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationListReqVO.java
  6. 2 2
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationUpdateMyReqVO.java
  7. 1 7
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/convert/AiChatConversationConvert.java
  8. 2 0
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatConversationDO.java
  9. 2 0
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatModelDO.java
  10. 8 15
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/AiChatModelMapper.java
  11. 10 0
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/AiChatRoleMapper.java
  12. 14 16
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatConversationService.java
  13. 112 0
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatConversationServiceImpl.java
  14. 0 121
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatConversationServiceImpl.java
  15. 1 1
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatServiceImpl.java
  16. 9 1
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatModelService.java
  17. 11 2
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatModelServiceImpl.java
  18. 10 0
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleService.java
  19. 11 2
      yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleServiceImpl.java

+ 9 - 8
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/ErrorCodeConstants.java

@@ -14,17 +14,21 @@ public interface ErrorCodeConstants {
     ErrorCode API_KEY_DISABLE = new ErrorCode(1_040_000_001, "AI API 密钥已禁用!");
 
     // ========== API 聊天模型 1-040-001-000 ==========
-
-    ErrorCode CHAT_MODAL_NOT_EXIST = new ErrorCode(1_040_001_000, "AI 模型不存在!");
-    ErrorCode CHAT_MODAL_DISABLE = new ErrorCode(1_040_001_001, "AI 模型({})已禁用!");
+    ErrorCode CHAT_MODEL_NOT_EXISTS = new ErrorCode(1_040_001_000, "AI 模型不存在!");
+    ErrorCode CHAT_MODEL_DISABLE = new ErrorCode(1_040_001_001, "AI 模型({})已禁用!");
+    ErrorCode CHAT_MODEL_DEFAULT_NOT_EXISTS = new ErrorCode(1_040_001_002, "操作失败,找不到默认聊天模型");
 
     // ========== API 聊天模型 1-040-002-000 ==========
     ErrorCode CHAT_ROLE_NOT_EXISTS = new ErrorCode(1_040_002_000, "AI 聊天角色不存在");
     ErrorCode CHAT_ROLE_DISABLE = new ErrorCode(1_040_001_001, "AI 聊天角色({})已禁用!");
+    ErrorCode CHAT_ROLE_DEFAULT_NOT_EXISTS = new ErrorCode(1_040_001_002, "操作失败,找不到默认聊天角色");
+
+    // ========== API 聊天会话 1-040-003-000 ==========
 
-    // conversation
+    ErrorCode CHAT_CONVERSATION_NOT_EXISTS = new ErrorCode(1_040_003_000, "AI 对话不存在!");;
 
-    ErrorCode AI_CONVERSATION_NOT_EXISTS = new ErrorCode(1_022_000_002, "AI 对话不存在!");;
+    // chat
+    ErrorCode AI_CHAT_MESSAGE_NOT_EXIST = new ErrorCode(1_022_000_100, "AI 提问的 MessageId 不存在!");
 
     // midjourney
 
@@ -32,7 +36,4 @@ public interface ErrorCodeConstants {
     ErrorCode AI_MIDJOURNEY_OPERATION_NOT_EXISTS = new ErrorCode(1_022_000_040, "midjourney 操作不存在!");
     ErrorCode AI_MIDJOURNEY_MESSAGE_ID_INCORRECT = new ErrorCode(1_022_000_040, "midjourney message id 不正确!");
 
-    // chat
-    ErrorCode AI_CHAT_MESSAGE_NOT_EXIST = new ErrorCode(1_022_000_100, "AI 提问的 MessageId 不存在!");
-
 }

+ 25 - 26
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatConversationController.java

@@ -1,53 +1,50 @@
 package cn.iocoder.yudao.module.ai.controller.admin.chat;
 
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateReqVO;
+import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO;
 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO;
-import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateReqVO;
-import cn.iocoder.yudao.module.ai.service.AiChatConversationService;
+import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO;
+import cn.iocoder.yudao.module.ai.service.chat.AiChatConversationService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
 import jakarta.validation.Valid;
-import lombok.AllArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 
-@Slf4j
-@Tag(name = "管理后台 - 聊天会话")
+@Tag(name = "管理后台 - AI 聊天会话")
 @RestController
 @RequestMapping("/ai/chat/conversation")
-@AllArgsConstructor
+@Validated
 public class AiChatConversationController {
 
-    private final AiChatConversationService aiChatConversationService;
+    @Resource
+    private AiChatConversationService chatConversationService;
 
-    // TODO done @fan:实现一下
-    @PostMapping("/create")
-    @Operation(summary = "创建聊天会话")
-    @PreAuthorize("@ss.hasPermission('ai:chat-conversation:create')")
-    public CommonResult<Long> createConversation(@RequestBody @Valid AiChatConversationCreateReqVO createReqVO) {
-        return success(aiChatConversationService.createConversation(createReqVO));
+    @PostMapping("/create-my")
+    @Operation(summary = "创建【我的】聊天会话")
+    public CommonResult<Long> createChatConversationMy(@RequestBody @Valid AiChatConversationCreateMyReqVO createReqVO) {
+        return success(chatConversationService.createChatConversationMy(createReqVO, getLoginUserId()));
     }
 
-    // TODO done @fan:实现一下
-    @PutMapping("/update")
-    @Operation(summary = "更新聊天会话")
-    @PreAuthorize("@ss.hasPermission('ai:chat-conversation:create')")
-    public CommonResult<Boolean> updateConversation(@RequestBody @Valid AiChatConversationUpdateReqVO updateReqVO) {
-        return success(aiChatConversationService.updateConversation(updateReqVO));
+    @PutMapping("/update-my")
+    @Operation(summary = "更新【我的】聊天会话")
+    public CommonResult<Boolean> updateChatConversationMy(@RequestBody @Valid AiChatConversationUpdateMyReqVO updateReqVO) {
+        chatConversationService.updateChatConversationMy(updateReqVO, getLoginUserId());
+        return success(true);
     }
 
     // TODO done @fan:实现一下
-    @GetMapping("/list")
+    @GetMapping("/my-list")
     @Operation(summary = "获得聊天会话列表")
     public CommonResult<List<AiChatConversationRespVO>> getConversationList() {
-        return success(aiChatConversationService.listConversation());
+        return success(chatConversationService.listConversation());
     }
 
     // TODO @fan:实现一下
@@ -55,7 +52,7 @@ public class AiChatConversationController {
     @Operation(summary = "获得聊天会话")
     @Parameter(name = "id", required = true, description = "会话编号", example = "1024")
     public CommonResult<AiChatConversationRespVO> getConversation(@RequestParam("id") Long id) {
-        return success(aiChatConversationService.getConversationOfValidate(id));
+        return success(chatConversationService.getConversationOfValidate(id));
     }
 
     // TODO @fan:实现一下
@@ -63,7 +60,9 @@ public class AiChatConversationController {
     @Operation(summary = "删除聊天会话")
     @Parameter(name = "id", required = true, description = "会话编号", example = "1024")
     public CommonResult<Boolean> deleteConversation(@RequestParam("id") Long id) {
-        return success(aiChatConversationService.deleteConversation(id));
+        return success(chatConversationService.deleteConversation(id));
     }
 
+    // ========== 会话管理 ==========
+
 }

+ 13 - 0
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationCreateMyReqVO.java

@@ -0,0 +1,13 @@
+package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - AI 聊天会话创建【我的】 Request VO")
+@Data
+public class AiChatConversationCreateMyReqVO {
+
+    @Schema(description = "聊天角色编号", example = "666")
+    private Long roleId;
+
+}

+ 0 - 17
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationCreateReqVO.java

@@ -1,17 +0,0 @@
-package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotNull;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-import lombok.experimental.Accessors;
-
-@Schema(description = "管理后台 - AI 聊天会话创建 Request VO")
-@Data
-public class AiChatConversationCreateReqVO {
-
-    @Schema(description = "角色编号", example = "666")
-    private Long roleId;
-
-}

+ 0 - 13
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationListReqVO.java

@@ -1,13 +0,0 @@
-package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-@Schema(description = "管理后台 - AI 聊天会话 Response VO")
-@Data
-public class AiChatConversationListReqVO {
-
-    @Schema(description = "会话标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是一个标题")
-    private String title;
-
-}

+ 2 - 2
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationUpdateReqVO.java → yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationUpdateMyReqVO.java

@@ -4,9 +4,9 @@ import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 
-@Schema(description = "管理后台 - AI 聊天会话更新 Request VO")
+@Schema(description = "管理后台 - AI 聊天会话更新【我的】 Request VO")
 @Data
-public class AiChatConversationUpdateReqVO {
+public class AiChatConversationUpdateMyReqVO {
 
     @Schema(description = "会话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
     @NotNull(message = "会话编号不能为空")

+ 1 - 7
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/convert/AiChatConversationConvert.java

@@ -1,6 +1,6 @@
 package cn.iocoder.yudao.module.ai.convert;
 
-import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateReqVO;
+import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO;
 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO;
 import org.mapstruct.Mapper;
@@ -36,10 +36,4 @@ public interface AiChatConversationConvert {
      */
     AiChatConversationRespVO covnertChatConversationRes(AiChatConversationDO aiChatConversationDO);
 
-    /**
-     * 转换 - AiChatConversationDO
-     *
-     * @param updateReqVO
-     */
-    AiChatConversationDO convertAiChatConversationDO(AiChatConversationUpdateReqVO updateReqVO);
 }

+ 2 - 0
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatConversationDO.java

@@ -26,6 +26,8 @@ import lombok.*;
 @AllArgsConstructor
 public class AiChatConversationDO extends BaseDO {
 
+    public static final String TITLE_DEFAULT = "新对话";
+
     /**
      * ID 编号,自增
      */

+ 2 - 0
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatModelDO.java

@@ -11,6 +11,8 @@ import lombok.*;
 /**
  * AI 聊天模型 DO
  *
+ * 默认聊天模型:{@link #status} 为开启,并且 {@link #sort} 排序第一
+ *
  * @author fansili
  * @since 2024/4/24 19:39
  */

+ 8 - 15
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/AiChatModelMapper.java

@@ -5,8 +5,10 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
 import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatModel.AiChatModelPageReqVO;
 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
 
 import java.util.List;
@@ -22,23 +24,14 @@ import java.util.List;
 @Mapper
 public interface AiChatModelMapper extends BaseMapperX<AiChatModelDO> {
 
-    // TODO 芋艿:要搞一下
-    /**
-     * 查询 - 第一个modal
-     *
-     * @return
-     */
-    default AiChatModelDO selectFirstModal() {
-        PageResult<AiChatModelDO> pageResult = selectPage(new PageParam().setPageNo(1).setPageSize(1),
-                new LambdaQueryWrapperX<AiChatModelDO>()
-                        .orderByAsc(AiChatModelDO::getSort)
-        );
-        if (CollUtil.isEmpty(pageResult.getList())) {
-            return null;
-        }
-        return pageResult.getList().get(0);
+    default AiChatModelDO selectFirstByStatus(Integer status) {
+        return selectOne(new QueryWrapperX<AiChatModelDO>()
+                .eq("status", status)
+                .limitN(1)
+                .orderByAsc("sort"));
     }
 
+    // TODO 芋艿:不需要哈
     /**
      * 查询 - 根据 ids
      *

+ 10 - 0
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/AiChatRoleMapper.java

@@ -4,7 +4,9 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
 import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRolePageReqVO;
+import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -18,6 +20,14 @@ import java.util.List;
 @Mapper
 public interface AiChatRoleMapper extends BaseMapperX<AiChatRoleDO> {
 
+    default AiChatRoleDO selectFirstByPublicStatusAndStatus(Boolean publicStatus, Integer status) {
+        return selectOne(new QueryWrapperX<AiChatRoleDO>()
+                .eq("status", status)
+                .eq("public_status", publicStatus)
+                .limitN(1)
+                .orderByAsc("sort"));
+    }
+
     default PageResult<AiChatRoleDO> selectPage(AiChatRolePageReqVO reqVO) {
         return selectPage(reqVO, new LambdaQueryWrapperX<AiChatRoleDO>()
                 .likeIfPresent(AiChatRoleDO::getName, reqVO.getName())

+ 14 - 16
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/AiChatConversationService.java → yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatConversationService.java

@@ -1,37 +1,35 @@
-package cn.iocoder.yudao.module.ai.service;
+package cn.iocoder.yudao.module.ai.service.chat;
 
-import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateReqVO;
-import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationListReqVO;
+import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO;
 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO;
-import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateReqVO;
+import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO;
 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
-import org.jetbrains.annotations.NotNull;
 
 import java.util.List;
 
 /**
- * chat 对话
+ * AI 聊天对话 Service 接口
  *
- * @fansili
- * @since v1.0
+ * @author fansili
  */
 public interface AiChatConversationService {
 
     /**
-     * 对话 - 创建对
+     * 创建【我的】聊天会
      *
-     * @param req
-     * @return
+     * @param createReqVO 创建信息
+     * @param userId 用户编号
+     * @return 聊天会话
      */
-    Long createConversation(AiChatConversationCreateReqVO req);
+    Long createChatConversationMy(AiChatConversationCreateMyReqVO createReqVO, Long userId);
 
     /**
-     * 对话 - 更新对
+     * 更新【我的】聊天会
      *
-     * @param updateReqVO
-     * @return
+     * @param updateReqVO 更新信息
+     * @param userId 用户编号
      */
-    Boolean updateConversation(AiChatConversationUpdateReqVO updateReqVO);
+    void updateChatConversationMy(AiChatConversationUpdateMyReqVO updateReqVO, Long userId);
 
     /**
      * 获取 - 对话列表

+ 112 - 0
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatConversationServiceImpl.java

@@ -0,0 +1,112 @@
+package cn.iocoder.yudao.module.ai.service.chat;
+
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO;
+import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO;
+import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO;
+import cn.iocoder.yudao.module.ai.convert.AiChatConversationConvert;
+import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
+import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
+import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO;
+import cn.iocoder.yudao.module.ai.dal.mysql.AiChatConversationMapper;
+import cn.iocoder.yudao.module.ai.service.model.AiChatModelService;
+import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.*;
+import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS;
+
+/**
+ * AI 聊天对话 Service 实现类
+ *
+ * @author fansili
+ */
+@Service
+@Validated
+@Slf4j
+public class AiChatConversationServiceImpl implements AiChatConversationService {
+
+    @Resource
+    private AiChatConversationMapper chatConversationMapper;
+
+    @Resource
+    private AiChatModelService chatModalService;
+    @Resource
+    private AiChatRoleService chatRoleService;
+
+    @Override
+    public Long createChatConversationMy(AiChatConversationCreateMyReqVO createReqVO, Long userId) {
+        // 1.1 获得 AiChatRoleDO 聊天角色
+        AiChatRoleDO role = createReqVO.getRoleId() != null ? chatRoleService.validateChatRole(createReqVO.getRoleId())
+                : chatRoleService.getRequiredDefaultChatRole();
+        Assert.notNull(role, "必须找到聊天角色");
+        // 1.2 获得 AiChatModelDO 聊天模型
+        AiChatModelDO model = role.getModelId() != null ? chatModalService.validateChatModel(role.getId())
+                : chatModalService.getRequiredDefaultChatModel();
+        Assert.notNull(role, "必须找到默认模型");
+
+        // 2. 创建 AiChatConversationDO 聊天对话
+        AiChatConversationDO conversation = new AiChatConversationDO()
+                .setUserId(userId).setTitle(AiChatConversationDO.TITLE_DEFAULT).setPinned(false)
+                .setRoleId(role.getId()).setModelId(model.getId()).setModel(model.getModel())
+                .setTemperature(model.getTemperature()).setMaxTokens(model.getMaxTokens()).setMaxContexts(model.getMaxContexts());
+        chatConversationMapper.insert(conversation);
+        return conversation.getId();
+    }
+
+    @Override
+    public void updateChatConversationMy(AiChatConversationUpdateMyReqVO updateReqVO, Long userId) {
+        // 1.1 校验对话是否存在
+        AiChatConversationDO conversation = validateExists(updateReqVO.getId());
+        if (ObjUtil.notEqual(conversation.getUserId(), userId)) {
+            throw exception(CHAT_CONVERSATION_NOT_EXISTS);
+        }
+        // 1.2 校验模型是否存在
+        AiChatModelDO model = null;
+        if (updateReqVO.getModelId() != null) {
+            model = chatModalService.validateChatModel(updateReqVO.getModelId());
+        }
+        // 1.3 校验温度参数、Token 数量、消息数量 TODO
+
+        // 更新对话信息
+        chatConversationMapper.updateById(BeanUtils.toBean(updateReqVO, AiChatConversationDO.class));
+    }
+
+    @Override
+    public List<AiChatConversationRespVO> listConversation() {
+        // 获取用户id
+        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
+        // 查询前100对话
+        List<AiChatConversationDO> top100Conversation
+                = chatConversationMapper.selectTop100Conversation(loginUserId, null);
+        return AiChatConversationConvert.INSTANCE.covnertChatConversationResList(top100Conversation);
+    }
+
+    @Override
+    public AiChatConversationRespVO getConversationOfValidate(Long id) {
+        AiChatConversationDO aiChatConversationDO = validateExists(id);
+        return AiChatConversationConvert.INSTANCE.covnertChatConversationRes(aiChatConversationDO);
+    }
+
+    @Override
+    public Boolean deleteConversation(Long id) {
+        return chatConversationMapper.deleteById(id) > 0;
+    }
+
+    public AiChatConversationDO validateExists(Long id) {
+        AiChatConversationDO conversation = chatConversationMapper.selectById(id);
+        if (conversation == null) {
+            throw exception(CHAT_CONVERSATION_NOT_EXISTS);
+        }
+        return conversation;
+    }
+
+}

+ 0 - 121
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatConversationServiceImpl.java

@@ -1,121 +0,0 @@
-package cn.iocoder.yudao.module.ai.service.impl;
-
-import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
-import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
-import cn.iocoder.yudao.module.ai.AiCommonConstants;
-import cn.iocoder.yudao.module.ai.ErrorCodeConstants;
-import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateReqVO;
-import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO;
-import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateReqVO;
-import cn.iocoder.yudao.module.ai.convert.AiChatConversationConvert;
-import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
-import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
-import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO;
-import cn.iocoder.yudao.module.ai.dal.mysql.AiChatConversationMapper;
-import cn.iocoder.yudao.module.ai.dal.mysql.AiChatModelMapper;
-import cn.iocoder.yudao.module.ai.service.AiChatConversationService;
-import cn.iocoder.yudao.module.ai.service.model.AiChatModelService;
-import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService;
-import lombok.AllArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.jetbrains.annotations.NotNull;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-
-/**
- * chat 对话
- *
- * @fansili
- * @since v1.0
- */
-@Service
-@Slf4j
-@AllArgsConstructor
-public class AiChatConversationServiceImpl implements AiChatConversationService {
-
-    private final AiChatModelMapper aiChatModalMapper;
-    private final AiChatModelService aiChatModalService;
-    private final AiChatRoleService aiChatRoleService;
-    private final AiChatConversationMapper aiChatConversationMapper;
-
-    @Override
-    public Long createConversation(AiChatConversationCreateReqVO req) {
-        // 获取用户id
-        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
-        // 默认使用 sort 排序第一个模型
-        AiChatModelDO aiChatModalDO = aiChatModalMapper.selectFirstModal();
-        // 查询角色
-        AiChatRoleDO chatRoleRes = req.getRoleId() != null ? aiChatRoleService.getChatRole(req.getRoleId()) : null;
-        Long chatRoleId = chatRoleRes != null ? chatRoleRes.getId() : null;
-        // 创建新的 Conversation
-        AiChatConversationDO insertConversation = saveConversation(AiCommonConstants.CONVERSATION_DEFAULT_TITLE,
-                loginUserId, chatRoleId, aiChatModalDO.getId(), aiChatModalDO.getModel()
-        );
-        // 返回对话id
-        return insertConversation.getId();
-    }
-
-    private @NotNull AiChatConversationDO saveConversation(String title,
-                                                           Long userId,
-                                                           Long roleId,
-                                                           Long modalId,
-                                                           String model) {
-        AiChatConversationDO insertConversation = new AiChatConversationDO();
-        insertConversation.setId(null);
-        insertConversation.setUserId(userId);
-        insertConversation.setTitle(title);
-        insertConversation.setPinned(false);
-
-        insertConversation.setRoleId(roleId);
-        insertConversation.setModelId(modalId);
-        insertConversation.setModel(model);
-
-        insertConversation.setTemperature(null);
-        insertConversation.setMaxTokens(null);
-        insertConversation.setMaxContexts(null);
-        aiChatConversationMapper.insert(insertConversation);
-        return insertConversation;
-    }
-
-    @Override
-    public Boolean updateConversation(AiChatConversationUpdateReqVO updateReqVO) {
-        // 校验对话是否存在
-        validateExists(updateReqVO.getId());
-        // 获取模型信息并验证
-        aiChatModalService.validateChatModel(updateReqVO.getModelId());
-        // 更新对话信息
-        AiChatConversationDO updateAiChatConversationDO
-                = AiChatConversationConvert.INSTANCE.convertAiChatConversationDO(updateReqVO);
-        return aiChatConversationMapper.updateById(updateAiChatConversationDO) > 0;
-    }
-
-    @Override
-    public List<AiChatConversationRespVO> listConversation() {
-        // 获取用户id
-        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
-        // 查询前100对话
-        List<AiChatConversationDO> top100Conversation
-                = aiChatConversationMapper.selectTop100Conversation(loginUserId, null);
-        return AiChatConversationConvert.INSTANCE.covnertChatConversationResList(top100Conversation);
-    }
-
-    @Override
-    public AiChatConversationRespVO getConversationOfValidate(Long id) {
-        AiChatConversationDO aiChatConversationDO = validateExists(id);
-        return AiChatConversationConvert.INSTANCE.covnertChatConversationRes(aiChatConversationDO);
-    }
-
-    @Override
-    public Boolean deleteConversation(Long id) {
-        return aiChatConversationMapper.deleteById(id) > 0;
-    }
-
-    public @NotNull AiChatConversationDO validateExists(Long id) {
-        AiChatConversationDO aiChatConversationDO = aiChatConversationMapper.selectById(id);
-        if (aiChatConversationDO == null) {
-            throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_CONVERSATION_NOT_EXISTS);
-        }
-        return aiChatConversationDO;
-    }
-}

+ 1 - 1
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatServiceImpl.java

@@ -22,7 +22,7 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO;
 import cn.iocoder.yudao.module.ai.dal.mysql.AiChatConversationMapper;
 import cn.iocoder.yudao.module.ai.dal.mysql.AiChatMessageMapper;
-import cn.iocoder.yudao.module.ai.service.AiChatConversationService;
+import cn.iocoder.yudao.module.ai.service.chat.AiChatConversationService;
 import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService;
 import cn.iocoder.yudao.module.ai.service.AiChatService;
 import cn.iocoder.yudao.module.ai.service.model.AiChatModelService;

+ 9 - 1
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatModelService.java

@@ -8,7 +8,6 @@ import jakarta.validation.Valid;
 
 import java.util.List;
 
-import java.util.List;
 import java.util.Set;
 
 /**
@@ -49,6 +48,15 @@ public interface AiChatModelService {
      */
     AiChatModelDO getChatModel(Long id);
 
+    /**
+     * 获得默认的聊天模型
+     *
+     * 如果获取不到,则抛出 {@link cn.iocoder.yudao.framework.common.exception.ServiceException} 业务异常
+     *
+     * @return 聊天模型
+     */
+    AiChatModelDO getRequiredDefaultChatModel();
+
     /**
      * 获得聊天模型分页
      *

+ 11 - 2
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatModelServiceImpl.java

@@ -69,7 +69,7 @@ public class AiChatModelServiceImpl implements AiChatModelService {
     private AiChatModelDO validateChatModelExists(Long id) {
         AiChatModelDO model = chatModelMapper.selectById(id);
         if (chatModelMapper.selectById(id) == null) {
-            throw exception(CHAT_MODAL_NOT_EXIST);
+            throw exception(CHAT_MODEL_NOT_EXISTS);
         }
         return model;
     }
@@ -79,6 +79,15 @@ public class AiChatModelServiceImpl implements AiChatModelService {
         return chatModelMapper.selectById(id);
     }
 
+    @Override
+    public AiChatModelDO getRequiredDefaultChatModel() {
+        AiChatModelDO model = chatModelMapper.selectFirstByStatus(CommonStatusEnum.ENABLE.getStatus());
+        if (model == null) {
+            throw exception(CHAT_MODEL_DEFAULT_NOT_EXISTS);
+        }
+        return model;
+    }
+
     @Override
     public PageResult<AiChatModelDO> getChatModelPage(AiChatModelPageReqVO pageReqVO) {
         return chatModelMapper.selectPage(pageReqVO);
@@ -88,7 +97,7 @@ public class AiChatModelServiceImpl implements AiChatModelService {
     public AiChatModelDO validateChatModel(Long id) {
         AiChatModelDO model = validateChatModelExists(id);
         if (CommonStatusEnum.isDisable(model.getStatus())) {
-            throw exception(CHAT_MODAL_DISABLE);
+            throw exception(CHAT_MODEL_DISABLE);
         }
         return model;
     }

+ 10 - 0
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleService.java

@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRolePageReqVO;
 import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveMyReqVO;
 import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveReqVO;
+import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO;
 import jakarta.validation.Valid;
 
@@ -78,6 +79,15 @@ public interface AiChatRoleService {
      */
     AiChatRoleDO validateChatRole(Long id);
 
+    /**
+     * 获得默认的聊天角色
+     *
+     * 如果获取不到,则抛出 {@link cn.iocoder.yudao.framework.common.exception.ServiceException} 业务异常
+     *
+     * @return 聊天角色
+     */
+    AiChatRoleDO getRequiredDefaultChatRole();
+
     /**
      * 获得聊天角色分页
      *

+ 11 - 2
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleServiceImpl.java

@@ -17,8 +17,7 @@ import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
-import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.CHAT_ROLE_DISABLE;
-import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.CHAT_ROLE_NOT_EXISTS;
+import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.*;
 
 /**
  * AI 聊天角色 Service 实现类
@@ -110,6 +109,16 @@ public class AiChatRoleServiceImpl implements AiChatRoleService {
         return chatRole;
     }
 
+    @Override
+    public AiChatRoleDO getRequiredDefaultChatRole() {
+        AiChatRoleDO chatRole = chatRoleMapper.selectFirstByPublicStatusAndStatus(
+                true, CommonStatusEnum.ENABLE.getStatus());
+        if (chatRole == null) {
+            throw exception(CHAT_ROLE_DEFAULT_NOT_EXISTS);
+        }
+        return chatRole;
+    }
+
     @Override
     public PageResult<AiChatRoleDO> getChatRolePage(AiChatRolePageReqVO pageReqVO) {
         return chatRoleMapper.selectPage(pageReqVO);