package com.iailab.module.ai.controller.admin.chat; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjUtil; import com.aliyun.tea.utils.StringUtils; import com.iailab.framework.common.pojo.CommonResult; import com.iailab.framework.common.pojo.PageResult; import com.iailab.framework.common.util.collection.MapUtils; import com.iailab.framework.common.util.object.BeanUtils; import com.iailab.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO; import com.iailab.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO; import com.iailab.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO; import com.iailab.module.ai.controller.admin.chat.vo.message.AiChatMessageSendRespVO; import com.iailab.module.ai.dal.dataobject.chat.AiChatConversationDO; import com.iailab.module.ai.dal.dataobject.chat.AiChatMessageDO; import com.iailab.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; import com.iailab.module.ai.dal.dataobject.knowledge.AiKnowledgeSegmentDO; import com.iailab.module.ai.dal.dataobject.model.AiChatRoleDO; import com.iailab.module.ai.service.chat.AiChatConversationService; import com.iailab.module.ai.service.chat.AiChatMessageService; import com.iailab.module.ai.service.knowledge.AiKnowledgeDocumentService; import com.iailab.module.ai.service.knowledge.AiKnowledgeSegmentService; import com.iailab.module.ai.service.model.AiChatRoleService; 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.annotation.security.PermitAll; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.springframework.http.MediaType; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Flux; import java.util.Collections; import java.util.List; import java.util.Map; import static com.iailab.framework.common.pojo.CommonResult.success; import static com.iailab.framework.common.util.collection.CollectionUtils.*; import static com.iailab.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @Tag(name = "管理后台 - 聊天消息") @RestController @RequestMapping("/ai/chat/message") @Slf4j public class AiChatMessageController { @Resource private AiChatMessageService chatMessageService; @Resource private AiChatConversationService chatConversationService; @Resource private AiChatRoleService chatRoleService; @Resource private AiKnowledgeSegmentService knowledgeSegmentService; @Resource private AiKnowledgeDocumentService knowledgeDocumentService; @Operation(summary = "发送消息(段式)", description = "一次性返回,响应较慢") @PostMapping("/send") public CommonResult sendMessage(@Valid @RequestBody AiChatMessageSendReqVO sendReqVO) { return success(chatMessageService.sendMessage(sendReqVO, getLoginUserId())); } @Operation(summary = "发送消息(流式)", description = "流式返回,响应较快") @PostMapping(value = "/send-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux> sendChatMessageStream(@Valid @RequestBody AiChatMessageSendReqVO sendReqVO) { return chatMessageService.sendChatMessageStream(sendReqVO, getLoginUserId()); } @Operation(summary = "获得指定对话的消息列表") @GetMapping("/list-by-conversation-id") @Parameter(name = "conversationId", required = true, description = "对话编号", example = "1024") public CommonResult> getChatMessageListByConversationId( @RequestParam("conversationId") Long conversationId) { AiChatConversationDO conversation = chatConversationService.getChatConversation(conversationId); if (conversation == null || ObjUtil.notEqual(conversation.getUserId(), getLoginUserId())) { return success(Collections.emptyList()); } // 1. 获取消息列表 List messageList = chatMessageService.getChatMessageListByConversationId(conversationId); if (CollUtil.isEmpty(messageList)) { return success(Collections.emptyList()); } // 2. 拼接数据,主要是知识库段落信息 Map segmentMap = knowledgeSegmentService.getKnowledgeSegmentMap(convertListByFlatMap(messageList, message -> CollUtil.isEmpty(message.getSegmentIds()) ? null : message.getSegmentIds().stream())); Map documentMap = knowledgeDocumentService.getKnowledgeDocumentMap( convertList(segmentMap.values(), AiKnowledgeSegmentDO::getDocumentId)); List messageVOList = BeanUtils.toBean(messageList, AiChatMessageRespVO.class); for (int i = 0; i < messageList.size(); i++) { AiChatMessageDO message = messageList.get(i); if (CollUtil.isEmpty(message.getSegmentIds())) { continue; } // 设置知识库段落信息 messageVOList.get(i).setSegments(convertList(message.getSegmentIds(), segmentId -> { AiKnowledgeSegmentDO segment = segmentMap.get(segmentId); if (segment == null) { return null; } AiKnowledgeDocumentDO document = documentMap.get(segment.getDocumentId()); if (document == null) { return null; } return new AiChatMessageRespVO.KnowledgeSegment().setId(segment.getId()).setContent(segment.getContent()) .setDocumentId(segment.getDocumentId()).setDocumentName(document.getName()); })); } return success(messageVOList); } @Operation(summary = "获得指定对话的消息列表【工业大模型专用】") @GetMapping("/energy-list-by-conversation-id") @Parameter(name = "conversationId", required = true, description = "对话编号", example = "1024") public CommonResult> getEnergyChatMessageListByConversationId( @RequestParam("conversationId") Long conversationId) { // 1. 获取消息列表 List messageList = chatMessageService.getChatMessageListByConversationId(conversationId); if (CollUtil.isEmpty(messageList)) { return success(Collections.emptyList()); } // 查询最近的一次对话 int size = messageList.size(); if(size >= 2) { AiChatMessageDO aiChatMessageDO = messageList.get(size - 1); if(size >= 4 && StringUtils.isEmpty(aiChatMessageDO.getContent())) { messageList = messageList.subList(size - 4, size - 2); } else { messageList = messageList.subList(size - 2, size); } } List messageVOList = BeanUtils.toBean(messageList, AiChatMessageRespVO.class); return success(messageVOList); } @Operation(summary = "删除消息") @DeleteMapping("/delete") @Parameter(name = "id", required = true, description = "消息编号", example = "1024") public CommonResult deleteChatMessage(@RequestParam("id") Long id) { chatMessageService.deleteChatMessage(id, getLoginUserId()); return success(true); } @Operation(summary = "删除指定对话的消息") @DeleteMapping("/delete-by-conversation-id") @Parameter(name = "conversationId", required = true, description = "对话编号", example = "1024") public CommonResult deleteChatMessageByConversationId(@RequestParam("conversationId") Long conversationId) { chatMessageService.deleteChatMessageByConversationId(conversationId, getLoginUserId()); return success(true); } // ========== 对话管理 ========== @GetMapping("/page") @Operation(summary = "获得消息分页", description = "用于【对话管理】菜单") @PreAuthorize("@ss.hasPermission('ai:chat-conversation:query')") public CommonResult> getChatMessagePage(AiChatMessagePageReqVO pageReqVO) { PageResult pageResult = chatMessageService.getChatMessagePage(pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return success(PageResult.empty()); } // 拼接数据 Map roleMap = chatRoleService.getChatRoleMap( convertSet(pageResult.getList(), AiChatMessageDO::getRoleId)); return success(BeanUtils.toBean(pageResult, AiChatMessageRespVO.class, respVO -> MapUtils.findAndThen(roleMap, respVO.getRoleId(), role -> respVO.setRoleName(role.getName())))); } @Operation(summary = "管理员删除消息") @DeleteMapping("/delete-by-admin") @Parameter(name = "id", required = true, description = "消息编号", example = "1024") @PreAuthorize("@ss.hasPermission('ai:chat-message:delete')") public CommonResult deleteChatMessageByAdmin(@RequestParam("id") Long id) { chatMessageService.deleteChatMessageByAdmin(id); return success(true); } }