mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-09-12 23:30:35 +00:00
fix(billing): surface quota saturation events for admin auditing
Thread int32 saturation clamps from tiered settlement and video task recompute into the consume/task logs under admin_info, so oversized or malformed billing inputs stay auditable. Clamp negative audio duration before token conversion and gate the saturation UI markers on admin.
This commit is contained in:
+11
-6
@@ -47,14 +47,14 @@ func hasCustomModelRatio(modelName string, currentRatio float64) bool {
|
||||
return currentRatio != defaultRatio
|
||||
}
|
||||
|
||||
func calculateAudioQuota(info QuotaInfo) int {
|
||||
func calculateAudioQuota(info QuotaInfo) (int, *common.QuotaClamp) {
|
||||
if info.UsePrice {
|
||||
modelPrice := decimal.NewFromFloat(info.ModelPrice)
|
||||
quotaPerUnit := decimal.NewFromFloat(common.QuotaPerUnit)
|
||||
groupRatio := decimal.NewFromFloat(info.GroupRatio)
|
||||
|
||||
quota := modelPrice.Mul(quotaPerUnit).Mul(groupRatio)
|
||||
return decimalToQuota(quota)
|
||||
return common.QuotaFromDecimalChecked(quota)
|
||||
}
|
||||
|
||||
completionRatio := decimal.NewFromFloat(ratio_setting.GetCompletionRatio(info.ModelName))
|
||||
@@ -83,7 +83,7 @@ func calculateAudioQuota(info QuotaInfo) int {
|
||||
quota = decimal.NewFromInt(1)
|
||||
}
|
||||
|
||||
return decimalToQuota(quota)
|
||||
return common.QuotaFromDecimalChecked(quota)
|
||||
}
|
||||
|
||||
func PreWssConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage *dto.RealtimeUsage) error {
|
||||
@@ -136,7 +136,8 @@ func PreWssConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usag
|
||||
GroupRatio: actualGroupRatio,
|
||||
}
|
||||
|
||||
quota := calculateAudioQuota(quotaInfo)
|
||||
quota, clamp := calculateAudioQuota(quotaInfo)
|
||||
noteQuotaClamp(relayInfo, clamp)
|
||||
|
||||
if userQuota < quota {
|
||||
return fmt.Errorf("user quota is not enough, user quota: %s, need quota: %s", logger.FormatQuota(userQuota), logger.FormatQuota(quota))
|
||||
@@ -199,7 +200,8 @@ func PostWssConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, mod
|
||||
GroupRatio: groupRatio,
|
||||
}
|
||||
|
||||
quota := calculateAudioQuota(quotaInfo)
|
||||
quota, clamp := calculateAudioQuota(quotaInfo)
|
||||
noteQuotaClamp(relayInfo, clamp)
|
||||
if tieredOk {
|
||||
quota = tieredQuota
|
||||
}
|
||||
@@ -239,6 +241,7 @@ func PostWssConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, mod
|
||||
if tieredResult != nil {
|
||||
InjectTieredBillingInfo(other, relayInfo, tieredResult)
|
||||
}
|
||||
attachQuotaSaturation(ctx, relayInfo, other)
|
||||
model.RecordConsumeLog(ctx, relayInfo.UserId, model.RecordConsumeLogParams{
|
||||
ChannelId: relayInfo.ChannelId,
|
||||
PromptTokens: usage.InputTokens,
|
||||
@@ -320,7 +323,8 @@ func PostAudioConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, u
|
||||
GroupRatio: groupRatio,
|
||||
}
|
||||
|
||||
quota := calculateAudioQuota(quotaInfo)
|
||||
quota, clamp := calculateAudioQuota(quotaInfo)
|
||||
noteQuotaClamp(relayInfo, clamp)
|
||||
if tieredOk {
|
||||
quota = tieredQuota
|
||||
}
|
||||
@@ -360,6 +364,7 @@ func PostAudioConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, u
|
||||
if tieredResult != nil {
|
||||
InjectTieredBillingInfo(other, relayInfo, tieredResult)
|
||||
}
|
||||
attachQuotaSaturation(ctx, relayInfo, other)
|
||||
model.RecordConsumeLog(ctx, relayInfo.UserId, model.RecordConsumeLogParams{
|
||||
ChannelId: relayInfo.ChannelId,
|
||||
PromptTokens: usage.PromptTokens,
|
||||
|
||||
Reference in New Issue
Block a user