From 530af5e35824aecba42e5d4b9493eab9688cdf29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?lollipopkit=F0=9F=8F=B3=EF=B8=8F=E2=80=8D=E2=9A=A7?= =?UTF-8?q?=EF=B8=8F?= <10864310+lollipopkit@users.noreply.github.com> Date: Tue, 29 Apr 2025 17:13:28 +0800 Subject: [PATCH 1/2] feat: `/api/token/usage` --- controller/token.go | 54 +++++++++++++++++++++++++++++++++++++++++++- router/api-router.go | 2 +- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/controller/token.go b/controller/token.go index a8803279..0afb1391 100644 --- a/controller/token.go +++ b/controller/token.go @@ -1,11 +1,13 @@ package controller import ( - "github.com/gin-gonic/gin" "net/http" "one-api/common" "one-api/model" "strconv" + "strings" + + "github.com/gin-gonic/gin" ) func GetAllTokens(c *gin.Context) { @@ -106,6 +108,56 @@ func GetTokenStatus(c *gin.Context) { }) } +func GetTokenUsage(c *gin.Context) { + authHeader := c.GetHeader("Authorization") + if authHeader == "" { + c.JSON(http.StatusUnauthorized, gin.H{ + "success": false, + "message": "No Authorization header", + }) + return + } + + parts := strings.Split(authHeader, " ") + if len(parts) != 2 || strings.ToLower(parts[0]) != "bearer" { + c.JSON(http.StatusUnauthorized, gin.H{ + "success": false, + "message": "Invalid Bearer token", + }) + return + } + tokenKey := parts[1] + + token, err := model.GetTokenByKey(tokenKey, true) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "success": false, + "message": err.Error(), + }) + return + } + + expiredAt := token.ExpiredTime + if expiredAt == -1 { + expiredAt = 0 + } + + c.JSON(http.StatusOK, gin.H{ + "code": true, + "message": "ok", + "data": gin.H{ + "object": "token_usage", + "id": token.Id, + "name": token.Name, + "total_granted": token.RemainQuota + token.UsedQuota, + "total_used": token.UsedQuota, + "total_available": token.RemainQuota, + "unlimited_quota": token.UnlimitedQuota, + "expires_at": expiredAt, + }, + }) +} + func AddToken(c *gin.Context) { token := model.Token{} err := c.ShouldBindJSON(&token) diff --git a/router/api-router.go b/router/api-router.go index 1720ff57..7bbc654a 100644 --- a/router/api-router.go +++ b/router/api-router.go @@ -111,6 +111,7 @@ func SetApiRouter(router *gin.Engine) { { tokenRoute.GET("/", controller.GetAllTokens) tokenRoute.GET("/search", controller.SearchTokens) + tokenRoute.GET("/usage", controller.GetTokenUsage) tokenRoute.GET("/:id", controller.GetToken) tokenRoute.POST("/", controller.AddToken) tokenRoute.PUT("/", controller.UpdateToken) @@ -142,7 +143,6 @@ func SetApiRouter(router *gin.Engine) { logRoute.Use(middleware.CORS()) { logRoute.GET("/token", controller.GetLogByKey) - } groupRoute := apiRouter.Group("/group") groupRoute.Use(middleware.AdminAuth()) From 93ce48aca85b0efe5d953a1bc1cb6613e17d1990 Mon Sep 17 00:00:00 2001 From: CaIon Date: Sat, 23 Aug 2025 15:45:43 +0800 Subject: [PATCH 2/2] feat: restructure token usage routes and enhance token retrieval logic --- controller/token.go | 21 +++++++++++---------- router/api-router.go | 12 +++++++++++- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/controller/token.go b/controller/token.go index 5b96a2b7..8ed8b957 100644 --- a/controller/token.go +++ b/controller/token.go @@ -103,7 +103,7 @@ func GetTokenUsage(c *gin.Context) { } tokenKey := parts[1] - token, err := model.GetTokenByKey(tokenKey, true) + token, err := model.GetTokenByKey(strings.TrimPrefix(tokenKey, "sk-"), false) if err != nil { c.JSON(http.StatusOK, gin.H{ "success": false, @@ -118,17 +118,18 @@ func GetTokenUsage(c *gin.Context) { } c.JSON(http.StatusOK, gin.H{ - "code": true, + "code": true, "message": "ok", "data": gin.H{ - "object": "token_usage", - "id": token.Id, - "name": token.Name, - "total_granted": token.RemainQuota + token.UsedQuota, - "total_used": token.UsedQuota, - "total_available": token.RemainQuota, - "unlimited_quota": token.UnlimitedQuota, - "expires_at": expiredAt, + "object": "token_usage", + "name": token.Name, + "total_granted": token.RemainQuota + token.UsedQuota, + "total_used": token.UsedQuota, + "total_available": token.RemainQuota, + "unlimited_quota": token.UnlimitedQuota, + "model_limits": token.GetModelLimitsMap(), + "model_limits_enabled": token.ModelLimitsEnabled, + "expires_at": expiredAt, }, }) } diff --git a/router/api-router.go b/router/api-router.go index 7a60994d..be721b05 100644 --- a/router/api-router.go +++ b/router/api-router.go @@ -139,13 +139,23 @@ func SetApiRouter(router *gin.Engine) { { tokenRoute.GET("/", controller.GetAllTokens) tokenRoute.GET("/search", controller.SearchTokens) - tokenRoute.GET("/usage", controller.GetTokenUsage) tokenRoute.GET("/:id", controller.GetToken) tokenRoute.POST("/", controller.AddToken) tokenRoute.PUT("/", controller.UpdateToken) tokenRoute.DELETE("/:id", controller.DeleteToken) tokenRoute.POST("/batch", controller.DeleteTokenBatch) } + + usageRoute := apiRouter.Group("/usage") + usageRoute.Use(middleware.CriticalRateLimit()) + { + tokenUsageRoute := usageRoute.Group("/token") + tokenUsageRoute.Use(middleware.TokenAuth()) + { + tokenUsageRoute.GET("/", controller.GetTokenUsage) + } + } + redemptionRoute := apiRouter.Group("/redemption") redemptionRoute.Use(middleware.AdminAuth()) {