【功能新增】AI:聊天角色,新增 document 的引用绑定

This commit is contained in:
YunaiV 2025-03-09 11:51:19 +08:00
parent f286a81392
commit 9126691ac0
11 changed files with 100 additions and 10 deletions

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.ai.controller.admin.knowledge; package cn.iocoder.yudao.module.ai.controller.admin.knowledge;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@ -10,8 +11,10 @@ import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowl
import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateStatusReqVO; import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateStatusReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO; import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO;
import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO;
import cn.iocoder.yudao.module.ai.dal.mysql.knowledge.AiKnowledgeDocumentMapper;
import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService; import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.validation.Valid; import jakarta.validation.Valid;
@ -22,6 +25,7 @@ import org.springframework.web.bind.annotation.*;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@Tag(name = "管理后台 - AI 知识库文档") @Tag(name = "管理后台 - AI 知识库文档")
@RestController @RestController
@ -91,4 +95,13 @@ public class AiKnowledgeDocumentController {
return success(true); return success(true);
} }
@GetMapping("/simple-list")
@Operation(summary = "获得知识库文档的精简列表")
public CommonResult<List<AiKnowledgeDocumentRespVO>> getKnowledgeDocumentSimpleList() {
List<AiKnowledgeDocumentDO> list = documentService
.getKnowledgeDocumentListByStatus(CommonStatusEnum.ENABLE.getStatus());
return success(convertList(list, document -> new AiKnowledgeDocumentRespVO()
.setId(document.getId()).setName(document.getName())));
}
} }

View File

@ -75,7 +75,7 @@ public class AiChatRoleController {
@GetMapping("/category-list") @GetMapping("/category-list")
@Operation(summary = "获得聊天角色的分类列表") @Operation(summary = "获得聊天角色的分类列表")
public CommonResult<List<String>> getChatRoleCategoryList() { public CommonResult<List<String>> getChatRoleCategoryList() {
return success(chatRoleService.getChatRoleCategoryList()); return success(chatRoleService.getChatRoleCategoryList());
} }
// ========== 角色管理 ========== // ========== 角色管理 ==========

View File

@ -8,6 +8,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - AI 聊天角色 Response VO") @Schema(description = "管理后台 - AI 聊天角色 Response VO")
@Data @Data
@ -20,7 +21,7 @@ public class AiChatRoleRespVO implements VO {
private Long userId; private Long userId;
@Schema(description = "模型编号", example = "17640") @Schema(description = "模型编号", example = "17640")
@Trans(type = TransType.SIMPLE, target = AiModelDO.class, fields = {"name", "model"}, refs = {"modelName", "model"}) @Trans(type = TransType.SIMPLE, target = AiModelDO.class, fields = { "name", "model" }, refs = { "modelName", "model" })
private Long modelId; private Long modelId;
@Schema(description = "模型名字", example = "张三") @Schema(description = "模型名字", example = "张三")
private String modelName; private String modelName;
@ -45,6 +46,9 @@ public class AiChatRoleRespVO implements VO {
@Schema(description = "角色设定", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "角色设定", requiredMode = Schema.RequiredMode.REQUIRED)
private String systemMessage; private String systemMessage;
@Schema(description = "知识库文档编号列表", example = "1,2,3")
private List<Long> documentIds;
@Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Boolean publicStatus; private Boolean publicStatus;

View File

@ -5,6 +5,8 @@ import jakarta.validation.constraints.NotEmpty;
import lombok.Data; import lombok.Data;
import org.hibernate.validator.constraints.URL; import org.hibernate.validator.constraints.URL;
import java.util.List;
@Schema(description = "管理后台 - AI 聊天角色新增/修改【我的】 Request VO") @Schema(description = "管理后台 - AI 聊天角色新增/修改【我的】 Request VO")
@Data @Data
public class AiChatRoleSaveMyReqVO { public class AiChatRoleSaveMyReqVO {
@ -29,4 +31,7 @@ public class AiChatRoleSaveMyReqVO {
@NotEmpty(message = "角色设定不能为空") @NotEmpty(message = "角色设定不能为空")
private String systemMessage; private String systemMessage;
@Schema(description = "知识库文档编号列表", example = "1,2,3")
private List<Long> documentIds;
} }

View File

@ -7,6 +7,8 @@ import lombok.*;
import jakarta.validation.constraints.*; import jakarta.validation.constraints.*;
import org.hibernate.validator.constraints.URL; import org.hibernate.validator.constraints.URL;
import java.util.List;
@Schema(description = "管理后台 - AI 聊天角色新增/修改 Request VO") @Schema(description = "管理后台 - AI 聊天角色新增/修改 Request VO")
@Data @Data
public class AiChatRoleSaveReqVO { public class AiChatRoleSaveReqVO {
@ -42,6 +44,9 @@ public class AiChatRoleSaveReqVO {
@NotEmpty(message = "角色设定不能为空") @NotEmpty(message = "角色设定不能为空")
private String systemMessage; private String systemMessage;
@Schema(description = "知识库文档编号列表", example = "1,2,3")
private List<Long> documentIds;
@Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "是否公开不能为空") @NotNull(message = "是否公开不能为空")
private Boolean publicStatus; private Boolean publicStatus;

View File

@ -2,11 +2,16 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.model;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler;
import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO;
import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*; import lombok.*;
import java.util.List;
/** /**
* AI 聊天角色 DO * AI 聊天角色 DO
* *
@ -62,6 +67,14 @@ public class AiChatRoleDO extends BaseDO {
*/ */
private Long modelId; private Long modelId;
/**
* 知识库文档编号列表
*
* 关联 {@link AiKnowledgeDocumentDO#getId()} 字段
*/
@TableField(typeHandler = LongListTypeHandler.class)
private List<Long> documentIds;
/** /**
* 是否公开 * 是否公开
* *

View File

@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.Collection; import java.util.Collection;
import java.util.List;
/** /**
* AI 知识库文档 Mapper * AI 知识库文档 Mapper
@ -26,9 +27,13 @@ public interface AiKnowledgeDocumentMapper extends BaseMapperX<AiKnowledgeDocume
} }
default void updateRetrievalCountIncr(Collection<Long> ids) { default void updateRetrievalCountIncr(Collection<Long> ids) {
update( new LambdaUpdateWrapper<AiKnowledgeDocumentDO>() update(new LambdaUpdateWrapper<AiKnowledgeDocumentDO>()
.setSql(" retrieval_count = retrieval_count + 1") .setSql(" retrieval_count = retrieval_count + 1")
.in(AiKnowledgeDocumentDO::getId, ids)); .in(AiKnowledgeDocumentDO::getId, ids));
} }
default List<AiKnowledgeDocumentDO> selectListByStatus(Integer status) {
return selectList(AiKnowledgeDocumentDO::getStatus, status);
}
} }

View File

@ -115,4 +115,12 @@ public interface AiKnowledgeDocumentService {
return convertMap(getKnowledgeDocumentList(ids), AiKnowledgeDocumentDO::getId); return convertMap(getKnowledgeDocumentList(ids), AiKnowledgeDocumentDO::getId);
} }
/**
* 获取指定状态的文档列表
*
* @param status 状态
* @return 文档列表
*/
List<AiKnowledgeDocumentDO> getKnowledgeDocumentListByStatus(Integer status);
} }

View File

@ -7,6 +7,7 @@ import cn.hutool.http.HttpUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentCreateListReqVO; import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentCreateListReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentPageReqVO; import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentPageReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateReqVO; import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateReqVO;
@ -210,4 +211,9 @@ public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentServic
return knowledgeDocumentMapper.selectByIds(ids); return knowledgeDocumentMapper.selectByIds(ids);
} }
@Override
public List<AiKnowledgeDocumentDO> getKnowledgeDocumentListByStatus(Integer status) {
return knowledgeDocumentMapper.selectListByStatus(status);
}
} }

View File

@ -32,7 +32,7 @@ public interface AiChatRoleService {
* 创建我的聊天角色 * 创建我的聊天角色
* *
* @param createReqVO 创建信息 * @param createReqVO 创建信息
* @param userId 用户编号 * @param userId 用户编号
* @return 编号 * @return 编号
*/ */
Long createChatRoleMy(AiChatRoleSaveMyReqVO createReqVO, Long userId); Long createChatRoleMy(AiChatRoleSaveMyReqVO createReqVO, Long userId);
@ -48,7 +48,7 @@ public interface AiChatRoleService {
* 创建我的聊天角色 * 创建我的聊天角色
* *
* @param updateReqVO 更新信息 * @param updateReqVO 更新信息
* @param userId 用户编号 * @param userId 用户编号
*/ */
void updateChatRoleMy(AiChatRoleSaveMyReqVO updateReqVO, Long userId); void updateChatRoleMy(AiChatRoleSaveMyReqVO updateReqVO, Long userId);
@ -62,7 +62,7 @@ public interface AiChatRoleService {
/** /**
* 删除我的聊天角色 * 删除我的聊天角色
* *
* @param id 编号 * @param id 编号
* @param userId 用户编号 * @param userId 用户编号
*/ */
void deleteChatRoleMy(Long id, Long userId); void deleteChatRoleMy(Long id, Long userId);
@ -106,7 +106,7 @@ public interface AiChatRoleService {
* 获得我的聊天角色分页 * 获得我的聊天角色分页
* *
* @param pageReqVO 分页查询 * @param pageReqVO 分页查询
* @param userId 用户编号 * @param userId 用户编号
* @return 聊天角色分页 * @return 聊天角色分页
*/ */
PageResult<AiChatRoleDO> getChatRoleMyPage(AiChatRolePageReqVO pageReqVO, Long userId); PageResult<AiChatRoleDO> getChatRoleMyPage(AiChatRolePageReqVO pageReqVO, Long userId);

View File

@ -5,12 +5,14 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRolePageReqVO; 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.AiChatRoleSaveMyReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveReqVO; import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveReqVO;
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO;
import cn.iocoder.yudao.module.ai.dal.mysql.model.AiChatRoleMapper; import cn.iocoder.yudao.module.ai.dal.mysql.model.AiChatRoleMapper;
import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -35,8 +37,15 @@ public class AiChatRoleServiceImpl implements AiChatRoleService {
@Resource @Resource
private AiChatRoleMapper chatRoleMapper; private AiChatRoleMapper chatRoleMapper;
@Resource
private AiKnowledgeDocumentService knowledgeDocumentService;
@Override @Override
public Long createChatRole(AiChatRoleSaveReqVO createReqVO) { public Long createChatRole(AiChatRoleSaveReqVO createReqVO) {
// 校验文档
validateDocuments(createReqVO.getDocumentIds());
// 保存角色
AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class); AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class);
chatRoleMapper.insert(chatRole); chatRoleMapper.insert(chatRole);
return chatRole.getId(); return chatRole.getId();
@ -44,6 +53,10 @@ public class AiChatRoleServiceImpl implements AiChatRoleService {
@Override @Override
public Long createChatRoleMy(AiChatRoleSaveMyReqVO createReqVO, Long userId) { public Long createChatRoleMy(AiChatRoleSaveMyReqVO createReqVO, Long userId) {
// 校验文档
validateDocuments(createReqVO.getDocumentIds());
// 保存角色
AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class).setUserId(userId) AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class).setUserId(userId)
.setStatus(CommonStatusEnum.ENABLE.getStatus()).setPublicStatus(false); .setStatus(CommonStatusEnum.ENABLE.getStatus()).setPublicStatus(false);
chatRoleMapper.insert(chatRole); chatRoleMapper.insert(chatRole);
@ -54,7 +67,10 @@ public class AiChatRoleServiceImpl implements AiChatRoleService {
public void updateChatRole(AiChatRoleSaveReqVO updateReqVO) { public void updateChatRole(AiChatRoleSaveReqVO updateReqVO) {
// 校验存在 // 校验存在
validateChatRoleExists(updateReqVO.getId()); validateChatRoleExists(updateReqVO.getId());
// 更新 // 校验文档
validateDocuments(updateReqVO.getDocumentIds());
// 更新角色
AiChatRoleDO updateObj = BeanUtils.toBean(updateReqVO, AiChatRoleDO.class); AiChatRoleDO updateObj = BeanUtils.toBean(updateReqVO, AiChatRoleDO.class);
chatRoleMapper.updateById(updateObj); chatRoleMapper.updateById(updateObj);
} }
@ -66,12 +82,27 @@ public class AiChatRoleServiceImpl implements AiChatRoleService {
if (ObjectUtil.notEqual(chatRole.getUserId(), userId)) { if (ObjectUtil.notEqual(chatRole.getUserId(), userId)) {
throw exception(CHAT_ROLE_NOT_EXISTS); throw exception(CHAT_ROLE_NOT_EXISTS);
} }
// 校验文档
validateDocuments(updateReqVO.getDocumentIds());
// 更新 // 更新
AiChatRoleDO updateObj = BeanUtils.toBean(updateReqVO, AiChatRoleDO.class); AiChatRoleDO updateObj = BeanUtils.toBean(updateReqVO, AiChatRoleDO.class);
chatRoleMapper.updateById(updateObj); chatRoleMapper.updateById(updateObj);
} }
/**
* 校验文档是否存在
*
* @param documentIds 文档编号列表
*/
private void validateDocuments(List<Long> documentIds) {
if (CollUtil.isEmpty(documentIds)) {
return;
}
// 校验文档是否存在
documentIds.forEach(knowledgeDocumentService::validateKnowledgeDocumentExists);
}
@Override @Override
public void deleteChatRole(Long id) { public void deleteChatRole(Long id) {
// 校验存在 // 校验存在
@ -134,7 +165,8 @@ public class AiChatRoleServiceImpl implements AiChatRoleService {
@Override @Override
public List<String> getChatRoleCategoryList() { public List<String> getChatRoleCategoryList() {
List<AiChatRoleDO> list = chatRoleMapper.selectListGroupByCategory(CommonStatusEnum.ENABLE.getStatus()); List<AiChatRoleDO> list = chatRoleMapper.selectListGroupByCategory(CommonStatusEnum.ENABLE.getStatus());
return convertList(list, AiChatRoleDO::getCategory, role -> role != null && StrUtil.isNotBlank(role.getCategory())); return convertList(list, AiChatRoleDO::getCategory,
role -> role != null && StrUtil.isNotBlank(role.getCategory()));
} }
@Override @Override
@ -143,4 +175,3 @@ public class AiChatRoleServiceImpl implements AiChatRoleService {
} }
} }