mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-12-02 12:11:54 +08:00
Merge branch 'master-jdk21-ai' of https://gitee.com/cherishsince/ruoyi-vue-pro into master-jdk21-ai
# Conflicts: # yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/AiChatModelMapper.java # yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatModelService.java # yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatModelServiceImpl.java
This commit is contained in:
commit
eb8cd3d736
@ -36,5 +36,9 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode AI_CHAT_ROLE_NOT_EXIST = new ErrorCode(1_022_000_060, "AI 角色不存在!");
|
ErrorCode AI_CHAT_ROLE_NOT_EXIST = new ErrorCode(1_022_000_060, "AI 角色不存在!");
|
||||||
ErrorCode AI_CHAT_ROLE_NOT_PUBLIC = new ErrorCode(1_022_000_060, "AI 角色未公开!");
|
ErrorCode AI_CHAT_ROLE_NOT_PUBLIC = new ErrorCode(1_022_000_060, "AI 角色未公开!");
|
||||||
|
|
||||||
|
// chat
|
||||||
|
|
||||||
|
ErrorCode AI_CHAT_MESSAGE_NOT_EXIST = new ErrorCode(1_022_000_100, "AI 提问的 MessageId 不存在!");
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.ai.controller.admin.chat;
|
package cn.iocoder.yudao.module.ai.controller.admin.chat;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO;
|
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.*;
|
||||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO;
|
|
||||||
import cn.iocoder.yudao.module.ai.service.AiChatService;
|
import cn.iocoder.yudao.module.ai.service.AiChatService;
|
||||||
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.Parameter;
|
||||||
@ -38,10 +37,16 @@ public class AiChatMessageController {
|
|||||||
// TODO @fan:要不要使用 Flux 来返回;可以使用 Flux<AiChatMessageRespVO>
|
// TODO @fan:要不要使用 Flux 来返回;可以使用 Flux<AiChatMessageRespVO>
|
||||||
@Operation(summary = "发送消息(流式)", description = "流式返回,响应较快")
|
@Operation(summary = "发送消息(流式)", description = "流式返回,响应较快")
|
||||||
@PostMapping(value = "/send-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
@PostMapping(value = "/send-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||||
public Flux<AiChatMessageRespVO> sendMessageStream(@Validated @RequestBody AiChatMessageSendReqVO sendReqVO) {
|
public Flux<AiChatMessageRespVO> sendMessageStream(@Validated @RequestBody AiChatMessageSendStreamReqVO sendReqVO) {
|
||||||
return chatService.chatStream(sendReqVO);
|
return chatService.chatStream(sendReqVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "添加/提问", description = "先创建好 message 前端才好渲染")
|
||||||
|
@PostMapping(value = "/add")
|
||||||
|
public CommonResult<AiChatMessageRespVO> add(@Validated @RequestBody AiChatMessageAddReqVO req) {
|
||||||
|
return success(chatService.add(req));
|
||||||
|
}
|
||||||
|
|
||||||
@Operation(summary = "获得指定会话的消息列表")
|
@Operation(summary = "获得指定会话的消息列表")
|
||||||
@GetMapping("/list-by-conversation-id")
|
@GetMapping("/list-by-conversation-id")
|
||||||
@Parameter(name = "conversationId", required = true, description = "会话编号", example = "1024")
|
@Parameter(name = "conversationId", required = true, description = "会话编号", example = "1024")
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - AI 聊天消息发送 Request VO")
|
||||||
|
@Data
|
||||||
|
public class AiChatMessageAddReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "聊天对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
|
@NotNull(message = "聊天对话编号不能为空")
|
||||||
|
private Long conversationId;
|
||||||
|
|
||||||
|
@Schema(description = "聊天内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "帮我写个 Java 算法")
|
||||||
|
@NotEmpty(message = "聊天内容不能为空")
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - AI 聊天消息 Add Response VO")
|
||||||
|
@Data
|
||||||
|
public class AiChatMessageAddRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "用户信息")
|
||||||
|
private AiChatMessageRespVO userMessage;
|
||||||
|
|
||||||
|
@Schema(description = "系统信息")
|
||||||
|
private AiChatMessageRespVO systemMessage;
|
||||||
|
}
|
@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@Schema(description = "管理后台 - AI 聊天消息 Response VO")
|
@Schema(description = "管理后台 - AI 聊天消息 Response VO")
|
||||||
@Data
|
@Data
|
||||||
public class AiChatMessageRespVO {
|
public class AiChatMessageRespVO {
|
||||||
@ -19,6 +21,9 @@ public class AiChatMessageRespVO {
|
|||||||
@Schema(description = "用户编号", example = "4096")
|
@Schema(description = "用户编号", example = "4096")
|
||||||
private Long userId; // 仅当 user 发送时非空
|
private Long userId; // 仅当 user 发送时非空
|
||||||
|
|
||||||
|
@Schema(description = "用户头像", example = "http://xxx")
|
||||||
|
private Long avatarUrl; // 仅当 user 发送时非空
|
||||||
|
|
||||||
@Schema(description = "角色编号", example = "888")
|
@Schema(description = "角色编号", example = "888")
|
||||||
private Long roleId; // 仅当 assistant 回复时非空
|
private Long roleId; // 仅当 assistant 回复时非空
|
||||||
|
|
||||||
@ -28,10 +33,15 @@ public class AiChatMessageRespVO {
|
|||||||
@Schema(description = "模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123")
|
@Schema(description = "模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123")
|
||||||
private Long modelId;
|
private Long modelId;
|
||||||
|
|
||||||
|
@Schema(description = "模型图片", requiredMode = Schema.RequiredMode.REQUIRED, example = "123")
|
||||||
|
private String modelImage;
|
||||||
|
|
||||||
@Schema(description = "聊天内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,你好啊")
|
@Schema(description = "聊天内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,你好啊")
|
||||||
private String content;
|
private String content;
|
||||||
|
|
||||||
@Schema(description = "消耗 Token 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "80")
|
@Schema(description = "消耗 Token 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "80")
|
||||||
private Integer tokens;
|
private Integer tokens;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-05-12 12:51")
|
||||||
|
private LocalDateTime createTime;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - AI 聊天消息发送 Request VO")
|
||||||
|
@Data
|
||||||
|
public class AiChatMessageSendStreamReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "提问的 messageId", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
|
@NotNull(message = "提问的 messageId 不能为空")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
}
|
@ -26,4 +26,13 @@ public interface AiChatMessageConvert {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
List<AiChatMessageRespVO> convertAiChatMessageRespVOList(List<AiChatMessageDO> aiChatMessageDOList);
|
List<AiChatMessageRespVO> convertAiChatMessageRespVOList(List<AiChatMessageDO> aiChatMessageDOList);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换 - aiChatMessageDO
|
||||||
|
*
|
||||||
|
* @param aiChatMessageDO
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
AiChatMessageRespVO convertAiChatMessageRespVO(AiChatMessageDO aiChatMessageDO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,9 @@ import org.apache.ibatis.annotations.Mapper;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API 聊天模型 Mapper
|
* API 聊天模型 Mapper
|
||||||
*
|
*
|
||||||
@ -36,6 +39,17 @@ public interface AiChatModelMapper extends BaseMapperX<AiChatModelDO> {
|
|||||||
return pageResult.getList().get(0);
|
return pageResult.getList().get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询 - 根据 ids
|
||||||
|
*
|
||||||
|
* @param modalIds
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
default List<AiChatModelDO> selectByIds(Collection<Long> modalIds) {
|
||||||
|
return this.selectList(new LambdaQueryWrapperX<AiChatModelDO>().eq(AiChatModelDO::getId, modalIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
default PageResult<AiChatModelDO> selectPage(AiChatModelPageReqVO reqVO) {
|
default PageResult<AiChatModelDO> selectPage(AiChatModelPageReqVO reqVO) {
|
||||||
return selectPage(reqVO, new LambdaQueryWrapperX<AiChatModelDO>()
|
return selectPage(reqVO, new LambdaQueryWrapperX<AiChatModelDO>()
|
||||||
.likeIfPresent(AiChatModelDO::getName, reqVO.getName())
|
.likeIfPresent(AiChatModelDO::getName, reqVO.getName())
|
||||||
@ -49,5 +63,4 @@ public interface AiChatModelMapper extends BaseMapperX<AiChatModelDO> {
|
|||||||
.eq(AiChatModelDO::getStatus, status)
|
.eq(AiChatModelDO::getStatus, status)
|
||||||
.orderByAsc(AiChatModelDO::getSort));
|
.orderByAsc(AiChatModelDO::getSort));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package cn.iocoder.yudao.module.ai.service;
|
package cn.iocoder.yudao.module.ai.service;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO;
|
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.*;
|
||||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO;
|
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -29,7 +28,15 @@ public interface AiChatService {
|
|||||||
* @param sendReqVO
|
* @param sendReqVO
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
Flux<AiChatMessageRespVO> chatStream(AiChatMessageSendReqVO sendReqVO);
|
Flux<AiChatMessageRespVO> chatStream(AiChatMessageSendStreamReqVO sendReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加 - message
|
||||||
|
*
|
||||||
|
* @param sendReqVO
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
AiChatMessageRespVO add(AiChatMessageAddReqVO sendReqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 - 获取对话 message list
|
* 获取 - 获取对话 message list
|
||||||
|
@ -7,11 +7,15 @@ import cn.iocoder.yudao.framework.ai.chat.ChatResponse;
|
|||||||
import cn.iocoder.yudao.framework.ai.chat.StreamingChatClient;
|
import cn.iocoder.yudao.framework.ai.chat.StreamingChatClient;
|
||||||
import cn.iocoder.yudao.framework.ai.chat.messages.MessageType;
|
import cn.iocoder.yudao.framework.ai.chat.messages.MessageType;
|
||||||
import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt;
|
import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt;
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
|
||||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
|
import cn.iocoder.yudao.module.ai.ErrorCodeConstants;
|
||||||
import cn.iocoder.yudao.module.ai.config.AiChatClientFactory;
|
import cn.iocoder.yudao.module.ai.config.AiChatClientFactory;
|
||||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO;
|
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO;
|
||||||
|
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageAddReqVO;
|
||||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO;
|
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.AiChatMessageSendReqVO;
|
||||||
|
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendStreamReqVO;
|
||||||
import cn.iocoder.yudao.module.ai.convert.AiChatMessageConvert;
|
import cn.iocoder.yudao.module.ai.convert.AiChatMessageConvert;
|
||||||
import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO;
|
import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO;
|
||||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
|
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
|
||||||
@ -19,18 +23,22 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO;
|
|||||||
import cn.iocoder.yudao.module.ai.dal.mysql.AiChatConversationMapper;
|
import cn.iocoder.yudao.module.ai.dal.mysql.AiChatConversationMapper;
|
||||||
import cn.iocoder.yudao.module.ai.dal.mysql.AiChatMessageMapper;
|
import cn.iocoder.yudao.module.ai.dal.mysql.AiChatMessageMapper;
|
||||||
import cn.iocoder.yudao.module.ai.service.AiChatConversationService;
|
import cn.iocoder.yudao.module.ai.service.AiChatConversationService;
|
||||||
import cn.iocoder.yudao.module.ai.service.model.AiChatModelService;
|
|
||||||
import cn.iocoder.yudao.module.ai.service.AiChatRoleService;
|
import cn.iocoder.yudao.module.ai.service.AiChatRoleService;
|
||||||
import cn.iocoder.yudao.module.ai.service.AiChatService;
|
import cn.iocoder.yudao.module.ai.service.AiChatService;
|
||||||
|
import cn.iocoder.yudao.module.ai.service.model.AiChatModelService;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 聊天 service
|
* 聊天 service
|
||||||
@ -50,6 +58,7 @@ public class AiChatServiceImpl implements AiChatService {
|
|||||||
private final AiChatConversationService chatConversationService;
|
private final AiChatConversationService chatConversationService;
|
||||||
private final AiChatModelService aiChatModalService;
|
private final AiChatModelService aiChatModalService;
|
||||||
private final AiChatRoleService aiChatRoleService;
|
private final AiChatRoleService aiChatRoleService;
|
||||||
|
private final HttpMessageConverters messageConverters;
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public AiChatMessageRespVO chat(AiChatMessageSendReqVO req) {
|
public AiChatMessageRespVO chat(AiChatMessageSendReqVO req) {
|
||||||
@ -121,7 +130,75 @@ public class AiChatServiceImpl implements AiChatService {
|
|||||||
return insertChatMessageDO;
|
return insertChatMessageDO;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Flux<AiChatMessageRespVO> chatStream(AiChatMessageSendReqVO req) {
|
public Flux<AiChatMessageRespVO> chatStream(AiChatMessageSendStreamReqVO req) {
|
||||||
|
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
|
// 查询提问的 message
|
||||||
|
AiChatMessageDO aiChatMessageDO = aiChatMessageMapper.selectById(req.getId());
|
||||||
|
if (aiChatMessageDO == null) {
|
||||||
|
throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_CHAT_MESSAGE_NOT_EXIST);
|
||||||
|
}
|
||||||
|
// 查询对话
|
||||||
|
AiChatConversationRespVO conversation = chatConversationService.getConversationOfValidate(aiChatMessageDO.getConversationId());
|
||||||
|
// 获取对话模型
|
||||||
|
AiChatModelDO chatModel = aiChatModalService.validateChatModel(conversation.getModelId());
|
||||||
|
// 获取角色信息
|
||||||
|
AiChatRoleDO aiChatRoleDO = null;
|
||||||
|
if (conversation.getRoleId() != null) {
|
||||||
|
aiChatRoleDO = aiChatRoleService.validateExists(conversation.getRoleId());
|
||||||
|
}
|
||||||
|
// 校验角色是否公开
|
||||||
|
aiChatRoleService.validateIsPublic(aiChatRoleDO);
|
||||||
|
// 创建 chat 需要的 Prompt
|
||||||
|
Prompt prompt = new Prompt(aiChatMessageDO.getContent());
|
||||||
|
// 提前创建一个 system message
|
||||||
|
AiChatMessageDO systemMessage = insertChatMessage(conversation.getId(), MessageType.SYSTEM, loginUserId, conversation.getRoleId(),
|
||||||
|
chatModel.getModel(), chatModel.getId(), "",
|
||||||
|
0, conversation.getTemperature(), conversation.getMaxTokens(), conversation.getMaxContexts());
|
||||||
|
// req.setTopK(req.getTopK());
|
||||||
|
// req.setTopP(req.getTopP());
|
||||||
|
// req.setTemperature(req.getTemperature());
|
||||||
|
// 获取 client 类型
|
||||||
|
AiPlatformEnum platformEnum = AiPlatformEnum.validatePlatform(chatModel.getPlatform());
|
||||||
|
StreamingChatClient streamingChatClient = aiChatClientFactory.getStreamingChatClient(platformEnum);
|
||||||
|
Flux<ChatResponse> streamResponse = streamingChatClient.stream(prompt);
|
||||||
|
// 转换 flex AiChatMessageRespVO
|
||||||
|
StringBuffer contentBuffer = new StringBuffer();
|
||||||
|
AtomicInteger tokens = new AtomicInteger(0);
|
||||||
|
return streamResponse.map(res -> {
|
||||||
|
AiChatMessageRespVO aiChatMessageRespVO =
|
||||||
|
AiChatMessageConvert.INSTANCE.convertAiChatMessageRespVO(systemMessage);
|
||||||
|
aiChatMessageRespVO.setContent(res.getResult().getOutput().getContent());
|
||||||
|
contentBuffer.append(res.getResult().getOutput().getContent());
|
||||||
|
tokens.incrementAndGet();
|
||||||
|
return aiChatMessageRespVO;
|
||||||
|
}
|
||||||
|
).doOnComplete(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
log.info("发送完成!");
|
||||||
|
// 保存 chat message
|
||||||
|
aiChatMessageMapper.updateById(new AiChatMessageDO()
|
||||||
|
.setId(systemMessage.getId())
|
||||||
|
.setContent(contentBuffer.toString())
|
||||||
|
.setTokens(tokens.get())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}).doOnError(new Consumer<Throwable>() {
|
||||||
|
@Override
|
||||||
|
public void accept(Throwable throwable) {
|
||||||
|
log.error("发送错误 {}!", throwable.getMessage());
|
||||||
|
// 更新错误信息
|
||||||
|
aiChatMessageMapper.updateById(new AiChatMessageDO()
|
||||||
|
.setId(systemMessage.getId())
|
||||||
|
.setContent(throwable.getMessage())
|
||||||
|
.setTokens(tokens.get())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AiChatMessageRespVO add(AiChatMessageAddReqVO req) {
|
||||||
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||||
// 查询对话
|
// 查询对话
|
||||||
AiChatConversationRespVO conversation = chatConversationService.getConversationOfValidate(req.getConversationId());
|
AiChatConversationRespVO conversation = chatConversationService.getConversationOfValidate(req.getConversationId());
|
||||||
@ -134,48 +211,10 @@ public class AiChatServiceImpl implements AiChatService {
|
|||||||
}
|
}
|
||||||
// 校验角色是否公开
|
// 校验角色是否公开
|
||||||
aiChatRoleService.validateIsPublic(aiChatRoleDO);
|
aiChatRoleService.validateIsPublic(aiChatRoleDO);
|
||||||
// 创建 chat 需要的 Prompt
|
AiChatMessageDO userMessage = insertChatMessage(conversation.getId(), MessageType.USER, loginUserId, conversation.getRoleId(),
|
||||||
Prompt prompt = new Prompt(req.getContent());
|
|
||||||
// req.setTopK(req.getTopK());
|
|
||||||
// req.setTopP(req.getTopP());
|
|
||||||
// req.setTemperature(req.getTemperature());
|
|
||||||
// 保存 chat message
|
|
||||||
insertChatMessage(conversation.getId(), MessageType.USER, loginUserId, conversation.getRoleId(),
|
|
||||||
chatModel.getModel(), chatModel.getId(), req.getContent(),
|
chatModel.getModel(), chatModel.getId(), req.getContent(),
|
||||||
null, conversation.getTemperature(), conversation.getMaxTokens(), conversation.getMaxContexts());
|
null, conversation.getTemperature(), conversation.getMaxTokens(), conversation.getMaxContexts());
|
||||||
// 获取 client 类型
|
return AiChatMessageConvert.INSTANCE.convertAiChatMessageRespVO(userMessage);
|
||||||
AiPlatformEnum platformEnum = AiPlatformEnum.validatePlatform(chatModel.getPlatform());
|
|
||||||
StreamingChatClient streamingChatClient = aiChatClientFactory.getStreamingChatClient(platformEnum);
|
|
||||||
Flux<ChatResponse> streamResponse = streamingChatClient.stream(prompt);
|
|
||||||
// 转换 flex AiChatMessageRespVO
|
|
||||||
StringBuffer contentBuffer = new StringBuffer();
|
|
||||||
AtomicInteger tokens = new AtomicInteger(0);
|
|
||||||
return streamResponse.map(res -> {
|
|
||||||
AiChatMessageRespVO aiChatMessageRespVO = new AiChatMessageRespVO();
|
|
||||||
aiChatMessageRespVO.setContent(res.getResult().getOutput().getContent());
|
|
||||||
contentBuffer.append(res.getResult().getOutput().getContent());
|
|
||||||
tokens.incrementAndGet();
|
|
||||||
return aiChatMessageRespVO;
|
|
||||||
}
|
|
||||||
).doOnComplete(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
log.info("发送完成!");
|
|
||||||
// 保存 chat message
|
|
||||||
insertChatMessage(conversation.getId(), MessageType.SYSTEM, loginUserId, conversation.getRoleId(),
|
|
||||||
chatModel.getModel(), chatModel.getId(), contentBuffer.toString(),
|
|
||||||
tokens.get(), conversation.getTemperature(), conversation.getMaxTokens(), conversation.getMaxContexts());
|
|
||||||
}
|
|
||||||
}).doOnError(new Consumer<Throwable>() {
|
|
||||||
@Override
|
|
||||||
public void accept(Throwable throwable) {
|
|
||||||
log.error("发送错误 {}!", throwable.getMessage());
|
|
||||||
// 保存 chat message
|
|
||||||
insertChatMessage(conversation.getId(), MessageType.SYSTEM, loginUserId, conversation.getRoleId(),
|
|
||||||
chatModel.getModel(), chatModel.getId(), throwable.getMessage(),
|
|
||||||
tokens.get(), conversation.getTemperature(), conversation.getMaxTokens(), conversation.getMaxContexts());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -184,12 +223,25 @@ public class AiChatServiceImpl implements AiChatService {
|
|||||||
chatConversationService.validateExists(conversationId);
|
chatConversationService.validateExists(conversationId);
|
||||||
// 获取对话所有 message
|
// 获取对话所有 message
|
||||||
List<AiChatMessageDO> aiChatMessageDOList = aiChatMessageMapper.selectByConversationId(conversationId);
|
List<AiChatMessageDO> aiChatMessageDOList = aiChatMessageMapper.selectByConversationId(conversationId);
|
||||||
|
// 获取模型信息
|
||||||
|
Set<Long> modalIds = aiChatMessageDOList.stream().map(AiChatMessageDO::getModelId).collect(Collectors.toSet());
|
||||||
|
List<AiChatModelDO> modalList = aiChatModalService.getModalByIds(modalIds);
|
||||||
|
Map<Long, AiChatModelDO> modalIdMap = modalList.stream().collect(Collectors.toMap(AiChatModelDO::getId, o -> o));
|
||||||
// 转换 AiChatMessageRespVO
|
// 转换 AiChatMessageRespVO
|
||||||
return AiChatMessageConvert.INSTANCE.convertAiChatMessageRespVOList(aiChatMessageDOList);
|
List<AiChatMessageRespVO> aiChatMessageRespList = AiChatMessageConvert.INSTANCE.convertAiChatMessageRespVOList(aiChatMessageDOList);
|
||||||
|
// 设置用户头像 和 模型头像 todo @芋艿 这里需要转换 用户头像、模型头像
|
||||||
|
return aiChatMessageRespList.stream().map(item -> {
|
||||||
|
if (modalIdMap.containsKey(item.getModelId())) {
|
||||||
|
// modalIdMap.get(item.getModelId());
|
||||||
|
// item.setModelImage()
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean deleteMessage(Long id) {
|
public Boolean deleteMessage(Long id) {
|
||||||
return aiChatMessageMapper.deleteById(id) > 0;
|
return aiChatMessageMapper.deleteById(id) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,9 @@ import jakarta.validation.Valid;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AI 聊天模型 Service 接口
|
* AI 聊天模型 Service 接口
|
||||||
*
|
*
|
||||||
@ -70,4 +73,11 @@ public interface AiChatModelService {
|
|||||||
*/
|
*/
|
||||||
List<AiChatModelDO> getChatModelList(Integer status);
|
List<AiChatModelDO> getChatModelList(Integer status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 - 根据多个 ids 获取
|
||||||
|
*
|
||||||
|
* @param modalIds
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<AiChatModelDO> getModalByIds(Set<Long> modalIds);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,9 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.*;
|
import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.*;
|
||||||
|
|
||||||
@ -97,4 +100,9 @@ public class AiChatModelServiceImpl implements AiChatModelService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AiChatModelDO> getModalByIds(Set<Long> modalIds) {
|
||||||
|
return chatModelMapper.selectByIds(modalIds);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user