Commit 64142965f36f6b4470e4637b320e99f08239e1a3
1 parent
7344ec8a
【新增】AI:聊天对话的新建(50%)
Showing
18 changed files
with
230 additions
and
221 deletions
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/ErrorCodeConstants.java
| ... | ... | @@ -14,17 +14,21 @@ public interface ErrorCodeConstants { |
| 14 | 14 | ErrorCode API_KEY_DISABLE = new ErrorCode(1_040_000_001, "AI API 密钥已禁用!"); |
| 15 | 15 | |
| 16 | 16 | // ========== API 聊天模型 1-040-001-000 ========== |
| 17 | - | |
| 18 | - ErrorCode CHAT_MODAL_NOT_EXIST = new ErrorCode(1_040_001_000, "AI 模型不存在!"); | |
| 19 | - ErrorCode CHAT_MODAL_DISABLE = new ErrorCode(1_040_001_001, "AI 模型({})已禁用!"); | |
| 17 | + ErrorCode CHAT_MODEL_NOT_EXISTS = new ErrorCode(1_040_001_000, "AI 模型不存在!"); | |
| 18 | + ErrorCode CHAT_MODEL_DISABLE = new ErrorCode(1_040_001_001, "AI 模型({})已禁用!"); | |
| 19 | + ErrorCode CHAT_MODEL_DEFAULT_NOT_EXISTS = new ErrorCode(1_040_001_002, "操作失败,找不到默认聊天模型"); | |
| 20 | 20 | |
| 21 | 21 | // ========== API 聊天模型 1-040-002-000 ========== |
| 22 | 22 | ErrorCode CHAT_ROLE_NOT_EXISTS = new ErrorCode(1_040_002_000, "AI 聊天角色不存在"); |
| 23 | 23 | ErrorCode CHAT_ROLE_DISABLE = new ErrorCode(1_040_001_001, "AI 聊天角色({})已禁用!"); |
| 24 | + ErrorCode CHAT_ROLE_DEFAULT_NOT_EXISTS = new ErrorCode(1_040_001_002, "操作失败,找不到默认聊天角色"); | |
| 25 | + | |
| 26 | + // ========== API 聊天会话 1-040-003-000 ========== | |
| 24 | 27 | |
| 25 | - // conversation | |
| 28 | + ErrorCode CHAT_CONVERSATION_NOT_EXISTS = new ErrorCode(1_040_003_000, "AI 对话不存在!");; | |
| 26 | 29 | |
| 27 | - ErrorCode AI_CONVERSATION_NOT_EXISTS = new ErrorCode(1_022_000_002, "AI 对话不存在!");; | |
| 30 | + // chat | |
| 31 | + ErrorCode AI_CHAT_MESSAGE_NOT_EXIST = new ErrorCode(1_022_000_100, "AI 提问的 MessageId 不存在!"); | |
| 28 | 32 | |
| 29 | 33 | // midjourney |
| 30 | 34 | |
| ... | ... | @@ -32,7 +36,4 @@ public interface ErrorCodeConstants { |
| 32 | 36 | ErrorCode AI_MIDJOURNEY_OPERATION_NOT_EXISTS = new ErrorCode(1_022_000_040, "midjourney 操作不存在!"); |
| 33 | 37 | ErrorCode AI_MIDJOURNEY_MESSAGE_ID_INCORRECT = new ErrorCode(1_022_000_040, "midjourney message id 不正确!"); |
| 34 | 38 | |
| 35 | - // chat | |
| 36 | - ErrorCode AI_CHAT_MESSAGE_NOT_EXIST = new ErrorCode(1_022_000_100, "AI 提问的 MessageId 不存在!"); | |
| 37 | - | |
| 38 | 39 | } | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatConversationController.java
| 1 | 1 | package cn.iocoder.yudao.module.ai.controller.admin.chat; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | -import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateReqVO; | |
| 4 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO; | |
| 5 | 5 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO; |
| 6 | -import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateReqVO; | |
| 7 | -import cn.iocoder.yudao.module.ai.service.AiChatConversationService; | |
| 6 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO; | |
| 7 | +import cn.iocoder.yudao.module.ai.service.chat.AiChatConversationService; | |
| 8 | 8 | import io.swagger.v3.oas.annotations.Operation; |
| 9 | 9 | import io.swagger.v3.oas.annotations.Parameter; |
| 10 | 10 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 11 | +import jakarta.annotation.Resource; | |
| 11 | 12 | import jakarta.validation.Valid; |
| 12 | -import lombok.AllArgsConstructor; | |
| 13 | -import lombok.extern.slf4j.Slf4j; | |
| 14 | -import org.springframework.security.access.prepost.PreAuthorize; | |
| 13 | +import org.springframework.validation.annotation.Validated; | |
| 15 | 14 | import org.springframework.web.bind.annotation.*; |
| 16 | 15 | |
| 17 | 16 | import java.util.List; |
| 18 | 17 | |
| 19 | 18 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 19 | +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | |
| 20 | 20 | |
| 21 | -@Slf4j | |
| 22 | -@Tag(name = "管理后台 - 聊天会话") | |
| 21 | +@Tag(name = "管理后台 - AI 聊天会话") | |
| 23 | 22 | @RestController |
| 24 | 23 | @RequestMapping("/ai/chat/conversation") |
| 25 | -@AllArgsConstructor | |
| 24 | +@Validated | |
| 26 | 25 | public class AiChatConversationController { |
| 27 | 26 | |
| 28 | - private final AiChatConversationService aiChatConversationService; | |
| 27 | + @Resource | |
| 28 | + private AiChatConversationService chatConversationService; | |
| 29 | 29 | |
| 30 | - // TODO done @fan:实现一下 | |
| 31 | - @PostMapping("/create") | |
| 32 | - @Operation(summary = "创建聊天会话") | |
| 33 | - @PreAuthorize("@ss.hasPermission('ai:chat-conversation:create')") | |
| 34 | - public CommonResult<Long> createConversation(@RequestBody @Valid AiChatConversationCreateReqVO createReqVO) { | |
| 35 | - return success(aiChatConversationService.createConversation(createReqVO)); | |
| 30 | + @PostMapping("/create-my") | |
| 31 | + @Operation(summary = "创建【我的】聊天会话") | |
| 32 | + public CommonResult<Long> createChatConversationMy(@RequestBody @Valid AiChatConversationCreateMyReqVO createReqVO) { | |
| 33 | + return success(chatConversationService.createChatConversationMy(createReqVO, getLoginUserId())); | |
| 36 | 34 | } |
| 37 | 35 | |
| 38 | - // TODO done @fan:实现一下 | |
| 39 | - @PutMapping("/update") | |
| 40 | - @Operation(summary = "更新聊天会话") | |
| 41 | - @PreAuthorize("@ss.hasPermission('ai:chat-conversation:create')") | |
| 42 | - public CommonResult<Boolean> updateConversation(@RequestBody @Valid AiChatConversationUpdateReqVO updateReqVO) { | |
| 43 | - return success(aiChatConversationService.updateConversation(updateReqVO)); | |
| 36 | + @PutMapping("/update-my") | |
| 37 | + @Operation(summary = "更新【我的】聊天会话") | |
| 38 | + public CommonResult<Boolean> updateChatConversationMy(@RequestBody @Valid AiChatConversationUpdateMyReqVO updateReqVO) { | |
| 39 | + chatConversationService.updateChatConversationMy(updateReqVO, getLoginUserId()); | |
| 40 | + return success(true); | |
| 44 | 41 | } |
| 45 | 42 | |
| 46 | 43 | // TODO done @fan:实现一下 |
| 47 | - @GetMapping("/list") | |
| 44 | + @GetMapping("/my-list") | |
| 48 | 45 | @Operation(summary = "获得聊天会话列表") |
| 49 | 46 | public CommonResult<List<AiChatConversationRespVO>> getConversationList() { |
| 50 | - return success(aiChatConversationService.listConversation()); | |
| 47 | + return success(chatConversationService.listConversation()); | |
| 51 | 48 | } |
| 52 | 49 | |
| 53 | 50 | // TODO @fan:实现一下 |
| ... | ... | @@ -55,7 +52,7 @@ public class AiChatConversationController { |
| 55 | 52 | @Operation(summary = "获得聊天会话") |
| 56 | 53 | @Parameter(name = "id", required = true, description = "会话编号", example = "1024") |
| 57 | 54 | public CommonResult<AiChatConversationRespVO> getConversation(@RequestParam("id") Long id) { |
| 58 | - return success(aiChatConversationService.getConversationOfValidate(id)); | |
| 55 | + return success(chatConversationService.getConversationOfValidate(id)); | |
| 59 | 56 | } |
| 60 | 57 | |
| 61 | 58 | // TODO @fan:实现一下 |
| ... | ... | @@ -63,7 +60,9 @@ public class AiChatConversationController { |
| 63 | 60 | @Operation(summary = "删除聊天会话") |
| 64 | 61 | @Parameter(name = "id", required = true, description = "会话编号", example = "1024") |
| 65 | 62 | public CommonResult<Boolean> deleteConversation(@RequestParam("id") Long id) { |
| 66 | - return success(aiChatConversationService.deleteConversation(id)); | |
| 63 | + return success(chatConversationService.deleteConversation(id)); | |
| 67 | 64 | } |
| 68 | 65 | |
| 66 | + // ========== 会话管理 ========== | |
| 67 | + | |
| 69 | 68 | } | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationCreateReqVO.java renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationCreateMyReqVO.java
| 1 | 1 | package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation; |
| 2 | 2 | |
| 3 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | -import jakarta.validation.constraints.NotNull; | |
| 5 | 4 | import lombok.Data; |
| 6 | -import lombok.EqualsAndHashCode; | |
| 7 | -import lombok.ToString; | |
| 8 | -import lombok.experimental.Accessors; | |
| 9 | 5 | |
| 10 | -@Schema(description = "管理后台 - AI 聊天会话创建 Request VO") | |
| 6 | +@Schema(description = "管理后台 - AI 聊天会话创建【我的】 Request VO") | |
| 11 | 7 | @Data |
| 12 | -public class AiChatConversationCreateReqVO { | |
| 8 | +public class AiChatConversationCreateMyReqVO { | |
| 13 | 9 | |
| 14 | - @Schema(description = "角色编号", example = "666") | |
| 10 | + @Schema(description = "聊天角色编号", example = "666") | |
| 15 | 11 | private Long roleId; |
| 16 | 12 | |
| 17 | 13 | } | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationListReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation; | |
| 2 | - | |
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | -import lombok.Data; | |
| 5 | - | |
| 6 | -@Schema(description = "管理后台 - AI 聊天会话 Response VO") | |
| 7 | -@Data | |
| 8 | -public class AiChatConversationListReqVO { | |
| 9 | - | |
| 10 | - @Schema(description = "会话标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是一个标题") | |
| 11 | - private String title; | |
| 12 | - | |
| 13 | -} |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationUpdateReqVO.java renamed to 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; |
| 4 | 4 | import jakarta.validation.constraints.NotNull; |
| 5 | 5 | import lombok.Data; |
| 6 | 6 | |
| 7 | -@Schema(description = "管理后台 - AI 聊天会话更新 Request VO") | |
| 7 | +@Schema(description = "管理后台 - AI 聊天会话更新【我的】 Request VO") | |
| 8 | 8 | @Data |
| 9 | -public class AiChatConversationUpdateReqVO { | |
| 9 | +public class AiChatConversationUpdateMyReqVO { | |
| 10 | 10 | |
| 11 | 11 | @Schema(description = "会话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| 12 | 12 | @NotNull(message = "会话编号不能为空") | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/convert/AiChatConversationConvert.java
| 1 | 1 | package cn.iocoder.yudao.module.ai.convert; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateReqVO; | |
| 3 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO; | |
| 4 | 4 | import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; |
| 5 | 5 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO; |
| 6 | 6 | import org.mapstruct.Mapper; |
| ... | ... | @@ -36,10 +36,4 @@ public interface AiChatConversationConvert { |
| 36 | 36 | */ |
| 37 | 37 | AiChatConversationRespVO covnertChatConversationRes(AiChatConversationDO aiChatConversationDO); |
| 38 | 38 | |
| 39 | - /** | |
| 40 | - * 转换 - AiChatConversationDO | |
| 41 | - * | |
| 42 | - * @param updateReqVO | |
| 43 | - */ | |
| 44 | - AiChatConversationDO convertAiChatConversationDO(AiChatConversationUpdateReqVO updateReqVO); | |
| 45 | 39 | } | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatConversationDO.java
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatModelDO.java
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; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | 6 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 7 | 7 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 8 | +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; | |
| 8 | 9 | import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatModel.AiChatModelPageReqVO; |
| 9 | 10 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; |
| 11 | +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | |
| 10 | 12 | import org.apache.ibatis.annotations.Mapper; |
| 11 | 13 | |
| 12 | 14 | import java.util.List; |
| ... | ... | @@ -22,23 +24,14 @@ import java.util.List; |
| 22 | 24 | @Mapper |
| 23 | 25 | public interface AiChatModelMapper extends BaseMapperX<AiChatModelDO> { |
| 24 | 26 | |
| 25 | - // TODO 芋艿:要搞一下 | |
| 26 | - /** | |
| 27 | - * 查询 - 第一个modal | |
| 28 | - * | |
| 29 | - * @return | |
| 30 | - */ | |
| 31 | - default AiChatModelDO selectFirstModal() { | |
| 32 | - PageResult<AiChatModelDO> pageResult = selectPage(new PageParam().setPageNo(1).setPageSize(1), | |
| 33 | - new LambdaQueryWrapperX<AiChatModelDO>() | |
| 34 | - .orderByAsc(AiChatModelDO::getSort) | |
| 35 | - ); | |
| 36 | - if (CollUtil.isEmpty(pageResult.getList())) { | |
| 37 | - return null; | |
| 38 | - } | |
| 39 | - return pageResult.getList().get(0); | |
| 27 | + default AiChatModelDO selectFirstByStatus(Integer status) { | |
| 28 | + return selectOne(new QueryWrapperX<AiChatModelDO>() | |
| 29 | + .eq("status", status) | |
| 30 | + .limitN(1) | |
| 31 | + .orderByAsc("sort")); | |
| 40 | 32 | } |
| 41 | 33 | |
| 34 | + // TODO 芋艿:不需要哈 | |
| 42 | 35 | /** |
| 43 | 36 | * 查询 - 根据 ids |
| 44 | 37 | * | ... | ... |
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; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | 5 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 6 | 6 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 7 | +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; | |
| 7 | 8 | import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRolePageReqVO; |
| 9 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | |
| 8 | 10 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; |
| 9 | 11 | import org.apache.ibatis.annotations.Mapper; |
| 10 | 12 | |
| ... | ... | @@ -18,6 +20,14 @@ import java.util.List; |
| 18 | 20 | @Mapper |
| 19 | 21 | public interface AiChatRoleMapper extends BaseMapperX<AiChatRoleDO> { |
| 20 | 22 | |
| 23 | + default AiChatRoleDO selectFirstByPublicStatusAndStatus(Boolean publicStatus, Integer status) { | |
| 24 | + return selectOne(new QueryWrapperX<AiChatRoleDO>() | |
| 25 | + .eq("status", status) | |
| 26 | + .eq("public_status", publicStatus) | |
| 27 | + .limitN(1) | |
| 28 | + .orderByAsc("sort")); | |
| 29 | + } | |
| 30 | + | |
| 21 | 31 | default PageResult<AiChatRoleDO> selectPage(AiChatRolePageReqVO reqVO) { |
| 22 | 32 | return selectPage(reqVO, new LambdaQueryWrapperX<AiChatRoleDO>() |
| 23 | 33 | .likeIfPresent(AiChatRoleDO::getName, reqVO.getName()) | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/AiChatConversationService.java renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatConversationService.java
| 1 | -package cn.iocoder.yudao.module.ai.service; | |
| 1 | +package cn.iocoder.yudao.module.ai.service.chat; | |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateReqVO; | |
| 4 | -import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationListReqVO; | |
| 3 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO; | |
| 5 | 4 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO; |
| 6 | -import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateReqVO; | |
| 5 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO; | |
| 7 | 6 | import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; |
| 8 | -import org.jetbrains.annotations.NotNull; | |
| 9 | 7 | |
| 10 | 8 | import java.util.List; |
| 11 | 9 | |
| 12 | 10 | /** |
| 13 | - * chat 对话 | |
| 11 | + * AI 聊天对话 Service 接口 | |
| 14 | 12 | * |
| 15 | - * @fansili | |
| 16 | - * @since v1.0 | |
| 13 | + * @author fansili | |
| 17 | 14 | */ |
| 18 | 15 | public interface AiChatConversationService { |
| 19 | 16 | |
| 20 | 17 | /** |
| 21 | - * 对话 - 创建对话 | |
| 18 | + * 创建【我的】聊天会话 | |
| 22 | 19 | * |
| 23 | - * @param req | |
| 24 | - * @return | |
| 20 | + * @param createReqVO 创建信息 | |
| 21 | + * @param userId 用户编号 | |
| 22 | + * @return 聊天会话 | |
| 25 | 23 | */ |
| 26 | - Long createConversation(AiChatConversationCreateReqVO req); | |
| 24 | + Long createChatConversationMy(AiChatConversationCreateMyReqVO createReqVO, Long userId); | |
| 27 | 25 | |
| 28 | 26 | /** |
| 29 | - * 对话 - 更新对话 | |
| 27 | + * 更新【我的】聊天会话 | |
| 30 | 28 | * |
| 31 | - * @param updateReqVO | |
| 32 | - * @return | |
| 29 | + * @param updateReqVO 更新信息 | |
| 30 | + * @param userId 用户编号 | |
| 33 | 31 | */ |
| 34 | - Boolean updateConversation(AiChatConversationUpdateReqVO updateReqVO); | |
| 32 | + void updateChatConversationMy(AiChatConversationUpdateMyReqVO updateReqVO, Long userId); | |
| 35 | 33 | |
| 36 | 34 | /** |
| 37 | 35 | * 获取 - 对话列表 | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatConversationServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.chat; | |
| 2 | + | |
| 3 | +import cn.hutool.core.lang.Assert; | |
| 4 | +import cn.hutool.core.util.ObjUtil; | |
| 5 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 6 | +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; | |
| 7 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO; | |
| 8 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO; | |
| 9 | +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO; | |
| 10 | +import cn.iocoder.yudao.module.ai.convert.AiChatConversationConvert; | |
| 11 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; | |
| 12 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | |
| 13 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | |
| 14 | +import cn.iocoder.yudao.module.ai.dal.mysql.AiChatConversationMapper; | |
| 15 | +import cn.iocoder.yudao.module.ai.service.model.AiChatModelService; | |
| 16 | +import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService; | |
| 17 | +import jakarta.annotation.Resource; | |
| 18 | +import lombok.extern.slf4j.Slf4j; | |
| 19 | +import org.springframework.stereotype.Service; | |
| 20 | +import org.springframework.validation.annotation.Validated; | |
| 21 | + | |
| 22 | +import java.util.List; | |
| 23 | + | |
| 24 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.*; | |
| 25 | +import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS; | |
| 26 | + | |
| 27 | +/** | |
| 28 | + * AI 聊天对话 Service 实现类 | |
| 29 | + * | |
| 30 | + * @author fansili | |
| 31 | + */ | |
| 32 | +@Service | |
| 33 | +@Validated | |
| 34 | +@Slf4j | |
| 35 | +public class AiChatConversationServiceImpl implements AiChatConversationService { | |
| 36 | + | |
| 37 | + @Resource | |
| 38 | + private AiChatConversationMapper chatConversationMapper; | |
| 39 | + | |
| 40 | + @Resource | |
| 41 | + private AiChatModelService chatModalService; | |
| 42 | + @Resource | |
| 43 | + private AiChatRoleService chatRoleService; | |
| 44 | + | |
| 45 | + @Override | |
| 46 | + public Long createChatConversationMy(AiChatConversationCreateMyReqVO createReqVO, Long userId) { | |
| 47 | + // 1.1 获得 AiChatRoleDO 聊天角色 | |
| 48 | + AiChatRoleDO role = createReqVO.getRoleId() != null ? chatRoleService.validateChatRole(createReqVO.getRoleId()) | |
| 49 | + : chatRoleService.getRequiredDefaultChatRole(); | |
| 50 | + Assert.notNull(role, "必须找到聊天角色"); | |
| 51 | + // 1.2 获得 AiChatModelDO 聊天模型 | |
| 52 | + AiChatModelDO model = role.getModelId() != null ? chatModalService.validateChatModel(role.getId()) | |
| 53 | + : chatModalService.getRequiredDefaultChatModel(); | |
| 54 | + Assert.notNull(role, "必须找到默认模型"); | |
| 55 | + | |
| 56 | + // 2. 创建 AiChatConversationDO 聊天对话 | |
| 57 | + AiChatConversationDO conversation = new AiChatConversationDO() | |
| 58 | + .setUserId(userId).setTitle(AiChatConversationDO.TITLE_DEFAULT).setPinned(false) | |
| 59 | + .setRoleId(role.getId()).setModelId(model.getId()).setModel(model.getModel()) | |
| 60 | + .setTemperature(model.getTemperature()).setMaxTokens(model.getMaxTokens()).setMaxContexts(model.getMaxContexts()); | |
| 61 | + chatConversationMapper.insert(conversation); | |
| 62 | + return conversation.getId(); | |
| 63 | + } | |
| 64 | + | |
| 65 | + @Override | |
| 66 | + public void updateChatConversationMy(AiChatConversationUpdateMyReqVO updateReqVO, Long userId) { | |
| 67 | + // 1.1 校验对话是否存在 | |
| 68 | + AiChatConversationDO conversation = validateExists(updateReqVO.getId()); | |
| 69 | + if (ObjUtil.notEqual(conversation.getUserId(), userId)) { | |
| 70 | + throw exception(CHAT_CONVERSATION_NOT_EXISTS); | |
| 71 | + } | |
| 72 | + // 1.2 校验模型是否存在 | |
| 73 | + AiChatModelDO model = null; | |
| 74 | + if (updateReqVO.getModelId() != null) { | |
| 75 | + model = chatModalService.validateChatModel(updateReqVO.getModelId()); | |
| 76 | + } | |
| 77 | + // 1.3 校验温度参数、Token 数量、消息数量 TODO | |
| 78 | + | |
| 79 | + // 更新对话信息 | |
| 80 | + chatConversationMapper.updateById(BeanUtils.toBean(updateReqVO, AiChatConversationDO.class)); | |
| 81 | + } | |
| 82 | + | |
| 83 | + @Override | |
| 84 | + public List<AiChatConversationRespVO> listConversation() { | |
| 85 | + // 获取用户id | |
| 86 | + Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); | |
| 87 | + // 查询前100对话 | |
| 88 | + List<AiChatConversationDO> top100Conversation | |
| 89 | + = chatConversationMapper.selectTop100Conversation(loginUserId, null); | |
| 90 | + return AiChatConversationConvert.INSTANCE.covnertChatConversationResList(top100Conversation); | |
| 91 | + } | |
| 92 | + | |
| 93 | + @Override | |
| 94 | + public AiChatConversationRespVO getConversationOfValidate(Long id) { | |
| 95 | + AiChatConversationDO aiChatConversationDO = validateExists(id); | |
| 96 | + return AiChatConversationConvert.INSTANCE.covnertChatConversationRes(aiChatConversationDO); | |
| 97 | + } | |
| 98 | + | |
| 99 | + @Override | |
| 100 | + public Boolean deleteConversation(Long id) { | |
| 101 | + return chatConversationMapper.deleteById(id) > 0; | |
| 102 | + } | |
| 103 | + | |
| 104 | + public AiChatConversationDO validateExists(Long id) { | |
| 105 | + AiChatConversationDO conversation = chatConversationMapper.selectById(id); | |
| 106 | + if (conversation == null) { | |
| 107 | + throw exception(CHAT_CONVERSATION_NOT_EXISTS); | |
| 108 | + } | |
| 109 | + return conversation; | |
| 110 | + } | |
| 111 | + | |
| 112 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatConversationServiceImpl.java deleted
| 1 | -package cn.iocoder.yudao.module.ai.service.impl; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; | |
| 4 | -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; | |
| 5 | -import cn.iocoder.yudao.module.ai.AiCommonConstants; | |
| 6 | -import cn.iocoder.yudao.module.ai.ErrorCodeConstants; | |
| 7 | -import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateReqVO; | |
| 8 | -import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO; | |
| 9 | -import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateReqVO; | |
| 10 | -import cn.iocoder.yudao.module.ai.convert.AiChatConversationConvert; | |
| 11 | -import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; | |
| 12 | -import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | |
| 13 | -import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | |
| 14 | -import cn.iocoder.yudao.module.ai.dal.mysql.AiChatConversationMapper; | |
| 15 | -import cn.iocoder.yudao.module.ai.dal.mysql.AiChatModelMapper; | |
| 16 | -import cn.iocoder.yudao.module.ai.service.AiChatConversationService; | |
| 17 | -import cn.iocoder.yudao.module.ai.service.model.AiChatModelService; | |
| 18 | -import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService; | |
| 19 | -import lombok.AllArgsConstructor; | |
| 20 | -import lombok.extern.slf4j.Slf4j; | |
| 21 | -import org.jetbrains.annotations.NotNull; | |
| 22 | -import org.springframework.stereotype.Service; | |
| 23 | - | |
| 24 | -import java.util.List; | |
| 25 | - | |
| 26 | -/** | |
| 27 | - * chat 对话 | |
| 28 | - * | |
| 29 | - * @fansili | |
| 30 | - * @since v1.0 | |
| 31 | - */ | |
| 32 | -@Service | |
| 33 | -@Slf4j | |
| 34 | -@AllArgsConstructor | |
| 35 | -public class AiChatConversationServiceImpl implements AiChatConversationService { | |
| 36 | - | |
| 37 | - private final AiChatModelMapper aiChatModalMapper; | |
| 38 | - private final AiChatModelService aiChatModalService; | |
| 39 | - private final AiChatRoleService aiChatRoleService; | |
| 40 | - private final AiChatConversationMapper aiChatConversationMapper; | |
| 41 | - | |
| 42 | - @Override | |
| 43 | - public Long createConversation(AiChatConversationCreateReqVO req) { | |
| 44 | - // 获取用户id | |
| 45 | - Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); | |
| 46 | - // 默认使用 sort 排序第一个模型 | |
| 47 | - AiChatModelDO aiChatModalDO = aiChatModalMapper.selectFirstModal(); | |
| 48 | - // 查询角色 | |
| 49 | - AiChatRoleDO chatRoleRes = req.getRoleId() != null ? aiChatRoleService.getChatRole(req.getRoleId()) : null; | |
| 50 | - Long chatRoleId = chatRoleRes != null ? chatRoleRes.getId() : null; | |
| 51 | - // 创建新的 Conversation | |
| 52 | - AiChatConversationDO insertConversation = saveConversation(AiCommonConstants.CONVERSATION_DEFAULT_TITLE, | |
| 53 | - loginUserId, chatRoleId, aiChatModalDO.getId(), aiChatModalDO.getModel() | |
| 54 | - ); | |
| 55 | - // 返回对话id | |
| 56 | - return insertConversation.getId(); | |
| 57 | - } | |
| 58 | - | |
| 59 | - private @NotNull AiChatConversationDO saveConversation(String title, | |
| 60 | - Long userId, | |
| 61 | - Long roleId, | |
| 62 | - Long modalId, | |
| 63 | - String model) { | |
| 64 | - AiChatConversationDO insertConversation = new AiChatConversationDO(); | |
| 65 | - insertConversation.setId(null); | |
| 66 | - insertConversation.setUserId(userId); | |
| 67 | - insertConversation.setTitle(title); | |
| 68 | - insertConversation.setPinned(false); | |
| 69 | - | |
| 70 | - insertConversation.setRoleId(roleId); | |
| 71 | - insertConversation.setModelId(modalId); | |
| 72 | - insertConversation.setModel(model); | |
| 73 | - | |
| 74 | - insertConversation.setTemperature(null); | |
| 75 | - insertConversation.setMaxTokens(null); | |
| 76 | - insertConversation.setMaxContexts(null); | |
| 77 | - aiChatConversationMapper.insert(insertConversation); | |
| 78 | - return insertConversation; | |
| 79 | - } | |
| 80 | - | |
| 81 | - @Override | |
| 82 | - public Boolean updateConversation(AiChatConversationUpdateReqVO updateReqVO) { | |
| 83 | - // 校验对话是否存在 | |
| 84 | - validateExists(updateReqVO.getId()); | |
| 85 | - // 获取模型信息并验证 | |
| 86 | - aiChatModalService.validateChatModel(updateReqVO.getModelId()); | |
| 87 | - // 更新对话信息 | |
| 88 | - AiChatConversationDO updateAiChatConversationDO | |
| 89 | - = AiChatConversationConvert.INSTANCE.convertAiChatConversationDO(updateReqVO); | |
| 90 | - return aiChatConversationMapper.updateById(updateAiChatConversationDO) > 0; | |
| 91 | - } | |
| 92 | - | |
| 93 | - @Override | |
| 94 | - public List<AiChatConversationRespVO> listConversation() { | |
| 95 | - // 获取用户id | |
| 96 | - Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); | |
| 97 | - // 查询前100对话 | |
| 98 | - List<AiChatConversationDO> top100Conversation | |
| 99 | - = aiChatConversationMapper.selectTop100Conversation(loginUserId, null); | |
| 100 | - return AiChatConversationConvert.INSTANCE.covnertChatConversationResList(top100Conversation); | |
| 101 | - } | |
| 102 | - | |
| 103 | - @Override | |
| 104 | - public AiChatConversationRespVO getConversationOfValidate(Long id) { | |
| 105 | - AiChatConversationDO aiChatConversationDO = validateExists(id); | |
| 106 | - return AiChatConversationConvert.INSTANCE.covnertChatConversationRes(aiChatConversationDO); | |
| 107 | - } | |
| 108 | - | |
| 109 | - @Override | |
| 110 | - public Boolean deleteConversation(Long id) { | |
| 111 | - return aiChatConversationMapper.deleteById(id) > 0; | |
| 112 | - } | |
| 113 | - | |
| 114 | - public @NotNull AiChatConversationDO validateExists(Long id) { | |
| 115 | - AiChatConversationDO aiChatConversationDO = aiChatConversationMapper.selectById(id); | |
| 116 | - if (aiChatConversationDO == null) { | |
| 117 | - throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_CONVERSATION_NOT_EXISTS); | |
| 118 | - } | |
| 119 | - return aiChatConversationDO; | |
| 120 | - } | |
| 121 | -} |
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; |
| 22 | 22 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; |
| 23 | 23 | import cn.iocoder.yudao.module.ai.dal.mysql.AiChatConversationMapper; |
| 24 | 24 | import cn.iocoder.yudao.module.ai.dal.mysql.AiChatMessageMapper; |
| 25 | -import cn.iocoder.yudao.module.ai.service.AiChatConversationService; | |
| 25 | +import cn.iocoder.yudao.module.ai.service.chat.AiChatConversationService; | |
| 26 | 26 | import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService; |
| 27 | 27 | import cn.iocoder.yudao.module.ai.service.AiChatService; |
| 28 | 28 | import cn.iocoder.yudao.module.ai.service.model.AiChatModelService; | ... | ... |
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; |
| 8 | 8 | |
| 9 | 9 | import java.util.List; |
| 10 | 10 | |
| 11 | -import java.util.List; | |
| 12 | 11 | import java.util.Set; |
| 13 | 12 | |
| 14 | 13 | /** |
| ... | ... | @@ -50,6 +49,15 @@ public interface AiChatModelService { |
| 50 | 49 | AiChatModelDO getChatModel(Long id); |
| 51 | 50 | |
| 52 | 51 | /** |
| 52 | + * 获得默认的聊天模型 | |
| 53 | + * | |
| 54 | + * 如果获取不到,则抛出 {@link cn.iocoder.yudao.framework.common.exception.ServiceException} 业务异常 | |
| 55 | + * | |
| 56 | + * @return 聊天模型 | |
| 57 | + */ | |
| 58 | + AiChatModelDO getRequiredDefaultChatModel(); | |
| 59 | + | |
| 60 | + /** | |
| 53 | 61 | * 获得聊天模型分页 |
| 54 | 62 | * |
| 55 | 63 | * @param pageReqVO 分页查询 | ... | ... |
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 { |
| 69 | 69 | private AiChatModelDO validateChatModelExists(Long id) { |
| 70 | 70 | AiChatModelDO model = chatModelMapper.selectById(id); |
| 71 | 71 | if (chatModelMapper.selectById(id) == null) { |
| 72 | - throw exception(CHAT_MODAL_NOT_EXIST); | |
| 72 | + throw exception(CHAT_MODEL_NOT_EXISTS); | |
| 73 | 73 | } |
| 74 | 74 | return model; |
| 75 | 75 | } |
| ... | ... | @@ -80,6 +80,15 @@ public class AiChatModelServiceImpl implements AiChatModelService { |
| 80 | 80 | } |
| 81 | 81 | |
| 82 | 82 | @Override |
| 83 | + public AiChatModelDO getRequiredDefaultChatModel() { | |
| 84 | + AiChatModelDO model = chatModelMapper.selectFirstByStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 85 | + if (model == null) { | |
| 86 | + throw exception(CHAT_MODEL_DEFAULT_NOT_EXISTS); | |
| 87 | + } | |
| 88 | + return model; | |
| 89 | + } | |
| 90 | + | |
| 91 | + @Override | |
| 83 | 92 | public PageResult<AiChatModelDO> getChatModelPage(AiChatModelPageReqVO pageReqVO) { |
| 84 | 93 | return chatModelMapper.selectPage(pageReqVO); |
| 85 | 94 | } |
| ... | ... | @@ -88,7 +97,7 @@ public class AiChatModelServiceImpl implements AiChatModelService { |
| 88 | 97 | public AiChatModelDO validateChatModel(Long id) { |
| 89 | 98 | AiChatModelDO model = validateChatModelExists(id); |
| 90 | 99 | if (CommonStatusEnum.isDisable(model.getStatus())) { |
| 91 | - throw exception(CHAT_MODAL_DISABLE); | |
| 100 | + throw exception(CHAT_MODEL_DISABLE); | |
| 92 | 101 | } |
| 93 | 102 | return model; |
| 94 | 103 | } | ... | ... |
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; |
| 4 | 4 | import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRolePageReqVO; |
| 5 | 5 | import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveMyReqVO; |
| 6 | 6 | import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveReqVO; |
| 7 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | |
| 7 | 8 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; |
| 8 | 9 | import jakarta.validation.Valid; |
| 9 | 10 | |
| ... | ... | @@ -79,6 +80,15 @@ public interface AiChatRoleService { |
| 79 | 80 | AiChatRoleDO validateChatRole(Long id); |
| 80 | 81 | |
| 81 | 82 | /** |
| 83 | + * 获得默认的聊天角色 | |
| 84 | + * | |
| 85 | + * 如果获取不到,则抛出 {@link cn.iocoder.yudao.framework.common.exception.ServiceException} 业务异常 | |
| 86 | + * | |
| 87 | + * @return 聊天角色 | |
| 88 | + */ | |
| 89 | + AiChatRoleDO getRequiredDefaultChatRole(); | |
| 90 | + | |
| 91 | + /** | |
| 82 | 92 | * 获得聊天角色分页 |
| 83 | 93 | * |
| 84 | 94 | * @param pageReqVO 分页查询 | ... | ... |
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; |
| 17 | 17 | |
| 18 | 18 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 19 | 19 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |
| 20 | -import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.CHAT_ROLE_DISABLE; | |
| 21 | -import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.CHAT_ROLE_NOT_EXISTS; | |
| 20 | +import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.*; | |
| 22 | 21 | |
| 23 | 22 | /** |
| 24 | 23 | * AI 聊天角色 Service 实现类 |
| ... | ... | @@ -111,6 +110,16 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { |
| 111 | 110 | } |
| 112 | 111 | |
| 113 | 112 | @Override |
| 113 | + public AiChatRoleDO getRequiredDefaultChatRole() { | |
| 114 | + AiChatRoleDO chatRole = chatRoleMapper.selectFirstByPublicStatusAndStatus( | |
| 115 | + true, CommonStatusEnum.ENABLE.getStatus()); | |
| 116 | + if (chatRole == null) { | |
| 117 | + throw exception(CHAT_ROLE_DEFAULT_NOT_EXISTS); | |
| 118 | + } | |
| 119 | + return chatRole; | |
| 120 | + } | |
| 121 | + | |
| 122 | + @Override | |
| 114 | 123 | public PageResult<AiChatRoleDO> getChatRolePage(AiChatRolePageReqVO pageReqVO) { |
| 115 | 124 | return chatRoleMapper.selectPage(pageReqVO); |
| 116 | 125 | } | ... | ... |