Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
e204b4d8
Unverified
Commit
e204b4d8
authored
Feb 02, 2026
by
Wesley Liddick
Committed by
GitHub
Feb 02, 2026
Browse files
Merge pull request #452 from s-Joshua-s/feat/enhance-usage-endpoint
feat(gateway): 增强 /v1/usage 端点返回完整用量统计
parents
325ed747
c441638f
Changes
2
Hide whitespace changes
Inline
Side-by-side
backend/cmd/server/wire_gen.go
View file @
e204b4d8
...
...
@@ -173,7 +173,7 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
userAttributeService
:=
service
.
NewUserAttributeService
(
userAttributeDefinitionRepository
,
userAttributeValueRepository
)
userAttributeHandler
:=
admin
.
NewUserAttributeHandler
(
userAttributeService
)
adminHandlers
:=
handler
.
ProvideAdminHandlers
(
dashboardHandler
,
adminUserHandler
,
groupHandler
,
accountHandler
,
adminAnnouncementHandler
,
oAuthHandler
,
openAIOAuthHandler
,
geminiOAuthHandler
,
antigravityOAuthHandler
,
proxyHandler
,
adminRedeemHandler
,
promoHandler
,
settingHandler
,
opsHandler
,
systemHandler
,
adminSubscriptionHandler
,
adminUsageHandler
,
userAttributeHandler
)
gatewayHandler
:=
handler
.
NewGatewayHandler
(
gatewayService
,
geminiMessagesCompatService
,
antigravityGatewayService
,
userService
,
concurrencyService
,
billingCacheService
,
configConfig
)
gatewayHandler
:=
handler
.
NewGatewayHandler
(
gatewayService
,
geminiMessagesCompatService
,
antigravityGatewayService
,
userService
,
concurrencyService
,
billingCacheService
,
usageService
,
configConfig
)
openAIGatewayHandler
:=
handler
.
NewOpenAIGatewayHandler
(
openAIGatewayService
,
concurrencyService
,
billingCacheService
,
configConfig
)
handlerSettingHandler
:=
handler
.
ProvideSettingHandler
(
settingService
,
buildInfo
)
totpHandler
:=
handler
.
NewTotpHandler
(
totpService
)
...
...
backend/internal/handler/gateway_handler.go
View file @
e204b4d8
...
...
@@ -30,6 +30,7 @@ type GatewayHandler struct {
antigravityGatewayService
*
service
.
AntigravityGatewayService
userService
*
service
.
UserService
billingCacheService
*
service
.
BillingCacheService
usageService
*
service
.
UsageService
concurrencyHelper
*
ConcurrencyHelper
maxAccountSwitches
int
maxAccountSwitchesGemini
int
...
...
@@ -43,6 +44,7 @@ func NewGatewayHandler(
userService
*
service
.
UserService
,
concurrencyService
*
service
.
ConcurrencyService
,
billingCacheService
*
service
.
BillingCacheService
,
usageService
*
service
.
UsageService
,
cfg
*
config
.
Config
,
)
*
GatewayHandler
{
pingInterval
:=
time
.
Duration
(
0
)
...
...
@@ -63,6 +65,7 @@ func NewGatewayHandler(
antigravityGatewayService
:
antigravityGatewayService
,
userService
:
userService
,
billingCacheService
:
billingCacheService
,
usageService
:
usageService
,
concurrencyHelper
:
NewConcurrencyHelper
(
concurrencyService
,
SSEPingFormatClaude
,
pingInterval
),
maxAccountSwitches
:
maxAccountSwitches
,
maxAccountSwitchesGemini
:
maxAccountSwitchesGemini
,
...
...
@@ -524,7 +527,7 @@ func (h *GatewayHandler) AntigravityModels(c *gin.Context) {
})
}
// Usage handles getting account balance for CC Switch integration
// Usage handles getting account balance
and usage statistics
for CC Switch integration
// GET /v1/usage
func
(
h
*
GatewayHandler
)
Usage
(
c
*
gin
.
Context
)
{
apiKey
,
ok
:=
middleware2
.
GetAPIKeyFromContext
(
c
)
...
...
@@ -539,7 +542,40 @@ func (h *GatewayHandler) Usage(c *gin.Context) {
return
}
// 订阅模式:返回订阅限额信息
// Best-effort: 获取用量统计,失败不影响基础响应
var
usageData
gin
.
H
if
h
.
usageService
!=
nil
{
dashStats
,
err
:=
h
.
usageService
.
GetUserDashboardStats
(
c
.
Request
.
Context
(),
subject
.
UserID
)
if
err
==
nil
&&
dashStats
!=
nil
{
usageData
=
gin
.
H
{
"today"
:
gin
.
H
{
"requests"
:
dashStats
.
TodayRequests
,
"input_tokens"
:
dashStats
.
TodayInputTokens
,
"output_tokens"
:
dashStats
.
TodayOutputTokens
,
"cache_creation_tokens"
:
dashStats
.
TodayCacheCreationTokens
,
"cache_read_tokens"
:
dashStats
.
TodayCacheReadTokens
,
"total_tokens"
:
dashStats
.
TodayTokens
,
"cost"
:
dashStats
.
TodayCost
,
"actual_cost"
:
dashStats
.
TodayActualCost
,
},
"total"
:
gin
.
H
{
"requests"
:
dashStats
.
TotalRequests
,
"input_tokens"
:
dashStats
.
TotalInputTokens
,
"output_tokens"
:
dashStats
.
TotalOutputTokens
,
"cache_creation_tokens"
:
dashStats
.
TotalCacheCreationTokens
,
"cache_read_tokens"
:
dashStats
.
TotalCacheReadTokens
,
"total_tokens"
:
dashStats
.
TotalTokens
,
"cost"
:
dashStats
.
TotalCost
,
"actual_cost"
:
dashStats
.
TotalActualCost
,
},
"average_duration_ms"
:
dashStats
.
AverageDurationMs
,
"rpm"
:
dashStats
.
Rpm
,
"tpm"
:
dashStats
.
Tpm
,
}
}
}
// 订阅模式:返回订阅限额信息 + 用量统计
if
apiKey
.
Group
!=
nil
&&
apiKey
.
Group
.
IsSubscriptionType
()
{
subscription
,
ok
:=
middleware2
.
GetSubscriptionFromContext
(
c
)
if
!
ok
{
...
...
@@ -548,28 +584,46 @@ func (h *GatewayHandler) Usage(c *gin.Context) {
}
remaining
:=
h
.
calculateSubscriptionRemaining
(
apiKey
.
Group
,
subscription
)
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
resp
:=
gin
.
H
{
"isValid"
:
true
,
"planName"
:
apiKey
.
Group
.
Name
,
"remaining"
:
remaining
,
"unit"
:
"USD"
,
})
"subscription"
:
gin
.
H
{
"daily_usage_usd"
:
subscription
.
DailyUsageUSD
,
"weekly_usage_usd"
:
subscription
.
WeeklyUsageUSD
,
"monthly_usage_usd"
:
subscription
.
MonthlyUsageUSD
,
"daily_limit_usd"
:
apiKey
.
Group
.
DailyLimitUSD
,
"weekly_limit_usd"
:
apiKey
.
Group
.
WeeklyLimitUSD
,
"monthly_limit_usd"
:
apiKey
.
Group
.
MonthlyLimitUSD
,
"expires_at"
:
subscription
.
ExpiresAt
,
},
}
if
usageData
!=
nil
{
resp
[
"usage"
]
=
usageData
}
c
.
JSON
(
http
.
StatusOK
,
resp
)
return
}
// 余额模式:返回钱包余额
// 余额模式:返回钱包余额
+ 用量统计
latestUser
,
err
:=
h
.
userService
.
GetByID
(
c
.
Request
.
Context
(),
subject
.
UserID
)
if
err
!=
nil
{
h
.
errorResponse
(
c
,
http
.
StatusInternalServerError
,
"api_error"
,
"Failed to get user info"
)
return
}
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
resp
:=
gin
.
H
{
"isValid"
:
true
,
"planName"
:
"钱包余额"
,
"remaining"
:
latestUser
.
Balance
,
"unit"
:
"USD"
,
})
"balance"
:
latestUser
.
Balance
,
}
if
usageData
!=
nil
{
resp
[
"usage"
]
=
usageData
}
c
.
JSON
(
http
.
StatusOK
,
resp
)
}
// calculateSubscriptionRemaining 计算订阅剩余可用额度
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment