From 64142965f36f6b4470e4637b320e99f08239e1a3 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 14 May 2024 13:24:55 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E3=80=91AI=EF=BC=9A?= =?UTF-8?q?=E8=81=8A=E5=A4=A9=E5=AF=B9=E8=AF=9D=E7=9A=84=E6=96=B0=E5=BB=BA?= =?UTF-8?q?=EF=BC=8850%=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/ai/ErrorCodeConstants.java | 17 +-- .../chat/AiChatConversationController.java | 55 ++++---- .../AiChatConversationCreateMyReqVO.java | 13 ++ .../AiChatConversationCreateReqVO.java | 17 --- .../AiChatConversationListReqVO.java | 13 -- ...a => AiChatConversationUpdateMyReqVO.java} | 4 +- .../ai/convert/AiChatConversationConvert.java | 8 +- .../dataobject/chat/AiChatConversationDO.java | 2 + .../dal/dataobject/model/AiChatModelDO.java | 2 + .../ai/dal/mysql/AiChatModelMapper.java | 23 ++-- .../module/ai/dal/mysql/AiChatRoleMapper.java | 10 ++ .../{ => chat}/AiChatConversationService.java | 30 ++--- .../chat/AiChatConversationServiceImpl.java | 112 ++++++++++++++++ .../impl/AiChatConversationServiceImpl.java | 121 ------------------ .../ai/service/impl/AiChatServiceImpl.java | 2 +- .../ai/service/model/AiChatModelService.java | 10 +- .../service/model/AiChatModelServiceImpl.java | 13 +- .../ai/service/model/AiChatRoleService.java | 10 ++ .../service/model/AiChatRoleServiceImpl.java | 13 +- 19 files changed, 242 insertions(+), 233 deletions(-) create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationCreateMyReqVO.java delete mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationCreateReqVO.java delete mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationListReqVO.java rename yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/{AiChatConversationUpdateReqVO.java => AiChatConversationUpdateMyReqVO.java} (88%) rename yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/{ => chat}/AiChatConversationService.java (60%) create mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatConversationServiceImpl.java delete mode 100644 yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatConversationServiceImpl.java diff --git a/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/ErrorCodeConstants.java b/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/ErrorCodeConstants.java index b65314f52..8948fcba4 100644 --- a/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/ErrorCodeConstants.java +++ b/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, "操作失败,找不到默认聊天角色"); - // conversation + // ========== API 聊天会话 1-040-003-000 ========== - ErrorCode AI_CONVERSATION_NOT_EXISTS = new ErrorCode(1_022_000_002, "AI 对话不存在!");; + ErrorCode CHAT_CONVERSATION_NOT_EXISTS = new ErrorCode(1_040_003_000, "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 不存在!"); - } diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatConversationController.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatConversationController.java index 7bd3c5a14..3e56cb999 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatConversationController.java +++ b/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 createConversation(@RequestBody @Valid AiChatConversationCreateReqVO createReqVO) { - return success(aiChatConversationService.createConversation(createReqVO)); + @PostMapping("/create-my") + @Operation(summary = "创建【我的】聊天会话") + public CommonResult createChatConversationMy(@RequestBody @Valid AiChatConversationCreateMyReqVO createReqVO) { + return success(chatConversationService.createChatConversationMy(createReqVO, getLoginUserId())); + } + + @PutMapping("/update-my") + @Operation(summary = "更新【我的】聊天会话") + public CommonResult updateChatConversationMy(@RequestBody @Valid AiChatConversationUpdateMyReqVO updateReqVO) { + chatConversationService.updateChatConversationMy(updateReqVO, getLoginUserId()); + return success(true); } // TODO done @fan:实现一下 - @PutMapping("/update") - @Operation(summary = "更新聊天会话") - @PreAuthorize("@ss.hasPermission('ai:chat-conversation:create')") - public CommonResult updateConversation(@RequestBody @Valid AiChatConversationUpdateReqVO updateReqVO) { - return success(aiChatConversationService.updateConversation(updateReqVO)); - } - - // TODO done @fan:实现一下 - @GetMapping("/list") + @GetMapping("/my-list") @Operation(summary = "获得聊天会话列表") public CommonResult> 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 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 deleteConversation(@RequestParam("id") Long id) { - return success(aiChatConversationService.deleteConversation(id)); + return success(chatConversationService.deleteConversation(id)); } + // ========== 会话管理 ========== + } diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationCreateMyReqVO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationCreateMyReqVO.java new file mode 100644 index 000000000..d64ea7f61 --- /dev/null +++ b/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; + +} diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationCreateReqVO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationCreateReqVO.java deleted file mode 100644 index b1e119659..000000000 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationCreateReqVO.java +++ /dev/null @@ -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; - -} diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationListReqVO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationListReqVO.java deleted file mode 100644 index 571cf0e38..000000000 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationListReqVO.java +++ /dev/null @@ -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; - -} diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationUpdateReqVO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationUpdateMyReqVO.java similarity index 88% rename from yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationUpdateReqVO.java rename to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationUpdateMyReqVO.java index e8bdabb19..4eb5a06c3 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationUpdateReqVO.java +++ b/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 = "会话编号不能为空") diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/convert/AiChatConversationConvert.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/convert/AiChatConversationConvert.java index 50c4b64d6..7e1350617 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/convert/AiChatConversationConvert.java +++ b/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); } diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatConversationDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatConversationDO.java index a4651323c..c8613b5e1 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatConversationDO.java +++ b/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 编号,自增 */ diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatModelDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatModelDO.java index 723428009..c943f7ea6 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatModelDO.java +++ b/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 */ diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/AiChatModelMapper.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/AiChatModelMapper.java index d254f9a81..3c959e961 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/AiChatModelMapper.java +++ b/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 { - // TODO 芋艿:要搞一下 - /** - * 查询 - 第一个modal - * - * @return - */ - default AiChatModelDO selectFirstModal() { - PageResult pageResult = selectPage(new PageParam().setPageNo(1).setPageSize(1), - new LambdaQueryWrapperX() - .orderByAsc(AiChatModelDO::getSort) - ); - if (CollUtil.isEmpty(pageResult.getList())) { - return null; - } - return pageResult.getList().get(0); + default AiChatModelDO selectFirstByStatus(Integer status) { + return selectOne(new QueryWrapperX() + .eq("status", status) + .limitN(1) + .orderByAsc("sort")); } + // TODO 芋艿:不需要哈 /** * 查询 - 根据 ids * diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/AiChatRoleMapper.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/AiChatRoleMapper.java index d89204005..c0eeb549e 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/AiChatRoleMapper.java +++ b/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 { + default AiChatRoleDO selectFirstByPublicStatusAndStatus(Boolean publicStatus, Integer status) { + return selectOne(new QueryWrapperX() + .eq("status", status) + .eq("public_status", publicStatus) + .limitN(1) + .orderByAsc("sort")); + } + default PageResult selectPage(AiChatRolePageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(AiChatRoleDO::getName, reqVO.getName()) diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/AiChatConversationService.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatConversationService.java similarity index 60% rename from yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/AiChatConversationService.java rename to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatConversationService.java index 1abf2476f..ed8fa101c 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/AiChatConversationService.java +++ b/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); /** * 获取 - 对话列表 diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatConversationServiceImpl.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatConversationServiceImpl.java new file mode 100644 index 000000000..b04f2b789 --- /dev/null +++ b/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 listConversation() { + // 获取用户id + Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); + // 查询前100对话 + List 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; + } + +} diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatConversationServiceImpl.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatConversationServiceImpl.java deleted file mode 100644 index 336f34858..000000000 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatConversationServiceImpl.java +++ /dev/null @@ -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 listConversation() { - // 获取用户id - Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); - // 查询前100对话 - List 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; - } -} diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatServiceImpl.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatServiceImpl.java index 87d652eef..d74880dfc 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatServiceImpl.java +++ b/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; diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatModelService.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatModelService.java index b589ba679..08f0110fe 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatModelService.java +++ b/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(); + /** * 获得聊天模型分页 * diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatModelServiceImpl.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatModelServiceImpl.java index 919fb5804..59298f9fe 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatModelServiceImpl.java +++ b/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 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; } diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleService.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleService.java index 8b22d638c..7206fd104 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleService.java +++ b/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(); + /** * 获得聊天角色分页 * diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleServiceImpl.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleServiceImpl.java index 507e4ce74..e039c4113 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleServiceImpl.java +++ b/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 getChatRolePage(AiChatRolePageReqVO pageReqVO) { return chatRoleMapper.selectPage(pageReqVO);