【新增】AI:聊天对话的更新模型
This commit is contained in:
parent
78bb2d1dc8
commit
d0c7b2333a
|
@ -1,5 +1,6 @@
|
|||
package cn.iocoder.yudao.module.ai.controller.admin.chat;
|
||||
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO;
|
||||
|
@ -49,20 +50,23 @@ public class AiChatConversationController {
|
|||
return success(BeanUtils.toBean(list, AiChatConversationRespVO.class));
|
||||
}
|
||||
|
||||
// TODO @fan:实现一下
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得聊天会话")
|
||||
@GetMapping("/get-my")
|
||||
@Operation(summary = "获得【我的】聊天会话")
|
||||
@Parameter(name = "id", required = true, description = "会话编号", example = "1024")
|
||||
public CommonResult<AiChatConversationRespVO> getConversation(@RequestParam("id") Long id) {
|
||||
return success(chatConversationService.getConversationOfValidate(id));
|
||||
public CommonResult<AiChatConversationRespVO> getChatConversationMy(@RequestParam("id") Long id) {
|
||||
AiChatConversationDO conversation = chatConversationService.getChatConversation(id);
|
||||
if (conversation != null && ObjUtil.notEqual(conversation.getUserId(), getLoginUserId())) {
|
||||
conversation = null;
|
||||
}
|
||||
return success(BeanUtils.toBean(conversation, AiChatConversationRespVO.class));
|
||||
}
|
||||
|
||||
// TODO @fan:实现一下
|
||||
@DeleteMapping("/delete")
|
||||
@DeleteMapping("/delete-my")
|
||||
@Operation(summary = "删除聊天会话")
|
||||
@Parameter(name = "id", required = true, description = "会话编号", example = "1024")
|
||||
public CommonResult<Boolean> deleteConversation(@RequestParam("id") Long id) {
|
||||
return success(chatConversationService.deleteConversation(id));
|
||||
public CommonResult<Boolean> deleteChatConversationMy(@RequestParam("id") Long id) {
|
||||
chatConversationService.deleteChatConversationMy(id, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
// ========== 会话管理 ==========
|
||||
|
|
|
@ -32,13 +32,14 @@ public class AiChatConversationRespVO implements VO {
|
|||
private Long roleId;
|
||||
|
||||
@Schema(description = "模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@Trans(type = TransType.SIMPLE, target = AiChatModelDO.class, fields = {"maxTokens", "maxContexts"},
|
||||
refs = {"modelMaxTokens", "modelMaxContexts"})
|
||||
private Long modelId;
|
||||
|
||||
@Schema(description = "模型标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "ERNIE-Bot-turbo-0922")
|
||||
private String model;
|
||||
|
||||
@Schema(description = "角色设定", example = "一个快乐的程序员")
|
||||
private String systemMessage;
|
||||
|
||||
@Schema(description = "温度参数", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.8")
|
||||
private Double temperature;
|
||||
|
||||
|
@ -53,12 +54,4 @@ public class AiChatConversationRespVO implements VO {
|
|||
@Schema(description = "角色头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
|
||||
private String roleAvatar;
|
||||
|
||||
// ========== 关联 model 信息 ==========
|
||||
|
||||
@Schema(description = "模型的单条回复的最大 Token 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096")
|
||||
private Integer modelMaxTokens;
|
||||
|
||||
@Schema(description = "模型的上下文的最大 Message 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer modelMaxContexts;
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,9 @@ public class AiChatConversationUpdateMyReqVO {
|
|||
@Schema(description = "模型编号", example = "1")
|
||||
private Long modelId;
|
||||
|
||||
@Schema(description = "角色设定", example = "一个快乐的程序员")
|
||||
private String systemMessage;
|
||||
|
||||
@Schema(description = "温度参数", example = "0.8")
|
||||
private Double temperature;
|
||||
|
||||
|
|
|
@ -42,10 +42,7 @@ public class AiChatRoleRespVO implements VO {
|
|||
@Schema(description = "角色描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "角色欢迎语", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String welcomeMessage;
|
||||
|
||||
@Schema(description = "角色上下文", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@Schema(description = "角色设定", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String systemMessage;
|
||||
|
||||
@Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
|
|
|
@ -25,12 +25,8 @@ public class AiChatRoleSaveMyReqVO {
|
|||
@NotEmpty(message = "角色描述不能为空")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "角色欢迎语", requiredMode = Schema.RequiredMode.REQUIRED, example = "Talk is cheap, i will show code")
|
||||
@NotEmpty(message = "角色欢迎语不能为空")
|
||||
private String welcomeMessage;
|
||||
|
||||
@Schema(description = "角色上下文", requiredMode = Schema.RequiredMode.REQUIRED, example = "现在开始你扮演一位程序员,你是一名优秀的程序员,具有很强的逻辑思维能力,总能高效的解决问题")
|
||||
@NotEmpty(message = "角色上下文不能为空")
|
||||
@Schema(description = "角色设定", requiredMode = Schema.RequiredMode.REQUIRED, example = "现在开始你扮演一位程序员,你是一名优秀的程序员,具有很强的逻辑思维能力,总能高效的解决问题")
|
||||
@NotEmpty(message = "角色设定不能为空")
|
||||
private String systemMessage;
|
||||
|
||||
}
|
|
@ -38,12 +38,8 @@ public class AiChatRoleSaveReqVO {
|
|||
@NotEmpty(message = "角色描述不能为空")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "角色欢迎语", requiredMode = Schema.RequiredMode.REQUIRED, example = "Talk is cheap, i will show code")
|
||||
@NotEmpty(message = "角色欢迎语不能为空")
|
||||
private String welcomeMessage;
|
||||
|
||||
@Schema(description = "角色上下文", requiredMode = Schema.RequiredMode.REQUIRED, example = "现在开始你扮演一位程序员,你是一名优秀的程序员,具有很强的逻辑思维能力,总能高效的解决问题")
|
||||
@NotEmpty(message = "角色上下文不能为空")
|
||||
@Schema(description = "角色设定", requiredMode = Schema.RequiredMode.REQUIRED, example = "现在开始你扮演一位程序员,你是一名优秀的程序员,具有很强的逻辑思维能力,总能高效的解决问题")
|
||||
@NotEmpty(message = "角色设定不能为空")
|
||||
private String systemMessage;
|
||||
|
||||
@Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
package cn.iocoder.yudao.module.ai.convert;
|
||||
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 聊天 对话 convert
|
||||
*
|
||||
* @author fansili
|
||||
* @time 2024/4/18 16:39
|
||||
* @since 1.0
|
||||
*/
|
||||
@Mapper
|
||||
public interface AiChatConversationConvert {
|
||||
|
||||
AiChatConversationConvert INSTANCE = Mappers.getMapper(AiChatConversationConvert.class);
|
||||
|
||||
/**
|
||||
* 转换 - 多个 ChatConversationRes
|
||||
*
|
||||
* @param top100Conversation
|
||||
* @return
|
||||
*/
|
||||
List<AiChatConversationRespVO> covnertChatConversationResList(List<AiChatConversationDO> top100Conversation);
|
||||
|
||||
/**
|
||||
* 转换 - 单个 ChatConversationRes
|
||||
*
|
||||
* @param aiChatConversationDO
|
||||
* @return
|
||||
*/
|
||||
AiChatConversationRespVO covnertChatConversationRes(AiChatConversationDO aiChatConversationDO);
|
||||
|
||||
}
|
|
@ -81,6 +81,10 @@ public class AiChatConversationDO extends BaseDO {
|
|||
|
||||
// ========== 会话配置 ==========
|
||||
|
||||
/**
|
||||
* 角色设定
|
||||
*/
|
||||
private String systemMessage;
|
||||
/**
|
||||
* 温度参数
|
||||
*
|
||||
|
|
|
@ -42,11 +42,7 @@ public class AiChatRoleDO extends BaseDO {
|
|||
*/
|
||||
private String description;
|
||||
/**
|
||||
* 角色欢迎语
|
||||
*/
|
||||
private String welcomeMessage;
|
||||
/**
|
||||
* 角色上下文
|
||||
* 角色设定
|
||||
*/
|
||||
private String systemMessage;
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package cn.iocoder.yudao.module.ai.service.chat;
|
||||
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
|
||||
|
||||
|
@ -40,19 +39,20 @@ public interface AiChatConversationService {
|
|||
List<AiChatConversationDO> getChatConversationListByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 获取 - 对话
|
||||
* 获得聊天会话
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
* @param id 编号
|
||||
* @return 聊天会话
|
||||
*/
|
||||
AiChatConversationRespVO getConversationOfValidate(Long id);
|
||||
AiChatConversationDO getChatConversation(Long id);
|
||||
|
||||
/**
|
||||
* 删除 - 根据id
|
||||
* 删除【我的】聊天会话
|
||||
*
|
||||
* @param id
|
||||
* @param id 编号
|
||||
* @param userId 用户编号
|
||||
*/
|
||||
Boolean deleteConversation(Long id);
|
||||
void deleteChatConversationMy(Long id, Long userId);
|
||||
|
||||
/**
|
||||
* 校验 - 是否存在
|
||||
|
@ -61,4 +61,5 @@ public interface AiChatConversationService {
|
|||
* @return
|
||||
*/
|
||||
AiChatConversationDO validateExists(Long id);
|
||||
|
||||
}
|
||||
|
|
|
@ -4,11 +4,9 @@ import cn.hutool.core.lang.Assert;
|
|||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO;
|
||||
import cn.iocoder.yudao.module.ai.convert.AiChatConversationConvert;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO;
|
||||
|
@ -59,7 +57,7 @@ public class AiChatConversationServiceImpl implements AiChatConversationService
|
|||
// 2. 创建 AiChatConversationDO 聊天对话
|
||||
AiChatConversationDO conversation = new AiChatConversationDO()
|
||||
.setUserId(userId).setTitle(AiChatConversationDO.TITLE_DEFAULT).setPinned(false)
|
||||
.setRoleId(role.getId()).setModelId(model.getId()).setModel(model.getModel())
|
||||
.setRoleId(role.getId()).setModelId(model.getId()).setModel(model.getModel()).setSystemMessage(role.getSystemMessage())
|
||||
.setTemperature(model.getTemperature()).setMaxTokens(model.getMaxTokens()).setMaxContexts(model.getMaxContexts());
|
||||
chatConversationMapper.insert(conversation);
|
||||
return conversation.getId();
|
||||
|
@ -73,24 +71,19 @@ public class AiChatConversationServiceImpl implements AiChatConversationService
|
|||
throw exception(CHAT_CONVERSATION_NOT_EXISTS);
|
||||
}
|
||||
// 1.2 校验模型是否存在(修改模型的情况)
|
||||
if (!ObjectUtil.isAllEmpty(updateReqVO.getModelId(), updateReqVO.getMaxTokens(), updateReqVO.getMaxContexts())) {
|
||||
AiChatModelDO model = chatModalService.validateChatModel(updateReqVO.getModelId());
|
||||
Assert.notNull(model, "必须找到默认模型");
|
||||
validateChatModel(model);
|
||||
// 校验 Token 数量、上下文数量
|
||||
if (updateReqVO.getMaxTokens() != null && updateReqVO.getMaxTokens() > model.getMaxTokens()) {
|
||||
throw exception(CHAT_CONVERSATION_UPDATE_MAX_TOKENS_ERROR);
|
||||
}
|
||||
if (updateReqVO.getMaxContexts() != null && updateReqVO.getMaxContexts() > model.getMaxContexts()) {
|
||||
throw exception(CHAT_CONVERSATION_UPDATE_MAX_CONTEXTS_ERROR);
|
||||
}
|
||||
AiChatModelDO model = null;
|
||||
if (updateReqVO.getModelId() != null) {
|
||||
model = chatModalService.validateChatModel(updateReqVO.getModelId());
|
||||
}
|
||||
|
||||
// 更新对话信息
|
||||
// 2. 更新对话信息
|
||||
AiChatConversationDO updateObj = BeanUtils.toBean(updateReqVO, AiChatConversationDO.class);
|
||||
if (Boolean.TRUE.equals(updateReqVO.getPinned())) {
|
||||
updateObj.setPinnedTime(LocalDateTime.now());
|
||||
}
|
||||
if (model != null) {
|
||||
updateObj.setModel(model.getModel());
|
||||
}
|
||||
chatConversationMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
|
@ -99,6 +92,23 @@ public class AiChatConversationServiceImpl implements AiChatConversationService
|
|||
return chatConversationMapper.selectListByUserId(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiChatConversationDO getChatConversation(Long id) {
|
||||
return chatConversationMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteChatConversationMy(Long id, Long userId) {
|
||||
// 1. 校验对话是否存在
|
||||
AiChatConversationDO conversation = validateExists(id);
|
||||
if (ObjUtil.notEqual(conversation.getUserId(), userId)) {
|
||||
throw exception(CHAT_CONVERSATION_NOT_EXISTS);
|
||||
}
|
||||
|
||||
// 2. 执行删除
|
||||
chatConversationMapper.deleteById(id);
|
||||
}
|
||||
|
||||
private void validateChatModel(AiChatModelDO model) {
|
||||
if (ObjectUtil.isAllNotEmpty(model.getTemperature(), model.getMaxTokens(), model.getMaxContexts())) {
|
||||
return;
|
||||
|
@ -106,17 +116,6 @@ public class AiChatConversationServiceImpl implements AiChatConversationService
|
|||
throw exception(CHAT_CONVERSATION_MODEL_ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiChatConversationRespVO getConversationOfValidate(Long id) {
|
||||
AiChatConversationDO aiChatConversationDO = validateExists(id);
|
||||
return AiChatConversationConvert.INSTANCE.covnertChatConversationRes(aiChatConversationDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteConversation(Long id) {
|
||||
return chatConversationMapper.deleteById(id) > 0;
|
||||
}
|
||||
|
||||
public AiChatConversationDO validateExists(Long id) {
|
||||
AiChatConversationDO conversation = chatConversationMapper.selectById(id);
|
||||
if (conversation == null) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.ai.service.impl;
|
|||
|
||||
import cn.hutool.core.exceptions.ExceptionUtil;
|
||||
import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
|
||||
import org.springframework.ai.chat.ChatClient;
|
||||
import org.springframework.ai.chat.ChatResponse;
|
||||
import org.springframework.ai.chat.StreamingChatClient;
|
||||
|
@ -54,7 +55,6 @@ public class AiChatServiceImpl implements AiChatService {
|
|||
private final AiChatClientFactory aiChatClientFactory;
|
||||
|
||||
private final AiChatMessageMapper aiChatMessageMapper;
|
||||
private final AiChatConversationMapper aiChatConversationMapper;
|
||||
private final AiChatConversationService chatConversationService;
|
||||
private final AiChatModelService aiChatModalService;
|
||||
private final AiChatRoleService chatRoleService;
|
||||
|
@ -63,7 +63,7 @@ public class AiChatServiceImpl implements AiChatService {
|
|||
public AiChatMessageRespVO chat(AiChatMessageSendReqVO req) {
|
||||
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||
// 查询对话
|
||||
AiChatConversationRespVO conversation = chatConversationService.getConversationOfValidate(req.getConversationId());
|
||||
AiChatConversationDO conversation = chatConversationService.validateExists(req.getConversationId());
|
||||
// 获取对话模型
|
||||
AiChatModelDO chatModel = aiChatModalService.validateChatModel(conversation.getModelId());
|
||||
// 获取角色信息
|
||||
|
@ -130,7 +130,7 @@ public class AiChatServiceImpl implements AiChatService {
|
|||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.AI_CHAT_MESSAGE_NOT_EXIST);
|
||||
}
|
||||
// 查询对话
|
||||
AiChatConversationRespVO conversation = chatConversationService.getConversationOfValidate(aiChatMessageDO.getConversationId());
|
||||
AiChatConversationDO conversation = chatConversationService.validateExists(aiChatMessageDO.getConversationId());
|
||||
// 获取对话模型
|
||||
AiChatModelDO chatModel = aiChatModalService.validateChatModel(conversation.getModelId());
|
||||
// 获取角色信息
|
||||
|
@ -188,7 +188,7 @@ public class AiChatServiceImpl implements AiChatService {
|
|||
public AiChatMessageRespVO add(AiChatMessageAddReqVO req) {
|
||||
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
|
||||
// 查询对话
|
||||
AiChatConversationRespVO conversation = chatConversationService.getConversationOfValidate(req.getConversationId());
|
||||
AiChatConversationDO conversation = chatConversationService.validateExists(req.getConversationId());
|
||||
// 获取对话模型
|
||||
AiChatModelDO chatModel = aiChatModalService.validateChatModel(conversation.getModelId());
|
||||
AiChatMessageDO userMessage = insertChatMessage(conversation.getId(), MessageType.USER, loginUserId, conversation.getRoleId(),
|
||||
|
|
|
@ -14,7 +14,6 @@ Authorization: {{token}}
|
|||
"avatar": "http://baidu.com",
|
||||
"category": "writing",
|
||||
"description": "采用gpt3.5模型,拥有小红书优质作者写作经验。",
|
||||
"welcomeMessage": "欢迎使用小红书写作模型!",
|
||||
"systemMessage": "你是一名优秀的小红书人文、风光作者,你热爱旅游,每去往一个城市你都会用美妙的文字抒写着这座城市的大街小巷,描述着这座城市的美好。",
|
||||
"publicStatus": 0,
|
||||
"sort": 0
|
||||
|
@ -33,7 +32,6 @@ Authorization: {{token}}
|
|||
"avatar": "http://baidu.com",
|
||||
"category": "writing",
|
||||
"description": "采用gpt3.5模型,拥有小红书优质作者写作经验。",
|
||||
"welcomeMessage": "欢迎使用小红书写作模型!",
|
||||
"systemMessage": "你是一名优秀的小红书人文、风光作者,你热爱旅游,每去往一个城市你都会用美妙的文字抒写着这座城市的大街小巷,描述着这座城市的美好。",
|
||||
"publicStatus": 0,
|
||||
"sort": 0,
|
||||
|
|
Loading…
Reference in New Issue