fix: restrict Model Pricing table to used models and fix cost stats
Implemented used_only filter for /api/models. Added missing cache token and cost fields to usage summary and provider usage endpoints.
This commit is contained in:
@@ -224,15 +224,19 @@ func (s *Server) handleUsageSummary(c *gin.Context) {
|
||||
|
||||
// Total stats
|
||||
var totalStats struct {
|
||||
TotalRequests int `db:"total_requests"`
|
||||
TotalTokens int `db:"total_tokens"`
|
||||
TotalCost float64 `db:"total_cost"`
|
||||
ActiveClients int `db:"active_clients"`
|
||||
TotalRequests int `db:"total_requests"`
|
||||
TotalTokens int `db:"total_tokens"`
|
||||
CacheReadTokens int `db:"total_cache_read_tokens"`
|
||||
CacheWriteTokens int `db:"total_cache_write_tokens"`
|
||||
TotalCost float64 `db:"total_cost"`
|
||||
ActiveClients int `db:"active_clients"`
|
||||
}
|
||||
err := s.database.Get(&totalStats, fmt.Sprintf(`
|
||||
SELECT
|
||||
COUNT(*) as total_requests,
|
||||
COALESCE(SUM(total_tokens), 0) as total_tokens,
|
||||
COALESCE(SUM(cache_read_tokens), 0) as total_cache_read_tokens,
|
||||
COALESCE(SUM(cache_write_tokens), 0) as total_cache_write_tokens,
|
||||
COALESCE(SUM(cost), 0.0) as total_cost,
|
||||
COUNT(DISTINCT client_id) as active_clients
|
||||
FROM llm_requests
|
||||
@@ -257,7 +261,6 @@ func (s *Server) handleUsageSummary(c *gin.Context) {
|
||||
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
|
||||
}
|
||||
@@ -279,14 +282,16 @@ func (s *Server) handleUsageSummary(c *gin.Context) {
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, SuccessResponse(gin.H{
|
||||
"total_requests": totalStats.TotalRequests,
|
||||
"total_tokens": totalStats.TotalTokens,
|
||||
"total_cost": totalStats.TotalCost,
|
||||
"active_clients": totalStats.ActiveClients,
|
||||
"today_requests": todayStats.TodayRequests,
|
||||
"today_cost": todayStats.TodayCost,
|
||||
"error_rate": miscStats.ErrorRate,
|
||||
"avg_response_time": miscStats.AvgResponseTime,
|
||||
"total_requests": totalStats.TotalRequests,
|
||||
"total_tokens": totalStats.TotalTokens,
|
||||
"total_cache_read_tokens": totalStats.CacheReadTokens,
|
||||
"total_cache_write_tokens": totalStats.CacheWriteTokens,
|
||||
"total_cost": totalStats.TotalCost,
|
||||
"active_clients": totalStats.ActiveClients,
|
||||
"today_requests": todayStats.TodayRequests,
|
||||
"today_cost": todayStats.TodayCost,
|
||||
"error_rate": miscStats.ErrorRate,
|
||||
"avg_response_time": miscStats.AvgResponseTime,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -307,7 +312,6 @@ func (s *Server) handleTimeSeries(c *gin.Context) {
|
||||
query := fmt.Sprintf(`
|
||||
SELECT
|
||||
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
|
||||
@@ -357,7 +361,10 @@ func (s *Server) handleProvidersUsage(c *gin.Context) {
|
||||
clause, binds := filter.ToSQL()
|
||||
|
||||
rows, err := s.database.Queryx(fmt.Sprintf(`
|
||||
SELECT COALESCE(provider, 'unknown') as provider, COUNT(*) as requests
|
||||
SELECT
|
||||
COALESCE(provider, 'unknown') as provider,
|
||||
COUNT(*) as requests,
|
||||
COALESCE(SUM(cost), 0.0) as cost
|
||||
FROM llm_requests
|
||||
WHERE 1=1 %s
|
||||
GROUP BY provider
|
||||
@@ -372,8 +379,9 @@ func (s *Server) handleProvidersUsage(c *gin.Context) {
|
||||
for rows.Next() {
|
||||
var provider string
|
||||
var requests int
|
||||
if err := rows.Scan(&provider, &requests); err == nil {
|
||||
results = append(results, gin.H{"provider": provider, "requests": requests})
|
||||
var cost float64
|
||||
if err := rows.Scan(&provider, &requests, &cost); err == nil {
|
||||
results = append(results, gin.H{"provider": provider, "requests": requests, "cost": cost})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -944,6 +952,8 @@ func (s *Server) handleTestProvider(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (s *Server) handleGetModels(c *gin.Context) {
|
||||
usedOnly := c.Query("used_only") == "true"
|
||||
|
||||
// Merge registry models with DB overrides
|
||||
var dbModels []db.ModelConfig
|
||||
_ = s.database.Select(&dbModels, "SELECT * FROM model_configs")
|
||||
@@ -953,10 +963,30 @@ func (s *Server) handleGetModels(c *gin.Context) {
|
||||
dbMap[m.ID] = m
|
||||
}
|
||||
|
||||
// Fetch set of used model IDs if requested
|
||||
usedModels := make(map[string]bool)
|
||||
if usedOnly {
|
||||
rows, err := s.database.Queryx("SELECT DISTINCT model FROM llm_requests")
|
||||
if err == nil {
|
||||
for rows.Next() {
|
||||
var mID string
|
||||
if err := rows.Scan(&mID); err == nil {
|
||||
usedModels[mID] = true
|
||||
}
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
}
|
||||
|
||||
var result []gin.H
|
||||
if s.registry != nil {
|
||||
for pID, pInfo := range s.registry.Providers {
|
||||
for mID, mMeta := range pInfo.Models {
|
||||
// Filter if used_only requested
|
||||
if usedOnly && !usedModels[mID] {
|
||||
continue
|
||||
}
|
||||
|
||||
enabled := true
|
||||
promptCost := 0.0
|
||||
completionCost := 0.0
|
||||
|
||||
Reference in New Issue
Block a user