diff --git a/internal/models/registry.go b/internal/models/registry.go index 6cd2b313..fea0d02f 100644 --- a/internal/models/registry.go +++ b/internal/models/registry.go @@ -1,5 +1,7 @@ package models +import "strings" + type ModelRegistry struct { Providers map[string]ProviderInfo `json:"-"` } @@ -54,5 +56,14 @@ func (r *ModelRegistry) FindModel(modelID string) *ModelMetadata { } } + // Try fuzzy matching (e.g. gpt-4o-2024-05-13 matching gpt-4o) + for _, provider := range r.Providers { + for id, model := range provider.Models { + if strings.HasPrefix(modelID, id) { + return &model + } + } + } + return nil } diff --git a/internal/server/dashboard.go b/internal/server/dashboard.go index 9e2f44b0..296771ed 100644 --- a/internal/server/dashboard.go +++ b/internal/server/dashboard.go @@ -254,9 +254,10 @@ func (s *Server) handleUsageSummary(c *gin.Context) { COUNT(*) as today_requests, COALESCE(SUM(cost), 0.0) as today_cost FROM llm_requests - WHERE strftime('%Y-%m-%d', timestamp) = ? - `, today) + WHERE timestamp LIKE ? + `, today+"%") if err != nil { + fmt.Printf("[ERROR] Failed to fetch today stats: %v\n", err) todayStats.TodayRequests = 0 todayStats.TodayCost = 0.0 } @@ -305,7 +306,8 @@ func (s *Server) handleTimeSeries(c *gin.Context) { query := fmt.Sprintf(` SELECT - COALESCE(strftime('%%Y-%%m-%%d', timestamp), 'unknown') as bucket, + COALESCE(SUBSTR(timestamp, 1, 10), 'unknown') as bucket, + COUNT(*) as requests, COALESCE(SUM(total_tokens), 0) as tokens, COALESCE(SUM(cost), 0.0) as cost @@ -468,7 +470,7 @@ func (s *Server) handleDetailedUsage(c *gin.Context) { query := fmt.Sprintf(` SELECT - COALESCE(strftime('%%Y-%%m-%%d', timestamp), 'unknown') as date, + COALESCE(SUBSTR(timestamp, 1, 10), 'unknown') as date, COALESCE(client_id, 'unknown') as client, COALESCE(provider, 'unknown') as provider, COALESCE(model, 'unknown') as model, diff --git a/internal/server/server.go b/internal/server/server.go index 02a02c70..66882e01 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -376,6 +376,8 @@ func (s *Server) logRequest(start time.Time, clientID, provider, model string, u // Calculate cost using registry entry.Cost = utils.CalculateCost(s.registry, model, entry.PromptTokens, entry.CompletionTokens, entry.CacheReadTokens, entry.CacheWriteTokens) + fmt.Printf("[DEBUG] Request logged: model=%s, prompt=%d, completion=%d, cache_read=%d, cost=%f\n", + model, entry.PromptTokens, entry.CompletionTokens, entry.CacheReadTokens, entry.Cost) } s.logger.LogRequest(entry) diff --git a/internal/utils/registry.go b/internal/utils/registry.go index fb612558..ccf5d4c5 100644 --- a/internal/utils/registry.go +++ b/internal/utils/registry.go @@ -40,7 +40,18 @@ func CalculateCost(registry *models.ModelRegistry, modelID string, promptTokens, return 0.0 } - cost := (float64(promptTokens) * meta.Cost.Input / 1000000.0) + + // promptTokens is usually the TOTAL prompt size. + // We subtract cacheRead from it to get the uncached part. + uncachedTokens := promptTokens + if cacheRead > 0 { + if cacheRead > promptTokens { + uncachedTokens = 0 + } else { + uncachedTokens = promptTokens - cacheRead + } + } + + cost := (float64(uncachedTokens) * meta.Cost.Input / 1000000.0) + (float64(completionTokens) * meta.Cost.Output / 1000000.0) if meta.Cost.CacheRead != nil {