feat: 完成用量统计功能模块

This commit is contained in:
ccnetcore
2025-06-27 22:13:26 +08:00
parent 96e275efa6
commit 01a3c81359
20 changed files with 281 additions and 98 deletions

View File

@@ -12,7 +12,9 @@ using Volo.Abp.Application.Services;
using Volo.Abp.Users;
using Yi.Framework.AiHub.Application.Contracts.Dtos;
using Yi.Framework.AiHub.Domain.Entities;
using Yi.Framework.AiHub.Domain.Entities.Model;
using Yi.Framework.AiHub.Domain.Managers;
using Yi.Framework.AiHub.Domain.Shared.Dtos;
using Yi.Framework.Rbac.Application.Contracts.IServices;
using Yi.Framework.Rbac.Domain.Shared.Dtos;
using Yi.Framework.SqlSugarCore.Abstractions;
@@ -28,15 +30,17 @@ public class AiChatService : ApplicationService
private readonly AiMessageManager _aiMessageManager;
private readonly ISqlSugarRepository<AiModelEntity> _aiModelRepository;
private readonly AiBlacklistManager _aiBlacklistManager;
private readonly UsageStatisticsManager _usageStatisticsManager;
public AiChatService(IHttpContextAccessor httpContextAccessor,
AiMessageManager aiMessageManager, AiBlacklistManager aiBlacklistManager,
ISqlSugarRepository<AiModelEntity> aiModelRepository)
ISqlSugarRepository<AiModelEntity> aiModelRepository, UsageStatisticsManager usageStatisticsManager)
{
this._httpContextAccessor = httpContextAccessor;
_aiMessageManager = aiMessageManager;
_aiBlacklistManager = aiBlacklistManager;
_aiModelRepository = aiModelRepository;
_usageStatisticsManager = usageStatisticsManager;
}
@@ -60,21 +64,21 @@ public class AiChatService : ApplicationService
public async Task<List<ModelGetListOutput>> GetModelAsync()
{
var output = await _aiModelRepository._DbQueryable
.OrderByDescending(x=>x.OrderNum)
.OrderByDescending(x => x.OrderNum)
.Select(x => new ModelGetListOutput
{
Id = x.Id,
Category = "chat",
ModelName = x.Name,
ModelDescribe = x.Description,
ModelPrice = 0,
ModelType = "1",
ModelShow = "0",
SystemPrompt = null,
ApiHost = null,
ApiKey = null,
Remark = x.Description
}).ToListAsync();
{
Id = x.Id,
Category = "chat",
ModelName = x.Name,
ModelDescribe = x.Description,
ModelPrice = 0,
ModelType = "1",
ModelShow = "0",
SystemPrompt = null,
ApiHost = null,
ApiKey = null,
Remark = x.Description
}).ToListAsync();
return output;
}
@@ -128,13 +132,15 @@ public class AiChatService : ApplicationService
var gateWay = LazyServiceProvider.GetRequiredService<AiGateWayManager>();
var completeChatResponse = gateWay.CompleteChatAsync(input.Model, history, cancellationToken);
var tokenUsage = new TokenUsage();
await using var writer = new StreamWriter(response.Body, Encoding.UTF8, leaveOpen: true);
//缓存队列算法
// 创建一个队列来缓存消息
var messageQueue = new ConcurrentQueue<string>();
StringBuilder backupSystemContent = new StringBuilder();
// 设置输出速率例如每50毫秒输出一次
var outputInterval = TimeSpan.FromMilliseconds(100);
// 标记是否完成接收
@@ -161,33 +167,49 @@ public class AiChatService : ApplicationService
await foreach (var data in completeChatResponse)
{
var model = MapToMessage(input.Model, data);
if (data.IsFinish)
{
tokenUsage = data.TokenUsage;
}
var model = MapToMessage(input.Model, data.Content);
var message = JsonConvert.SerializeObject(model, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
backupSystemContent.Append(data.Content);
// 将消息加入队列而不是直接写入
messageQueue.Enqueue($"data: {message}\n");
}
// 标记完成并发送结束标记
isComplete = true;
//断开连接
messageQueue.Enqueue("data: done\n");
// 标记完成并发送结束标记
isComplete = true;
await outputTask;
if (CurrentUser.IsAuthenticated && input.SessionId.HasValue)
{
await _aiMessageManager.CreateMessageAsync(CurrentUser.GetId(), input.SessionId.Value, new MessageInputDto
{
Content = input.Messages.LastOrDefault().Content,
Role = input.Messages.LastOrDefault().Role,
DeductCost = 0,
TotalTokens = 0,
ModelId = input.Model,
Remark = null
});
await _aiMessageManager.CreateUserMessageAsync(CurrentUser.GetId(), input.SessionId.Value,
new MessageInputDto
{
Content = input.Messages.LastOrDefault()
.Content,
ModelId = input.Model,
TokenUsage = tokenUsage,
});
await _aiMessageManager.CreateSystemMessageAsync(CurrentUser.GetId(), input.SessionId.Value,
new MessageInputDto
{
Content = backupSystemContent.ToString(),
ModelId = input.Model,
TokenUsage = tokenUsage
});
await _usageStatisticsManager.SetUsageAsync(CurrentUser.GetId(), input.Model, tokenUsage.InputTokenCount,
tokenUsage.OutputTokenCount);
}
}
@@ -249,9 +271,9 @@ public class AiChatService : ApplicationService
SystemFingerprint = "",
Usage = new Usage
{
PromptTokens = 75,
CompletionTokens = 25,
TotalTokens = 100,
PromptTokens = 0,
CompletionTokens = 0,
TotalTokens = 0,
PromptTokensDetails = new()
{
AudioTokens = 0,

View File

@@ -7,6 +7,7 @@ using Volo.Abp.Application.Services;
using Volo.Abp.Users;
using Yi.Framework.AiHub.Application.Contracts.Dtos;
using Yi.Framework.AiHub.Domain.Entities;
using Yi.Framework.AiHub.Domain.Entities.Chat;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.AiHub.Application.Services;
@@ -34,7 +35,7 @@ public class MessageService : ApplicationService
var entities = await _repository._DbQueryable
.Where(x => x.SessionId == input.SessionId)
.Where(x=>x.UserId == userId)
.OrderByDescending(x => x.Id)
.OrderBy(x => x.Id)
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
return new PagedResultDto<MessageDto>(total, entities.Adapt<List<MessageDto>>());
}

View File

@@ -8,6 +8,7 @@ using Volo.Abp.Domain.Repositories;
using Volo.Abp.Users;
using Yi.Framework.AiHub.Application.Contracts.Dtos;
using Yi.Framework.AiHub.Domain.Entities;
using Yi.Framework.AiHub.Domain.Entities.Chat;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.AiHub.Application.Services;