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.Models;
using LINGYUN.Abp.AI.Tokens; using LINGYUN.Abp.AI.Tokens;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI; using Microsoft.Extensions.AI;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -8,24 +9,29 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Timing;
using AIChatMessage = Microsoft.Extensions.AI.ChatMessage;
namespace LINGYUN.Abp.AI.Agent; namespace LINGYUN.Abp.AI.Agent;
public class AgentService : IAgentService, IScopedDependency public class AgentService : IAgentService, IScopedDependency
{ {
private readonly IClock _clock;
private readonly IAgentFactory _agentFactory; private readonly IAgentFactory _agentFactory;
private readonly ITokenUsageStore _tokenUsageStore; private readonly ITokenUsageStore _tokenUsageStore;
private readonly IUserMessageStore _userMessageStore; private readonly IChatMessageStore _chatMessageStore;
public AgentService( public AgentService(
IClock clock,
IAgentFactory agentFactory, IAgentFactory agentFactory,
ITokenUsageStore tokenUsageStore, ITokenUsageStore tokenUsageStore,
IUserMessageStore userMessageStore) IChatMessageStore chatMessageStore)
{ {
_clock = clock;
_agentFactory = agentFactory; _agentFactory = agentFactory;
_tokenUsageStore = tokenUsageStore; _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); var messages = await BuildChatMessages(message);
@ -33,62 +39,70 @@ public class AgentService : IAgentService, IScopedDependency
var agentRunRes = agent.RunStreamingAsync(messages); var agentRunRes = agent.RunStreamingAsync(messages);
var tokenUsageInfo = new TokenUsageInfo(message.Workspace);
var agentMessageBuilder = new StringBuilder(); var agentMessageBuilder = new StringBuilder();
await foreach (var item in agentRunRes) await foreach (var response in agentRunRes)
{ {
agentMessageBuilder.Append(item); UpdateTokenUsageInfo(tokenUsageInfo, response);
yield return item.Text; agentMessageBuilder.Append(response.Text);
yield return response.Text;
await StoreTokenUsageInfo(message, item.RawRepresentation);
} }
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()) if (!message.ConversationId.IsNullOrWhiteSpace())
{ {
var historyMessages = await _userMessageStore.GetHistoryMessagesAsync(message.ConversationId); var historyMessages = await _chatMessageStore.GetHistoryMessagesAsync(message.ConversationId);
foreach (var chatMessage in historyMessages) 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; 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 var usageContents = update.Contents.OfType<UsageContent>();
.OfType<UsageContent>()
.Where(usage => usage.Details != null) tokenUsageInfo.InputTokenCount = usageContents.Max(x => x.Details.InputTokenCount);
.Select(usage => new TokenUsageInfo(message.Workspace) tokenUsageInfo.OutputTokenCount = usageContents.Max(x => x.Details.OutputTokenCount);
{ tokenUsageInfo.TotalTokenCount = usageContents.Max(x => x.Details.TotalTokenCount);
TotalTokenCount = usage.Details.TotalTokenCount, tokenUsageInfo.ReasoningTokenCount = usageContents.Max(x => x.Details.ReasoningTokenCount);
CachedInputTokenCount = usage.Details.CachedInputTokenCount, tokenUsageInfo.CachedInputTokenCount = usageContents.Max(x => x.Details.CachedInputTokenCount);
InputTokenCount = usage.Details.InputTokenCount,
OutputTokenCount = usage.Details.OutputTokenCount,
ReasoningTokenCount = usage.Details.ReasoningTokenCount,
});
await _tokenUsageStore.SaveTokenUsagesAsync(tokenUsageInfos);
} }
} }
} }

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; namespace LINGYUN.Abp.AI.Agent;
public interface IAgentService 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> <ItemGroup>
<PackageReference Include="Volo.Abp.AI" /> <PackageReference Include="Volo.Abp.AI" />
<PackageReference Include="Volo.Abp.Localization" /> <PackageReference Include="Volo.Abp.Localization" />
<PackageReference Include="Volo.Abp.Timing" />
</ItemGroup> </ItemGroup>
</Project> </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 class TokenUsageInfo
{ {
public string Workspace { get; } public string Workspace { get; }
public string? MessageId { get; private set; }
public string? ConversationId { get; private set; }
public long? InputTokenCount { get; set; } public long? InputTokenCount { get; set; }
public long? OutputTokenCount { get; set; } public long? OutputTokenCount { get; set; }
public long? TotalTokenCount { get; set; } public long? TotalTokenCount { get; set; }
@ -11,4 +15,32 @@ public class TokenUsageInfo
{ {
Workspace = workspace; 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 LINGYUN.Abp.AI.Models;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace LINGYUN.Abp.AI.Tokens; namespace LINGYUN.Abp.AI.Tokens;
public interface ITokenUsageStore 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 Microsoft.Extensions.DependencyInjection;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
@ -11,31 +10,19 @@ namespace LINGYUN.Abp.AI.Tokens;
[Dependency(ServiceLifetime.Singleton, TryRegister = true)] [Dependency(ServiceLifetime.Singleton, TryRegister = true)]
public class InMemoryTokenUsageStore : ITokenUsageStore 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) tokenUsageInfos.Add(tokenUsageInfo);
{
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;
}
} }
else
{
_tokenUsageCache.TryAdd(tokenUsageInfo.Workspace, [tokenUsageInfo]);
}
return Task.CompletedTask; 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)] [Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
[MapExtraProperties(DefinitionChecks = MappingPropertyDefinitionChecks.None)] [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 TextChatMessage Map(UserTextMessageRecord source);
public override partial void Map(UserTextMessageRecord source, UserTextMessage destination); 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.AI.Models;
using LINGYUN.Abp.AIManagement.Settings; using LINGYUN.Abp.AIManagement.Settings;
using System; using System;
@ -10,23 +10,23 @@ using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectMapping; using Volo.Abp.ObjectMapping;
using Volo.Abp.Settings; using Volo.Abp.Settings;
namespace LINGYUN.Abp.AIManagement.Messages; namespace LINGYUN.Abp.AIManagement.Chats;
[Dependency(ReplaceServices = true)] [Dependency(ReplaceServices = true)]
public class UserMessageStore : IUserMessageStore, ITransientDependency public class ChatMessageStore : IChatMessageStore, ITransientDependency
{ {
private readonly ICurrentTenant _currentTenant; private readonly ICurrentTenant _currentTenant;
private readonly IGuidGenerator _guidGenerator; private readonly IGuidGenerator _guidGenerator;
private readonly ISettingProvider _settingProvider; private readonly ISettingProvider _settingProvider;
private readonly IObjectMapper<AbpAIManagementDomainModule> _objectMapper; private readonly IObjectMapper<AbpAIManagementDomainModule> _objectMapper;
private readonly IUserTextMessageRecordRepository _messageRecordRepository; private readonly ITextChatMessageRecordRepository _messageRecordRepository;
public UserMessageStore( public ChatMessageStore(
ICurrentTenant currentTenant, ICurrentTenant currentTenant,
IGuidGenerator guidGenerator, IGuidGenerator guidGenerator,
ISettingProvider settingProvider, ISettingProvider settingProvider,
IObjectMapper<AbpAIManagementDomainModule> objectMapper, IObjectMapper<AbpAIManagementDomainModule> objectMapper,
IUserTextMessageRecordRepository messageRecordRepository) ITextChatMessageRecordRepository messageRecordRepository)
{ {
_currentTenant = currentTenant; _currentTenant = currentTenant;
_guidGenerator = guidGenerator; _guidGenerator = guidGenerator;
@ -35,20 +35,21 @@ public class UserMessageStore : IUserMessageStore, ITransientDependency
_messageRecordRepository = messageRecordRepository; _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) if (maxLatestHistoryMessagesToKeep < 1)
{ {
return Array.Empty<UserMessage>(); return Array.Empty<ChatMessage>();
} }
var userTextMessages = await _messageRecordRepository.GetHistoryMessagesAsync(conversationId, maxLatestHistoryMessagesToKeep); 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; var messageId = message.Id;
if (messageId.IsNullOrWhiteSpace()) if (messageId.IsNullOrWhiteSpace())
@ -62,25 +63,27 @@ public class UserMessageStore : IUserMessageStore, ITransientDependency
return messageId; return messageId;
} }
protected async virtual Task StoreMessageAsync(Guid messageId, UserMessage message) protected async virtual Task StoreMessageAsync(Guid messageId, ChatMessage message)
{ {
switch (message) switch (message)
{ {
case UserTextMessage textMessage: case TextChatMessage textMessage:
await StoreUserTextMessageAsync(messageId, textMessage); await StoreUserTextMessageAsync(messageId, textMessage);
break; 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); var textMessageRecord = await _messageRecordRepository.FindAsync(messageId);
if (textMessageRecord == null) if (textMessageRecord == null)
{ {
textMessageRecord = new UserTextMessageRecord( textMessageRecord = new TextChatMessageRecord(
messageId, messageId,
textMessage.Workspace, textMessage.Workspace,
textMessage.Content, textMessage.Content,
textMessage.Role,
textMessage.CreatedAt,
_currentTenant.Id); _currentTenant.Id);
UpdateUserMessageRecord(textMessageRecord, textMessage); UpdateUserMessageRecord(textMessageRecord, textMessage);
@ -89,7 +92,7 @@ public class UserMessageStore : IUserMessageStore, ITransientDependency
} }
else else
{ {
textMessageRecord.WithContent(textMessage.Content); textMessageRecord.SetContent(textMessage.Content);
UpdateUserMessageRecord(textMessageRecord, textMessage); 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()) if (!message.ConversationId.IsNullOrWhiteSpace())
{ {
messageRecord.WithConversationId(message.ConversationId); messageRecord.SetConversationId(message.ConversationId);
} }
if (!message.ReplyMessage.IsNullOrWhiteSpace()) 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 System.Threading.Tasks;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
namespace LINGYUN.Abp.AIManagement.Messages; namespace LINGYUN.Abp.AIManagement.Chats;
public interface IUserTextMessageRecordRepository : IBasicRepository<UserTextMessageRecord, Guid> public interface ITextChatMessageRecordRepository : IBasicRepository<TextChatMessageRecord, Guid>
{ {
Task<IEnumerable<UserTextMessageRecord>> GetHistoryMessagesAsync( Task<IEnumerable<TextChatMessageRecord>> GetHistoryMessagesAsync(
string conversationId, string conversationId,
int maxResultCount = 0, int maxResultCount = 0,
CancellationToken cancellationToken = default); 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( context.Add(
new SettingDefinition( new SettingDefinition(
AIManagementSettingNames.UserMessage.MaxLatestHistoryMessagesToKeep, AIManagementSettingNames.ChatMessage.MaxLatestHistoryMessagesToKeep,
defaultValue: "5", defaultValue: "5",
displayName: L("DisplayName:MaxLatestHistoryMessagesToKeep"), displayName: L("DisplayName:MaxLatestHistoryMessagesToKeep"),
description: L("Description: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 const string Prefix = "Abp.AIManagement";
public static class UserMessage public static class ChatMessage
{ {
public const string MaxLatestHistoryMessagesToKeep = Prefix + ".MaxLatestHistoryMessagesToKeep"; 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.Collections.Generic;
using System.Text; using System.Text;
namespace LINGYUN.Abp.AI.Models; namespace LINGYUN.Abp.AIManagement.Tokens;
internal class ChatMessageInfo 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 JetBrains.Annotations;
using LINGYUN.Abp.AIManagement.Messages; using LINGYUN.Abp.AIManagement.Chats;
using LINGYUN.Abp.AIManagement.EntityFrameworkCore.ValueConversions;
using LINGYUN.Abp.AIManagement.Workspaces; using LINGYUN.Abp.AIManagement.Workspaces;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Volo.Abp; using Volo.Abp;
@ -13,15 +14,24 @@ public static class AIManagementDbContextModelBuilderExtensions
{ {
Check.NotNull(builder, nameof(builder)); 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.ConfigureByConvention();
b.Property(x => x.Workspace).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxNameLength).IsRequired(); b.Property(x => x.Workspace)
b.Property(x => x.ConversationId).HasMaxLength(UserMessageRecordConsts.MaxConversationIdLength); .HasMaxLength(WorkspaceDefinitionRecordConsts.MaxNameLength)
b.Property(x => x.Content).HasMaxLength(UserTextMessageRecordConsts.MaxContentLength).IsRequired(); .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 }); b.HasIndex(x => new { x.TenantId, x.ConversationId });
@ -36,16 +46,30 @@ public static class AIManagementDbContextModelBuilderExtensions
b.ConfigureByConvention(); b.ConfigureByConvention();
b.Property(x => x.Name).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxNameLength).IsRequired(); b.Property(x => x.Name)
b.Property(x => x.Provider).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxProviderLength).IsRequired(); .HasMaxLength(WorkspaceDefinitionRecordConsts.MaxNameLength)
b.Property(x => x.ModelName).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxModelNameLength).IsRequired(); .IsRequired();
b.Property(x => x.DisplayName).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxDisplayNameLength).IsRequired(); b.Property(x => x.Provider)
b.Property(x => x.Description).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxDescriptionLength); .HasMaxLength(WorkspaceDefinitionRecordConsts.MaxProviderLength)
b.Property(x => x.ApiKey).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxApiKeyLength); .IsRequired();
b.Property(x => x.ApiBaseUrl).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxApiKeyLength); b.Property(x => x.ModelName)
b.Property(x => x.SystemPrompt).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxSystemPromptLength); .HasMaxLength(WorkspaceDefinitionRecordConsts.MaxModelNameLength)
b.Property(x => x.Instructions).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxInstructionsLength); .IsRequired();
b.Property(x => x.StateCheckers).HasMaxLength(WorkspaceDefinitionRecordConsts.MaxStateCheckersLength); 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(); 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 LINGYUN.Abp.AIManagement.Workspaces;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore;
@ -17,7 +17,7 @@ public class AbpAIManagementEntityFrameworkCoreModule : AbpModule
{ {
options.AddDefaultRepositories<IAIManagementDbContext>(); options.AddDefaultRepositories<IAIManagementDbContext>();
options.AddRepository<UserTextMessageRecord, EfCoreUserTextMessageRecordRepository>(); options.AddRepository<TextChatMessageRecord, EfCoreTextChatMessageRecordRepository>();
options.AddRepository<WorkspaceDefinitionRecord, EfCoreWorkspaceDefinitionRecordRepository>(); 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 Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -9,15 +9,15 @@ using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore;
namespace LINGYUN.Abp.AIManagement.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) IDbContextProvider<IAIManagementDbContext> dbContextProvider)
: base(dbContextProvider) : base(dbContextProvider)
{ {
} }
public async virtual Task<IEnumerable<UserTextMessageRecord>> GetHistoryMessagesAsync( public async virtual Task<IEnumerable<TextChatMessageRecord>> GetHistoryMessagesAsync(
string conversationId, string conversationId,
int maxResultCount = 0, int maxResultCount = 0,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
@ -26,6 +26,7 @@ public class EfCoreUserTextMessageRecordRepository : EfCoreRepository<IAIManagem
.Where(x => x.ConversationId == conversationId) .Where(x => x.ConversationId == conversationId)
.OrderByDescending(x => x.CreationTime) .OrderByDescending(x => x.CreationTime)
.Take(maxResultCount) .Take(maxResultCount)
.OrderBy(x => x.CreationTime)
.ToListAsync(GetCancellationToken(cancellationToken)); .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