diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/UsageStatistics/HourlyTokenUsageDto.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/UsageStatistics/HourlyTokenUsageDto.cs
new file mode 100644
index 00000000..ef86c78e
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/UsageStatistics/HourlyTokenUsageDto.cs
@@ -0,0 +1,22 @@
+namespace Yi.Framework.AiHub.Application.Contracts.Dtos.UsageStatistics;
+
+///
+/// 每小时Token使用量统计DTO(柱状图)
+///
+public class HourlyTokenUsageDto
+{
+ ///
+ /// 小时时间点
+ ///
+ public DateTime Hour { get; set; }
+
+ ///
+ /// 该小时总Token消耗量
+ ///
+ public long TotalTokens { get; set; }
+
+ ///
+ /// 各模型Token消耗明细
+ ///
+ public List ModelBreakdown { get; set; } = new();
+}
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/UsageStatistics/ModelTodayUsageDto.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/UsageStatistics/ModelTodayUsageDto.cs
new file mode 100644
index 00000000..afc163e5
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/UsageStatistics/ModelTodayUsageDto.cs
@@ -0,0 +1,22 @@
+namespace Yi.Framework.AiHub.Application.Contracts.Dtos.UsageStatistics;
+
+///
+/// 模型今日使用量统计DTO(卡片列表)
+///
+public class ModelTodayUsageDto
+{
+ ///
+ /// 模型ID
+ ///
+ public string ModelId { get; set; }
+
+ ///
+ /// 今日使用次数
+ ///
+ public int UsageCount { get; set; }
+
+ ///
+ /// 今日消耗总Token数
+ ///
+ public long TotalTokens { get; set; }
+}
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/UsageStatistics/ModelTokenBreakdownDto.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/UsageStatistics/ModelTokenBreakdownDto.cs
new file mode 100644
index 00000000..8c1e831e
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/UsageStatistics/ModelTokenBreakdownDto.cs
@@ -0,0 +1,17 @@
+namespace Yi.Framework.AiHub.Application.Contracts.Dtos.UsageStatistics;
+
+///
+/// 模型Token堆叠数据DTO(用于柱状图)
+///
+public class ModelTokenBreakdownDto
+{
+ ///
+ /// 模型ID
+ ///
+ public string ModelId { get; set; }
+
+ ///
+ /// Token消耗量
+ ///
+ public long Tokens { get; set; }
+}
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/IServices/IUsageStatisticsService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/IServices/IUsageStatisticsService.cs
index 99be00a6..31a2ef87 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/IServices/IUsageStatisticsService.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/IServices/IUsageStatisticsService.cs
@@ -24,4 +24,16 @@ public interface IUsageStatisticsService
///
/// 尊享服务Token用量统计
Task GetPremiumTokenUsageAsync();
+
+ ///
+ /// 获取当前用户近24小时每小时Token消耗统计(柱状图)
+ ///
+ /// 每小时Token使用量列表,包含各模型堆叠数据
+ Task> GetLast24HoursTokenUsageAsync(UsageStatisticsGetInput input);
+
+ ///
+ /// 获取当前用户今日各模型使用量统计(卡片列表)
+ ///
+ /// 模型今日使用量列表,包含使用次数和总Token
+ Task> GetTodayModelUsageAsync(UsageStatisticsGetInput input);
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/UsageStatisticsService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/UsageStatisticsService.cs
index 6f988d41..d3d38bae 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/UsageStatisticsService.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/UsageStatisticsService.cs
@@ -57,7 +57,7 @@ public class UsageStatisticsService : ApplicationService, IUsageStatisticsServic
// 从Message表统计近7天的token消耗
var dailyUsage = await _messageRepository._DbQueryable
.Where(x => x.UserId == userId)
- .Where(x => x.Role == "assistant" || x.Role == "system")
+ .Where(x => x.Role == "system")
.Where(x => x.CreationTime >= startDate && x.CreationTime < endDate.AddDays(1))
.WhereIF(input.TokenId.HasValue,x => x.TokenId == input.TokenId)
.GroupBy(x => x.CreationTime.Date)
@@ -228,4 +228,106 @@ public class UsageStatisticsService : ApplicationService, IUsageStatisticsServic
return result;
}
+
+ ///
+ /// 获取当前用户近24小时每小时Token消耗统计(柱状图)
+ ///
+ /// 每小时Token使用量列表,包含各模型堆叠数据
+ public async Task> GetLast24HoursTokenUsageAsync([FromQuery]UsageStatisticsGetInput input)
+ {
+ var userId = CurrentUser.GetId();
+ var now = DateTime.Now;
+ var startTime = now.AddHours(-23); // 滚动24小时,从23小时前到现在
+ var startHour = new DateTime(startTime.Year, startTime.Month, startTime.Day, startTime.Hour, 0, 0);
+
+ // 从Message表查询近24小时的数据,只选择需要的字段
+ var messages = await _messageRepository._DbQueryable
+ .Where(x => x.UserId == userId)
+ .Where(x => x.Role == "system")
+ .Where(x => x.CreationTime >= startHour)
+ .WhereIF(input.TokenId.HasValue, x => x.TokenId == input.TokenId)
+ .Select(x => new
+ {
+ x.CreationTime,
+ x.ModelId,
+ x.TokenUsage.TotalTokenCount
+ })
+ .ToListAsync();
+
+ // 在内存中按小时和模型分组统计
+ var hourlyGrouped = messages
+ .GroupBy(x => new
+ {
+ Hour = new DateTime(x.CreationTime.Year, x.CreationTime.Month, x.CreationTime.Day, x.CreationTime.Hour, 0, 0),
+ x.ModelId
+ })
+ .Select(g => new
+ {
+ g.Key.Hour,
+ g.Key.ModelId,
+ Tokens = g.Sum(x => x.TotalTokenCount)
+ })
+ .ToList();
+
+ // 生成完整的24小时数据
+ var result = new List();
+ for (int i = 0; i < 24; i++)
+ {
+ var hour = startHour.AddHours(i);
+ var hourData = hourlyGrouped.Where(x => x.Hour == hour).ToList();
+
+ var modelBreakdown = hourData.Select(x => new ModelTokenBreakdownDto
+ {
+ ModelId = x.ModelId,
+ Tokens = x.Tokens
+ }).ToList();
+
+ result.Add(new HourlyTokenUsageDto
+ {
+ Hour = hour,
+ TotalTokens = modelBreakdown.Sum(x => x.Tokens),
+ ModelBreakdown = modelBreakdown
+ });
+ }
+
+ return result;
+ }
+
+ ///
+ /// 获取当前用户今日各模型使用量统计(卡片列表)
+ ///
+ /// 模型今日使用量列表,包含使用次数和总Token
+ public async Task> GetTodayModelUsageAsync([FromQuery]UsageStatisticsGetInput input)
+ {
+ var userId = CurrentUser.GetId();
+ var todayStart = DateTime.Today; // 今天凌晨0点
+ var tomorrowStart = todayStart.AddDays(1);
+
+ // 从Message表查询今天的数据,只选择需要的字段
+ var messages = await _messageRepository._DbQueryable
+ .Where(x => x.UserId == userId)
+ .Where(x => x.Role == "system")
+ .Where(x => x.CreationTime >= todayStart && x.CreationTime < tomorrowStart)
+ .WhereIF(input.TokenId.HasValue, x => x.TokenId == input.TokenId)
+ .Select(x => new
+ {
+ x.ModelId,
+ x.TokenUsage.TotalTokenCount
+ })
+ .ToListAsync();
+
+ // 在内存中按模型分组统计
+ var modelStats = messages
+ .GroupBy(x => x.ModelId)
+ .Select(g => new ModelTodayUsageDto
+ {
+ ModelId = g.Key,
+ UsageCount = g.Count(),
+ TotalTokens = g.Sum(x => x.TotalTokenCount)
+ })
+ .OrderByDescending(x => x.TotalTokens)
+ .ToList();
+
+ return modelStats;
+ }
}
\ No newline at end of file