namespace HuanMeng.MiaoYu.Code.Chat; /// /// 聊天类 /// public class ChatBLL : MiaoYuBase { public ChatBLL(IServiceProvider serviceProvider) : base(serviceProvider) { //logger.i } /// /// 获取用户和角色的聊天记录 /// /// /// /// public async Task>> GetChatMessage(int characterId) { var charact = MiaoYuCache.CharacterList.FirstOrDefault(it => it.Id == characterId); if (charact == null) { throw new ArgumentException("角色不存在"); } var list = new List(); ChatMessageDto chatMessageDto2 = new ChatMessageDto() { ClaudeType = ChatMessageType.text.ToString(), Content = charact.Biography ?? "", Role = ChatRole.profile.ToString(), Timestamp = DateTime.Now, UserIcon = "", Id = 0 }; list.Add(chatMessageDto2); if (_UserId == 0) { var chat = new ChatMessageDto() { Id = 0, Role = ChatRole.assistant.ToString(), ClaudeType = "text", Content = charact.Prologue, Timestamp = DateTime.Now, UserIcon = charact.IconImage }; list.Add(chat); return new BaseResponse>(ResonseCode.Success, "", list); } var userChatSession = await Dao.daoDbMiaoYu.context.T_User_Chat.Where(it => it.CharacterId == characterId && it.UserId == _UserId && !it.IsDelete).FirstOrDefaultAsync(); if (userChatSession == null) { userChatSession = new T_User_Chat() { SessionId = Guid.NewGuid(), CharacterId = characterId, CreateAt = DateTime.Now, IsDelete = false, SessionName = "新会话", UpdateAt = DateTime.Now, ModelConfigId = charact.ModelConfigId, TenantId = charact.TenantId, UserId = _UserId, }; Dao.daoDbMiaoYu.context.T_User_Chat.Add(userChatSession); Dao.daoDbMiaoYu.context.SaveChanges(); } var chatList = await Dao.daoDbMiaoYu.context.T_Chat.Where(it => it.SessionId == userChatSession.SessionId && it.UserId == _UserId && it.Type == (int)ChatType.正常).OrderByDescending(it => it.SendMessageDay).ToListAsync(); if (chatList == null || chatList.Count == 0) { //添加第一句 var chat = new T_Chat() { Role = ChatRole.initialization.ToString(), CharacterId = characterId, ClaudeId = "", ClaudeType = "text", CreateTime = DateTime.Now, Content = charact.Prologue, Input_tokens = 0, Output_tokens = 0, SendDateDay = int.Parse(DateTime.Now.ToString("yyyyMMdd")), TimeStamp = DateTime.Now,//DateTimeExtensions.ToUnixTimestamp(),.ToUnixTimestamp() SendMessageDay = DateTime.Now.ToUnixTimestamp(), SessionId = userChatSession.SessionId, TenantId = userChatSession.TenantId, Type = 0, UpdateTime = DateTime.Now, UserId = userChatSession.UserId, ClaudeModel = "" }; Dao.daoDbMiaoYu.context.T_Chat.Add(chat); Dao.daoDbMiaoYu.context.SaveChanges(); chatList = new List(); chatList.Add(chat); } var message = Mapper.Map>(chatList); //设置头像 message.Where(it => it.Role == ChatRole.assistant.ToString() || it.Role == ChatRole.initialization.ToString() ).ToList() .ForEach(it => it.UserIcon = charact.IconImage); //用户头像 var userData = await Dao.daoDbMiaoYu.context.T_User_Data.FirstOrDefaultAsync(it => it.UserId == _UserId); var userIconUrl = userData?.UserIconUrl ?? ""; message.Where(it => it.Role == ChatRole.user.ToString()).ToList().ForEach(it => it.UserIcon = userIconUrl); //将第一句修改角色 var initia = message.FirstOrDefault(it => it.Role == ChatRole.initialization.ToString()); if (initia != null) { initia.Role = ChatRole.assistant.ToString(); } message.Insert(0, chatMessageDto2); return new BaseResponse>(ResonseCode.Success, "", message); } /// /// 发送消息接口 /// /// 角色Id /// 消息内容 /// /// public async Task> Message(int characterId, string message) { ChatMessageDataDto chatListDto = new ChatMessageDataDto(); List chatMessageDtos = new List(); if (TextCensor.TextCensor(message)) { var chatMessage = new ChatMessageDto() { Id = 0, Role = ChatRole.tips.ToString(), ClaudeType = "text", Content = "输入内容违规", Timestamp = DateTime.Now, UserIcon = "" }; chatMessageDtos.Add(chatMessage); chatListDto.ChatList = chatMessageDtos; return new BaseResponse(ResonseCode.Success, "", chatListDto); } var charact = MiaoYuCache.CharacterList.FirstOrDefault(it => it.Id == characterId); if (charact == null) { throw new ArgumentException("角色不存在"); } if (_UserId == 0) { var chatMessage = new ChatMessageDto() { Id = 0, Role = ChatRole.assistant.ToString(), ClaudeType = "text", Content = charact.Prologue, Timestamp = DateTime.Now, UserIcon = charact.IconImage }; chatMessageDtos.Add(chatMessage); chatListDto.ChatList = chatMessageDtos; return new BaseResponse(ResonseCode.Success, "", chatListDto); } //if(timeStamp.) UserInfoBLL userInfoBLL = new UserInfoBLL(Dao, _UserId); if (!userInfoBLL.IsCheckingSufficient(UserCurrencyType.聊天次数)) { throw new Exception("聊天次数不足"); } //userInfoBLL.User.GetUserCurrency(Model.EnumModel.User.UserCurrencyType.聊天次数); var userChatSession = await Dao.daoDbMiaoYu.context.T_User_Chat.Where(it => it.CharacterId == characterId && it.UserId == _UserId && !it.IsDelete).FirstOrDefaultAsync(); if (userChatSession == null) { userChatSession = new T_User_Chat() { SessionId = Guid.NewGuid(), CharacterId = characterId, CreateAt = DateTime.Now, IsDelete = false, SessionName = $"{charact.Name}-{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}", UpdateAt = DateTime.Now, ModelConfigId = charact.ModelConfigId, TenantId = charact.TenantId, UserId = _UserId, TotalToken = 0, }; Dao.daoDbMiaoYu.context.T_User_Chat.Add(userChatSession); Dao.daoDbMiaoYu.context.SaveChanges(); } List mess = new List(); int maxToken = 7000; // var _memoryCardType = userInfoBLL[Model.EnumModel.UserMemoryCardType.记忆卡, charact.Id]; (maxToken, var isMemoryCard) = userInfoBLL.GetMemoryCardMaxToken(charact.Id); //await AddMessage(userChatSession, mess); //递归获取聊天记录 var _token = await AddMessage(userChatSession.SessionId, _UserId, 1, 0, maxToken, mess); //将聊天数据反转 // mess.Reverse(); mess = mess.OrderBy(it => it.MessageDay).ToList(); mess.Add(new ClaudeChatMessage { Role = ChatRole.user.ToString(), Content = message, }); #region 添加数据库 T_Chat t_Chat1 = new T_Chat { CharacterId = charact.Id, ClaudeModel = "", ClaudeId = "", ClaudeType = "text", Content = message, CreateTime = DateTime.Now, Input_tokens = 0, Output_tokens = 0, Role = ChatRole.user.ToString(), SendDateDay = int.Parse(DateTime.Now.ToString("yyyyMMdd")), SendMessageDay = DateTime.Now.ToUnixTimestamp(), SessionId = userChatSession.SessionId, TenantId = userChatSession.TenantId, TimeStamp = DateTime.Now, Type = 0, UpdateTime = DateTime.Now, UserId = _UserId, }; #endregion var claudeChatResponse = await Chat(charact, mess); var t_Chat = new T_Chat { CharacterId = charact.Id, ClaudeModel = claudeChatResponse.Model, ClaudeId = claudeChatResponse.Id, ClaudeType = "text", Content = claudeChatResponse.Message, CreateTime = DateTime.Now, Input_tokens = claudeChatResponse.InputTokens, Output_tokens = claudeChatResponse.OutputTokens, Role = ChatRole.assistant.ToString(), SendDateDay = int.Parse(DateTime.Now.ToString("yyyyMMdd")), SendMessageDay = DateTime.Now.ToUnixTimestamp(), SessionId = userChatSession.SessionId, TenantId = userChatSession.TenantId, TimeStamp = DateTime.Now, Type = 0, UpdateTime = DateTime.Now, UserId = _UserId, Tokens = claudeChatResponse.OutputTokens }; #region 开启事务 using (IDbContextTransaction transaction = Dao.daoDbMiaoYu.context.Database.BeginTransaction()) { try { if (charact.Token == null || charact.Token == 0) { charact.Token = (int)(claudeChatResponse.InputTokens - (message.Length * 2)); if (charact.Token <= 0) { charact.Token = claudeChatResponse.Message.Length * 2; } var t_Character = await Dao.daoDbMiaoYu.context.T_Character.FirstOrDefaultAsync(it => it.Id == charact.Id); if (t_Character != null) { t_Character.Token = charact.Token; } } t_Chat1.Tokens = claudeChatResponse.InputTokens - charact.Token; t_Chat1.Input_tokens = claudeChatResponse.InputTokens; //设置消耗的总token userChatSession.TotalToken += claudeChatResponse.InputTokens + claudeChatResponse.OutputTokens; Dao.daoDbMiaoYu.context.Add(t_Chat1); Dao.daoDbMiaoYu.context.Add(t_Chat); //最后一次聊天时间 userChatSession.UpdateAt = DateTime.Now; //最后一次聊天记录 userChatSession.LastMessage = t_Chat.Content; if (userChatSession.LastMessage.Length > 10) { userChatSession.LastMessage = userChatSession.LastMessage.Substring(0, 10) + "..."; } await Dao.daoDbMiaoYu.context.SaveChangesAsync(); //扣除货币 userInfoBLL[UserCurrencyType.聊天次数].ConsumeMoneyNoWork(-1, Dao); if (isMemoryCard) { //扣除记忆卡 userInfoBLL[Model.EnumModel.UserMemoryCardType.记忆卡, charact.Id].ConsumeMemoryCard(-1, Dao); } transaction.Commit(); } catch (Exception) { transaction.Rollback(); throw; } } #endregion //claudeChatResponse. ChatMessageDto chatMessageDto = new ChatMessageDto() { ClaudeType = ChatMessageType.text.ToString(), Content = claudeChatResponse.Message, Role = ChatRole.assistant.ToString(), Timestamp = DateTime.Now, UserIcon = charact.IconImage, Id = t_Chat.Id }; chatMessageDtos.Add(chatMessageDto); #region 添加返回次数 var cishu = userInfoBLL[UserCurrencyType.聊天次数].CurrencyMoney; if (cishu <= 3) { ChatMessageDto chatMessageDto1 = new ChatMessageDto() { ClaudeType = ChatMessageType.text.ToString(), Content = $"您还剩余{cishu:F0}次聊天次数", Role = ChatRole.tips.ToString(), Timestamp = DateTime.Now, Id = 0 }; chatMessageDtos.Add(chatMessageDto1); } #endregion chatListDto.ChatList = chatMessageDtos; chatListDto.LastMessageId = t_Chat1.Id; chatListDto.RemainingChatCount = (int)cishu; return new BaseResponse(ResonseCode.Success, "", chatListDto); } public async Task Chat(CharacterCache? charact, List mess) { if (charact.ModelConfig.ModelName.Contains("minimaxi")) { var chat = new MinimaxChat(HttpClientFactory); MinimaxChatParams minimaxChatParams = new MinimaxChatParams(mess, charact, charact.Name); return await chat.MessagesAsync(minimaxChatParams); } else { return await ClaudeChat(charact, mess); } } /// /// /// /// /// /// /// private async Task ClaudeChat(CharacterCache? charact, List mess) { #region 调用api ClaudeChatChatParams baseChatParams = new ClaudeChatChatParams(); baseChatParams.Messages = mess.ToArray(); baseChatParams.System = charact.System; baseChatParams.MaxTokens = charact.ModelConfig.MaxTokens; var claude = charact.ModelConfig.GetClaudeChatConfig(); IChat chat = new ClaudeChat(claude, HttpClientFactory); var response = await chat.MessagesAsync(baseChatParams); if (response == null) { throw new Exception("ai出现错误"); } var claudeChatResponse = response as ClaudeChatResponse; if (claudeChatResponse == null) { throw new Exception("ai返回出现错误"); } #endregion claudeChatResponse.TotalTokens = claudeChatResponse.Usage.OutputTokens + claudeChatResponse.Usage.InputTokens; claudeChatResponse.InputTokens = claudeChatResponse.Usage.InputTokens; claudeChatResponse.OutputTokens = claudeChatResponse.Usage.OutputTokens; claudeChatResponse.Message = claudeChatResponse.Content[0].Text; return claudeChatResponse; } /// /// 通过递归判断聊天是否满足 /// /// /// /// /// /// /// /// private async Task AddMessage(Guid sessionId, int userId, int index, int tokens, int maxTokens, List mess) { int size = 50; var role = new List(); role.Add(ChatRole.assistant.ToString()); role.Add(ChatRole.user.ToString()); var chatList = await Dao.daoDbMiaoYu.context.T_Chat.AsNoTracking().Where(it => it.SessionId == sessionId && it.UserId == userId && role.Contains(it.Role)).OrderByDescending(it => it.SendMessageDay).Skip((index - 1) * size).Take(size) .Select(it => new { it.Role, it.Content, it.Tokens, it.SendMessageDay }).ToListAsync(); if (chatList != null || chatList.Count == 0) { for (int i = 0; i < chatList.Count; i++) { var chat = chatList[i]; if ((tokens + chat.Tokens) > maxTokens) { return tokens; } mess.Add(new ClaudeChatMessage { Role = chat.Role, Content = chat.Content, MessageDay = chat.SendMessageDay }); tokens += chat.Tokens ?? 0; } //数据不够 if (chatList.Count < size) { return tokens; } if (tokens < maxTokens) { index++; await AddMessage(sessionId, userId, index, tokens, maxTokens, mess); } } return tokens; } /// /// 删除聊天记录 /// /// 聊天id /// /// public async Task DelChatByIds(List id, int characterId) { var chatsToDelete = await Dao.daoDbMiaoYu.context.T_Chat.Where(t => id.Contains(t.Id)).ToListAsync(); if (chatsToDelete.Count <= 0) { throw new Exception("删除失败"); } var chatList = chatsToDelete.Where(t => t.UserId == _UserId && t.CharacterId == characterId && (t.Type == (int)ChatType.正常 || t.Type == (int)ChatType.重新生成)).ToList(); if (chatList.Count > 0) { chatList.ForEach(t => t.Type = 2); } Dao.daoDbMiaoYu.context.SaveChanges(); return true; } /// /// 清空聊天记录 /// /// /// public async Task DelChat(int characterId) { var tempList = await Dao.daoDbMiaoYu.context.T_User_Chat.Where(t => t.UserId == _UserId && t.CharacterId == characterId && t.IsDelete == false).FirstOrDefaultAsync(); if (tempList != null) { tempList.IsDelete = true; } Dao.daoDbMiaoYu.context.SaveChanges(); return true; } /// /// 获取消息聊天记录列表 /// /// //public async Task>> GetChatHistoryList() //{ // var userChatSessions = await Dao.daoDbMiaoYu.context.T_User_Chat.Where(it => it.UserId == _UserId && !it.IsDelete).ToListAsync(); // List chatHistoryInfos = new List(); // var charactersIds = MiaoYuCache.CharacterList.ToList(); // userChatSessions.ForEach(it => // { // var model = charactersIds.FirstOrDefault(item => item.Id == it.CharacterId); // if (model != null) // { // var info = Mapper.Map(model); // info.LastContactTime = it.UpdateAt; // chatHistoryInfos.Add(info); // } // }); // chatHistoryInfos = chatHistoryInfos.OrderByDescending(it => it.LastContactTime).ToList(); // return new BaseResponse>(ResonseCode.Success, "", chatHistoryInfos) { }; //} /// /// 获取消息聊天记录列表 /// /// public async Task>> GetChatHistoryList() { var userChatSessions = await Dao.daoDbMiaoYu.context.T_User_Chat.Where(it => it.UserId == _UserId && !it.IsDelete).ToListAsync(); List chatHistoryInfos = new List(); var charactersIds = MiaoYuCache.CharacterList.ToList(); userChatSessions.ForEach(it => { var model = charactersIds.FirstOrDefault(item => item.Id == it.CharacterId); if (model != null) { var info = Mapper.Map(model); //获取最新的聊天记录 //var c = Dao.daoDbMiaoYu.context.T_Chat.Where(it => it.SessionId == it.SessionId).OrderByDescending(it => it.SendMessageDay).FirstOrDefault(); info.LastContactTime = it.UpdateAt; info.LastMessage = it.LastMessage; if (string.IsNullOrEmpty(info.LastMessage)) { info.LastMessage = model.Prologue; if (info.LastMessage.IndexOf("*") > -1) { // 定义正则表达式模式来匹配*号之间的文本 string pattern = @"\*.*?\*"; // 使用正则表达式替换*号之间的文本为空 info.LastMessage = Regex.Replace(info.LastMessage, pattern, ""); } } //if (c != null) //{ // info.LastMessage = c.Content; //} chatHistoryInfos.Add(info); } }); chatHistoryInfos = chatHistoryInfos.OrderByDescending(it => it.LastContactTime).ToList(); return new BaseResponse>(ResonseCode.Success, "", chatHistoryInfos) { }; } }