diff --git a/src/0-core/HuanMeng.MiaoYu.Code/Base/MiaoYuBase.cs b/src/0-core/HuanMeng.MiaoYu.Code/Base/MiaoYuBase.cs index ad3b19b..acd94fd 100644 --- a/src/0-core/HuanMeng.MiaoYu.Code/Base/MiaoYuBase.cs +++ b/src/0-core/HuanMeng.MiaoYu.Code/Base/MiaoYuBase.cs @@ -92,7 +92,24 @@ namespace HuanMeng.MiaoYu.Code.Base } } #endregion + #region http请求 + private IHttpClientFactory? _httpClientFactory; + /// + /// http请求 + /// + public IHttpClientFactory HttpClientFactory + { + get + { + if (_httpClientFactory == null) + { + _httpClientFactory = _serviceProvider.GetRequiredService(); + } + return _httpClientFactory; + } + } + #endregion #region 映射 private IMapper _mapper; diff --git a/src/0-core/HuanMeng.MiaoYu.Code/Chat/ChatBLL.cs b/src/0-core/HuanMeng.MiaoYu.Code/Chat/ChatBLL.cs index 58432f2..45ec3c1 100644 --- a/src/0-core/HuanMeng.MiaoYu.Code/Chat/ChatBLL.cs +++ b/src/0-core/HuanMeng.MiaoYu.Code/Chat/ChatBLL.cs @@ -1,5 +1,8 @@ using HuanMeng.DotNetCore.Base; using HuanMeng.MiaoYu.Code.Cache; +using HuanMeng.MiaoYu.Code.Chat.Claude; +using HuanMeng.MiaoYu.Code.Chat.Claude.Model; +using HuanMeng.MiaoYu.Code.Chat.Contract; using HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu; using HuanMeng.MiaoYu.Model.Dto.Chat; using HuanMeng.MiaoYu.Model.EnumModel.Chat; @@ -46,7 +49,7 @@ namespace HuanMeng.MiaoYu.Code.Chat var chat = new ChatMessageDto() { - Id=0, + Id = 0, Role = ChatRole.assistant.ToString(), ClaudeType = "text", Content = charact.Prologue, @@ -87,7 +90,7 @@ namespace HuanMeng.MiaoYu.Code.Chat ClaudeId = "", ClaudeType = "text", CreateTime = DateTime.Now, - Content = "", + Content = charact.Prologue, Input_tokens = 0, Output_tokens = 0, SendDateDay = int.Parse(DateTime.Now.ToString("yyyyMMdd")), @@ -126,6 +129,150 @@ namespace HuanMeng.MiaoYu.Code.Chat return new BaseResponse>(ResonseCode.Success, "", message); } + + /// + /// 发送消息接口 + /// + /// 角色Id + /// 消息内容 + /// + /// + public async Task>> Message(int characterId, string message) + { + + List chatMessageDtos = new List(); + 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); + return new BaseResponse>(ResonseCode.Success, "", chatMessageDtos); + } + //if(timeStamp.) + 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 notRole = new List(); + notRole.Add(ChatRole.initialization.ToString()); + notRole.Add(ChatRole.tips.ToString()); + var chatList = await Dao.daoDbMiaoYu.context.T_Chat.Where(it => it.SessionId == userChatSession.SessionId && it.UserId == _UserId && it.Type == (int)ChatType.正常 && !notRole.Contains(it.Role)).OrderBy(it => it.SendMessageDay).ToListAsync(); + if (chatList == null) + { + chatList = new List(); + } + List mess = new List(); + for (int i = 0; i < chatList.Count; i++) + { + mess.Add(new ClaudeChatMessage + { + Role = chatList[i].Role, + Content = chatList[i].Content, + }); + } + 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 + #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); + var claudeChatResponse = response as ClaudeChatResponse; + #endregion + + + T_Chat t_Chat = new T_Chat + { + CharacterId = charact.Id, + ClaudeModel = claudeChatResponse.Model, + ClaudeId = claudeChatResponse.Id, + ClaudeType = claudeChatResponse.Content[0]?.Type, + Content = claudeChatResponse.Content[0]?.Text, + CreateTime = DateTime.Now, + Input_tokens = claudeChatResponse.Usage.InputTokens, + Output_tokens = claudeChatResponse.Usage.OutputTokens, + Role = claudeChatResponse.Role, + 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, + }; + Dao.daoDbMiaoYu.context.Add(t_Chat1); + Dao.daoDbMiaoYu.context.Add(t_Chat); + await Dao.daoDbMiaoYu.context.SaveChangesAsync(); + //claudeChatResponse. + ChatMessageDto chatMessageDto = new ChatMessageDto() + { + ClaudeType = ChatMessageType.text.ToString(), + Content = claudeChatResponse.Content[0].Text, + Role = ChatRole.assistant.ToString(), + Timestamp = DateTime.Now, + UserIcon = charact.IconImage, + Id = t_Chat.Id + }; + chatMessageDtos.Add(chatMessageDto); + return new BaseResponse>(ResonseCode.Success, "", chatMessageDtos); + } /// /// 删除聊天记录 /// diff --git a/src/0-core/HuanMeng.MiaoYu.Code/Chat/Claude/ClaudeChat.cs b/src/0-core/HuanMeng.MiaoYu.Code/Chat/Claude/ClaudeChat.cs index 9fb0e0b..e1102d2 100644 --- a/src/0-core/HuanMeng.MiaoYu.Code/Chat/Claude/ClaudeChat.cs +++ b/src/0-core/HuanMeng.MiaoYu.Code/Chat/Claude/ClaudeChat.cs @@ -42,9 +42,9 @@ namespace HuanMeng.MiaoYu.Code.Chat.Claude claudeChatChatParams.MaxTokens = claudeChatConfig.MaxTokens; } //添加默认值 - if (!string.IsNullOrEmpty(claudeChatChatParams.Model)) + if (string.IsNullOrEmpty(claudeChatChatParams.Model)) { - claudeChatChatParams.Model = claudeChatChatParams.Model; + claudeChatChatParams.Model = claudeChatConfig.Model; } //去线程池里拿http线程 using (var httpClient = factory.CreateClient()) diff --git a/src/0-core/HuanMeng.MiaoYu.Code/Chat/Claude/ClaudeChatConfig.cs b/src/0-core/HuanMeng.MiaoYu.Code/Chat/Claude/ClaudeChatConfig.cs index e3e73ae..5d787fd 100644 --- a/src/0-core/HuanMeng.MiaoYu.Code/Chat/Claude/ClaudeChatConfig.cs +++ b/src/0-core/HuanMeng.MiaoYu.Code/Chat/Claude/ClaudeChatConfig.cs @@ -1,3 +1,6 @@ +using AutoMapper; +using AutoMapper.Configuration.Annotations; + using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using System; @@ -11,30 +14,36 @@ namespace HuanMeng.MiaoYu.Code.Chat.Claude /// /// 配置类 /// + [AutoMap(typeof(T_Model_Config))] public class ClaudeChatConfig { /// /// 模型 /// + [SourceMember(nameof(T_Model_Config.Model))] public string Model { get; set; } /// /// 最大token数 /// + [SourceMember(nameof(T_Model_Config.MaxTokens))] public int MaxTokens { get; set; } /// /// api key /// + [SourceMember(nameof(T_Model_Config.ApiKey))] public string ApiKey { get; set; } /// /// 模型版本 /// + [SourceMember(nameof(T_Model_Config.AnthropicVersion))] public string AnthropicVersion { get; set; } /// /// 请求地址 = "api.gptsapi.net"; /// + [SourceMember(nameof(T_Model_Config.Url))] public string RequestUrl { get; set; } } } diff --git a/src/0-core/HuanMeng.MiaoYu.Code/GlobalUsings.cs b/src/0-core/HuanMeng.MiaoYu.Code/GlobalUsings.cs index 2110fe8..bdecd20 100644 --- a/src/0-core/HuanMeng.MiaoYu.Code/GlobalUsings.cs +++ b/src/0-core/HuanMeng.MiaoYu.Code/GlobalUsings.cs @@ -1,3 +1,4 @@ global using HuanMeng.MiaoYu.Code.Base; global using HuanMeng.MiaoYu.Code.DataAccess; global using HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu; +global using HuanMeng.MiaoYu.Code.Other; \ No newline at end of file diff --git a/src/0-core/HuanMeng.MiaoYu.Code/Other/ModelConfigExtend.cs b/src/0-core/HuanMeng.MiaoYu.Code/Other/ModelConfigExtend.cs new file mode 100644 index 0000000..ff6531d --- /dev/null +++ b/src/0-core/HuanMeng.MiaoYu.Code/Other/ModelConfigExtend.cs @@ -0,0 +1,46 @@ +using AutoMapper; + +using HuanMeng.MiaoYu.Code.Chat.Claude; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HuanMeng.MiaoYu.Code.Other +{ + /// + /// 扩展方法 + /// + public static class ModelConfigExtend + { + /// + /// 获取配置项 + /// + /// + /// + public static ClaudeChatConfig GetClaudeChatConfig(this T_Model_Config config) + { + ClaudeChatConfig claudeChatConfig = new ClaudeChatConfig(); + claudeChatConfig.AnthropicVersion = config.AnthropicVersion; + claudeChatConfig.ApiKey = config.ApiKey; + claudeChatConfig.Model = config.Model; + claudeChatConfig.ApiKey = config.ApiKey; + claudeChatConfig.RequestUrl = config.Url; + return claudeChatConfig; + } + + /// + /// 获取配置项 + /// + /// + /// + /// + public static ClaudeChatConfig GetClaudeChatConfig(this T_Model_Config config, IMapper mapper) + { + ClaudeChatConfig claudeChatConfig = mapper.Map(config); + return claudeChatConfig; + } + } +} diff --git a/src/0-core/HuanMeng.MiaoYu.Model/DbSqlServer/Db_MiaoYu/MiaoYuContext.cs b/src/0-core/HuanMeng.MiaoYu.Model/DbSqlServer/Db_MiaoYu/MiaoYuContext.cs index 00e1a7e..68b3107 100644 --- a/src/0-core/HuanMeng.MiaoYu.Model/DbSqlServer/Db_MiaoYu/MiaoYuContext.cs +++ b/src/0-core/HuanMeng.MiaoYu.Model/DbSqlServer/Db_MiaoYu/MiaoYuContext.cs @@ -114,9 +114,7 @@ public partial class MiaoYuContext : MultiTenantDbContext//DbContext entity.ToTable(tb => tb.HasComment("人物表")); - entity.Property(e => e.Id) - .ValueGeneratedNever() - .HasComment("人物id"); + entity.Property(e => e.Id).HasComment("人物id"); entity.Property(e => e.BgImg).HasComment("背景图片"); entity.Property(e => e.Biography) .HasMaxLength(500) @@ -154,9 +152,7 @@ public partial class MiaoYuContext : MultiTenantDbContext//DbContext entity.ToTable(tb => tb.HasComment("角色标签表")); - entity.Property(e => e.Id) - .ValueGeneratedNever() - .HasComment("标签id"); + entity.Property(e => e.Id).HasComment("标签id"); entity.Property(e => e.CreateTime) .HasComment("创建时间") .HasColumnType("datetime"); @@ -203,9 +199,7 @@ public partial class MiaoYuContext : MultiTenantDbContext//DbContext entity.ToTable(tb => tb.HasComment("发现页类型分类")); - entity.Property(e => e.Id) - .ValueGeneratedNever() - .HasComment("类型id"); + entity.Property(e => e.Id).HasComment("类型id"); entity.Property(e => e.CreateTime) .HasComment("创建时间") .HasColumnType("datetime"); @@ -253,9 +247,7 @@ public partial class MiaoYuContext : MultiTenantDbContext//DbContext entity.ToTable(tb => tb.HasComment("聊天记录表")); - entity.Property(e => e.Id) - .ValueGeneratedNever() - .HasComment("聊天id"); + entity.Property(e => e.Id).HasComment("聊天id"); entity.Property(e => e.CharacterId).HasComment("人物表Id"); entity.Property(e => e.ClaudeId) .HasMaxLength(100) diff --git a/src/0-core/HuanMeng.MiaoYu.Model/Dto/Chat/RequestMessage.cs b/src/0-core/HuanMeng.MiaoYu.Model/Dto/Chat/RequestMessage.cs new file mode 100644 index 0000000..2964383 --- /dev/null +++ b/src/0-core/HuanMeng.MiaoYu.Model/Dto/Chat/RequestMessage.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HuanMeng.MiaoYu.Model.Dto.Chat +{ + /// + /// 发送消息接口 + /// + public class RequestMessage + { + /// + /// 角色Id + /// + public int CharacterId { get; set; } + /// + /// 消息内容 + /// + public string Message { get; set; } + } +} diff --git a/src/2-api/HuanMeng.MiaoYu.WebApi/Controllers/ChatController.cs b/src/2-api/HuanMeng.MiaoYu.WebApi/Controllers/ChatController.cs index 1f45660..920c73d 100644 --- a/src/2-api/HuanMeng.MiaoYu.WebApi/Controllers/ChatController.cs +++ b/src/2-api/HuanMeng.MiaoYu.WebApi/Controllers/ChatController.cs @@ -77,6 +77,18 @@ namespace HuanMeng.MiaoYu.WebApi.Controllers return new BaseResponse(ResonseCode.Success, "", chatListDto); } + /// + /// 发送消息接口 + /// + /// + /// + [HttpPost] + public async Task>> SendMessage([FromBody] RequestMessage requestMessage) + { + ChatBLL chatBLL = new ChatBLL(ServiceProvider); + var obj = await chatBLL.Message(requestMessage.CharacterId, requestMessage.Message); + return obj; + } /// /// 删除聊天记录 /// diff --git a/src/2-api/HuanMeng.MiaoYu.WebApi/Program.cs b/src/2-api/HuanMeng.MiaoYu.WebApi/Program.cs index 042f040..b680f30 100644 --- a/src/2-api/HuanMeng.MiaoYu.WebApi/Program.cs +++ b/src/2-api/HuanMeng.MiaoYu.WebApi/Program.cs @@ -28,6 +28,7 @@ builder.Host.UseSerilog((context, services, configuration) => configuration // 检索程序集信息 AssemblyInfo assemblyInfo = AssemblyInfoHelper.GetAssemblyInfo(); // Add services to the container. +builder.Services.AddHttpClient(); builder.Services.AddHttpContextAccessor(); //添加httpContext注入访问 #region 添加跨域 var _myAllowSpecificOrigins = "_myAllowSpecificOrigins";