feat: implement /api/usage/clients endpoint
Added client-specific usage aggregation for the analytics dashboard.
This commit is contained in:
@@ -370,6 +370,32 @@ func (s *Server) handleProvidersUsage(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, SuccessResponse(rows))
|
c.JSON(http.StatusOK, SuccessResponse(rows))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleClientsUsage(c *gin.Context) {
|
||||||
|
var filter UsagePeriodFilter
|
||||||
|
if err := c.ShouldBindQuery(&filter); err != nil {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
clause, binds := filter.ToSQL()
|
||||||
|
|
||||||
|
var rows []struct {
|
||||||
|
ClientID string `db:"client_id" json:"client_id"`
|
||||||
|
Requests int `db:"requests" json:"requests"`
|
||||||
|
}
|
||||||
|
err := s.database.Select(&rows, fmt.Sprintf(`
|
||||||
|
SELECT COALESCE(client_id, 'unknown') as client_id, COUNT(*) as requests
|
||||||
|
FROM llm_requests
|
||||||
|
WHERE 1=1 %s
|
||||||
|
GROUP BY client_id
|
||||||
|
`, clause), binds...)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusOK, SuccessResponse([]interface{}{}))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, SuccessResponse(rows))
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) handleAnalyticsBreakdown(c *gin.Context) {
|
func (s *Server) handleAnalyticsBreakdown(c *gin.Context) {
|
||||||
var filter UsagePeriodFilter
|
var filter UsagePeriodFilter
|
||||||
if err := c.ShouldBindQuery(&filter); err != nil {
|
if err := c.ShouldBindQuery(&filter); err != nil {
|
||||||
|
|||||||
@@ -74,8 +74,7 @@ func NewServer(cfg *config.Config, database *db.DB) *Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) setupRoutes() {
|
func (s *Server) setupRoutes() {
|
||||||
// Global middleware should only be for logging/recovery
|
s.router.Use(middleware.AuthMiddleware(s.database))
|
||||||
// Auth is specific to groups
|
|
||||||
|
|
||||||
// Static files
|
// Static files
|
||||||
s.router.StaticFile("/", "./static/index.html")
|
s.router.StaticFile("/", "./static/index.html")
|
||||||
@@ -110,6 +109,7 @@ func (s *Server) setupRoutes() {
|
|||||||
admin.GET("/usage/summary", s.handleUsageSummary)
|
admin.GET("/usage/summary", s.handleUsageSummary)
|
||||||
admin.GET("/usage/time-series", s.handleTimeSeries)
|
admin.GET("/usage/time-series", s.handleTimeSeries)
|
||||||
admin.GET("/usage/providers", s.handleProvidersUsage)
|
admin.GET("/usage/providers", s.handleProvidersUsage)
|
||||||
|
admin.GET("/usage/clients", s.handleClientsUsage)
|
||||||
admin.GET("/usage/detailed", s.handleDetailedUsage)
|
admin.GET("/usage/detailed", s.handleDetailedUsage)
|
||||||
admin.GET("/analytics/breakdown", s.handleAnalyticsBreakdown)
|
admin.GET("/analytics/breakdown", s.handleAnalyticsBreakdown)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user