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
|
// Total stats
|
||||||
var totalStats struct {
|
var totalStats struct {
|
||||||
TotalRequests int `db:"total_requests"`
|
TotalRequests int `db:"total_requests"`
|
||||||
TotalTokens int `db:"total_tokens"`
|
TotalTokens int `db:"total_tokens"`
|
||||||
TotalCost float64 `db:"total_cost"`
|
CacheReadTokens int `db:"total_cache_read_tokens"`
|
||||||
ActiveClients int `db:"active_clients"`
|
CacheWriteTokens int `db:"total_cache_write_tokens"`
|
||||||
|
TotalCost float64 `db:"total_cost"`
|
||||||
|
ActiveClients int `db:"active_clients"`
|
||||||
}
|
}
|
||||||
err := s.database.Get(&totalStats, fmt.Sprintf(`
|
err := s.database.Get(&totalStats, fmt.Sprintf(`
|
||||||
SELECT
|
SELECT
|
||||||
COUNT(*) as total_requests,
|
COUNT(*) as total_requests,
|
||||||
COALESCE(SUM(total_tokens), 0) as total_tokens,
|
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,
|
COALESCE(SUM(cost), 0.0) as total_cost,
|
||||||
COUNT(DISTINCT client_id) as active_clients
|
COUNT(DISTINCT client_id) as active_clients
|
||||||
FROM llm_requests
|
FROM llm_requests
|
||||||
@@ -257,7 +261,6 @@ func (s *Server) handleUsageSummary(c *gin.Context) {
|
|||||||
WHERE timestamp LIKE ?
|
WHERE timestamp LIKE ?
|
||||||
`, today+"%")
|
`, today+"%")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("[ERROR] Failed to fetch today stats: %v\n", err)
|
|
||||||
todayStats.TodayRequests = 0
|
todayStats.TodayRequests = 0
|
||||||
todayStats.TodayCost = 0.0
|
todayStats.TodayCost = 0.0
|
||||||
}
|
}
|
||||||
@@ -279,14 +282,16 @@ func (s *Server) handleUsageSummary(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, SuccessResponse(gin.H{
|
c.JSON(http.StatusOK, SuccessResponse(gin.H{
|
||||||
"total_requests": totalStats.TotalRequests,
|
"total_requests": totalStats.TotalRequests,
|
||||||
"total_tokens": totalStats.TotalTokens,
|
"total_tokens": totalStats.TotalTokens,
|
||||||
"total_cost": totalStats.TotalCost,
|
"total_cache_read_tokens": totalStats.CacheReadTokens,
|
||||||
"active_clients": totalStats.ActiveClients,
|
"total_cache_write_tokens": totalStats.CacheWriteTokens,
|
||||||
"today_requests": todayStats.TodayRequests,
|
"total_cost": totalStats.TotalCost,
|
||||||
"today_cost": todayStats.TodayCost,
|
"active_clients": totalStats.ActiveClients,
|
||||||
"error_rate": miscStats.ErrorRate,
|
"today_requests": todayStats.TodayRequests,
|
||||||
"avg_response_time": miscStats.AvgResponseTime,
|
"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(`
|
query := fmt.Sprintf(`
|
||||||
SELECT
|
SELECT
|
||||||
COALESCE(SUBSTR(timestamp, 1, 10), 'unknown') as bucket,
|
COALESCE(SUBSTR(timestamp, 1, 10), 'unknown') as bucket,
|
||||||
|
|
||||||
COUNT(*) as requests,
|
COUNT(*) as requests,
|
||||||
COALESCE(SUM(total_tokens), 0) as tokens,
|
COALESCE(SUM(total_tokens), 0) as tokens,
|
||||||
COALESCE(SUM(cost), 0.0) as cost
|
COALESCE(SUM(cost), 0.0) as cost
|
||||||
@@ -357,7 +361,10 @@ func (s *Server) handleProvidersUsage(c *gin.Context) {
|
|||||||
clause, binds := filter.ToSQL()
|
clause, binds := filter.ToSQL()
|
||||||
|
|
||||||
rows, err := s.database.Queryx(fmt.Sprintf(`
|
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
|
FROM llm_requests
|
||||||
WHERE 1=1 %s
|
WHERE 1=1 %s
|
||||||
GROUP BY provider
|
GROUP BY provider
|
||||||
@@ -372,8 +379,9 @@ func (s *Server) handleProvidersUsage(c *gin.Context) {
|
|||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var provider string
|
var provider string
|
||||||
var requests int
|
var requests int
|
||||||
if err := rows.Scan(&provider, &requests); err == nil {
|
var cost float64
|
||||||
results = append(results, gin.H{"provider": provider, "requests": requests})
|
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) {
|
func (s *Server) handleGetModels(c *gin.Context) {
|
||||||
|
usedOnly := c.Query("used_only") == "true"
|
||||||
|
|
||||||
// Merge registry models with DB overrides
|
// Merge registry models with DB overrides
|
||||||
var dbModels []db.ModelConfig
|
var dbModels []db.ModelConfig
|
||||||
_ = s.database.Select(&dbModels, "SELECT * FROM model_configs")
|
_ = s.database.Select(&dbModels, "SELECT * FROM model_configs")
|
||||||
@@ -953,10 +963,30 @@ func (s *Server) handleGetModels(c *gin.Context) {
|
|||||||
dbMap[m.ID] = m
|
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
|
var result []gin.H
|
||||||
if s.registry != nil {
|
if s.registry != nil {
|
||||||
for pID, pInfo := range s.registry.Providers {
|
for pID, pInfo := range s.registry.Providers {
|
||||||
for mID, mMeta := range pInfo.Models {
|
for mID, mMeta := range pInfo.Models {
|
||||||
|
// Filter if used_only requested
|
||||||
|
if usedOnly && !usedModels[mID] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
enabled := true
|
enabled := true
|
||||||
promptCost := 0.0
|
promptCost := 0.0
|
||||||
completionCost := 0.0
|
completionCost := 0.0
|
||||||
|
|||||||
Reference in New Issue
Block a user