diff --git a/backend/internal/pkg/usagestats/usage_log_types.go b/backend/internal/pkg/usagestats/usage_log_types.go index 5307389d21..7e0d12fdd2 100644 --- a/backend/internal/pkg/usagestats/usage_log_types.go +++ b/backend/internal/pkg/usagestats/usage_log_types.go @@ -278,18 +278,20 @@ type UsageLogFilters struct { // UsageStats represents usage statistics type UsageStats struct { - TotalRequests int64 `json:"total_requests"` - TotalInputTokens int64 `json:"total_input_tokens"` - TotalOutputTokens int64 `json:"total_output_tokens"` - TotalCacheTokens int64 `json:"total_cache_tokens"` - TotalTokens int64 `json:"total_tokens"` - TotalCost float64 `json:"total_cost"` - TotalActualCost float64 `json:"total_actual_cost"` - TotalAccountCost *float64 `json:"total_account_cost,omitempty"` - AverageDurationMs float64 `json:"average_duration_ms"` - Endpoints []EndpointStat `json:"endpoints,omitempty"` - UpstreamEndpoints []EndpointStat `json:"upstream_endpoints,omitempty"` - EndpointPaths []EndpointStat `json:"endpoint_paths,omitempty"` + TotalRequests int64 `json:"total_requests"` + TotalInputTokens int64 `json:"total_input_tokens"` + TotalOutputTokens int64 `json:"total_output_tokens"` + TotalCacheTokens int64 `json:"total_cache_tokens"` + TotalCacheCreationTokens int64 `json:"total_cache_creation_tokens"` + TotalCacheReadTokens int64 `json:"total_cache_read_tokens"` + TotalTokens int64 `json:"total_tokens"` + TotalCost float64 `json:"total_cost"` + TotalActualCost float64 `json:"total_actual_cost"` + TotalAccountCost *float64 `json:"total_account_cost,omitempty"` + AverageDurationMs float64 `json:"average_duration_ms"` + Endpoints []EndpointStat `json:"endpoints,omitempty"` + UpstreamEndpoints []EndpointStat `json:"upstream_endpoints,omitempty"` + EndpointPaths []EndpointStat `json:"endpoint_paths,omitempty"` } // PlatformUsage 表示某用户/某 API key 在单个"有效平台"维度的用量明细。 diff --git a/backend/internal/repository/usage_log_repo.go b/backend/internal/repository/usage_log_repo.go index b0992dae10..7913ba667d 100644 --- a/backend/internal/repository/usage_log_repo.go +++ b/backend/internal/repository/usage_log_repo.go @@ -1795,6 +1795,8 @@ func (r *usageLogRepository) GetUserStatsAggregated(ctx context.Context, userID COALESCE(SUM(input_tokens), 0) as total_input_tokens, COALESCE(SUM(output_tokens), 0) as total_output_tokens, COALESCE(SUM(cache_creation_tokens + cache_read_tokens), 0) as total_cache_tokens, + COALESCE(SUM(cache_creation_tokens), 0) as total_cache_creation_tokens, + COALESCE(SUM(cache_read_tokens), 0) as total_cache_read_tokens, COALESCE(SUM(total_cost), 0) as total_cost, COALESCE(SUM(actual_cost), 0) as total_actual_cost, COALESCE(AVG(COALESCE(duration_ms, 0)), 0) as avg_duration_ms @@ -1812,6 +1814,8 @@ func (r *usageLogRepository) GetUserStatsAggregated(ctx context.Context, userID &stats.TotalInputTokens, &stats.TotalOutputTokens, &stats.TotalCacheTokens, + &stats.TotalCacheCreationTokens, + &stats.TotalCacheReadTokens, &stats.TotalCost, &stats.TotalActualCost, &stats.AverageDurationMs, @@ -1830,6 +1834,8 @@ func (r *usageLogRepository) GetAPIKeyStatsAggregated(ctx context.Context, apiKe COALESCE(SUM(input_tokens), 0) as total_input_tokens, COALESCE(SUM(output_tokens), 0) as total_output_tokens, COALESCE(SUM(cache_creation_tokens + cache_read_tokens), 0) as total_cache_tokens, + COALESCE(SUM(cache_creation_tokens), 0) as total_cache_creation_tokens, + COALESCE(SUM(cache_read_tokens), 0) as total_cache_read_tokens, COALESCE(SUM(total_cost), 0) as total_cost, COALESCE(SUM(actual_cost), 0) as total_actual_cost, COALESCE(AVG(COALESCE(duration_ms, 0)), 0) as avg_duration_ms @@ -1847,6 +1853,8 @@ func (r *usageLogRepository) GetAPIKeyStatsAggregated(ctx context.Context, apiKe &stats.TotalInputTokens, &stats.TotalOutputTokens, &stats.TotalCacheTokens, + &stats.TotalCacheCreationTokens, + &stats.TotalCacheReadTokens, &stats.TotalCost, &stats.TotalActualCost, &stats.AverageDurationMs, @@ -1875,6 +1883,8 @@ func (r *usageLogRepository) GetAccountStatsAggregated(ctx context.Context, acco COALESCE(SUM(input_tokens), 0) as total_input_tokens, COALESCE(SUM(output_tokens), 0) as total_output_tokens, COALESCE(SUM(cache_creation_tokens + cache_read_tokens), 0) as total_cache_tokens, + COALESCE(SUM(cache_creation_tokens), 0) as total_cache_creation_tokens, + COALESCE(SUM(cache_read_tokens), 0) as total_cache_read_tokens, COALESCE(SUM(total_cost), 0) as total_cost, COALESCE(SUM(actual_cost), 0) as total_actual_cost, COALESCE(AVG(COALESCE(duration_ms, 0)), 0) as avg_duration_ms @@ -1892,6 +1902,8 @@ func (r *usageLogRepository) GetAccountStatsAggregated(ctx context.Context, acco &stats.TotalInputTokens, &stats.TotalOutputTokens, &stats.TotalCacheTokens, + &stats.TotalCacheCreationTokens, + &stats.TotalCacheReadTokens, &stats.TotalCost, &stats.TotalActualCost, &stats.AverageDurationMs, @@ -1911,6 +1923,8 @@ func (r *usageLogRepository) GetModelStatsAggregated(ctx context.Context, modelN COALESCE(SUM(input_tokens), 0) as total_input_tokens, COALESCE(SUM(output_tokens), 0) as total_output_tokens, COALESCE(SUM(cache_creation_tokens + cache_read_tokens), 0) as total_cache_tokens, + COALESCE(SUM(cache_creation_tokens), 0) as total_cache_creation_tokens, + COALESCE(SUM(cache_read_tokens), 0) as total_cache_read_tokens, COALESCE(SUM(total_cost), 0) as total_cost, COALESCE(SUM(actual_cost), 0) as total_actual_cost, COALESCE(AVG(COALESCE(duration_ms, 0)), 0) as avg_duration_ms @@ -1928,6 +1942,8 @@ func (r *usageLogRepository) GetModelStatsAggregated(ctx context.Context, modelN &stats.TotalInputTokens, &stats.TotalOutputTokens, &stats.TotalCacheTokens, + &stats.TotalCacheCreationTokens, + &stats.TotalCacheReadTokens, &stats.TotalCost, &stats.TotalActualCost, &stats.AverageDurationMs, diff --git a/backend/internal/server/api_contract_test.go b/backend/internal/server/api_contract_test.go index c7a23d1f46..54719cda2e 100644 --- a/backend/internal/server/api_contract_test.go +++ b/backend/internal/server/api_contract_test.go @@ -506,6 +506,8 @@ func TestAPIContracts(t *testing.T) { "total_input_tokens": 15, "total_output_tokens": 35, "total_cache_tokens": 3, + "total_cache_creation_tokens": 1, + "total_cache_read_tokens": 2, "total_tokens": 53, "total_cost": 0.75, "total_actual_cost": 0.75, @@ -2364,6 +2366,8 @@ func (r *stubUsageLogRepo) GetUserStatsAggregated(ctx context.Context, userID in var totalInputTokens int64 var totalOutputTokens int64 var totalCacheTokens int64 + var totalCacheCreationTokens int64 + var totalCacheReadTokens int64 var totalCost float64 var totalActualCost float64 var totalDuration int64 @@ -2374,6 +2378,8 @@ func (r *stubUsageLogRepo) GetUserStatsAggregated(ctx context.Context, userID in totalInputTokens += int64(log.InputTokens) totalOutputTokens += int64(log.OutputTokens) totalCacheTokens += int64(log.CacheCreationTokens + log.CacheReadTokens) + totalCacheCreationTokens += int64(log.CacheCreationTokens) + totalCacheReadTokens += int64(log.CacheReadTokens) totalCost += log.TotalCost totalActualCost += log.ActualCost if log.DurationMs != nil { @@ -2388,14 +2394,16 @@ func (r *stubUsageLogRepo) GetUserStatsAggregated(ctx context.Context, userID in } return &usagestats.UsageStats{ - TotalRequests: totalRequests, - TotalInputTokens: totalInputTokens, - TotalOutputTokens: totalOutputTokens, - TotalCacheTokens: totalCacheTokens, - TotalTokens: totalInputTokens + totalOutputTokens + totalCacheTokens, - TotalCost: totalCost, - TotalActualCost: totalActualCost, - AverageDurationMs: avgDuration, + TotalRequests: totalRequests, + TotalInputTokens: totalInputTokens, + TotalOutputTokens: totalOutputTokens, + TotalCacheTokens: totalCacheTokens, + TotalCacheCreationTokens: totalCacheCreationTokens, + TotalCacheReadTokens: totalCacheReadTokens, + TotalTokens: totalInputTokens + totalOutputTokens + totalCacheTokens, + TotalCost: totalCost, + TotalActualCost: totalActualCost, + AverageDurationMs: avgDuration, }, nil } diff --git a/backend/internal/service/usage_service.go b/backend/internal/service/usage_service.go index db572cc390..b56f96edf7 100644 --- a/backend/internal/service/usage_service.go +++ b/backend/internal/service/usage_service.go @@ -42,14 +42,16 @@ type CreateUsageLogRequest struct { // UsageStats 使用统计 type UsageStats struct { - TotalRequests int64 `json:"total_requests"` - TotalInputTokens int64 `json:"total_input_tokens"` - TotalOutputTokens int64 `json:"total_output_tokens"` - TotalCacheTokens int64 `json:"total_cache_tokens"` - TotalTokens int64 `json:"total_tokens"` - TotalCost float64 `json:"total_cost"` - TotalActualCost float64 `json:"total_actual_cost"` - AverageDurationMs float64 `json:"average_duration_ms"` + TotalRequests int64 `json:"total_requests"` + TotalInputTokens int64 `json:"total_input_tokens"` + TotalOutputTokens int64 `json:"total_output_tokens"` + TotalCacheTokens int64 `json:"total_cache_tokens"` + TotalCacheCreationTokens int64 `json:"total_cache_creation_tokens"` + TotalCacheReadTokens int64 `json:"total_cache_read_tokens"` + TotalTokens int64 `json:"total_tokens"` + TotalCost float64 `json:"total_cost"` + TotalActualCost float64 `json:"total_actual_cost"` + AverageDurationMs float64 `json:"average_duration_ms"` } // UsageService 使用统计服务 @@ -190,14 +192,16 @@ func (s *UsageService) GetStatsByUser(ctx context.Context, userID int64, startTi } return &UsageStats{ - TotalRequests: stats.TotalRequests, - TotalInputTokens: stats.TotalInputTokens, - TotalOutputTokens: stats.TotalOutputTokens, - TotalCacheTokens: stats.TotalCacheTokens, - TotalTokens: stats.TotalTokens, - TotalCost: stats.TotalCost, - TotalActualCost: stats.TotalActualCost, - AverageDurationMs: stats.AverageDurationMs, + TotalRequests: stats.TotalRequests, + TotalInputTokens: stats.TotalInputTokens, + TotalOutputTokens: stats.TotalOutputTokens, + TotalCacheTokens: stats.TotalCacheTokens, + TotalCacheCreationTokens: stats.TotalCacheCreationTokens, + TotalCacheReadTokens: stats.TotalCacheReadTokens, + TotalTokens: stats.TotalTokens, + TotalCost: stats.TotalCost, + TotalActualCost: stats.TotalActualCost, + AverageDurationMs: stats.AverageDurationMs, }, nil } @@ -209,14 +213,16 @@ func (s *UsageService) GetStatsByAPIKey(ctx context.Context, apiKeyID int64, sta } return &UsageStats{ - TotalRequests: stats.TotalRequests, - TotalInputTokens: stats.TotalInputTokens, - TotalOutputTokens: stats.TotalOutputTokens, - TotalCacheTokens: stats.TotalCacheTokens, - TotalTokens: stats.TotalTokens, - TotalCost: stats.TotalCost, - TotalActualCost: stats.TotalActualCost, - AverageDurationMs: stats.AverageDurationMs, + TotalRequests: stats.TotalRequests, + TotalInputTokens: stats.TotalInputTokens, + TotalOutputTokens: stats.TotalOutputTokens, + TotalCacheTokens: stats.TotalCacheTokens, + TotalCacheCreationTokens: stats.TotalCacheCreationTokens, + TotalCacheReadTokens: stats.TotalCacheReadTokens, + TotalTokens: stats.TotalTokens, + TotalCost: stats.TotalCost, + TotalActualCost: stats.TotalActualCost, + AverageDurationMs: stats.AverageDurationMs, }, nil } @@ -228,14 +234,16 @@ func (s *UsageService) GetStatsByAccount(ctx context.Context, accountID int64, s } return &UsageStats{ - TotalRequests: stats.TotalRequests, - TotalInputTokens: stats.TotalInputTokens, - TotalOutputTokens: stats.TotalOutputTokens, - TotalCacheTokens: stats.TotalCacheTokens, - TotalTokens: stats.TotalTokens, - TotalCost: stats.TotalCost, - TotalActualCost: stats.TotalActualCost, - AverageDurationMs: stats.AverageDurationMs, + TotalRequests: stats.TotalRequests, + TotalInputTokens: stats.TotalInputTokens, + TotalOutputTokens: stats.TotalOutputTokens, + TotalCacheTokens: stats.TotalCacheTokens, + TotalCacheCreationTokens: stats.TotalCacheCreationTokens, + TotalCacheReadTokens: stats.TotalCacheReadTokens, + TotalTokens: stats.TotalTokens, + TotalCost: stats.TotalCost, + TotalActualCost: stats.TotalActualCost, + AverageDurationMs: stats.AverageDurationMs, }, nil } @@ -247,14 +255,16 @@ func (s *UsageService) GetStatsByModel(ctx context.Context, modelName string, st } return &UsageStats{ - TotalRequests: stats.TotalRequests, - TotalInputTokens: stats.TotalInputTokens, - TotalOutputTokens: stats.TotalOutputTokens, - TotalCacheTokens: stats.TotalCacheTokens, - TotalTokens: stats.TotalTokens, - TotalCost: stats.TotalCost, - TotalActualCost: stats.TotalActualCost, - AverageDurationMs: stats.AverageDurationMs, + TotalRequests: stats.TotalRequests, + TotalInputTokens: stats.TotalInputTokens, + TotalOutputTokens: stats.TotalOutputTokens, + TotalCacheTokens: stats.TotalCacheTokens, + TotalCacheCreationTokens: stats.TotalCacheCreationTokens, + TotalCacheReadTokens: stats.TotalCacheReadTokens, + TotalTokens: stats.TotalTokens, + TotalCost: stats.TotalCost, + TotalActualCost: stats.TotalActualCost, + AverageDurationMs: stats.AverageDurationMs, }, nil } diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index 067ebbc0a7..1ad34b0e65 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -896,6 +896,9 @@ export default { unknown: 'Unknown', in: 'In', out: 'Out', + cacheHit: 'Cache hit', + cacheCreate: 'Cache create', + cacheHitRate: 'Cache hit rate', inputTokenPrice: 'Input price', outputTokenPrice: 'Output price', perMillionTokens: '/ 1M tokens', diff --git a/frontend/src/i18n/locales/zh.ts b/frontend/src/i18n/locales/zh.ts index a4f3b3eb60..2868e5d598 100644 --- a/frontend/src/i18n/locales/zh.ts +++ b/frontend/src/i18n/locales/zh.ts @@ -900,6 +900,9 @@ export default { unknown: '未知', in: '输入', out: '输出', + cacheHit: '缓存命中', + cacheCreate: '缓存创建', + cacheHitRate: '缓存命中率', inputTokenPrice: '输入单价', outputTokenPrice: '输出单价', perMillionTokens: '/ 1M Token',