package cn.iocoder.yudao.module.ai.controller.admin.chat; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO; import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO; import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO; import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendRespVO; import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; import cn.iocoder.yudao.module.ai.service.chat.AiChatConversationService; import cn.iocoder.yudao.module.ai.service.chat.AiChatMessageService; import cn.iocoder.yudao.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 cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.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; @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) @PermitAll // 解决 SSE 最终响应的时候,会被 Access Denied 拦截的问题 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()); } List messageList = chatMessageService.getChatMessageListByConversationId(conversationId); return success(BeanUtils.toBean(messageList, AiChatMessageRespVO.class)); } @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); } }