Browse Source

feat: Rename UserMessage to ChatMessage

pull/1421/head
colin 2 months ago
parent
commit
3ab9926bfc
  1. 82
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Agent/LINGYUN/Abp/AI/Agent/AgentService.cs
  2. 2
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Agent/LINGYUN/Abp/AI/Agent/IAgentService.cs
  3. 1
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN.Abp.AI.Core.csproj
  4. 11
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Chats/IChatMessageStore.cs
  5. 52
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Chats/InMemoryChatMessageStore.cs
  6. 11
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Messages/IUserMessageStore.cs
  7. 46
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Messages/InMemoryUserMessageStore.cs
  8. 53
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Models/ChatMessage.cs
  9. 25
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Models/TextChatMessage.cs
  10. 34
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Models/TokenUsageInfo.cs
  11. 53
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Models/UserMessage.cs
  12. 20
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Models/UserTextMessage.cs
  13. 3
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Tokens/ITokenUsageStore.cs
  14. 31
      aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Tokens/InMemoryTokenUsageStore.cs
  15. 6
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Chats/ChatMessageRecordConsts.cs
  16. 5
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Chats/TextChatMessageRecordConsts.cs
  17. 5
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Messages/UserMessageRecordConsts.cs
  18. 5
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Messages/UserTextMessageRecordConsts.cs
  19. 6
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/AbpAIManagementDomainMappers.cs
  20. 57
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/ChatMessageRecord.cs
  21. 41
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/ChatMessageStore.cs
  22. 6
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/ITextChatMessageRecordRepository.cs
  23. 31
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/TextChatMessageRecord.cs
  24. 69
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Messages/UserMessageRecord.cs
  25. 27
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Messages/UserTextMessageRecord.cs
  26. 2
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Settings/AIManagementSettingDefinitionProvider.cs
  27. 2
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Settings/AIManagementSettingNames.cs
  28. 4
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Tokens/TokenUsageRecord.cs
  29. 56
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.EntityFrameworkCore/LINGYUN/Abp/AIManagement/EntityFrameworkCore/AIManagementDbContextModelBuilderExtensions.cs
  30. 4
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.EntityFrameworkCore/LINGYUN/Abp/AIManagement/EntityFrameworkCore/AbpAIManagementEntityFrameworkCoreModule.cs
  31. 9
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.EntityFrameworkCore/LINGYUN/Abp/AIManagement/EntityFrameworkCore/EfCoreTextChatMessageRecordRepository.cs
  32. 11
      aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.EntityFrameworkCore/LINGYUN/Abp/AIManagement/EntityFrameworkCore/ValueConversions/ChatRoleValueConverter.cs

82
aspnet-core/modules/ai/LINGYUN.Abp.AI.Agent/LINGYUN/Abp/AI/Agent/AgentService.cs

@ -1,6 +1,7 @@
using LINGYUN.Abp.AI.Messages;
using LINGYUN.Abp.AI.Chats;
using LINGYUN.Abp.AI.Models;
using LINGYUN.Abp.AI.Tokens;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using System;
using System.Collections.Generic;
@ -8,24 +9,29 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Timing;
using AIChatMessage = Microsoft.Extensions.AI.ChatMessage;
namespace LINGYUN.Abp.AI.Agent;
public class AgentService : IAgentService, IScopedDependency
{
private readonly IClock _clock;
private readonly IAgentFactory _agentFactory;
private readonly ITokenUsageStore _tokenUsageStore;
private readonly IUserMessageStore _userMessageStore;
private readonly IChatMessageStore _chatMessageStore;
public AgentService(
IClock clock,
IAgentFactory agentFactory,
ITokenUsageStore tokenUsageStore,
IUserMessageStore userMessageStore)
IChatMessageStore chatMessageStore)
{
_clock = clock;
_agentFactory = agentFactory;
_tokenUsageStore = tokenUsageStore;
_userMessageStore = userMessageStore;
_chatMessageStore = chatMessageStore;
}
public async virtual IAsyncEnumerable<string> SendMessageAsync(UserMessage message)
public async virtual IAsyncEnumerable<string> SendMessageAsync(Models.ChatMessage message)
{
var messages = await BuildChatMessages(message);
@ -33,62 +39,70 @@ public class AgentService : IAgentService, IScopedDependency
var agentRunRes = agent.RunStreamingAsync(messages);
var tokenUsageInfo = new TokenUsageInfo(message.Workspace);
var agentMessageBuilder = new StringBuilder();
await foreach (var item in agentRunRes)
await foreach (var response in agentRunRes)
{
agentMessageBuilder.Append(item);
yield return item.Text;
await StoreTokenUsageInfo(message, item.RawRepresentation);
UpdateTokenUsageInfo(tokenUsageInfo, response);
agentMessageBuilder.Append(response.Text);
yield return response.Text;
}
await StoreChatMessage(message, agentMessageBuilder.ToString());
var messageId = await StoreChatMessage(message, agentMessageBuilder.ToString());
tokenUsageInfo.WithConversationId(message.ConversationId);
tokenUsageInfo.WithMessageId(messageId);
Console.WriteLine();
Console.WriteLine($"消耗Token: {tokenUsageInfo}");
await StoreTokenUsageInfo(tokenUsageInfo);
}
protected virtual async Task<IEnumerable<ChatMessage>> BuildChatMessages(UserMessage message)
protected virtual async Task<IEnumerable<AIChatMessage>> BuildChatMessages(Models.ChatMessage message)
{
var messages = new List<ChatMessage>();
var messages = new List<AIChatMessage>();
if (!message.ConversationId.IsNullOrWhiteSpace())
{
var historyMessages = await _userMessageStore.GetHistoryMessagesAsync(message.ConversationId);
var historyMessages = await _chatMessageStore.GetHistoryMessagesAsync(message.ConversationId);
foreach (var chatMessage in historyMessages)
{
messages.Add(new ChatMessage(ChatRole.System, chatMessage.GetMessagePrompt()));
messages.Add(new AIChatMessage(ChatRole.System, chatMessage.GetMessagePrompt()));
}
}
messages.Add(new ChatMessage(ChatRole.User, message.GetMessagePrompt()));
messages.Add(new AIChatMessage(ChatRole.User, message.GetMessagePrompt()));
return messages;
}
protected async virtual Task StoreChatMessage(UserMessage message, string agentMessage)
protected async virtual Task<string> StoreChatMessage(Models.ChatMessage message, string agentMessage)
{
message.WithReply(agentMessage);
message.WithReply(agentMessage, _clock.Now);
await _userMessageStore.SaveMessageAsync(message);
return await _chatMessageStore.SaveMessageAsync(message);
}
protected async virtual Task StoreTokenUsageInfo(UserMessage message, object? rawRepresentation)
protected async virtual Task StoreTokenUsageInfo(TokenUsageInfo tokenUsageInfo)
{
if (rawRepresentation is ChatResponseUpdate update)
await _tokenUsageStore.SaveTokenUsageAsync(tokenUsageInfo);
}
private static void UpdateTokenUsageInfo(TokenUsageInfo tokenUsageInfo, AgentRunResponseUpdate response)
{
if (response.RawRepresentation != null &&
response.RawRepresentation is ChatResponseUpdate update)
{
var tokenUsageInfos = update.Contents
.OfType<UsageContent>()
.Where(usage => usage.Details != null)
.Select(usage => new TokenUsageInfo(message.Workspace)
{
TotalTokenCount = usage.Details.TotalTokenCount,
CachedInputTokenCount = usage.Details.CachedInputTokenCount,
InputTokenCount = usage.Details.InputTokenCount,
OutputTokenCount = usage.Details.OutputTokenCount,
ReasoningTokenCount = usage.Details.ReasoningTokenCount,
});
await _tokenUsageStore.SaveTokenUsagesAsync(tokenUsageInfos);
var usageContents = update.Contents.OfType<UsageContent>();
tokenUsageInfo.InputTokenCount = usageContents.Max(x => x.Details.InputTokenCount);
tokenUsageInfo.OutputTokenCount = usageContents.Max(x => x.Details.OutputTokenCount);
tokenUsageInfo.TotalTokenCount = usageContents.Max(x => x.Details.TotalTokenCount);
tokenUsageInfo.ReasoningTokenCount = usageContents.Max(x => x.Details.ReasoningTokenCount);
tokenUsageInfo.CachedInputTokenCount = usageContents.Max(x => x.Details.CachedInputTokenCount);
}
}
}

2
aspnet-core/modules/ai/LINGYUN.Abp.AI.Agent/LINGYUN/Abp/AI/Agent/IAgentService.cs

@ -4,5 +4,5 @@ using System.Collections.Generic;
namespace LINGYUN.Abp.AI.Agent;
public interface IAgentService
{
IAsyncEnumerable<string> SendMessageAsync(UserMessage message);
IAsyncEnumerable<string> SendMessageAsync(ChatMessage message);
}

1
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN.Abp.AI.Core.csproj

@ -22,6 +22,7 @@
<ItemGroup>
<PackageReference Include="Volo.Abp.AI" />
<PackageReference Include="Volo.Abp.Localization" />
<PackageReference Include="Volo.Abp.Timing" />
</ItemGroup>
</Project>

11
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Chats/IChatMessageStore.cs

@ -0,0 +1,11 @@
using LINGYUN.Abp.AI.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LINGYUN.Abp.AI.Chats;
public interface IChatMessageStore
{
Task<string> SaveMessageAsync(ChatMessage message);
Task<IEnumerable<ChatMessage>> GetHistoryMessagesAsync(string conversationId);
}

52
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Chats/InMemoryChatMessageStore.cs

@ -0,0 +1,52 @@
using LINGYUN.Abp.AI.Models;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.AI.Chats;
[Dependency(ServiceLifetime.Singleton, TryRegister = true)]
public class InMemoryChatMessageStore : IChatMessageStore
{
private static readonly ConcurrentDictionary<string, List<ChatMessage>> _userMessageCache = new ConcurrentDictionary<string, List<ChatMessage>>();
public Task<IEnumerable<ChatMessage>> GetHistoryMessagesAsync(string conversationId)
{
var messages = new List<ChatMessage>();
foreach (var userMessages in _userMessageCache.Values)
{
messages.AddRange(userMessages.Where(x => x.ConversationId == conversationId));
}
return Task.FromResult<IEnumerable<ChatMessage>>(
messages
.OrderByDescending(x => x.CreatedAt)
.Take(5)
.OrderBy(x => x.CreatedAt));
}
public Task<string> SaveMessageAsync(ChatMessage message)
{
var messageId = message.Id;
if (messageId.IsNullOrWhiteSpace())
{
messageId = Guid.NewGuid().ToString();
message.WithMessageId(messageId);
}
if (_userMessageCache.ContainsKey(messageId))
{
_userMessageCache[messageId].Add(message);
}
else
{
_userMessageCache[messageId] = new List<ChatMessage>() { message };
}
return Task.FromResult(messageId);
}
}

11
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Messages/IUserMessageStore.cs

@ -1,11 +0,0 @@
using LINGYUN.Abp.AI.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LINGYUN.Abp.AI.Messages;
public interface IUserMessageStore
{
Task<string> SaveMessageAsync(UserMessage message);
Task<IEnumerable<UserMessage>> GetHistoryMessagesAsync(string conversationId);
}

46
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Messages/InMemoryUserMessageStore.cs

@ -1,46 +0,0 @@
using LINGYUN.Abp.AI.Models;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.AI.Messages;
[Dependency(ServiceLifetime.Singleton, TryRegister = true)]
public class InMemoryUserMessageStore : IUserMessageStore
{
private static readonly ConcurrentDictionary<string, List<UserMessage>> _userMessageCache = new ConcurrentDictionary<string, List<UserMessage>>();
public Task<IEnumerable<UserMessage>> GetHistoryMessagesAsync(string conversationId)
{
if (_userMessageCache.TryGetValue(conversationId, out var messages))
{
return Task.FromResult(messages.Take(5));
}
return Task.FromResult<IEnumerable<UserMessage>>(Array.Empty<UserMessage>());
}
public Task<string> SaveMessageAsync(UserMessage message)
{
var messageId = message.Id;
if (messageId.IsNullOrWhiteSpace())
{
messageId = Guid.NewGuid().ToString();
message.WithMessageId(messageId);
}
if (_userMessageCache.ContainsKey(messageId))
{
_userMessageCache[messageId].Add(message);
}
else
{
_userMessageCache[messageId] = new List<UserMessage>() { message };
}
return Task.FromResult(messageId);
}
}

53
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Models/ChatMessage.cs

@ -0,0 +1,53 @@
using Microsoft.Extensions.AI;
using System;
namespace LINGYUN.Abp.AI.Models;
public abstract class ChatMessage
{
public string Workspace { get; }
public string? Id { get; private set; }
public string? ConversationId { get; private set; }
public string? ReplyMessage { get; private set; }
public DateTime? ReplyAt { get; private set; }
public ChatRole Role { get; private set; }
public DateTime CreatedAt { get; private set; }
protected ChatMessage(
string workspace,
ChatRole? role = null,
DateTime? createdAt = null)
{
Workspace = workspace;
Role = role ?? ChatRole.User;
CreatedAt = createdAt ?? DateTime.Now;
}
public virtual ChatMessage WithMessageId(string id)
{
Id = id;
return this;
}
public virtual ChatMessage WithConversationId(string conversationId)
{
ConversationId = conversationId;
return this;
}
public virtual ChatMessage WithReply(string replyMessage, DateTime replyAt)
{
ReplyMessage = replyMessage;
ReplyAt = replyAt;
return this;
}
public virtual string GetMessagePrompt()
{
return string.Empty;
}
}

25
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Models/TextChatMessage.cs

@ -0,0 +1,25 @@
using Microsoft.Extensions.AI;
using System;
namespace LINGYUN.Abp.AI.Models;
public class TextChatMessage : ChatMessage
{
/// <summary>
/// 消息内容
/// </summary>
public string Content { get; }
public TextChatMessage(
string workspace,
string content,
ChatRole? role = null,
DateTime? createdAt = null)
: base(workspace, role, createdAt)
{
Content = content;
}
public override string GetMessagePrompt()
{
return Content;
}
}

34
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Models/TokenUsageInfo.cs

@ -1,7 +1,11 @@
namespace LINGYUN.Abp.AI.Models;
using System.Text;
namespace LINGYUN.Abp.AI.Models;
public class TokenUsageInfo
{
public string Workspace { get; }
public string? MessageId { get; private set; }
public string? ConversationId { get; private set; }
public long? InputTokenCount { get; set; }
public long? OutputTokenCount { get; set; }
public long? TotalTokenCount { get; set; }
@ -11,4 +15,32 @@ public class TokenUsageInfo
{
Workspace = workspace;
}
public virtual TokenUsageInfo WithMessageId(string id)
{
MessageId = id;
return this;
}
public virtual TokenUsageInfo WithConversationId(string? conversationId)
{
ConversationId = conversationId;
return this;
}
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendLine("---------------------- TokenUsage Begin ----------------------");
sb.AppendLine($"====== Workspace - {Workspace}");
sb.AppendLine($"====== MessageId - {MessageId}");
sb.AppendLine($"====== ConversationId - {ConversationId}");
sb.AppendLine($"====== InputTokenCount - {InputTokenCount}");
sb.AppendLine($"====== OutputTokenCount - {OutputTokenCount}");
sb.AppendLine($"====== TotalTokenCount - {TotalTokenCount}");
sb.AppendLine($"====== ReasoningTokenCount - {ReasoningTokenCount}");
sb.AppendLine("---------------------- TokenUsage End ----------------------");
return sb.ToString();
}
}

53
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Models/UserMessage.cs

@ -1,53 +0,0 @@
namespace LINGYUN.Abp.AI.Models;
public abstract class UserMessage
{
/// <summary>
/// 工作区
/// </summary>
public string Workspace { get; }
/// <summary>
/// 消息Id
/// </summary>
/// <remarks>
/// 在持久化设施处更新
/// </remarks>
public string? Id { get; private set; }
/// <summary>
/// 对话Id
/// </summary>
/// <remarks>
/// 用于从客户端存储中持久化和检索聊天历史的唯一标识符,如果未指定则与AI对话时无上下文关联
/// </remarks>
public string? ConversationId { get; private set; }
/// <summary>
/// AI回复消息
/// </summary>
public string ReplyMessage { get; private set; }
protected UserMessage(string workspace)
{
Workspace = workspace;
}
public virtual UserMessage WithMessageId(string id)
{
Id = id;
return this;
}
public virtual UserMessage WithConversationId(string conversationId)
{
ConversationId = conversationId;
return this;
}
public virtual UserMessage WithReply(string replyMessage)
{
ReplyMessage = replyMessage;
return this;
}
public virtual string GetMessagePrompt()
{
return string.Empty;
}
}

20
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Models/UserTextMessage.cs

@ -1,20 +0,0 @@
namespace LINGYUN.Abp.AI.Models;
public class UserTextMessage : UserMessage
{
/// <summary>
/// 消息内容
/// </summary>
public string Content { get; }
public UserTextMessage(
string workspace,
string content)
: base(workspace)
{
Content = content;
}
public override string GetMessagePrompt()
{
return Content;
}
}

3
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Tokens/ITokenUsageStore.cs

@ -1,9 +1,8 @@
using LINGYUN.Abp.AI.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LINGYUN.Abp.AI.Tokens;
public interface ITokenUsageStore
{
Task SaveTokenUsagesAsync(IEnumerable<TokenUsageInfo> usageInfos);
Task SaveTokenUsageAsync(TokenUsageInfo tokenUsageInfo);
}

31
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Tokens/InMemoryTokenUsageStore.cs

@ -2,7 +2,6 @@
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
@ -11,31 +10,19 @@ namespace LINGYUN.Abp.AI.Tokens;
[Dependency(ServiceLifetime.Singleton, TryRegister = true)]
public class InMemoryTokenUsageStore : ITokenUsageStore
{
private static readonly ConcurrentDictionary<string, TokenUsageInfo> _tokenUsageCache = new ConcurrentDictionary<string, TokenUsageInfo>();
private static readonly ConcurrentDictionary<string, List<TokenUsageInfo>> _tokenUsageCache = new ConcurrentDictionary<string, List<TokenUsageInfo>>();
public Task SaveTokenUsagesAsync(IEnumerable<TokenUsageInfo> usageInfos)
public Task SaveTokenUsageAsync(TokenUsageInfo tokenUsageInfo)
{
foreach (var usageInfo in usageInfos.GroupBy(x => x.Workspace))
if (_tokenUsageCache.TryGetValue(tokenUsageInfo.Workspace, out var tokenUsageInfos))
{
var tokenUsageInfo = new TokenUsageInfo(usageInfo.Key)
{
InputTokenCount = usageInfo.Sum(x => x.InputTokenCount),
TotalTokenCount = usageInfo.Sum(x => x.TotalTokenCount),
OutputTokenCount = usageInfo.Sum(x => x.OutputTokenCount),
ReasoningTokenCount = usageInfo.Sum(x => x.ReasoningTokenCount),
CachedInputTokenCount = usageInfo.Sum(x => x.CachedInputTokenCount),
};
if (!_tokenUsageCache.ContainsKey(usageInfo.Key))
{
_tokenUsageCache.TryAdd(usageInfo.Key, tokenUsageInfo);
}
else
{
_tokenUsageCache[usageInfo.Key] = tokenUsageInfo;
}
tokenUsageInfos.Add(tokenUsageInfo);
}
else
{
_tokenUsageCache.TryAdd(tokenUsageInfo.Workspace, [tokenUsageInfo]);
}
return Task.CompletedTask;
}
}

6
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Chats/ChatMessageRecordConsts.cs

@ -0,0 +1,6 @@
namespace LINGYUN.Abp.AIManagement.Chats;
public static class ChatMessageRecordConsts
{
public static int MaxConversationIdLength { get; set; } = 64;
public static int MaxChatRoleLength { get; set; } = 20;
}

5
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Chats/TextChatMessageRecordConsts.cs

@ -0,0 +1,5 @@
namespace LINGYUN.Abp.AIManagement.Chats;
public static class TextChatMessageRecordConsts
{
public static int MaxContentLength { get; set; } = 1024;
}

5
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Messages/UserMessageRecordConsts.cs

@ -1,5 +0,0 @@
namespace LINGYUN.Abp.AIManagement.Messages;
public static class UserMessageRecordConsts
{
public static int MaxConversationIdLength { get; set; } = 64;
}

5
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain.Shared/LINGYUN/Abp/AIManagement/Messages/UserTextMessageRecordConsts.cs

@ -1,5 +0,0 @@
namespace LINGYUN.Abp.AIManagement.Messages;
public static class UserTextMessageRecordConsts
{
public static int MaxContentLength { get; set; } = 1024;
}

6
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/AbpAIManagementDomainMappers.cs

@ -8,8 +8,8 @@ namespace LINGYUN.Abp.AIManagement;
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
[MapExtraProperties(DefinitionChecks = MappingPropertyDefinitionChecks.None)]
public partial class UserTextMessageRecordToUserTextMessageMapper : MapperBase<UserTextMessageRecord, UserTextMessage>
public partial class UserTextMessageRecordToUserTextMessageMapper : MapperBase<UserTextMessageRecord, TextChatMessage>
{
public override partial UserTextMessage Map(UserTextMessageRecord source);
public override partial void Map(UserTextMessageRecord source, UserTextMessage destination);
public override partial TextChatMessage Map(UserTextMessageRecord source);
public override partial void Map(UserTextMessageRecord source, TextChatMessage destination);
}

57
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/ChatMessageRecord.cs

@ -0,0 +1,57 @@
using Microsoft.Extensions.AI;
using System;
using Volo.Abp;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.AIManagement.Chats;
public abstract class ChatMessageRecord : AuditedAggregateRoot<Guid>, IMultiTenant
{
public Guid? TenantId { get; private set; }
public string Workspace { get; private set; }
public ChatRole Role { get; private set; }
public DateTime CreatedAt { get; private set; }
public string? ConversationId { get; private set; }
public string? ReplyMessage { get; private set; }
public DateTime? ReplyAt { get; private set; }
protected ChatMessageRecord()
{
ExtraProperties = new ExtraPropertyDictionary();
this.SetDefaultsForExtraProperties();
}
public ChatMessageRecord(
Guid id,
string workspace,
ChatRole role,
DateTime createdAt,
Guid? tenantId = null)
: base(id)
{
Workspace = workspace;
Role = role;
CreatedAt = createdAt;
TenantId = tenantId;
}
public virtual ChatMessageRecord SetConversationId(string conversationId)
{
ConversationId = Check.NotNullOrWhiteSpace(conversationId, nameof(conversationId), ChatMessageRecordConsts.MaxConversationIdLength);
return this;
}
public virtual ChatMessageRecord SetReply(string replyMessage, DateTime? replyAt)
{
ReplyMessage = replyMessage;
ReplyAt = replyAt;
return this;
}
}

41
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Messages/UserMessageStore.cs → aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/ChatMessageStore.cs

@ -1,4 +1,4 @@
using LINGYUN.Abp.AI.Messages;
using LINGYUN.Abp.AI.Chats;
using LINGYUN.Abp.AI.Models;
using LINGYUN.Abp.AIManagement.Settings;
using System;
@ -10,23 +10,23 @@ using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectMapping;
using Volo.Abp.Settings;
namespace LINGYUN.Abp.AIManagement.Messages;
namespace LINGYUN.Abp.AIManagement.Chats;
[Dependency(ReplaceServices = true)]
public class UserMessageStore : IUserMessageStore, ITransientDependency
public class ChatMessageStore : IChatMessageStore, ITransientDependency
{
private readonly ICurrentTenant _currentTenant;
private readonly IGuidGenerator _guidGenerator;
private readonly ISettingProvider _settingProvider;
private readonly IObjectMapper<AbpAIManagementDomainModule> _objectMapper;
private readonly IUserTextMessageRecordRepository _messageRecordRepository;
private readonly ITextChatMessageRecordRepository _messageRecordRepository;
public UserMessageStore(
public ChatMessageStore(
ICurrentTenant currentTenant,
IGuidGenerator guidGenerator,
ISettingProvider settingProvider,
IObjectMapper<AbpAIManagementDomainModule> objectMapper,
IUserTextMessageRecordRepository messageRecordRepository)
ITextChatMessageRecordRepository messageRecordRepository)
{
_currentTenant = currentTenant;
_guidGenerator = guidGenerator;
@ -35,20 +35,21 @@ public class UserMessageStore : IUserMessageStore, ITransientDependency
_messageRecordRepository = messageRecordRepository;
}
public async virtual Task<IEnumerable<UserMessage>> GetHistoryMessagesAsync(string conversationId)
public async virtual Task<IEnumerable<ChatMessage>> GetHistoryMessagesAsync(string conversationId)
{
var maxLatestHistoryMessagesToKeep = await _settingProvider.GetAsync(AIManagementSettingNames.UserMessage.MaxLatestHistoryMessagesToKeep, 0);
var maxLatestHistoryMessagesToKeep = await _settingProvider.GetAsync(
AIManagementSettingNames.ChatMessage.MaxLatestHistoryMessagesToKeep, 0);
if (maxLatestHistoryMessagesToKeep < 1)
{
return Array.Empty<UserMessage>();
return Array.Empty<ChatMessage>();
}
var userTextMessages = await _messageRecordRepository.GetHistoryMessagesAsync(conversationId, maxLatestHistoryMessagesToKeep);
return _objectMapper.Map<IEnumerable<UserTextMessageRecord>, IEnumerable<UserTextMessage>>(userTextMessages);
return _objectMapper.Map<IEnumerable<TextChatMessageRecord>, IEnumerable<TextChatMessage>>(userTextMessages);
}
public async virtual Task<string> SaveMessageAsync(UserMessage message)
public async virtual Task<string> SaveMessageAsync(ChatMessage message)
{
var messageId = message.Id;
if (messageId.IsNullOrWhiteSpace())
@ -62,25 +63,27 @@ public class UserMessageStore : IUserMessageStore, ITransientDependency
return messageId;
}
protected async virtual Task StoreMessageAsync(Guid messageId, UserMessage message)
protected async virtual Task StoreMessageAsync(Guid messageId, ChatMessage message)
{
switch (message)
{
case UserTextMessage textMessage:
case TextChatMessage textMessage:
await StoreUserTextMessageAsync(messageId, textMessage);
break;
}
}
protected async virtual Task StoreUserTextMessageAsync(Guid messageId, UserTextMessage textMessage)
protected async virtual Task StoreUserTextMessageAsync(Guid messageId, TextChatMessage textMessage)
{
var textMessageRecord = await _messageRecordRepository.FindAsync(messageId);
if (textMessageRecord == null)
{
textMessageRecord = new UserTextMessageRecord(
textMessageRecord = new TextChatMessageRecord(
messageId,
textMessage.Workspace,
textMessage.Content,
textMessage.Role,
textMessage.CreatedAt,
_currentTenant.Id);
UpdateUserMessageRecord(textMessageRecord, textMessage);
@ -89,7 +92,7 @@ public class UserMessageStore : IUserMessageStore, ITransientDependency
}
else
{
textMessageRecord.WithContent(textMessage.Content);
textMessageRecord.SetContent(textMessage.Content);
UpdateUserMessageRecord(textMessageRecord, textMessage);
@ -97,15 +100,15 @@ public class UserMessageStore : IUserMessageStore, ITransientDependency
}
}
private static void UpdateUserMessageRecord(UserMessageRecord messageRecord, UserMessage message)
private static void UpdateUserMessageRecord(ChatMessageRecord messageRecord, ChatMessage message)
{
if (!message.ConversationId.IsNullOrWhiteSpace())
{
messageRecord.WithConversationId(message.ConversationId);
messageRecord.SetConversationId(message.ConversationId);
}
if (!message.ReplyMessage.IsNullOrWhiteSpace())
{
messageRecord.WithConversationId(message.ReplyMessage);
messageRecord.SetReply(message.ReplyMessage, message.ReplyAt);
}
}
}

6
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Messages/IUserTextMessageRecordRepository.cs → aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/ITextChatMessageRecordRepository.cs

@ -4,10 +4,10 @@ using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
namespace LINGYUN.Abp.AIManagement.Messages;
public interface IUserTextMessageRecordRepository : IBasicRepository<UserTextMessageRecord, Guid>
namespace LINGYUN.Abp.AIManagement.Chats;
public interface ITextChatMessageRecordRepository : IBasicRepository<TextChatMessageRecord, Guid>
{
Task<IEnumerable<UserTextMessageRecord>> GetHistoryMessagesAsync(
Task<IEnumerable<TextChatMessageRecord>> GetHistoryMessagesAsync(
string conversationId,
int maxResultCount = 0,
CancellationToken cancellationToken = default);

31
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/TextChatMessageRecord.cs

@ -0,0 +1,31 @@
using Microsoft.Extensions.AI;
using System;
using Volo.Abp;
namespace LINGYUN.Abp.AIManagement.Chats;
public class TextChatMessageRecord : ChatMessageRecord
{
public string Content { get; private set; }
public TextChatMessageRecord()
{
}
public TextChatMessageRecord(
Guid id,
string workspace,
string content,
ChatRole role,
DateTime createdAt,
Guid? tenantId = null)
: base(id, workspace, role, createdAt, tenantId)
{
SetContent(content);
}
public virtual TextChatMessageRecord SetContent(string content)
{
Content = Check.NotNullOrWhiteSpace(content, nameof(content), TextChatMessageRecordConsts.MaxContentLength);
return this;
}
}

69
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Messages/UserMessageRecord.cs

@ -1,69 +0,0 @@
using LINGYUN.Abp.AIManagement.Workspaces;
using System;
using Volo.Abp;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.AIManagement.Messages;
public abstract class UserMessageRecord : AuditedAggregateRoot<Guid>, IMultiTenant
{
public Guid? TenantId { get; private set; }
public string Workspace { get; private set; }
public string? ConversationId { get; private set; }
public string? ReplyMessage { get; private set; }
protected UserMessageRecord()
{
ExtraProperties = new ExtraPropertyDictionary();
this.SetDefaultsForExtraProperties();
}
public UserMessageRecord(
Guid id,
string workspace,
Guid? tenantId = null)
: base(id)
{
TenantId = tenantId;
Workspace = workspace;
}
public virtual UserMessageRecord WithConversationId(string conversationId)
{
ConversationId = Check.NotNullOrWhiteSpace(conversationId, nameof(conversationId), UserMessageRecordConsts.MaxConversationIdLength);
return this;
}
public virtual UserMessageRecord WithReply(string replyMessage)
{
ReplyMessage = replyMessage;
return this;
}
public void Patch(UserMessageRecord otherMessage)
{
if (ConversationId != otherMessage.ConversationId)
{
ConversationId = otherMessage.ConversationId;
}
if (ReplyMessage != otherMessage.ReplyMessage)
{
ReplyMessage = otherMessage.ReplyMessage;
}
if (!this.HasSameExtraProperties(otherMessage))
{
ExtraProperties.Clear();
foreach (var property in otherMessage.ExtraProperties)
{
ExtraProperties.Add(property.Key, property.Value);
}
}
}
}

27
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Messages/UserTextMessageRecord.cs

@ -1,27 +0,0 @@
using System;
using Volo.Abp;
namespace LINGYUN.Abp.AIManagement.Messages;
public class UserTextMessageRecord : UserMessageRecord
{
public string Content { get; private set; }
public UserTextMessageRecord()
{
}
public UserTextMessageRecord(
Guid id,
string workspace,
string content,
Guid? tenantId = null) : base(id, workspace, tenantId)
{
WithContent(content);
}
public virtual UserTextMessageRecord WithContent(string content)
{
Content = Check.NotNullOrWhiteSpace(content, nameof(content), UserTextMessageRecordConsts.MaxContentLength);
return this;
}
}

2
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Settings/AIManagementSettingDefinitionProvider.cs

@ -9,7 +9,7 @@ public class AIManagementSettingDefinitionProvider : SettingDefinitionProvider
{
context.Add(
new SettingDefinition(
AIManagementSettingNames.UserMessage.MaxLatestHistoryMessagesToKeep,
AIManagementSettingNames.ChatMessage.MaxLatestHistoryMessagesToKeep,
defaultValue: "5",
displayName: L("DisplayName:MaxLatestHistoryMessagesToKeep"),
description: L("Description:MaxLatestHistoryMessagesToKeep")));

2
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Settings/AIManagementSettingNames.cs

@ -3,7 +3,7 @@ public static class AIManagementSettingNames
{
public const string Prefix = "Abp.AIManagement";
public static class UserMessage
public static class ChatMessage
{
public const string MaxLatestHistoryMessagesToKeep = Prefix + ".MaxLatestHistoryMessagesToKeep";
}

4
aspnet-core/modules/ai/LINGYUN.Abp.AI.Core/LINGYUN/Abp/AI/Models/ChatMessageInfo.cs → aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Tokens/TokenUsageRecord.cs

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Text;
namespace LINGYUN.Abp.AI.Models;
internal class ChatMessageInfo
namespace LINGYUN.Abp.AIManagement.Tokens;
public class TokenUsageRecord
{
}

56
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.EntityFrameworkCore/LINGYUN/Abp/AIManagement/EntityFrameworkCore/AIManagementDbContextModelBuilderExtensions.cs

@ -1,5 +1,6 @@
using JetBrains.Annotations;
using LINGYUN.Abp.AIManagement.Messages;
using LINGYUN.Abp.AIManagement.Chats;
using LINGYUN.Abp.AIManagement.EntityFrameworkCore.ValueConversions;
using LINGYUN.Abp.AIManagement.Workspaces;
using Microsoft.EntityFrameworkCore;
using Volo.Abp;
@ -13,15 +14,24 @@ public static class AIManagementDbContextModelBuilderExtensions
{
Check.NotNull(builder, nameof(builder));
builder.Entity<UserTextMessageRecord>(b =>
builder.Entity<TextChatMessageRecord>(b =>
{
b.ToTable(AbpAIManagementDbProperties.DbTablePrefix + "UserTextMessages", AbpAIManagementDbProperties.DbSchema);
b.ToTable(AbpAIManagementDbProperties.DbTablePrefix + "TextChatMessages", AbpAIManagementDbProperties.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.Workspace).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxNameLength).IsRequired();
b.Property(x => x.ConversationId).HasMaxLength(UserMessageRecordConsts.MaxConversationIdLength);
b.Property(x => x.Content).HasMaxLength(UserTextMessageRecordConsts.MaxContentLength).IsRequired();
b.Property(x => x.Workspace)
.HasMaxLength(WorkspaceDefinitionRecordConsts.MaxNameLength)
.IsRequired();
b.Property(x => x.Role)
.HasMaxLength(ChatMessageRecordConsts.MaxChatRoleLength)
.HasConversion(new ChatRoleValueConverter())
.IsRequired();
b.Property(x => x.ConversationId)
.HasMaxLength(ChatMessageRecordConsts.MaxConversationIdLength);
b.Property(x => x.Content)
.HasMaxLength(TextChatMessageRecordConsts.MaxContentLength)
.IsRequired();
b.HasIndex(x => new { x.TenantId, x.ConversationId });
@ -36,16 +46,30 @@ public static class AIManagementDbContextModelBuilderExtensions
b.ConfigureByConvention();
b.Property(x => x.Name).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxNameLength).IsRequired();
b.Property(x => x.Provider).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxProviderLength).IsRequired();
b.Property(x => x.ModelName).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxModelNameLength).IsRequired();
b.Property(x => x.DisplayName).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxDisplayNameLength).IsRequired();
b.Property(x => x.Description).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxDescriptionLength);
b.Property(x => x.ApiKey).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxApiKeyLength);
b.Property(x => x.ApiBaseUrl).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxApiKeyLength);
b.Property(x => x.SystemPrompt).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxSystemPromptLength);
b.Property(x => x.Instructions).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxInstructionsLength);
b.Property(x => x.StateCheckers).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxStateCheckersLength);
b.Property(x => x.Name)
.HasMaxLength(WorkspaceDefinitionRecordConsts.MaxNameLength)
.IsRequired();
b.Property(x => x.Provider)
.HasMaxLength(WorkspaceDefinitionRecordConsts.MaxProviderLength)
.IsRequired();
b.Property(x => x.ModelName)
.HasMaxLength(WorkspaceDefinitionRecordConsts.MaxModelNameLength)
.IsRequired();
b.Property(x => x.DisplayName)
.HasMaxLength(WorkspaceDefinitionRecordConsts.MaxDisplayNameLength)
.IsRequired();
b.Property(x => x.Description)
.HasMaxLength(WorkspaceDefinitionRecordConsts.MaxDescriptionLength);
b.Property(x => x.ApiKey)
.HasMaxLength(WorkspaceDefinitionRecordConsts.MaxApiKeyLength);
b.Property(x => x.ApiBaseUrl)
.HasMaxLength(WorkspaceDefinitionRecordConsts.MaxApiKeyLength);
b.Property(x => x.SystemPrompt)
.HasMaxLength(WorkspaceDefinitionRecordConsts.MaxSystemPromptLength);
b.Property(x => x.Instructions)
.HasMaxLength(WorkspaceDefinitionRecordConsts.MaxInstructionsLength);
b.Property(x => x.StateCheckers)
.HasMaxLength(WorkspaceDefinitionRecordConsts.MaxStateCheckersLength);
b.HasIndex(x => new { x.Name }).IsUnique();

4
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.EntityFrameworkCore/LINGYUN/Abp/AIManagement/EntityFrameworkCore/AbpAIManagementEntityFrameworkCoreModule.cs

@ -1,4 +1,4 @@
using LINGYUN.Abp.AIManagement.Messages;
using LINGYUN.Abp.AIManagement.Chats;
using LINGYUN.Abp.AIManagement.Workspaces;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EntityFrameworkCore;
@ -17,7 +17,7 @@ public class AbpAIManagementEntityFrameworkCoreModule : AbpModule
{
options.AddDefaultRepositories<IAIManagementDbContext>();
options.AddRepository<UserTextMessageRecord, EfCoreUserTextMessageRecordRepository>();
options.AddRepository<TextChatMessageRecord, EfCoreTextChatMessageRecordRepository>();
options.AddRepository<WorkspaceDefinitionRecord, EfCoreWorkspaceDefinitionRecordRepository>();
});

9
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.EntityFrameworkCore/LINGYUN/Abp/AIManagement/EntityFrameworkCore/EfCoreUserTextMessageRecordRepository.cs → aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.EntityFrameworkCore/LINGYUN/Abp/AIManagement/EntityFrameworkCore/EfCoreTextChatMessageRecordRepository.cs

@ -1,4 +1,4 @@
using LINGYUN.Abp.AIManagement.Messages;
using LINGYUN.Abp.AIManagement.Chats;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
@ -9,15 +9,15 @@ using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace LINGYUN.Abp.AIManagement.EntityFrameworkCore;
public class EfCoreUserTextMessageRecordRepository : EfCoreRepository<IAIManagementDbContext, UserTextMessageRecord, Guid>, IUserTextMessageRecordRepository
public class EfCoreTextChatMessageRecordRepository : EfCoreRepository<IAIManagementDbContext, TextChatMessageRecord, Guid>, ITextChatMessageRecordRepository
{
public EfCoreUserTextMessageRecordRepository(
public EfCoreTextChatMessageRecordRepository(
IDbContextProvider<IAIManagementDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public async virtual Task<IEnumerable<UserTextMessageRecord>> GetHistoryMessagesAsync(
public async virtual Task<IEnumerable<TextChatMessageRecord>> GetHistoryMessagesAsync(
string conversationId,
int maxResultCount = 0,
CancellationToken cancellationToken = default)
@ -26,6 +26,7 @@ public class EfCoreUserTextMessageRecordRepository : EfCoreRepository<IAIManagem
.Where(x => x.ConversationId == conversationId)
.OrderByDescending(x => x.CreationTime)
.Take(maxResultCount)
.OrderBy(x => x.CreationTime)
.ToListAsync(GetCancellationToken(cancellationToken));
}
}

11
aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.EntityFrameworkCore/LINGYUN/Abp/AIManagement/EntityFrameworkCore/ValueConversions/ChatRoleValueConverter.cs

@ -0,0 +1,11 @@
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Microsoft.Extensions.AI;
namespace LINGYUN.Abp.AIManagement.EntityFrameworkCore.ValueConversions;
public class ChatRoleValueConverter(ConverterMappingHints? mappingHints = null) : ValueConverter<ChatRole, string>(
value => value.Value,
value => new ChatRole(value),
mappingHints
)
{
}
Loading…
Cancel
Save