Commit 1e8845ce6d229130ae4a804e578d52cf20f5fa15
1 parent
e869aaee
【功能新增】AI:增加 AI 对话,与 tool 的打通
Showing
10 changed files
with
147 additions
and
33 deletions
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/AiToolController.java
| 1 | package cn.iocoder.yudao.module.ai.controller.admin.model; | 1 | package cn.iocoder.yudao.module.ai.controller.admin.model; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 6 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| @@ -17,8 +18,10 @@ import org.springframework.security.access.prepost.PreAuthorize; | @@ -17,8 +18,10 @@ import org.springframework.security.access.prepost.PreAuthorize; | ||
| 17 | import org.springframework.validation.annotation.Validated; | 18 | import org.springframework.validation.annotation.Validated; |
| 18 | import org.springframework.web.bind.annotation.*; | 19 | import org.springframework.web.bind.annotation.*; |
| 19 | 20 | ||
| 20 | -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 21 | +import java.util.List; |
| 21 | 22 | ||
| 23 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 24 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | ||
| 22 | 25 | ||
| 23 | @Tag(name = "管理后台 - AI 工具") | 26 | @Tag(name = "管理后台 - AI 工具") |
| 24 | @RestController | 27 | @RestController |
| @@ -30,14 +33,14 @@ public class AiToolController { | @@ -30,14 +33,14 @@ public class AiToolController { | ||
| 30 | private AiToolService toolService; | 33 | private AiToolService toolService; |
| 31 | 34 | ||
| 32 | @PostMapping("/create") | 35 | @PostMapping("/create") |
| 33 | - @Operation(summary = "创建AI 工具") | 36 | + @Operation(summary = "创建工具") |
| 34 | @PreAuthorize("@ss.hasPermission('ai:tool:create')") | 37 | @PreAuthorize("@ss.hasPermission('ai:tool:create')") |
| 35 | public CommonResult<Long> createTool(@Valid @RequestBody AiToolSaveReqVO createReqVO) { | 38 | public CommonResult<Long> createTool(@Valid @RequestBody AiToolSaveReqVO createReqVO) { |
| 36 | return success(toolService.createTool(createReqVO)); | 39 | return success(toolService.createTool(createReqVO)); |
| 37 | } | 40 | } |
| 38 | 41 | ||
| 39 | @PutMapping("/update") | 42 | @PutMapping("/update") |
| 40 | - @Operation(summary = "更新AI 工具") | 43 | + @Operation(summary = "更新工具") |
| 41 | @PreAuthorize("@ss.hasPermission('ai:tool:update')") | 44 | @PreAuthorize("@ss.hasPermission('ai:tool:update')") |
| 42 | public CommonResult<Boolean> updateTool(@Valid @RequestBody AiToolSaveReqVO updateReqVO) { | 45 | public CommonResult<Boolean> updateTool(@Valid @RequestBody AiToolSaveReqVO updateReqVO) { |
| 43 | toolService.updateTool(updateReqVO); | 46 | toolService.updateTool(updateReqVO); |
| @@ -45,7 +48,7 @@ public class AiToolController { | @@ -45,7 +48,7 @@ public class AiToolController { | ||
| 45 | } | 48 | } |
| 46 | 49 | ||
| 47 | @DeleteMapping("/delete") | 50 | @DeleteMapping("/delete") |
| 48 | - @Operation(summary = "删除AI 工具") | 51 | + @Operation(summary = "删除工具") |
| 49 | @Parameter(name = "id", description = "编号", required = true) | 52 | @Parameter(name = "id", description = "编号", required = true) |
| 50 | @PreAuthorize("@ss.hasPermission('ai:tool:delete')") | 53 | @PreAuthorize("@ss.hasPermission('ai:tool:delete')") |
| 51 | public CommonResult<Boolean> deleteTool(@RequestParam("id") Long id) { | 54 | public CommonResult<Boolean> deleteTool(@RequestParam("id") Long id) { |
| @@ -54,7 +57,7 @@ public class AiToolController { | @@ -54,7 +57,7 @@ public class AiToolController { | ||
| 54 | } | 57 | } |
| 55 | 58 | ||
| 56 | @GetMapping("/get") | 59 | @GetMapping("/get") |
| 57 | - @Operation(summary = "获得AI 工具") | 60 | + @Operation(summary = "获得工具") |
| 58 | @Parameter(name = "id", description = "编号", required = true, example = "1024") | 61 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| 59 | @PreAuthorize("@ss.hasPermission('ai:tool:query')") | 62 | @PreAuthorize("@ss.hasPermission('ai:tool:query')") |
| 60 | public CommonResult<AiToolRespVO> getTool(@RequestParam("id") Long id) { | 63 | public CommonResult<AiToolRespVO> getTool(@RequestParam("id") Long id) { |
| @@ -63,11 +66,19 @@ public class AiToolController { | @@ -63,11 +66,19 @@ public class AiToolController { | ||
| 63 | } | 66 | } |
| 64 | 67 | ||
| 65 | @GetMapping("/page") | 68 | @GetMapping("/page") |
| 66 | - @Operation(summary = "获得AI 工具分页") | 69 | + @Operation(summary = "获得工具分页") |
| 67 | @PreAuthorize("@ss.hasPermission('ai:tool:query')") | 70 | @PreAuthorize("@ss.hasPermission('ai:tool:query')") |
| 68 | public CommonResult<PageResult<AiToolRespVO>> getToolPage(@Valid AiToolPageReqVO pageReqVO) { | 71 | public CommonResult<PageResult<AiToolRespVO>> getToolPage(@Valid AiToolPageReqVO pageReqVO) { |
| 69 | PageResult<AiToolDO> pageResult = toolService.getToolPage(pageReqVO); | 72 | PageResult<AiToolDO> pageResult = toolService.getToolPage(pageReqVO); |
| 70 | return success(BeanUtils.toBean(pageResult, AiToolRespVO.class)); | 73 | return success(BeanUtils.toBean(pageResult, AiToolRespVO.class)); |
| 71 | } | 74 | } |
| 72 | 75 | ||
| 76 | + @GetMapping("/simple-list") | ||
| 77 | + @Operation(summary = "获得工具列表") | ||
| 78 | + public CommonResult<List<AiToolRespVO>> getToolSimpleList() { | ||
| 79 | + List<AiToolDO> list = toolService.getToolListByStatus(CommonStatusEnum.ENABLE.getStatus()); | ||
| 80 | + return success(convertList(list, tool -> new AiToolRespVO() | ||
| 81 | + .setId(tool.getId()).setName(tool.getName()))); | ||
| 82 | + } | ||
| 83 | + | ||
| 73 | } | 84 | } |
| 74 | \ No newline at end of file | 85 | \ No newline at end of file |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatRole/AiChatRoleRespVO.java
| @@ -49,6 +49,9 @@ public class AiChatRoleRespVO implements VO { | @@ -49,6 +49,9 @@ public class AiChatRoleRespVO implements VO { | ||
| 49 | @Schema(description = "引用的知识库编号列表", example = "1,2,3") | 49 | @Schema(description = "引用的知识库编号列表", example = "1,2,3") |
| 50 | private List<Long> knowledgeIds; | 50 | private List<Long> knowledgeIds; |
| 51 | 51 | ||
| 52 | + @Schema(description = "引用的工具编号列表", example = "1,2,3") | ||
| 53 | + private List<Long> toolIds; | ||
| 54 | + | ||
| 52 | @Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | 55 | @Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 53 | private Boolean publicStatus; | 56 | private Boolean publicStatus; |
| 54 | 57 |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatRole/AiChatRoleSaveMyReqVO.java
| @@ -34,4 +34,7 @@ public class AiChatRoleSaveMyReqVO { | @@ -34,4 +34,7 @@ public class AiChatRoleSaveMyReqVO { | ||
| 34 | @Schema(description = "引用的知识库编号列表", example = "1,2,3") | 34 | @Schema(description = "引用的知识库编号列表", example = "1,2,3") |
| 35 | private List<Long> knowledgeIds; | 35 | private List<Long> knowledgeIds; |
| 36 | 36 | ||
| 37 | + @Schema(description = "引用的工具编号列表", example = "1,2,3") | ||
| 38 | + private List<Long> toolIds; | ||
| 39 | + | ||
| 37 | } | 40 | } |
| 38 | \ No newline at end of file | 41 | \ No newline at end of file |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatRole/AiChatRoleSaveReqVO.java
| @@ -47,6 +47,9 @@ public class AiChatRoleSaveReqVO { | @@ -47,6 +47,9 @@ public class AiChatRoleSaveReqVO { | ||
| 47 | @Schema(description = "引用的知识库编号列表", example = "1,2,3") | 47 | @Schema(description = "引用的知识库编号列表", example = "1,2,3") |
| 48 | private List<Long> knowledgeIds; | 48 | private List<Long> knowledgeIds; |
| 49 | 49 | ||
| 50 | + @Schema(description = "引用的工具编号列表", example = "1,2,3") | ||
| 51 | + private List<Long> toolIds; | ||
| 52 | + | ||
| 50 | @Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | 53 | @Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 51 | @NotNull(message = "是否公开不能为空") | 54 | @NotNull(message = "是否公开不能为空") |
| 52 | private Boolean publicStatus; | 55 | private Boolean publicStatus; |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatRoleDO.java
| @@ -74,6 +74,13 @@ public class AiChatRoleDO extends BaseDO { | @@ -74,6 +74,13 @@ public class AiChatRoleDO extends BaseDO { | ||
| 74 | */ | 74 | */ |
| 75 | @TableField(typeHandler = LongListTypeHandler.class) | 75 | @TableField(typeHandler = LongListTypeHandler.class) |
| 76 | private List<Long> knowledgeIds; | 76 | private List<Long> knowledgeIds; |
| 77 | + /** | ||
| 78 | + * 引用的工具编号列表 | ||
| 79 | + * | ||
| 80 | + * 关联 {@link AiToolDO#getId()} 字段 | ||
| 81 | + */ | ||
| 82 | + @TableField(typeHandler = LongListTypeHandler.class) | ||
| 83 | + private List<Long> toolIds; | ||
| 77 | 84 | ||
| 78 | /** | 85 | /** |
| 79 | * 是否公开 | 86 | * 是否公开 |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/model/AiToolMapper.java
| @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.ai.controller.admin.model.vo.tool.AiToolPageReqVO | @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.ai.controller.admin.model.vo.tool.AiToolPageReqVO | ||
| 7 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiToolDO; | 7 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiToolDO; |
| 8 | import org.apache.ibatis.annotations.Mapper; | 8 | import org.apache.ibatis.annotations.Mapper; |
| 9 | 9 | ||
| 10 | +import java.util.List; | ||
| 11 | + | ||
| 10 | /** | 12 | /** |
| 11 | * AI 工具 Mapper | 13 | * AI 工具 Mapper |
| 12 | * | 14 | * |
| @@ -24,4 +26,10 @@ public interface AiToolMapper extends BaseMapperX<AiToolDO> { | @@ -24,4 +26,10 @@ public interface AiToolMapper extends BaseMapperX<AiToolDO> { | ||
| 24 | .orderByDesc(AiToolDO::getId)); | 26 | .orderByDesc(AiToolDO::getId)); |
| 25 | } | 27 | } |
| 26 | 28 | ||
| 29 | + default List<AiToolDO> selectListByStatus(Integer status) { | ||
| 30 | + return selectList(new LambdaQueryWrapperX<AiToolDO>() | ||
| 31 | + .eq(AiToolDO::getStatus, status) | ||
| 32 | + .orderByDesc(AiToolDO::getId)); | ||
| 33 | + } | ||
| 34 | + | ||
| 27 | } | 35 | } |
| 28 | \ No newline at end of file | 36 | \ No newline at end of file |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java
| @@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; | @@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; | ||
| 7 | import cn.iocoder.yudao.framework.ai.core.util.AiUtils; | 7 | import cn.iocoder.yudao.framework.ai.core.util.AiUtils; |
| 8 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 8 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 9 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 9 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 10 | -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; | ||
| 11 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 10 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 12 | import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | 11 | import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; |
| 13 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO; | 12 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO; |
| @@ -19,6 +18,7 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; | @@ -19,6 +18,7 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; | ||
| 19 | import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; | 18 | import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; |
| 20 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | 19 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; |
| 21 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO; | 20 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO; |
| 21 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiToolDO; | ||
| 22 | import cn.iocoder.yudao.module.ai.dal.mysql.chat.AiChatMessageMapper; | 22 | import cn.iocoder.yudao.module.ai.dal.mysql.chat.AiChatMessageMapper; |
| 23 | import cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants; | 23 | import cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants; |
| 24 | import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService; | 24 | import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService; |
| @@ -27,6 +27,7 @@ import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchR | @@ -27,6 +27,7 @@ import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchR | ||
| 27 | import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchRespBO; | 27 | import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchRespBO; |
| 28 | import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService; | 28 | import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService; |
| 29 | import cn.iocoder.yudao.module.ai.service.model.AiModelService; | 29 | import cn.iocoder.yudao.module.ai.service.model.AiModelService; |
| 30 | +import cn.iocoder.yudao.module.ai.service.model.AiToolService; | ||
| 30 | import jakarta.annotation.Resource; | 31 | import jakarta.annotation.Resource; |
| 31 | import lombok.extern.slf4j.Slf4j; | 32 | import lombok.extern.slf4j.Slf4j; |
| 32 | import org.springframework.ai.chat.messages.Message; | 33 | import org.springframework.ai.chat.messages.Message; |
| @@ -50,6 +51,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU | @@ -50,6 +51,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU | ||
| 50 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error; | 51 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error; |
| 51 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 52 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 52 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | 53 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |
| 54 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | ||
| 53 | import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS; | 55 | import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS; |
| 54 | import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_MESSAGE_NOT_EXIST; | 56 | import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_MESSAGE_NOT_EXIST; |
| 55 | 57 | ||
| @@ -82,6 +84,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | @@ -82,6 +84,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | ||
| 82 | private AiKnowledgeSegmentService knowledgeSegmentService; | 84 | private AiKnowledgeSegmentService knowledgeSegmentService; |
| 83 | @Resource | 85 | @Resource |
| 84 | private AiKnowledgeDocumentService knowledgeDocumentService; | 86 | private AiKnowledgeDocumentService knowledgeDocumentService; |
| 87 | + @Resource | ||
| 88 | + private AiToolService toolService; | ||
| 85 | 89 | ||
| 86 | @Transactional(rollbackFor = Exception.class) | 90 | @Transactional(rollbackFor = Exception.class) |
| 87 | public AiChatMessageSendRespVO sendMessage(AiChatMessageSendReqVO sendReqVO, Long userId) { | 91 | public AiChatMessageSendRespVO sendMessage(AiChatMessageSendReqVO sendReqVO, Long userId) { |
| @@ -118,11 +122,13 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | @@ -118,11 +122,13 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | ||
| 118 | String newContent = chatResponse.getResult().getOutput().getText(); | 122 | String newContent = chatResponse.getResult().getOutput().getText(); |
| 119 | chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(newContent)); | 123 | chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(newContent)); |
| 120 | // 3.4 响应结果 | 124 | // 3.4 响应结果 |
| 121 | - List<AiChatMessageRespVO.KnowledgeSegment> segments = BeanUtils.toBean(knowledgeSegments, AiChatMessageRespVO.KnowledgeSegment.class, | 125 | + List<AiChatMessageRespVO.KnowledgeSegment> segments = BeanUtils.toBean(knowledgeSegments, |
| 126 | + AiChatMessageRespVO.KnowledgeSegment.class, | ||
| 122 | segment -> { | 127 | segment -> { |
| 123 | - AiKnowledgeDocumentDO document = knowledgeDocumentService.getKnowledgeDocument(segment.getDocumentId()); | ||
| 124 | - segment.setDocumentName(document != null ? document.getName() : null); | ||
| 125 | - }); | 128 | + AiKnowledgeDocumentDO document = knowledgeDocumentService |
| 129 | + .getKnowledgeDocument(segment.getDocumentId()); | ||
| 130 | + segment.setDocumentName(document != null ? document.getName() : null); | ||
| 131 | + }); | ||
| 126 | return new AiChatMessageSendRespVO() | 132 | return new AiChatMessageSendRespVO() |
| 127 | .setSend(BeanUtils.toBean(userMessage, AiChatMessageSendRespVO.Message.class)) | 133 | .setSend(BeanUtils.toBean(userMessage, AiChatMessageSendRespVO.Message.class)) |
| 128 | .setReceive(BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class) | 134 | .setReceive(BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class) |
| @@ -130,7 +136,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | @@ -130,7 +136,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | ||
| 130 | } | 136 | } |
| 131 | 137 | ||
| 132 | @Override | 138 | @Override |
| 133 | - public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId) { | 139 | + public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, |
| 140 | + Long userId) { | ||
| 134 | // 1.1 校验对话存在 | 141 | // 1.1 校验对话存在 |
| 135 | AiChatConversationDO conversation = chatConversationService | 142 | AiChatConversationDO conversation = chatConversationService |
| 136 | .validateChatConversationExists(sendReqVO.getConversationId()); | 143 | .validateChatConversationExists(sendReqVO.getConversationId()); |
| @@ -143,7 +150,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | @@ -143,7 +150,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | ||
| 143 | StreamingChatModel chatModel = modalService.getChatModel(model.getId()); | 150 | StreamingChatModel chatModel = modalService.getChatModel(model.getId()); |
| 144 | 151 | ||
| 145 | // 2. 知识库找回 | 152 | // 2. 知识库找回 |
| 146 | - List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments = recallKnowledgeSegment(sendReqVO.getContent(), conversation); | 153 | + List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments = recallKnowledgeSegment(sendReqVO.getContent(), |
| 154 | + conversation); | ||
| 147 | 155 | ||
| 148 | // 3. 插入 user 发送消息 | 156 | // 3. 插入 user 发送消息 |
| 149 | AiChatMessageDO userMessage = createChatMessage(conversation.getId(), null, model, | 157 | AiChatMessageDO userMessage = createChatMessage(conversation.getId(), null, model, |
| @@ -167,7 +175,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | @@ -167,7 +175,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | ||
| 167 | if (StrUtil.isEmpty(contentBuffer)) { | 175 | if (StrUtil.isEmpty(contentBuffer)) { |
| 168 | segments = BeanUtils.toBean(knowledgeSegments, AiChatMessageRespVO.KnowledgeSegment.class, | 176 | segments = BeanUtils.toBean(knowledgeSegments, AiChatMessageRespVO.KnowledgeSegment.class, |
| 169 | segment -> TenantUtils.executeIgnore(() -> { | 177 | segment -> TenantUtils.executeIgnore(() -> { |
| 170 | - AiKnowledgeDocumentDO document = knowledgeDocumentService.getKnowledgeDocument(segment.getDocumentId()); | 178 | + AiKnowledgeDocumentDO document = knowledgeDocumentService |
| 179 | + .getKnowledgeDocument(segment.getDocumentId()); | ||
| 171 | segment.setDocumentName(document != null ? document.getName() : null); | 180 | segment.setDocumentName(document != null ? document.getName() : null); |
| 172 | })); | 181 | })); |
| 173 | } | 182 | } |
| @@ -192,7 +201,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | @@ -192,7 +201,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | ||
| 192 | } | 201 | } |
| 193 | 202 | ||
| 194 | private List<AiKnowledgeSegmentSearchRespBO> recallKnowledgeSegment(String content, | 203 | private List<AiKnowledgeSegmentSearchRespBO> recallKnowledgeSegment(String content, |
| 195 | - AiChatConversationDO conversation) { | 204 | + AiChatConversationDO conversation) { |
| 196 | // 1. 查询聊天角色 | 205 | // 1. 查询聊天角色 |
| 197 | if (conversation == null || conversation.getRoleId() == null) { | 206 | if (conversation == null || conversation.getRoleId() == null) { |
| 198 | return Collections.emptyList(); | 207 | return Collections.emptyList(); |
| @@ -212,8 +221,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | @@ -212,8 +221,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | ||
| 212 | } | 221 | } |
| 213 | 222 | ||
| 214 | private Prompt buildPrompt(AiChatConversationDO conversation, List<AiChatMessageDO> messages, | 223 | private Prompt buildPrompt(AiChatConversationDO conversation, List<AiChatMessageDO> messages, |
| 215 | - List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments, | ||
| 216 | - AiModelDO model, AiChatMessageSendReqVO sendReqVO) { | 224 | + List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments, |
| 225 | + AiModelDO model, AiChatMessageSendReqVO sendReqVO) { | ||
| 217 | List<Message> chatMessages = new ArrayList<>(); | 226 | List<Message> chatMessages = new ArrayList<>(); |
| 218 | // 1.1 System Context 角色设定 | 227 | // 1.1 System Context 角色设定 |
| 219 | if (StrUtil.isNotBlank(conversation.getSystemMessage())) { | 228 | if (StrUtil.isNotBlank(conversation.getSystemMessage())) { |
| @@ -236,11 +245,18 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | @@ -236,11 +245,18 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | ||
| 236 | chatMessages.add(new UserMessage(String.format(KNOWLEDGE_USER_MESSAGE_TEMPLATE, reference))); | 245 | chatMessages.add(new UserMessage(String.format(KNOWLEDGE_USER_MESSAGE_TEMPLATE, reference))); |
| 237 | } | 246 | } |
| 238 | 247 | ||
| 239 | - // 2. 构建 ChatOptions 对象 | 248 | + // 2.1 查询 tool 工具 |
| 249 | + Set<String> toolNames = null; | ||
| 250 | + if (conversation.getRoleId() != null) { | ||
| 251 | + AiChatRoleDO chatRole = chatRoleService.getChatRole(conversation.getRoleId()); | ||
| 252 | + if (chatRole != null && CollUtil.isNotEmpty(chatRole.getToolIds())) { | ||
| 253 | + toolNames = convertSet(toolService.getToolList(chatRole.getToolIds()), AiToolDO::getName); | ||
| 254 | + } | ||
| 255 | + } | ||
| 256 | + // 2.2 构建 ChatOptions 对象 | ||
| 240 | AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform()); | 257 | AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform()); |
| 241 | ChatOptions chatOptions = AiUtils.buildChatOptions(platform, model.getModel(), | 258 | ChatOptions chatOptions = AiUtils.buildChatOptions(platform, model.getModel(), |
| 242 | - conversation.getTemperature(), conversation.getMaxTokens(), | ||
| 243 | - SetUtils.asSet("directory_list", "weather_query")); | 259 | + conversation.getTemperature(), conversation.getMaxTokens(), toolNames); |
| 244 | return new Prompt(chatMessages, chatOptions); | 260 | return new Prompt(chatMessages, chatOptions); |
| 245 | } | 261 | } |
| 246 | 262 | ||
| @@ -255,8 +271,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | @@ -255,8 +271,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | ||
| 255 | * @return 消息上下文 | 271 | * @return 消息上下文 |
| 256 | */ | 272 | */ |
| 257 | private List<AiChatMessageDO> filterContextMessages(List<AiChatMessageDO> messages, | 273 | private List<AiChatMessageDO> filterContextMessages(List<AiChatMessageDO> messages, |
| 258 | - AiChatConversationDO conversation, | ||
| 259 | - AiChatMessageSendReqVO sendReqVO) { | 274 | + AiChatConversationDO conversation, |
| 275 | + AiChatMessageSendReqVO sendReqVO) { | ||
| 260 | if (conversation.getMaxContexts() == null || ObjUtil.notEqual(sendReqVO.getUseContext(), Boolean.TRUE)) { | 276 | if (conversation.getMaxContexts() == null || ObjUtil.notEqual(sendReqVO.getUseContext(), Boolean.TRUE)) { |
| 261 | return Collections.emptyList(); | 277 | return Collections.emptyList(); |
| 262 | } | 278 | } |
| @@ -285,9 +301,9 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | @@ -285,9 +301,9 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | ||
| 285 | } | 301 | } |
| 286 | 302 | ||
| 287 | private AiChatMessageDO createChatMessage(Long conversationId, Long replyId, | 303 | private AiChatMessageDO createChatMessage(Long conversationId, Long replyId, |
| 288 | - AiModelDO model, Long userId, Long roleId, | ||
| 289 | - MessageType messageType, String content, Boolean useContext, | ||
| 290 | - List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments) { | 304 | + AiModelDO model, Long userId, Long roleId, |
| 305 | + MessageType messageType, String content, Boolean useContext, | ||
| 306 | + List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments) { | ||
| 291 | AiChatMessageDO message = new AiChatMessageDO().setConversationId(conversationId).setReplyId(replyId) | 307 | AiChatMessageDO message = new AiChatMessageDO().setConversationId(conversationId).setReplyId(replyId) |
| 292 | .setModel(model.getModel()).setModelId(model.getId()).setUserId(userId).setRoleId(roleId) | 308 | .setModel(model.getModel()).setModelId(model.getId()).setUserId(userId).setRoleId(roleId) |
| 293 | .setType(messageType.getValue()).setContent(content).setUseContext(useContext) | 309 | .setType(messageType.getValue()).setContent(content).setUseContext(useContext) |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleServiceImpl.java
| @@ -39,11 +39,15 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { | @@ -39,11 +39,15 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { | ||
| 39 | 39 | ||
| 40 | @Resource | 40 | @Resource |
| 41 | private AiKnowledgeService knowledgeService; | 41 | private AiKnowledgeService knowledgeService; |
| 42 | + @Resource | ||
| 43 | + private AiToolService toolService; | ||
| 42 | 44 | ||
| 43 | @Override | 45 | @Override |
| 44 | public Long createChatRole(AiChatRoleSaveReqVO createReqVO) { | 46 | public Long createChatRole(AiChatRoleSaveReqVO createReqVO) { |
| 45 | // 校验文档 | 47 | // 校验文档 |
| 46 | validateDocuments(createReqVO.getKnowledgeIds()); | 48 | validateDocuments(createReqVO.getKnowledgeIds()); |
| 49 | + // 校验工具 | ||
| 50 | + validateTools(createReqVO.getToolIds()); | ||
| 47 | 51 | ||
| 48 | // 保存角色 | 52 | // 保存角色 |
| 49 | AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class); | 53 | AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class); |
| @@ -55,6 +59,8 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { | @@ -55,6 +59,8 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { | ||
| 55 | public Long createChatRoleMy(AiChatRoleSaveMyReqVO createReqVO, Long userId) { | 59 | public Long createChatRoleMy(AiChatRoleSaveMyReqVO createReqVO, Long userId) { |
| 56 | // 校验文档 | 60 | // 校验文档 |
| 57 | validateDocuments(createReqVO.getKnowledgeIds()); | 61 | validateDocuments(createReqVO.getKnowledgeIds()); |
| 62 | + // 校验工具 | ||
| 63 | + validateTools(createReqVO.getToolIds()); | ||
| 58 | 64 | ||
| 59 | // 保存角色 | 65 | // 保存角色 |
| 60 | AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class).setUserId(userId) | 66 | AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class).setUserId(userId) |
| @@ -69,6 +75,8 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { | @@ -69,6 +75,8 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { | ||
| 69 | validateChatRoleExists(updateReqVO.getId()); | 75 | validateChatRoleExists(updateReqVO.getId()); |
| 70 | // 校验文档 | 76 | // 校验文档 |
| 71 | validateDocuments(updateReqVO.getKnowledgeIds()); | 77 | validateDocuments(updateReqVO.getKnowledgeIds()); |
| 78 | + // 校验工具 | ||
| 79 | + validateTools(updateReqVO.getToolIds()); | ||
| 72 | 80 | ||
| 73 | // 更新角色 | 81 | // 更新角色 |
| 74 | AiChatRoleDO updateObj = BeanUtils.toBean(updateReqVO, AiChatRoleDO.class); | 82 | AiChatRoleDO updateObj = BeanUtils.toBean(updateReqVO, AiChatRoleDO.class); |
| @@ -84,6 +92,8 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { | @@ -84,6 +92,8 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { | ||
| 84 | } | 92 | } |
| 85 | // 校验文档 | 93 | // 校验文档 |
| 86 | validateDocuments(updateReqVO.getKnowledgeIds()); | 94 | validateDocuments(updateReqVO.getKnowledgeIds()); |
| 95 | + // 校验工具 | ||
| 96 | + validateTools(updateReqVO.getToolIds()); | ||
| 87 | 97 | ||
| 88 | // 更新 | 98 | // 更新 |
| 89 | AiChatRoleDO updateObj = BeanUtils.toBean(updateReqVO, AiChatRoleDO.class); | 99 | AiChatRoleDO updateObj = BeanUtils.toBean(updateReqVO, AiChatRoleDO.class); |
| @@ -103,6 +113,19 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { | @@ -103,6 +113,19 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { | ||
| 103 | knowledgeIds.forEach(knowledgeService::validateKnowledgeExists); | 113 | knowledgeIds.forEach(knowledgeService::validateKnowledgeExists); |
| 104 | } | 114 | } |
| 105 | 115 | ||
| 116 | + /** | ||
| 117 | + * 校验工具是否存在 | ||
| 118 | + * | ||
| 119 | + * @param toolIds 工具编号列表 | ||
| 120 | + */ | ||
| 121 | + private void validateTools(List<Long> toolIds) { | ||
| 122 | + if (CollUtil.isEmpty(toolIds)) { | ||
| 123 | + return; | ||
| 124 | + } | ||
| 125 | + // 遍历校验每个工具是否存在 | ||
| 126 | + toolIds.forEach(toolService::validateToolExists); | ||
| 127 | + } | ||
| 128 | + | ||
| 106 | @Override | 129 | @Override |
| 107 | public void deleteChatRole(Long id) { | 130 | public void deleteChatRole(Long id) { |
| 108 | // 校验存在 | 131 | // 校验存在 |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiToolService.java
| @@ -6,6 +6,9 @@ import cn.iocoder.yudao.module.ai.controller.admin.model.vo.tool.AiToolSaveReqVO | @@ -6,6 +6,9 @@ import cn.iocoder.yudao.module.ai.controller.admin.model.vo.tool.AiToolSaveReqVO | ||
| 6 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiToolDO; | 6 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiToolDO; |
| 7 | import jakarta.validation.Valid; | 7 | import jakarta.validation.Valid; |
| 8 | 8 | ||
| 9 | +import java.util.Collection; | ||
| 10 | +import java.util.List; | ||
| 11 | + | ||
| 9 | /** | 12 | /** |
| 10 | * AI 工具 Service 接口 | 13 | * AI 工具 Service 接口 |
| 11 | * | 14 | * |
| @@ -14,7 +17,7 @@ import jakarta.validation.Valid; | @@ -14,7 +17,7 @@ import jakarta.validation.Valid; | ||
| 14 | public interface AiToolService { | 17 | public interface AiToolService { |
| 15 | 18 | ||
| 16 | /** | 19 | /** |
| 17 | - * 创建AI 工具 | 20 | + * 创建工具 |
| 18 | * | 21 | * |
| 19 | * @param createReqVO 创建信息 | 22 | * @param createReqVO 创建信息 |
| 20 | * @return 编号 | 23 | * @return 编号 |
| @@ -22,33 +25,56 @@ public interface AiToolService { | @@ -22,33 +25,56 @@ public interface AiToolService { | ||
| 22 | Long createTool(@Valid AiToolSaveReqVO createReqVO); | 25 | Long createTool(@Valid AiToolSaveReqVO createReqVO); |
| 23 | 26 | ||
| 24 | /** | 27 | /** |
| 25 | - * 更新AI 工具 | 28 | + * 更新工具 |
| 26 | * | 29 | * |
| 27 | * @param updateReqVO 更新信息 | 30 | * @param updateReqVO 更新信息 |
| 28 | */ | 31 | */ |
| 29 | void updateTool(@Valid AiToolSaveReqVO updateReqVO); | 32 | void updateTool(@Valid AiToolSaveReqVO updateReqVO); |
| 30 | 33 | ||
| 31 | /** | 34 | /** |
| 32 | - * 删除AI 工具 | 35 | + * 删除工具 |
| 33 | * | 36 | * |
| 34 | * @param id 编号 | 37 | * @param id 编号 |
| 35 | */ | 38 | */ |
| 36 | void deleteTool(Long id); | 39 | void deleteTool(Long id); |
| 37 | 40 | ||
| 38 | /** | 41 | /** |
| 39 | - * 获得AI 工具 | 42 | + * 校验工具是否存在 |
| 40 | * | 43 | * |
| 41 | * @param id 编号 | 44 | * @param id 编号 |
| 42 | - * @return AI 工具 | 45 | + */ |
| 46 | + void validateToolExists(Long id); | ||
| 47 | + | ||
| 48 | + /** | ||
| 49 | + * 获得工具 | ||
| 50 | + * | ||
| 51 | + * @param id 编号 | ||
| 52 | + * @return 工具 | ||
| 43 | */ | 53 | */ |
| 44 | AiToolDO getTool(Long id); | 54 | AiToolDO getTool(Long id); |
| 45 | 55 | ||
| 46 | /** | 56 | /** |
| 47 | - * 获得AI 工具分页 | 57 | + * 获得工具列表 |
| 58 | + * | ||
| 59 | + * @param ids 编号列表 | ||
| 60 | + * @return 工具列表 | ||
| 61 | + */ | ||
| 62 | + List<AiToolDO> getToolList(Collection<Long> ids); | ||
| 63 | + | ||
| 64 | + /** | ||
| 65 | + * 获得工具分页 | ||
| 48 | * | 66 | * |
| 49 | * @param pageReqVO 分页查询 | 67 | * @param pageReqVO 分页查询 |
| 50 | - * @return AI 工具分页 | 68 | + * @return 工具分页 |
| 51 | */ | 69 | */ |
| 52 | PageResult<AiToolDO> getToolPage(AiToolPageReqVO pageReqVO); | 70 | PageResult<AiToolDO> getToolPage(AiToolPageReqVO pageReqVO); |
| 53 | 71 | ||
| 72 | + /** | ||
| 73 | + * 获得工具列表 | ||
| 74 | + * | ||
| 75 | + * @param status 状态 | ||
| 76 | + * @return 工具列表 | ||
| 77 | + */ | ||
| 78 | + List<AiToolDO> getToolListByStatus(Integer status); | ||
| 79 | + | ||
| 54 | } | 80 | } |
| 55 | \ No newline at end of file | 81 | \ No newline at end of file |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiToolServiceImpl.java
| @@ -12,6 +12,9 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; | @@ -12,6 +12,9 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; | ||
| 12 | import org.springframework.stereotype.Service; | 12 | import org.springframework.stereotype.Service; |
| 13 | import org.springframework.validation.annotation.Validated; | 13 | import org.springframework.validation.annotation.Validated; |
| 14 | 14 | ||
| 15 | +import java.util.Collection; | ||
| 16 | +import java.util.List; | ||
| 17 | + | ||
| 15 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 18 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 16 | import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.TOOL_NAME_NOT_EXISTS; | 19 | import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.TOOL_NAME_NOT_EXISTS; |
| 17 | import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.TOOL_NOT_EXISTS; | 20 | import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.TOOL_NOT_EXISTS; |
| @@ -59,7 +62,8 @@ public class AiToolServiceImpl implements AiToolService { | @@ -59,7 +62,8 @@ public class AiToolServiceImpl implements AiToolService { | ||
| 59 | toolMapper.deleteById(id); | 62 | toolMapper.deleteById(id); |
| 60 | } | 63 | } |
| 61 | 64 | ||
| 62 | - private void validateToolExists(Long id) { | 65 | + @Override |
| 66 | + public void validateToolExists(Long id) { | ||
| 63 | if (toolMapper.selectById(id) == null) { | 67 | if (toolMapper.selectById(id) == null) { |
| 64 | throw exception(TOOL_NOT_EXISTS); | 68 | throw exception(TOOL_NOT_EXISTS); |
| 65 | } | 69 | } |
| @@ -79,8 +83,18 @@ public class AiToolServiceImpl implements AiToolService { | @@ -79,8 +83,18 @@ public class AiToolServiceImpl implements AiToolService { | ||
| 79 | } | 83 | } |
| 80 | 84 | ||
| 81 | @Override | 85 | @Override |
| 86 | + public List<AiToolDO> getToolList(Collection<Long> ids) { | ||
| 87 | + return toolMapper.selectBatchIds(ids); | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + @Override | ||
| 82 | public PageResult<AiToolDO> getToolPage(AiToolPageReqVO pageReqVO) { | 91 | public PageResult<AiToolDO> getToolPage(AiToolPageReqVO pageReqVO) { |
| 83 | return toolMapper.selectPage(pageReqVO); | 92 | return toolMapper.selectPage(pageReqVO); |
| 84 | } | 93 | } |
| 85 | 94 | ||
| 95 | + @Override | ||
| 96 | + public List<AiToolDO> getToolListByStatus(Integer status) { | ||
| 97 | + return toolMapper.selectListByStatus(status); | ||
| 98 | + } | ||
| 99 | + | ||
| 86 | } | 100 | } |
| 87 | \ No newline at end of file | 101 | \ No newline at end of file |