9 changed files with 203 additions and 4 deletions
@ -0,0 +1,26 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
using Volo.Abp.Specifications; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AIManagement.Tokens; |
||||
|
public interface ITokenUsageRecordRepository : IBasicRepository<TokenUsageRecord, Guid> |
||||
|
{ |
||||
|
Task<TokenUsageRecord?> FindByMessageIdAsync( |
||||
|
Guid conversationId, |
||||
|
Guid? messageId, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<int> GetCountAsync( |
||||
|
ISpecification<TokenUsageRecord> specification, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
|
||||
|
Task<List<TokenUsageRecord>> GetListAsync( |
||||
|
ISpecification<TokenUsageRecord> specification, |
||||
|
string sorting = $"{nameof(TokenUsageRecord.CreationTime)}", |
||||
|
int maxResultCount = 10, |
||||
|
int skipCount = 0, |
||||
|
CancellationToken cancellationToken = default); |
||||
|
} |
||||
@ -1,8 +1,42 @@ |
|||||
using System; |
using System; |
||||
using System.Collections.Generic; |
using Volo.Abp.Domain.Entities.Auditing; |
||||
using System.Text; |
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
namespace LINGYUN.Abp.AIManagement.Tokens; |
namespace LINGYUN.Abp.AIManagement.Tokens; |
||||
public class TokenUsageRecord |
public class TokenUsageRecord : AuditedEntity<Guid>, IMultiTenant |
||||
{ |
{ |
||||
|
public Guid? TenantId { get; private set; } |
||||
|
public Guid? MessageId { get; private set; } |
||||
|
public Guid? ConversationId { get; private set; } |
||||
|
public long? InputTokenCount { get; set; } |
||||
|
public long? OutputTokenCount { get; set; } |
||||
|
public long? TotalTokenCount { get; set; } |
||||
|
public long? CachedInputTokenCount { get; set; } |
||||
|
public long? ReasoningTokenCount { get; set; } |
||||
|
protected TokenUsageRecord() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public TokenUsageRecord( |
||||
|
Guid id, |
||||
|
Guid? messageId = null, |
||||
|
Guid? conversationId = null, |
||||
|
long? inputTokenCount = null, |
||||
|
long? outputTokenCount = null, |
||||
|
long? totalTokenCount = null, |
||||
|
long? cachedInputTokenCount = null, |
||||
|
long? reasoningTokenCount = null, |
||||
|
Guid? tenantId = null) |
||||
|
: base(id) |
||||
|
{ |
||||
|
MessageId = messageId; |
||||
|
ConversationId = conversationId; |
||||
|
InputTokenCount = inputTokenCount; |
||||
|
OutputTokenCount = outputTokenCount; |
||||
|
TotalTokenCount = totalTokenCount; |
||||
|
CachedInputTokenCount = cachedInputTokenCount; |
||||
|
ReasoningTokenCount = reasoningTokenCount; |
||||
|
TenantId = tenantId; |
||||
|
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,68 @@ |
|||||
|
using LINGYUN.Abp.AI.Models; |
||||
|
using LINGYUN.Abp.AI.Tokens; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Guids; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AIManagement.Tokens; |
||||
|
|
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
public class TokenUsageStore : ITokenUsageStore, ITransientDependency |
||||
|
{ |
||||
|
private readonly ICurrentTenant _currentTenant; |
||||
|
private readonly IGuidGenerator _guidGenerator; |
||||
|
private readonly ITokenUsageRecordRepository _tokenUsageRecordRepository; |
||||
|
|
||||
|
public TokenUsageStore( |
||||
|
ICurrentTenant currentTenant, |
||||
|
IGuidGenerator guidGenerator, |
||||
|
ITokenUsageRecordRepository tokenUsageRecordRepository) |
||||
|
{ |
||||
|
_currentTenant = currentTenant; |
||||
|
_guidGenerator = guidGenerator; |
||||
|
_tokenUsageRecordRepository = tokenUsageRecordRepository; |
||||
|
} |
||||
|
|
||||
|
public async virtual Task SaveTokenUsageAsync(TokenUsageInfo tokenUsageInfo) |
||||
|
{ |
||||
|
var tokenUsageRecord = await _tokenUsageRecordRepository.FindByMessageIdAsync( |
||||
|
tokenUsageInfo.ConversationId, |
||||
|
tokenUsageInfo.MessageId); |
||||
|
|
||||
|
if (tokenUsageRecord == null) |
||||
|
{ |
||||
|
tokenUsageRecord = new TokenUsageRecord( |
||||
|
_guidGenerator.Create(), |
||||
|
tokenUsageInfo.MessageId, |
||||
|
tokenUsageInfo.ConversationId, |
||||
|
tokenUsageInfo.InputTokenCount, |
||||
|
tokenUsageInfo.OutputTokenCount, |
||||
|
tokenUsageInfo.TotalTokenCount, |
||||
|
tokenUsageInfo.CachedInputTokenCount, |
||||
|
tokenUsageInfo.ReasoningTokenCount, |
||||
|
_currentTenant.Id); |
||||
|
|
||||
|
await _tokenUsageRecordRepository.InsertAsync(tokenUsageRecord); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
tokenUsageRecord.InputTokenCount ??= 0; |
||||
|
tokenUsageRecord.InputTokenCount += tokenUsageInfo.InputTokenCount; |
||||
|
|
||||
|
tokenUsageRecord.OutputTokenCount ??= 0; |
||||
|
tokenUsageRecord.OutputTokenCount += tokenUsageInfo.OutputTokenCount; |
||||
|
|
||||
|
tokenUsageRecord.CachedInputTokenCount ??= 0; |
||||
|
tokenUsageRecord.CachedInputTokenCount += tokenUsageInfo.CachedInputTokenCount; |
||||
|
|
||||
|
tokenUsageRecord.ReasoningTokenCount ??= 0; |
||||
|
tokenUsageRecord.ReasoningTokenCount += tokenUsageInfo.ReasoningTokenCount; |
||||
|
|
||||
|
tokenUsageRecord.TotalTokenCount ??= 0; |
||||
|
tokenUsageRecord.TotalTokenCount += tokenUsageInfo.TotalTokenCount; |
||||
|
|
||||
|
await _tokenUsageRecordRepository.UpdateAsync(tokenUsageRecord); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,54 @@ |
|||||
|
using LINGYUN.Abp.AIManagement.Tokens; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Linq.Dynamic.Core; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
using Volo.Abp.Specifications; |
||||
|
|
||||
|
namespace LINGYUN.Abp.AIManagement.EntityFrameworkCore; |
||||
|
public class EfCoreTokenUsageRecordRepository : EfCoreRepository<IAIManagementDbContext, TokenUsageRecord, Guid>, ITokenUsageRecordRepository |
||||
|
{ |
||||
|
public EfCoreTokenUsageRecordRepository( |
||||
|
IDbContextProvider<IAIManagementDbContext> dbContextProvider) |
||||
|
: base(dbContextProvider) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<TokenUsageRecord?> FindByMessageIdAsync( |
||||
|
Guid conversationId, |
||||
|
Guid? messageId, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return await (await GetQueryableAsync()) |
||||
|
.Where(x => x.ConversationId == conversationId && x.MessageId == messageId) |
||||
|
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<int> GetCountAsync( |
||||
|
ISpecification<TokenUsageRecord> specification, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return await (await GetQueryableAsync()) |
||||
|
.Where(specification.ToExpression()) |
||||
|
.CountAsync(GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<List<TokenUsageRecord>> GetListAsync( |
||||
|
ISpecification<TokenUsageRecord> specification, |
||||
|
string sorting = $"{nameof(TokenUsageRecord.CreationTime)}", |
||||
|
int maxResultCount = 10, |
||||
|
int skipCount = 0, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return await (await GetQueryableAsync()) |
||||
|
.Where(specification.ToExpression()) |
||||
|
.OrderBy(!sorting.IsNullOrWhiteSpace() ? sorting : $"{nameof(TokenUsageRecord.CreationTime)}") |
||||
|
.PageBy(skipCount, maxResultCount) |
||||
|
.ToListAsync(GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue