Compare commits

...

23 Commits

Author SHA1 Message Date
zpc
2bdd14da94 提交代码 2024-07-15 14:13:56 +08:00
zpc
bdcf89bc35 Merge branch 'dev' of 123.207.203.228:server/HuanMengProject into dev 2024-07-14 15:42:33 +08:00
zpc
8418cfa56e 修改实体类 2024-07-14 15:42:13 +08:00
0a0b80cc1c Merge branch 'dev' of http://123.207.203.228:3000/server/HuanMengProject into dev 2024-07-14 15:18:02 +08:00
ac95d9b438 添加注释 2024-07-14 15:17:02 +08:00
zpc
f82e97b4ef 修改实体类 2024-07-14 15:16:40 +08:00
zpc
2268c115e3 添加角色实体类缓存 2024-07-13 23:00:01 +08:00
zpc
d19afd6e8a 添加日志 2024-07-13 21:42:23 +08:00
zpc
72f84dce05 日志组件 2024-07-13 18:31:17 +08:00
zpc
9222d5d4f4 删除首页角色字段 2024-07-13 18:22:03 +08:00
zpc
af016b57e5 添加缓存 2024-07-13 16:29:27 +08:00
zpc
5263badb1a Merge branch 'dev' of 123.207.203.228:server/HuanMengProject into dev 2024-07-13 15:43:34 +08:00
zpc
14600d3392 修改注释 2024-07-13 15:43:28 +08:00
b7cae0952e 添加缓存 2024-07-13 15:42:36 +08:00
bcdfc25af1 删除聊天 2024-07-13 12:16:53 +08:00
8db46fb36d 删除聊天记录接口 2024-07-13 12:14:22 +08:00
zpc
cb73982ef0 修改验证代码 2024-07-12 16:56:46 +08:00
zpc
02ac4e3961 Merge branch 'dev' of 123.207.203.228:server/HuanMengProject into dev 2024-07-12 16:43:39 +08:00
zpc
b300c7df52 添加注释 2024-07-12 16:43:37 +08:00
4fe894fb6f Merge branch 'dev' of http://123.207.203.228:3000/server/HuanMengProject into dev 2024-07-12 16:42:19 +08:00
03710a37b1 删除聊天记录 2024-07-12 16:41:24 +08:00
zpc
ac181d208d Merge branch 'dev' of 123.207.203.228:server/HuanMengProject into dev 2024-07-12 16:16:00 +08:00
zpc
49e9ded36a 添加Claude对话 2024-07-12 16:15:55 +08:00
47 changed files with 2019 additions and 86 deletions

4
.gitignore vendored
View File

@ -360,4 +360,6 @@ MigrationBackup/
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
FodyWeavers.xsd
output/
logs/

View File

@ -1 +1,13 @@
# HuanMengProject
# HuanMengProject 开发文档
### 项目说明
```sh
# Program.cs 文件说明
# 输出的时候,将请求的参数转换成小写
c.ParameterFilter<LowercaseParameterFilter>();
c.RequestBodyFilter<LowercaseRequestFilter>();
//配置路由选项使URL全部小写
builder.Services.AddRouting(options => options.LowercaseUrls = true);
```

View File

@ -0,0 +1,55 @@
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace XLib.DotNetCore.CacheHelper
{
/// <summary>
/// 内存缓存帮助类
/// </summary>
public class MemoryCacheHelper
{
private static MemoryCache cache = new MemoryCache(new MemoryCacheOptions());
/// <summary>
/// 获取缓存
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="cacheName"></param>
/// <returns></returns>
public static T? GetCache<T>(string cacheName) where T : class, new()
{
return cache.TryGetValue(cacheName, out var value) ? value as T : null;
}
/// <summary>
/// 设置缓存
/// </summary>
/// <param name="cacheName"></param>
/// <param name="val"></param>
/// <param name="cacheTime">单位秒默认1小时</param>
public static void SetCache(string cacheName, object val, int cacheTime = 21000)
{
//数据量渐渐大了,每次因为很多都是同时缓存 所以在这里分流一下
if (cacheTime == 21000)
cacheTime = new Random().Next(21000, 43200);
cache.Set(cacheName, val, TimeSpan.FromSeconds(cacheTime));
}
/// <summary>
/// 删除缓存
/// </summary>
/// <param name="cacheName"></param>
public static void DelCache(string? cacheName = null)
{
if (!string.IsNullOrEmpty(cacheName))
cache.Remove(cacheName);
else
cache.Dispose();
}
}
}

View File

@ -4,6 +4,7 @@ using HuanMeng.DotNetCore.Base;
using HuanMeng.DotNetCore.JwtInfrastructure;
using HuanMeng.DotNetCore.JwtInfrastructure.Interface;
using HuanMeng.DotNetCore.MultiTenant;
using HuanMeng.MiaoYu.Code.Cache;
using HuanMeng.MiaoYu.Code.DataAccess;
using HuanMeng.MiaoYu.Code.TencentUtile;
using HuanMeng.MiaoYu.Code.Users.UserAccount;
@ -13,6 +14,7 @@ using HuanMeng.MiaoYu.Model.Dto;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using System;
@ -29,10 +31,12 @@ namespace HuanMeng.MiaoYu.Code.Base
/// </summary>
public class MiaoYuBase : BLLBase<DAO>
{
public MiaoYuBase(IServiceProvider serviceProvider) : base(serviceProvider)
{
}
#region
private DAO _dao;
/// <summary>
/// dao 数据库
@ -48,6 +52,7 @@ namespace HuanMeng.MiaoYu.Code.Base
return _dao;
}
}
#endregion
#region
/// <summary>
@ -79,7 +84,7 @@ namespace HuanMeng.MiaoYu.Code.Base
{
get
{
if (_mapper == null)
if (_HttpContextAccessor == null)
{
_HttpContextAccessor = _serviceProvider.GetRequiredService<IHttpContextAccessor>();
}
@ -179,25 +184,31 @@ namespace HuanMeng.MiaoYu.Code.Base
var accessToken = HttpContextAccessor.HttpContext.GetTokenAsync("Bearer", "access_token").Result;
if (string.IsNullOrEmpty(accessToken))
{
_userInfo = new RequestUserInfo()
{
UserId = 0
};
}
var (principal, jwtToken) = JwtAuthManager.DecodeJwtToken(accessToken);
if (jwtToken == null || !jwtToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256Signature))
else
{
throw new SecurityTokenException("无效的token");
var (principal, jwtToken) = JwtAuthManager.DecodeJwtToken(accessToken);
if (jwtToken == null || !jwtToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256Signature))
{
throw new SecurityTokenException("无效的token");
}
var userIdStr = principal.FindFirst("UserId")?.Value;
if (string.IsNullOrEmpty(userIdStr))
{
throw new SecurityTokenException("无效的token");
}
var nickName = principal.FindFirst("NickName")?.Value;
var userId = int.Parse(userIdStr);
_userInfo = new RequestUserInfo()
{
UserId = userId,
NickName = nickName
};
}
var userIdStr = principal.FindFirst("UserId")?.Value;
if (string.IsNullOrEmpty(userIdStr))
{
throw new SecurityTokenException("无效的token");
}
var nickName = principal.FindFirst("NickName")?.Value;
var userId = int.Parse(userIdStr);
_userInfo = new RequestUserInfo()
{
UserId = userId,
NickName = nickName
};
}
return _userInfo;
}
@ -214,5 +225,40 @@ namespace HuanMeng.MiaoYu.Code.Base
}
}
#endregion
#region
private MiaoYuCache? _miaoYuCache; //new MiaoYuCache(Dao, Mapper);
/// <summary>
/// 妙语实现类
/// </summary>
public MiaoYuCache MiaoYuCache
{
get
{
if (_miaoYuCache == null)
{
//new MiaoYuDataEntityCache<T_Character>(Dao).DataList
_miaoYuCache = new MiaoYuCache(Dao, Mapper);
}
return _miaoYuCache;
}
}
#endregion
#region
private Logger<MiaoYuBase>? _logger;
public Logger<MiaoYuBase> _Logger
{
get
{
if (_logger == null)
{
_logger = _serviceProvider.GetRequiredService<Logger<MiaoYuBase>>();
}
return _logger;
}
}
#endregion
}
}

View File

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HuanMeng.MiaoYu.Code.DataAccess;
using HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;
using Microsoft.Extensions.Caching.Memory;
namespace HuanMeng.MiaoYu.Code.Cache
{
/// <summary>
/// 人物信息缓存
/// </summary>
public class CharacterInfoBaseCache
{
private IMemoryCache _memoryCache;
private object _cacheLock = new object(); // 用于线程安全的锁
private const string CharactersCacheKey = "Characters";
private DAO _dao;
public CharacterInfoBaseCache(IMemoryCache memoryCache, DAO dao)
{
this._memoryCache = memoryCache;
this._dao = dao;
}
public List<T_Character> GetCharacterFromCache(int userId)
{
lock (_cacheLock) // 加锁以防止并发访问
{
if (!_memoryCache.TryGetValue(CharactersCacheKey , out List<T_Character> cachedCharacter))
{
// 如果缓存中没有数据,则从数据库中获取
//var db = new YourDbContext();
var character = _dao.daoDbMiaoYu.context.T_Character.ToList();
if (character != null && character.Count > 0)
{
// 将数据放入缓存
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(30)) // 设置缓存过期时间
.SetSlidingExpiration(TimeSpan.FromMinutes(5)); // 设置滑动过期时间
_memoryCache.Set(CharactersCacheKey , character, cacheEntryOptions);
cachedCharacter = character;
}
else
{
cachedCharacter = new List<T_Character>();
}
}
return cachedCharacter;
}
}
}
}

View File

@ -0,0 +1,63 @@
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XLib.DotNetCore.CacheHelper;
namespace HuanMeng.MiaoYu.Code.Cache
{
/// <summary>
///
/// </summary>
public abstract class CommonDataEntityCache<T>(object lockObj, int cacheTime = 36000) where T : class
{
/// <summary>
///
/// </summary>
public abstract string key { get; }
/// <summary>
/// 缓存数据
/// </summary>
protected List<T>? _dataList;
/// <summary>
/// 数据
/// </summary>
public List<T> DataList
{
get
{
if (_dataList == null)
{
var tempDataList = MemoryCacheHelper.GetCache<List<T>>(key);
if (tempDataList == null)
{
lock (lockObj)
{
if (tempDataList == null)
{
tempDataList = GetDataList();
MemoryCacheHelper.SetCache(key, tempDataList, cacheTime);
}
}
}
_dataList = JsonConvert.DeserializeObject<List<T>>(JsonConvert.SerializeObject(tempDataList));
}
return _dataList ?? new List<T>();
}
}
/// <summary>
/// 获取缓存数据
/// </summary>
public abstract List<T> GetDataList();
}
}

View File

@ -0,0 +1,119 @@
using AutoMapper;
using HuanMeng.MiaoYu.Code.Cache.Special;
using HuanMeng.MiaoYu.Model.Dto.Character;
namespace HuanMeng.MiaoYu.Code.Cache
{
/// <summary>
/// 缓存类
/// </summary>
/// <param name="dao"></param>
public partial class MiaoYuCache(DAO dao, IMapper mapper)
{
#region
/// <summary>
/// 对话角色缓存表
/// </summary>
private static object CharacterLock = new object();
/// <summary>
/// 对话角色缓存表
/// </summary>
public MiaoYuDataEntityCache<T_Character>? Character { get; set; }
/// <summary>
/// 角色数据表
/// </summary>
public List<T_Character> CharactersList
{
get
{
if (Character == null)
{
Character = new MiaoYuDataEntityCache<T_Character>(dao, CharacterLock);
}
return Character.DataList ?? new List<T_Character>();
}
}
#endregion
#region
/// <summary>
/// 模型缓存表
/// </summary>
private static object ModelConfigLock = new object();
/// <summary>
/// 模型缓存表
/// </summary>
public MiaoYuDataEntityCache<T_Model_Config>? ModelConfig { get; set; }
/// <summary>
/// 模型
/// </summary>
public List<T_Model_Config> ModelConfigList
{
get
{
if (ModelConfig == null)
{
ModelConfig = new MiaoYuDataEntityCache<T_Model_Config>(dao, ModelConfigLock);
}
return ModelConfig.DataList ?? new List<T_Model_Config>();
}
}
#endregion
#region
/// <summary>
/// 角色缓存表
/// </summary>
public CharacterEntityCache? CharacterCache { get; set; }
/// <summary>
/// 角色
/// </summary>
public List<CharacterCache> CharacterList
{
get
{
if (CharacterCache == null)
{
CharacterCache = new CharacterEntityCache(dao, mapper);
}
return CharacterCache.DataList ?? new List<CharacterCache>();
}
}
#endregion
#region
/// <summary>
/// 图片缓存表
/// </summary>
private static object ImageConfigLock = new object();
/// <summary>
/// 图片缓存表
/// </summary>
public MiaoYuDataEntityCache<T_Image_Config>? ImageConfigCache { get; set; }
/// <summary>
/// 图片
/// </summary>
public List<T_Image_Config> ImageConfigList
{
get
{
if (ImageConfigCache == null)
{
ImageConfigCache = new MiaoYuDataEntityCache<T_Image_Config>(dao, ImageConfigLock);
}
return ImageConfigCache.DataList ?? new List<T_Image_Config>();
}
}
#endregion
}
}

View File

@ -0,0 +1,35 @@
namespace HuanMeng.MiaoYu.Code.Cache
{
/// <summary>
/// 妙语数据库实体类缓存
/// </summary>
public class MiaoYuDataEntityCache<T>(DAO _dao, object lockObj, int cacheTime = 36000)
: CommonDataEntityCache<T>(lockObj, cacheTime) where T : class
{
/// <summary>
/// 缓存的key
/// </summary>
public override string key
{
get
{
return $"{_dao.daoDbMiaoYu.context.TenantInfo?.TenantId}:MiaoYu:{typeof(T).Name}";
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override List<T> GetDataList()
{
var dbSet = _dao.daoDbMiaoYu.context.Set<T>();
if (dbSet == null)
{
return new List<T>();
}
return dbSet.ToList();
}
}
}

View File

@ -0,0 +1,93 @@
using AutoMapper;
using HuanMeng.MiaoYu.Code.DataAccess;
using HuanMeng.MiaoYu.Code.Other;
using HuanMeng.MiaoYu.Model.Dto.Character;
using HuanMeng.MiaoYu.Model.Dto.Label;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Cache.Special
{
/// <summary>
///
/// </summary>
/// <param name="_dao"></param>
public class CharacterEntityCache(DAO _dao, IMapper mapper) : MiaoYuDataEntityCache<CharacterCache>(_dao, CharacterCacheLock)
{
/// <summary>
/// 锁
/// </summary>
private static object CharacterCacheLock = new object();
private static object ImageLock = new object();
private static object T_Character_LabelLock = new object();
private static object T_Character_Label_RelationLock = new object();
/// <summary>
/// 获取缓存数据
/// </summary>
/// <returns></returns>
public override List<CharacterCache> GetDataList()
{
List<CharacterCache> characterCaches = new List<CharacterCache>();
//读取角色表
var characters = _dao.daoDbMiaoYu.context.T_Character.ToList();
if (characters == null)
{
return characterCaches;
}
characterCaches = mapper.Map<List<CharacterCache>>(characters);
string sqlString = $"select TOP 100 CharacterId,count(DISTINCT UserId ) UserCount from T_User_Char where isdelete=0 and TenantId='{_dao.daoDbMiaoYu.context.TenantInfo?.TenantId}' GROUP BY CharacterId";
//获取查看次数
var characteChatCounts = _dao.daoDbMiaoYu.SqlQueryList<CharacteChatCountModel>(sqlString);
//查询配置表
var modelConfigs = _dao.daoDbMiaoYu.context.T_Model_Config.ToList();
var ImageConfigCache = new MiaoYuDataEntityCache<T_Image_Config>(_dao, ImageLock);
var images = ImageConfigCache.DataList;
//标签
var labelCache = new MiaoYuDataEntityCache<T_Character_Label>(_dao, T_Character_LabelLock);
var labels = labelCache.DataList;
var labelRelationCache = new MiaoYuDataEntityCache<T_Character_Label_Relation>(_dao, T_Character_Label_RelationLock);
var labelRelations = labelRelationCache.DataList;
foreach (var characterCache in characterCaches)
{
var modelConfig = modelConfigs.FirstOrDefault(it => it.Id == characterCache.ModelConfigId);
if (modelConfig != null)
{
characterCache.ModelConfig = modelConfig;
//查询图片
characterCache.IconImage = images.GetImageUrl(characterCache.IconImg ?? 0);
characterCache.BgImage = images.GetImageUrl(characterCache.BgImg ?? 0);
var c = characteChatCounts.FirstOrDefault(it => it.CharacterId == characterCache.Id);
if (c != null)
{
characterCache.LookCount = c.UserCount;
}
var characterLabelIds = labelRelations.Where(it => it.CharacterId == characterCache.Id).Select(it => it.CharacterLabelId).ToList();
if (characterLabelIds.Count > 0)
{
var lab = labels.Where(it => characterLabelIds.Contains(it.Id)).ToList();
var labs = mapper.Map<List<LabelDto>>(lab);
characterCache.Label = labs;
}
else
{
characterCache.Label = new List<LabelDto>();
}
}
}
//移除没有配置模型的类
characterCaches.Where(it => it.ModelConfig == null).ToList().ForEach(characterCache =>
{
characterCaches.Remove(characterCache);
});
return characterCaches;
}
}
}

View File

@ -0,0 +1,99 @@
using AutoMapper;
using HuanMeng.DotNetCore.Base;
using HuanMeng.MiaoYu.Model.Dto.Character;
using HuanMeng.MiaoYu.Model.Dto.Chat;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Character
{
/// <summary>
/// 角色信息类
/// </summary>
public class CharacterBLL : MiaoYuBase
{
public CharacterBLL(IServiceProvider serviceProvider) : base(serviceProvider)
{
}
/// <summary>
/// 首页获取角色列表
/// </summary>
/// <returns></returns>
public async Task<BaseResponse<List<CharacterInfoDto>>> GetHomeCharacter(RequestCharacterInfoPage requestCharacterInfo)
{
var index = requestCharacterInfo.Index ?? 0;
var size = requestCharacterInfo.Size ?? 10;
var charactersList = MiaoYuCache.CharacterList.OrderByDescending(it => it.LookCount)
.Skip((index - 1) * size).Take(size).ToList();
if (charactersList.Count == 0)
{
return new BaseResponse<List<CharacterInfoDto>>();
}
var list = Mapper.Map<List<CharacterInfoDto>>(charactersList);
//不是游客
if (_UserId != 0)
{
List<int> characterIds = list.Select(it => it.CharacterId).ToList();
//获取亲密值
var intimacys = await Dao.daoDbMiaoYu.context.T_Character_User_Intimacy.Where(it => it.UserId == _UserId
&& characterIds.Contains(it.CharacterId)).ToListAsync();
list.ForEach(it =>
{
it.Intimacy = intimacys.FirstOrDefault(item => item.CharacterId == it.CharacterId)?.IntimacyValue ?? 0;
});
}
return new BaseResponse<List<CharacterInfoDto>>(ResonseCode.Success, "", list);
}
/// <summary>
/// 获取角色详情
/// </summary>
/// <param name="requestCharacterInfo"></param>
/// <returns></returns>
public async Task<BaseResponse<CharacterInfoDto>> GetCharacterInfo(RequestCharacterInfo requestCharacterInfo)
{
var charactersinfo = MiaoYuCache.CharacterList.FirstOrDefault(it => it.Id == requestCharacterInfo.CharacterId);
if (charactersinfo == null)
{
return new BaseResponse<CharacterInfoDto>();
}
var info = Mapper.Map<CharacterInfoDto>(charactersinfo);
//不是游客
if (_UserId != 0)
{
//获取亲密值
var intimacys = await Dao.daoDbMiaoYu.context.T_Character_User_Intimacy.Where(it => it.UserId == _UserId
&& it.CharacterId == info.CharacterId).FirstOrDefaultAsync();
info.Intimacy = intimacys?.IntimacyValue ?? 0;
}
return new BaseResponse<CharacterInfoDto>(ResonseCode.Success, "", info);
}
/// <summary>
/// 获取全部角色的Id
/// </summary>
/// <returns></returns>
public BaseResponse<List<int>> GetCharacters()
{
Random rng = new Random();
var charactersIds = MiaoYuCache.CharacterList.Select(it => it.Id).OrderBy(x => rng.Next()).ToList();
if (charactersIds == null)
{
charactersIds = new List<int>();
}
return new BaseResponse<List<int>>(ResonseCode.Success, "", charactersIds);
}
}
}

View File

@ -0,0 +1,67 @@
using HuanMeng.DotNetCore.Base;
using HuanMeng.MiaoYu.Code.Cache;
using HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Chat
{
/// <summary>
/// 聊天类
/// </summary>
public class ChatBLL : MiaoYuBase
{
public ChatBLL(IServiceProvider serviceProvider) : base(serviceProvider)
{
}
/// <summary>
/// 删除聊天记录
/// </summary>
/// <param name="id">聊天id</param>
/// <param name="characterId"></param>
/// <returns></returns>
public async Task<bool> DelChatByIds(List<int> id, int characterId)
{
//var charactersList = MiaoYuCache.CharactersList;
//List<T_Character> list = _characterCache.GetCharacterFromCache(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 == 0).ToList();
//if (chatList.Count > 0)
//{
// chatList.ForEach(t => t.Type = 2);
//}
//Dao.daoDbMiaoYu.context.SaveChanges();
return true;
}
/// <summary>
/// 清空聊天记录
/// </summary>
/// <param name="characterId"></param>
/// <returns></returns>
public async Task<bool> DelChat(int characterId)
{
//var tempList = await Dao.daoDbMiaoYu.context.T_Chat.Where(t => t.UserId == _UserId && t.CharacterId == characterId && t.IsDel == false).ToListAsync();
//if (tempList.Count > 0)
//{
// tempList.ForEach(t => t.IsDel = true);
//}
//Dao.daoDbMiaoYu.context.SaveChanges();
return true;
}
}
}

View File

@ -13,6 +13,7 @@ using System.Net.Http.Json;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Serialization;
using HuanMeng.MiaoYu.Code.Chat.Claude.Model;
namespace HuanMeng.MiaoYu.Code.Chat.Claude
{
@ -21,6 +22,13 @@ namespace HuanMeng.MiaoYu.Code.Chat.Claude
/// </summary>
public class ClaudeChat(ClaudeChatConfig claudeChatConfig, IHttpClientFactory factory) : IChat
{
/// <summary>
///
/// </summary>
/// <param name="chatParams"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="NotImplementedException"></exception>
public async Task<BaseChatInfo> MessagesAsync(BaseChatParams chatParams)
{
var claudeChatChatParams = chatParams as ClaudeChatChatParams;
@ -52,20 +60,71 @@ namespace HuanMeng.MiaoYu.Code.Chat.Claude
};
string json = JsonConvert.SerializeObject(chatParams, settings);
var content = new StringContent(json, Encoding.UTF8, "application/json");
//HttpClientHandler httpClientHandler = new HttpClientHandler();
//HttpContent httpContent = new JsonContent();
var response = await httpClient.PostAsync(claudeChatConfig.RequestUrl, content);
if (response.IsSuccessStatusCode)
{
var chatInfo = response.Content.ReadFromJsonAsync<BaseChatInfo?>();
var chatInfo = await response.Content.ReadFromJsonAsync<ClaudeChatResponse?>();
return chatInfo;
}
}
throw new NotImplementedException();
return null;
}
public IAsyncEnumerable<BaseChatStream> MessagesStreamAsync(BaseChatParams chatParams)
public async IAsyncEnumerable<string> MessagesStreamAsync(BaseChatParams chatParams)
{
throw new NotImplementedException();
var claudeChatChatParams = chatParams as ClaudeChatChatStreamParams;
if (claudeChatChatParams == null)
{
throw new ArgumentException("参数异常");
}
//添加默认值
if (claudeChatChatParams.MaxTokens == 0)
{
claudeChatChatParams.MaxTokens = claudeChatConfig.MaxTokens;
}
claudeChatChatParams.Stream = true;
//添加默认值
if (!string.IsNullOrEmpty(claudeChatChatParams.Model))
{
claudeChatChatParams.Model = claudeChatChatParams.Model;
}
//去线程池里拿http线程
using (var httpClient = factory.CreateClient())
{
// 设置请求头
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Add("x-api-key", claudeChatConfig.ApiKey);
httpClient.DefaultRequestHeaders.Add("anthropic-version", claudeChatConfig.AnthropicVersion);
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
string json = JsonConvert.SerializeObject(chatParams, settings);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(claudeChatConfig.RequestUrl, content);
if (response.IsSuccessStatusCode)
{
var chatInfo = await response.Content.ReadFromJsonAsync<ClaudeChatStreamResponse?>();
if (chatInfo?.Type == "message_delta")
{
claudeChatChatParams.OutCharResponse.Usage.OutputTokens = chatInfo.Usage?.OutputTokens ?? 0;
}
else if (chatInfo?.Type == "content_block_start")
{
claudeChatChatParams.OutCharResponse = chatInfo?.Message ?? new ClaudeChatResponse();
}
else if (chatInfo?.Type == "content_block_delta")
{
var text = chatInfo?.Delta?.Text ?? "";
if (!string.IsNullOrEmpty(text))
{
yield return text;
}
}
claudeChatChatParams.OutObj.Add(chatInfo);
}
}
}
}
}

View File

@ -9,7 +9,7 @@ using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Chat.Claude
{
/// <summary>
/// Claude3 请求的参数
/// Claude3 请求的参数
/// </summary>
public class ClaudeChatChatParams : BaseClaudeChatChatParams
{

View File

@ -0,0 +1,31 @@
using HuanMeng.MiaoYu.Code.Chat.Claude.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Chat.Claude
{
/// <summary>
/// 实时流
/// </summary>
public class ClaudeChatChatStreamParams : BaseClaudeChatChatParams
{
/// <summary>
/// 视频流
/// </summary>
public bool Stream { get; set; }
/// <summary>
/// 返回消息内容
/// </summary>
public ClaudeChatResponse OutCharResponse { get; set; }
/// <summary>
///
/// </summary>
public List<object> OutObj { get; set; }
}
}

View File

@ -1,20 +0,0 @@
using HuanMeng.MiaoYu.Code.Chat.Contract;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Chat.Claude
{
/// <summary>
/// 返回内容
/// </summary>
public class ClaudeChatInfo : BaseChatInfo
{
}
}

View File

@ -0,0 +1,28 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Chat.Claude.Model
{
/// <summary>
/// 消息内容
/// </summary>
public class ClaudeChatContent
{
/// <summary>
/// 内容类型
/// </summary>
[JsonProperty("type")]
public string Type { get; set; }
/// <summary>
/// 文本内容
/// </summary>
[JsonProperty("text")]
public string Text { get; set; }
}
}

View File

@ -0,0 +1,60 @@
using HuanMeng.MiaoYu.Code.Chat.Contract;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Chat.Claude.Model
{
/// <summary>
/// 返回内容
/// </summary>
public class ClaudeChatResponse : BaseChatInfo
{
/// <summary>
/// 消息 ID
/// </summary>
[JsonProperty("id")]
public string Id { get; set; }
/// <summary>
/// 模型
/// </summary>
[JsonProperty("model")]
public string Model { get; set; }
/// <summary>
/// 消息类型
/// </summary>
[JsonProperty("type")]
public string Type { get; set; }
/// <summary>
/// 角色
/// </summary>
[JsonProperty("role")]
public string Role { get; set; }
/// <summary>
/// 消息内容
/// </summary>
[JsonProperty("content")]
public ClaudeChatContent[] Content { get; set; }
/// <summary>
/// 停止原因
/// </summary>
[JsonProperty("stop_reason")]
public string StopReason { get; set; }
/// <summary>
/// 使用情况
/// </summary>
[JsonProperty("usage")]
public ClaudeChatUsage Usage { get; set; }
}
}

View File

@ -0,0 +1,41 @@
using HuanMeng.MiaoYu.Code.Chat.Contract;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Chat.Claude.Model
{
/// <summary>
///
/// </summary>
public class ClaudeChatStreamResponse : BaseChatStream
{
public int? Index { get; set; }
/// <summary>
/// 类型
/// </summary>
public string Type { get; set; }
/// <summary>
/// 内容
/// </summary>
public ClaudeChatContent? Delta { get; set; }
/// <summary>
/// 结尾
/// </summary>
public ClaudeChatResponse? Message { get; set; }
/// <summary>
/// 使用情况
/// </summary>
[JsonProperty("usage")]
public ClaudeChatUsage Usage { get; set; }
}
//delta
}

View File

@ -0,0 +1,28 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Chat.Claude.Model
{
/// <summary>
/// 使用情况
/// </summary>
public class ClaudeChatUsage
{
/// <summary>
/// 输入的 token 数量
/// </summary>
[JsonProperty("input_tokens")]
public int InputTokens { get; set; }
/// <summary>
/// 输出的 token 数量
/// </summary>
[JsonProperty("output_tokens")]
public int OutputTokens { get; set; }
}
}

View File

@ -23,6 +23,6 @@ namespace HuanMeng.MiaoYu.Code.Chat.Contract
/// </summary>
/// <param name="chatParams"></param>
/// <returns></returns>
IAsyncEnumerable<BaseChatStream> MessagesStreamAsync(BaseChatParams chatParams);
IAsyncEnumerable<string> MessagesStreamAsync(BaseChatParams chatParams);
}
}

View File

@ -1 +1,3 @@
global using HuanMeng.MiaoYu.Code.Base;
global using HuanMeng.MiaoYu.Code.Base;
global using HuanMeng.MiaoYu.Code.DataAccess;
global using HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Other
{
/// <summary>
/// 图片扩展类
/// </summary>
public static class ImageExtend
{
/// <summary>
/// 获取图片地址
/// </summary>
/// <param name="configs"></param>
/// <param name="imageId"></param>
/// <returns></returns>
public static string GetImageUrl(this List<T_Image_Config> configs, int imageId)
{
if (imageId > 0 && configs != null && configs.Count > 0)
{
return configs.FirstOrDefault(it => it.ImageId == imageId)?.Url ?? "";
}
return "";
}
}
}

View File

@ -38,11 +38,56 @@ public partial class MiaoYuContext : MultiTenantDbContext//DbContext
}
/// <summary>
/// 人物表
/// </summary>
public virtual DbSet<T_Character> T_Character { get; set; }
/// <summary>
/// 角色标签表
/// </summary>
public virtual DbSet<T_Character_Label> T_Character_Label { get; set; }
/// <summary>
/// 关联角色和标签
/// </summary>
public virtual DbSet<T_Character_Label_Relation> T_Character_Label_Relation { get; set; }
/// <summary>
/// 发现页类型分类
/// </summary>
public virtual DbSet<T_Character_Type> T_Character_Type { get; set; }
/// <summary>
/// 存储用户和角色之间的亲密值
/// </summary>
public virtual DbSet<T_Character_User_Intimacy> T_Character_User_Intimacy { get; set; }
/// <summary>
/// 聊天记录表
/// </summary>
public virtual DbSet<T_Chat> T_Chat { get; set; }
/// <summary>
/// 图片表
/// </summary>
public virtual DbSet<T_Image_Config> T_Image_Config { get; set; }
/// <summary>
///
/// </summary>
public virtual DbSet<T_Model_Config> T_Model_Config { get; set; }
/// <summary>
/// 用户表
/// </summary>
public virtual DbSet<T_User> T_User { get; set; }
/// <summary>
///
/// </summary>
public virtual DbSet<T_User_Char> T_User_Char { get; set; }
/// <summary>
/// 用户信息表
/// </summary>
@ -63,6 +108,248 @@ public partial class MiaoYuContext : MultiTenantDbContext//DbContext
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<T_Character>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__T_Charac__3214EC070A8D79B3");
entity.ToTable(tb => tb.HasComment("人物表"));
entity.Property(e => e.Id)
.ValueGeneratedNever()
.HasComment("人物id");
entity.Property(e => e.BgImg).HasComment("背景图片");
entity.Property(e => e.Biography)
.HasMaxLength(500)
.HasComment("人物简介");
entity.Property(e => e.CreateTime)
.HasComment("创建时间")
.HasColumnType("datetime");
entity.Property(e => e.Gender).HasComment("性别0男1女2其他");
entity.Property(e => e.IconImg).HasComment("角色头像");
entity.Property(e => e.ModelConfigId).HasComment("模型Id");
entity.Property(e => e.Name)
.HasMaxLength(50)
.HasComment("人物名字");
entity.Property(e => e.Prologue)
.HasMaxLength(255)
.HasComment("开场白");
entity.Property(e => e.System)
.HasMaxLength(1000)
.HasComment("人物初始设定");
entity.Property(e => e.TenantId).HasComment("租户Id");
entity.Property(e => e.UpdateTime)
.HasComment("更新时间")
.HasColumnType("datetime");
entity.Property(e => e.Visibility).HasComment("公开/私密 0公开 1私密");
//添加全局筛选器
if (this.TenantInfo != null)
{
entity.HasQueryFilter(it => it.TenantId == this.TenantInfo.TenantId);
}
});
modelBuilder.Entity<T_Character_Label>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__T_Charac__3214EC0777B5F217");
entity.ToTable(tb => tb.HasComment("角色标签表"));
entity.Property(e => e.Id)
.ValueGeneratedNever()
.HasComment("标签id");
entity.Property(e => e.CreateTime)
.HasComment("创建时间")
.HasColumnType("datetime");
entity.Property(e => e.LabelName)
.HasMaxLength(50)
.HasComment("标签名称");
entity.Property(e => e.TenantId).HasComment("租户id");
entity.Property(e => e.UpdateTime)
.HasComment("更新时间")
.HasColumnType("datetime");
//添加全局筛选器
if (this.TenantInfo != null)
{
entity.HasQueryFilter(it => it.TenantId == this.TenantInfo.TenantId);
}
});
modelBuilder.Entity<T_Character_Label_Relation>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__T_Charac__3214EC071FC16A53");
entity.ToTable(tb => tb.HasComment("关联角色和标签"));
entity.Property(e => e.Id).HasComment("人物和标签的关联id");
entity.Property(e => e.CharacterId).HasComment("人物Id");
entity.Property(e => e.CharacterLabelId).HasComment("人物标签id");
entity.Property(e => e.CreateTime)
.HasComment("创建时间")
.HasColumnType("datetime");
entity.Property(e => e.TenantId).HasComment("租户id");
entity.Property(e => e.UpdateTime)
.HasComment("更新时间")
.HasColumnType("datetime");
//添加全局筛选器
if (this.TenantInfo != null)
{
entity.HasQueryFilter(it => it.TenantId == this.TenantInfo.TenantId);
}
});
modelBuilder.Entity<T_Character_Type>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__T_Charac__3214EC070CC04F82");
entity.ToTable(tb => tb.HasComment("发现页类型分类"));
entity.Property(e => e.Id)
.ValueGeneratedNever()
.HasComment("类型id");
entity.Property(e => e.CreateTime)
.HasComment("创建时间")
.HasColumnType("datetime");
entity.Property(e => e.Name)
.HasMaxLength(255)
.HasComment("类型名称");
entity.Property(e => e.TenantId).HasComment("租户id");
entity.Property(e => e.UpdateTime)
.HasComment("更新时间")
.HasColumnType("datetime");
//添加全局筛选器
if (this.TenantInfo != null)
{
entity.HasQueryFilter(it => it.TenantId == this.TenantInfo.TenantId);
}
});
modelBuilder.Entity<T_Character_User_Intimacy>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__T_Charac__3214EC079BEEBDEA");
entity.ToTable(tb => tb.HasComment("存储用户和角色之间的亲密值"));
entity.Property(e => e.Id).HasComment("亲密度id");
entity.Property(e => e.CharacterId).HasComment("人物Id");
entity.Property(e => e.CreateTime)
.HasComment("创建时间")
.HasColumnType("datetime");
entity.Property(e => e.IntimacyValue).HasComment("亲密值");
entity.Property(e => e.TenantId).HasComment("租户id");
entity.Property(e => e.UpdateTime)
.HasComment("更新时间")
.HasColumnType("datetime");
entity.Property(e => e.UserId).HasComment("用户Id");
//添加全局筛选器
if (this.TenantInfo != null)
{
entity.HasQueryFilter(it => it.TenantId == this.TenantInfo.TenantId);
}
});
modelBuilder.Entity<T_Chat>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__T_Chat__3214EC079C2C8859");
entity.ToTable(tb => tb.HasComment("聊天记录表"));
entity.Property(e => e.Id)
.ValueGeneratedNever()
.HasComment("聊天id");
entity.Property(e => e.CharacterId).HasComment("人物表Id");
entity.Property(e => e.ClaudeId)
.HasMaxLength(100)
.HasComment("聊天返回的Id");
entity.Property(e => e.ClaudeModel)
.HasMaxLength(50)
.HasComment("人物模型,聊天返回的模型");
entity.Property(e => e.ClaudeType)
.HasMaxLength(20)
.HasComment("聊天返回的消息的类型");
entity.Property(e => e.Content)
.HasMaxLength(1000)
.HasComment("消息内容");
entity.Property(e => e.CreateTime)
.HasComment("创建时间")
.HasColumnType("datetime");
entity.Property(e => e.Input_tokens).HasComment("输入token");
entity.Property(e => e.Output_tokens).HasComment("输出token");
entity.Property(e => e.Role)
.HasMaxLength(50)
.HasComment("user/assistant");
entity.Property(e => e.SendDateDay).HasComment("发送消息,天");
entity.Property(e => e.SendMessageDay).HasComment("发送消息时间戳");
entity.Property(e => e.TenantId).HasComment("租户id");
entity.Property(e => e.TimeStamp)
.HasComment("发送时间")
.HasColumnType("datetime");
entity.Property(e => e.Type).HasComment("0正常1重新生成2 删除");
entity.Property(e => e.UpdateTime)
.HasComment("更新时间")
.HasColumnType("datetime");
entity.Property(e => e.UserId).HasComment("聊天内容");
//添加全局筛选器
if (this.TenantInfo != null)
{
entity.HasQueryFilter(it => it.TenantId == this.TenantInfo.TenantId);
}
});
modelBuilder.Entity<T_Image_Config>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__T_Image___3214EC072BCFE4E5");
entity.ToTable(tb => tb.HasComment("图片表"));
entity.Property(e => e.ImageId).HasComment("图片Id");
entity.Property(e => e.Name)
.HasMaxLength(50)
.HasComment("图片名称");
entity.Property(e => e.TenantId).HasComment("租户");
entity.Property(e => e.Url)
.HasMaxLength(500)
.HasComment("图片地址");
//添加全局筛选器
if (this.TenantInfo != null)
{
entity.HasQueryFilter(it => it.TenantId == this.TenantInfo.TenantId);
}
});
modelBuilder.Entity<T_Model_Config>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__T_Model___3214EC074121E040");
entity.Property(e => e.AnthropicVersion)
.HasMaxLength(255)
.HasComment("模型版本 anthropic-version");
entity.Property(e => e.ApiKey)
.HasMaxLength(255)
.HasComment("模型key x-api-key");
entity.Property(e => e.CreateTime)
.HasComment("创建时间")
.HasColumnType("datetime");
entity.Property(e => e.MaxTokens).HasComment("模型运行最大的max_tokens");
entity.Property(e => e.Model)
.HasMaxLength(50)
.HasComment("模型model");
entity.Property(e => e.ModelName)
.HasMaxLength(50)
.HasComment("模型名称");
entity.Property(e => e.TenantId).HasComment("租户");
entity.Property(e => e.UpdateTime)
.HasComment("修改时间")
.HasColumnType("datetime");
entity.Property(e => e.Url)
.HasMaxLength(255)
.HasComment("模型请求地址");
//添加全局筛选器
if (this.TenantInfo != null)
{
entity.HasQueryFilter(it => it.TenantId == this.TenantInfo.TenantId);
}
});
modelBuilder.Entity<T_User>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__T_User__3214EC073733108B");
@ -106,6 +393,30 @@ public partial class MiaoYuContext : MultiTenantDbContext//DbContext
}
});
modelBuilder.Entity<T_User_Char>(entity =>
{
entity.Property(e => e.CharacterId).HasComment("角色Id");
entity.Property(e => e.CreateAt)
.HasComment("创建时间")
.HasColumnType("datetime");
entity.Property(e => e.IsDelete).HasComment("是否删除");
entity.Property(e => e.ModelConfigId).HasComment("使用模型Id");
entity.Property(e => e.SessionId).HasComment("会话Id");
entity.Property(e => e.SessionName)
.HasMaxLength(50)
.HasComment("会话名称");
entity.Property(e => e.TenantId).HasComment("租户");
entity.Property(e => e.UpdateAt)
.HasComment("修改时间")
.HasColumnType("datetime");
entity.Property(e => e.UserId).HasComment("用户Id");
//添加全局筛选器
if (this.TenantInfo != null)
{
entity.HasQueryFilter(it => it.TenantId == this.TenantInfo.TenantId);
}
});
modelBuilder.Entity<T_User_Data>(entity =>
{
entity.HasKey(e => new { e.Id, e.UserId }).HasName("PK__T_User_D__E36C60C3D959FD89");

View File

@ -0,0 +1,70 @@
using System;
namespace HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;
/// <summary>
/// 人物表
/// </summary>
public partial class T_Character: MultiTenantEntity
{
/// <summary>
/// 人物id
/// </summary>
public int Id { get; set; }
/// <summary>
/// 人物名字
/// </summary>
public string? Name { get; set; }
/// <summary>
/// 人物简介
/// </summary>
public string? Biography { get; set; }
/// <summary>
/// 开场白
/// </summary>
public string Prologue { get; set; } = null!;
/// <summary>
/// 模型Id
/// </summary>
public int ModelConfigId { get; set; }
/// <summary>
/// 公开/私密 0公开 1私密
/// </summary>
public bool Visibility { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime? CreateTime { get; set; }
/// <summary>
/// 更新时间
/// </summary>
public DateTime? UpdateTime { get; set; }
/// <summary>
/// 性别0男1女2其他
/// </summary>
public int Gender { get; set; }
/// <summary>
/// 人物初始设定
/// </summary>
public string? System { get; set; }
/// <summary>
/// 背景图片
/// </summary>
public int? BgImg { get; set; }
/// <summary>
/// 角色头像
/// </summary>
public int? IconImg { get; set; }
}

View File

@ -0,0 +1,30 @@
using System;
namespace HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;
/// <summary>
/// 角色标签表
/// </summary>
public partial class T_Character_Label: MultiTenantEntity
{
/// <summary>
/// 标签id
/// </summary>
public int Id { get; set; }
/// <summary>
/// 标签名称
/// </summary>
public string? LabelName { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime? CreateTime { get; set; }
/// <summary>
/// 更新时间
/// </summary>
public DateTime? UpdateTime { get; set; }
}

View File

@ -0,0 +1,35 @@
using System;
namespace HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;
/// <summary>
/// 关联角色和标签
/// </summary>
public partial class T_Character_Label_Relation: MultiTenantEntity
{
/// <summary>
/// 人物和标签的关联id
/// </summary>
public int Id { get; set; }
/// <summary>
/// 人物Id
/// </summary>
public int CharacterId { get; set; }
/// <summary>
/// 人物标签id
/// </summary>
public int CharacterLabelId { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateTime { get; set; }
/// <summary>
/// 更新时间
/// </summary>
public DateTime UpdateTime { get; set; }
}

View File

@ -0,0 +1,30 @@
using System;
namespace HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;
/// <summary>
/// 发现页类型分类
/// </summary>
public partial class T_Character_Type: MultiTenantEntity
{
/// <summary>
/// 类型id
/// </summary>
public int Id { get; set; }
/// <summary>
/// 类型名称
/// </summary>
public string Name { get; set; } = null!;
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateTime { get; set; }
/// <summary>
/// 更新时间
/// </summary>
public DateTime UpdateTime { get; set; }
}

View File

@ -0,0 +1,40 @@
using System;
namespace HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;
/// <summary>
/// 存储用户和角色之间的亲密值
/// </summary>
public partial class T_Character_User_Intimacy: MultiTenantEntity
{
/// <summary>
/// 亲密度id
/// </summary>
public int Id { get; set; }
/// <summary>
/// 人物Id
/// </summary>
public int CharacterId { get; set; }
/// <summary>
/// 用户Id
/// </summary>
public int UserId { get; set; }
/// <summary>
/// 亲密值
/// </summary>
public int IntimacyValue { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateTime { get; set; }
/// <summary>
/// 更新时间
/// </summary>
public DateTime UpdateTime { get; set; }
}

View File

@ -0,0 +1,92 @@
using System;
namespace HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;
/// <summary>
/// 聊天记录表
/// </summary>
public partial class T_Chat: MultiTenantEntity
{
/// <summary>
/// 聊天id
/// </summary>
public int Id { get; set; }
/// <summary>
/// 聊天内容
/// </summary>
public int UserId { get; set; }
/// <summary>
/// 消息内容
/// </summary>
public string Content { get; set; } = null!;
/// <summary>
/// 发送时间
/// </summary>
public DateTime TimeStamp { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateTime { get; set; }
/// <summary>
/// 更新时间
/// </summary>
public DateTime UpdateTime { get; set; }
/// <summary>
/// 输入token
/// </summary>
public int Input_tokens { get; set; }
/// <summary>
/// 输出token
/// </summary>
public int Output_tokens { get; set; }
/// <summary>
/// 人物表Id
/// </summary>
public int CharacterId { get; set; }
/// <summary>
/// user/assistant
/// </summary>
public string Role { get; set; } = null!;
public Guid SessionId { get; set; }
/// <summary>
/// 发送消息,天
/// </summary>
public long SendDateDay { get; set; }
/// <summary>
/// 发送消息时间戳
/// </summary>
public long SendMessageDay { get; set; }
/// <summary>
/// 0正常1重新生成2 删除
/// </summary>
public int Type { get; set; }
/// <summary>
/// 聊天返回的消息的类型
/// </summary>
public string? ClaudeType { get; set; }
/// <summary>
/// 聊天返回的Id
/// </summary>
public string? ClaudeId { get; set; }
/// <summary>
/// 人物模型,聊天返回的模型
/// </summary>
public string? ClaudeModel { get; set; }
}

View File

@ -0,0 +1,26 @@

namespace HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;
/// <summary>
/// 图片表
/// </summary>
public partial class T_Image_Config: MultiTenantEntity
{
public int Id { get; set; }
/// <summary>
/// 图片Id
/// </summary>
public int ImageId { get; set; }
/// <summary>
/// 图片名称
/// </summary>
public string Name { get; set; } = null!;
/// <summary>
/// 图片地址
/// </summary>
public string Url { get; set; } = null!;
}

View File

@ -0,0 +1,49 @@
using System;
namespace HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;
public partial class T_Model_Config: MultiTenantEntity
{
public int Id { get; set; }
/// <summary>
/// 模型名称
/// </summary>
public string ModelName { get; set; } = null!;
/// <summary>
/// 模型model
/// </summary>
public string Model { get; set; } = null!;
/// <summary>
/// 模型运行最大的max_tokens
/// </summary>
public int MaxTokens { get; set; }
/// <summary>
/// 模型key x-api-key
/// </summary>
public string ApiKey { get; set; } = null!;
/// <summary>
/// 模型请求地址
/// </summary>
public string Url { get; set; } = null!;
/// <summary>
/// 模型版本 anthropic-version
/// </summary>
public string AnthropicVersion { get; set; } = null!;
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateTime { get; set; }
/// <summary>
/// 修改时间
/// </summary>
public DateTime UpdateTime { get; set; }
}

View File

@ -0,0 +1,49 @@
using System;
namespace HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;
public partial class T_User_Char: MultiTenantEntity
{
public int Id { get; set; }
/// <summary>
/// 会话Id
/// </summary>
public Guid SessionId { get; set; }
/// <summary>
/// 会话名称
/// </summary>
public string SessionName { get; set; } = null!;
/// <summary>
/// 角色Id
/// </summary>
public int CharacterId { get; set; }
/// <summary>
/// 使用模型Id
/// </summary>
public int ModelConfigId { get; set; }
/// <summary>
/// 用户Id
/// </summary>
public int UserId { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateAt { get; set; }
/// <summary>
/// 修改时间
/// </summary>
public DateTime UpdateAt { get; set; }
/// <summary>
/// 是否删除
/// </summary>
public bool IsDelete { get; set; }
}

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Model.Dto.Character
{
/// <summary>
/// 角色聊天次数
/// </summary>
public class CharacteChatCountModel
{
/// <summary>
/// 角色Id
/// </summary>
public int CharacterId { get; set; }
/// <summary>
/// 聊天次数
/// </summary>
public int UserCount { get; set; }
}
}

View File

@ -0,0 +1,45 @@
using AutoMapper;
using HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;
using HuanMeng.MiaoYu.Model.Dto.Label;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Model.Dto.Character
{
/// <summary>
/// 模型
/// </summary>
[AutoMap(typeof(T_Character))]
public class CharacterCache : T_Character
{
/// <summary>
/// 模型配置
/// </summary>
public T_Model_Config ModelConfig { get; set; }
/// <summary>
/// 多少人聊天过
/// </summary>
public int LookCount { get; set; }
/// <summary>
/// 背景图片
/// </summary>
public string BgImage { get; set; }
/// <summary>
/// 用户头像url
/// </summary>
public string IconImage { get; set; }
/// <summary>
/// 标签
/// </summary>
public List<LabelDto> Label { get; set; }
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Model.Dto.Character
{
/// <summary>
///
/// </summary>
public class RequestCharacterInfo
{
/// <summary>
/// 角色Id
/// </summary>
public int CharacterId { get; set; }
}
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Model.Dto.Character
{
/// <summary>
/// 请求参数
/// </summary>
public class RequestCharacterInfoPage
{
/// <summary>
/// 起始页
/// </summary>
public int? Index { get; set; } = 1;
/// <summary>
/// 页大小
/// </summary>
public int? Size { get; set; } = 10;
}
}

View File

@ -1,19 +1,31 @@
using AutoMapper;
using AutoMapper.Configuration.Annotations;
using HuanMeng.MiaoYu.Model.Dto.Character;
using HuanMeng.MiaoYu.Model.Dto.Label;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Model.Dto.Home
namespace HuanMeng.MiaoYu.Model.Dto.Chat
{
public class CharacterInfo
{
public List<CharacterInfoDto> CharacterInfos { get; set; }
}
/// <summary>
/// 用户和人物信息
/// </summary>
[AutoMap(typeof(CharacterCache))]
public class CharacterInfoDto
{
/// <summary>
/// 头像
/// </summary>
[SourceMember(nameof(CharacterCache.IconImage))]
public string Icon { get; set; }
/// <summary>
@ -24,16 +36,19 @@ namespace HuanMeng.MiaoYu.Model.Dto.Home
/// <summary>
/// 人物id
/// </summary>
[SourceMember(nameof(CharacterCache.Id))]
public int CharacterId { get; set; }
/// <summary>
/// 人物名称
/// </summary>
[SourceMember(nameof(CharacterCache.Name))]
public string CharacterName { get; set; }
/// <summary>
/// 性别
/// </summary>
public int Gender { get; set; }
/// <summary>
@ -44,11 +59,13 @@ namespace HuanMeng.MiaoYu.Model.Dto.Home
/// <summary>
/// 背景图片
/// </summary>
[SourceMember(nameof(CharacterCache.BgImage))]
public string BgUrl { get; set; }
/// <summary>
/// 简介
/// </summary>
public string Biography { get; set; }
/// <summary>
@ -59,22 +76,15 @@ namespace HuanMeng.MiaoYu.Model.Dto.Home
/// <summary>
/// 标签
/// </summary>
[SourceMember(nameof(CharacterCache.Label))]
public List<LabelDto> Label { get; set; }
/// <summary>
/// 余下聊天次数
/// </summary>
public int RemainingChatCount { get; set; }
//public int RemainingChatCount { get; set; }
}
/// <summary>
/// 人物角色标签
/// </summary>
public class LabelDto
{
public int Id { get; set; }
public string Name { get; set; }
}
/// <summary>
/// 聊天列表信息
@ -94,6 +104,36 @@ namespace HuanMeng.MiaoYu.Model.Dto.Home
/// </summary>
public class ChatListDto
{
/// <summary>
/// 聊天列表
/// </summary>
public List<ChatMessageDto> ChatList { get; set; }
}
/// <summary>
/// 删除聊天
/// </summary>
public class DelChat
{
/// <summary>
/// 聊天记录id
/// </summary>
public List<int> Id { get; set; }
/// <summary>
/// 人物id
/// </summary>
public int CharacterId { get; set; }
}
/// <summary>
/// 清空聊天记录
/// </summary>
public class DelChatList
{
/// <summary>
/// 人物id
/// </summary>
public int CharacterId { get; set; }
}
}

View File

@ -0,0 +1,32 @@
using AutoMapper;
using AutoMapper.Configuration.Annotations;
using HuanMeng.MiaoYu.Model.DbSqlServer.Db_MiaoYu;
using HuanMeng.MiaoYu.Model.Dto.Character;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Model.Dto.Label
{
/// <summary>
/// 人物角色标签
/// </summary>
[AutoMap(typeof(T_Character_Label))]
public class LabelDto
{
/// <summary>
///
/// </summary>
public int Id { get; set; }
/// <summary>
/// 标签名称
/// </summary>
[SourceMember(nameof(T_Character_Label.LabelName))]
public string Name { get; set; }
}
}

View File

@ -5,9 +5,11 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<AnalysisLevel>latest</AnalysisLevel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.6">
<PrivateAssets>all</PrivateAssets>

View File

@ -1,9 +0,0 @@
using System;
namespace HuanMeng.Utility
{
public class Class1
{
}
}

View File

@ -1,11 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace HuanMeng.MiaoYu.Code.Other
namespace HuanMeng.Utility
{
/// <summary>
/// 手机号

View File

@ -6,6 +6,7 @@ using HuanMeng.MiaoYu.Code.Users;
using HuanMeng.MiaoYu.Model.Dto;
using HuanMeng.MiaoYu.Model.Dto.Account;
using HuanMeng.MiaoYu.WebApi.Base;
using HuanMeng.Utility;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
@ -24,15 +25,17 @@ namespace HuanMeng.MiaoYu.WebApi.Controllers
[ApiController]
public class AccountController : MiaoYuControllerBase
{
public AccountController(IServiceProvider _serviceProvider) : base(_serviceProvider)
public AccountController(IServiceProvider _serviceProvider, ILogger<AccountController> logger) : base(_serviceProvider)
{
logger.LogInformation("aaaaa");
}
/// <summary>
/// 发送手机号验证码
/// 发送手机号验证码
/// </summary>
/// <param name="PhoneNumber">手机号</param>
/// <param name="phone"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
[HttpPost]
public async Task<BaseResponse<bool>> SendPhoneNumber([FromBody] RequestPhoneNumberModel phone)
{

View File

@ -1,45 +1,108 @@
using HuanMeng.DotNetCore.Base;
using HuanMeng.MiaoYu.Model.Dto.Home;
using HuanMeng.MiaoYu.Code.Character;
using HuanMeng.MiaoYu.Code.Chat;
using HuanMeng.MiaoYu.Model.Dto.Character;
using HuanMeng.MiaoYu.Model.Dto.Chat;
using HuanMeng.MiaoYu.WebApi.Base;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace HuanMeng.MiaoYu.WebApi.Controllers
{
/// <summary>
/// 首页聊天
/// </summary>
[Route("api/[controller]/[action]")]
[ApiController]
public class ChatController : MiaoYuControllerBase
{
private ChatBLL _chatBLL;
/// <summary>
///
/// </summary>
/// <param name="_serviceProvider"></param>
public ChatController(IServiceProvider _serviceProvider) : base(_serviceProvider)
{
_chatBLL = new ChatBLL(_serviceProvider);
}
/// <summary>
/// 获取人物信息
/// 获取角色Id
/// </summary>
/// <returns></returns>
[HttpGet]
[AllowAnonymous]
public async Task<BaseResponse<CharacterInfoDto>> GetCharacterInfo(int userId)
public BaseResponse<List<int>> GetCharacterIdList()
{
var obj = JsonConvert.DeserializeObject<CharacterInfoDto>("{\"Icon\":\"\",\"Intimacy\":10,\"CharacterId\":2,\"CharacterName\":\"许荷姻\",\"Gender\":1,\"LookCount\":2,\"BgUrl\":\"\",\"Biography\":\"你那商业联姻得来的妻子,原本的天才女孩,聪明伶俐,生的漂亮、端庄,不知贵圈多少人梦寐以求的存在。\",\"Prologue\":\"坐在轮椅上,眼神平静的看着你,语气也同样平静)你回来了。饭菜在桌上,我刚刚热了。(说到这,又垂下眸子道)我还做了碗醒酒汤,记得喝\",\"Label\":[{\"Id\":1,\"Name\":\"美女\"},{\"Id\":2,\"Name\":\"二次元\"}],\"RemainingChatCount\":1}");
CharacterBLL characterBLL = new CharacterBLL(ServiceProvider);
var obj = characterBLL.GetCharacters();
return obj;
}
/// <summary>
/// 获取角色人物信息
/// </summary>
/// <returns></returns>
[HttpGet]
[AllowAnonymous]
public async Task<BaseResponse<CharacterInfoDto>> GetCharacterInfo([FromQuery] RequestCharacterInfo requestCharacterInfo)
{
CharacterBLL characterBLL = new CharacterBLL(ServiceProvider);
var obj = await characterBLL.GetCharacterInfo(requestCharacterInfo);
return obj;
return new BaseResponse<CharacterInfoDto>(ResonseCode.Success, "", obj);
}
/// <summary>
/// 获取聊天列表信息
/// </summary>
/// <param name="userId"></param>
/// <param name="characterId"></param>
/// <returns></returns>
[HttpGet]
[AllowAnonymous]
public async Task<BaseResponse<ChatListDto>> GetChatInfo(int userId)
public async Task<BaseResponse<ChatListDto>> GetChatInfo(int characterId)
{
var obj = JsonConvert.DeserializeObject<ChatListDto>("{\"ChatList\":[{\"Id\":\"1\",\"Role\":\"user\",\"Content\":\"Hello, how are you?\",\"Timestamp\":\"2022-03-01 12:00:00 \",\"MessageType\":0,\"UserIcon\":\"\"},{\"Id\":\"2\",\"Role\":\"assistant\",\"Content\":\"I'm fine, thanks!\",\"Timestamp\":\"2022-03-01 12:05:00 \",\"UserIcon\":\"\"}]}");
return new BaseResponse<ChatListDto>(ResonseCode.Success, "", obj);
}
/// <summary>
/// 删除聊天记录
/// </summary>
/// <param name="delChat"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
[HttpPost]
[AllowAnonymous]
public async Task<BaseResponse<bool>> DelChatByIds([FromBody] DelChat delChat)
{
if (delChat.Id == null || delChat.CharacterId == 0)
{
throw new ArgumentNullException();
}
//ChatBLL chatBLL = new ChatBLL(ServiceProvider);
var obj = await _chatBLL.DelChatByIds(delChat.Id, delChat.CharacterId);
return new BaseResponse<bool>(ResonseCode.Success, "", obj);
}
/// <summary>
/// 清空聊天记录
/// </summary>
/// <param name="characterId">人物id</param>
/// <returns></returns>
[HttpPost]
[AllowAnonymous]
public async Task<BaseResponse<bool>> DelChat([FromBody] DelChatList delChatList)
{
//ChatBLL chatBLL = new ChatBLL(ServiceProvider);
var obj = await _chatBLL.DelChat(delChatList.CharacterId);
return new BaseResponse<bool>(ResonseCode.Success, "", obj);
}
}
}

View File

@ -11,6 +11,10 @@
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.6" />
<PackageReference Include="Serilog" Version="4.0.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>

View File

@ -10,8 +10,19 @@ using HuanMeng.MiaoYu.Code.JwtUtil;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using HuanMeng.Utility.AssemblyHelper;
using HuanMeng.DotNetCore.CustomExtension;
using HuanMeng.MiaoYu.Code.Cache;
using HuanMeng.MiaoYu.Code.Chat;
using Serilog;
using HuanMeng.MiaoYu.Model.Dto;
var builder = WebApplication.CreateBuilder(args);
//Log.Logger = new LoggerConfiguration()
// .WriteTo.Console()
// .WriteTo.File("../output/logs/log-.txt", rollingInterval: RollingInterval.Day)
// .CreateLogger();
builder.Host.UseSerilog((context, services, configuration) => configuration
.ReadFrom.Configuration(context.Configuration)
.ReadFrom.Services(services)
.Enrich.FromLogContext());
// 检索程序集信息
AssemblyInfo assemblyInfo = AssemblyInfoHelper.GetAssemblyInfo();
// Add services to the container.
@ -20,7 +31,20 @@ builder.Services.AddHttpContextAccessor(); //添加httpContext注入访问
var _myAllowSpecificOrigins = "_myAllowSpecificOrigins";
builder.Services.AddCustomCors(_myAllowSpecificOrigins);
#endregion
builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies().Where(it => it.FullName.Contains("HuanMeng") || it.FullName.Contains("XLib.")).ToList());
#region automap
var mapperDomain = AppDomain.CurrentDomain.GetAssemblies().Where(it => it.FullName.Contains("HuanMeng") || it.FullName.Contains("XLib.")).ToList();
Type type = typeof(ResponseUserInfo);
if (type != null)
{
Assembly assembly = Assembly.GetAssembly(type);
if (!mapperDomain.Any(it => it.FullName == assembly.FullName))
{
mapperDomain.Add(assembly);
}
}
builder.Services.AddAutoMapper(mapperDomain);
#endregion
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
@ -71,6 +95,9 @@ builder.AddTencent();
builder.AddMemoryVerificationCode();
//添加jwt验证
builder.AddJwtConfig();
//builder.Services.AddMemoryCache();
//builder.Services.AddScoped<CharacterInfoBaseCache>();
////builder.Services.AddScoped<ChatBLL>();
var app = builder.Build();
// Configure the HTTP request pipeline.
@ -85,10 +112,10 @@ app.UseSwaggerUI(c =>
c.DefaultModelExpandDepth(3);
c.EnableFilter("true");
//c.RoutePrefix = string.Empty;
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Your API V1");
c.SwaggerEndpoint("/swagger/v1/swagger.json", "寰梦 API V1");
});
//}
app.UseSerilogRequestLogging();
app.UseAuthorization();
//自定义初始化
//使用跨域

View File

@ -8,6 +8,27 @@
"Microsoft.AspNetCore": "Warning"
}
},
"Serilog": {
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{ "Name": "Console" },
{
"Name": "File",
"Args": {
"path": "../output/logs/log-.txt",
"rollingInterval": "Day"
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
},
//
"TencentCloud": {
"SecretId": "AKIDLbhdP0Vs57yd7QZWu8A2jFbno8JKBUp6",

View File

@ -7,7 +7,7 @@ var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddHttpContextAccessor(); //添加httpContext注入访问
builder.Services.AddControllers();
builder.Services.AddHttpClient();
//注入数据库
builder.Services.AddDbContext<TextGenerationTestContext>((options) =>
{