diff --git a/model/pricing.go b/model/pricing.go index 0fee7cae..0fe23562 100644 --- a/model/pricing.go +++ b/model/pricing.go @@ -323,8 +323,8 @@ func updatePricing() { pricing.AudioCompletionRatio = &audioCompletionRatio } if billingMode := billing_setting.GetBillingMode(model); billingMode == "tiered_expr" { - pricing.BillingMode = billingMode - if expr, ok := billing_setting.GetBillingExpr(model); ok { + if expr, ok := billing_setting.GetBillingExpr(model); ok && expr != "" { + pricing.BillingMode = billingMode pricing.BillingExpr = expr } } diff --git a/relay/helper/price.go b/relay/helper/price.go index 09509cff..52b971c2 100644 --- a/relay/helper/price.go +++ b/relay/helper/price.go @@ -269,7 +269,7 @@ func modelPriceHelperTiered(c *gin.Context, info *relaycommon.RelayInfo, promptT freeModel := false if !operation_setting.GetQuotaSetting().EnableFreeModelPreConsume { - if groupRatioInfo.GroupRatio == 0 || quotaBeforeGroup == 0 { + if groupRatioInfo.GroupRatio == 0 { preConsumedQuota = 0 freeModel = true } diff --git a/service/quota.go b/service/quota.go index 7c54fc23..1f1f76ae 100644 --- a/service/quota.go +++ b/service/quota.go @@ -226,6 +226,10 @@ func PostWssConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, mod model.UpdateChannelUsedQuota(relayInfo.ChannelId, quota) } + if err := SettleBilling(ctx, relayInfo, quota); err != nil { + logger.LogError(ctx, "error settling billing: "+err.Error()) + } + logModel := modelName if extraContent != "" { logContent += ", " + extraContent diff --git a/service/text_quota.go b/service/text_quota.go index e2ec87b2..6f9f73c2 100644 --- a/service/text_quota.go +++ b/service/text_quota.go @@ -330,6 +330,7 @@ func PostTextConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, us summary := calculateTextQuotaSummary(ctx, relayInfo, usage) var tieredResult *billingexpr.TieredResult + tieredBillingApplied := false if originUsage != nil { var tieredUsedVars map[string]bool if snap := relayInfo.TieredBillingSnapshot; snap != nil { @@ -337,6 +338,7 @@ func PostTextConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, us } tieredOk, tieredQuota, tieredRes := TryTieredSettle(relayInfo, BuildTieredTokenParams(usage, summary.IsClaudeUsageSemantic, tieredUsedVars)) if tieredOk { + tieredBillingApplied = true tieredResult = tieredRes summary.Quota = composeTieredTextQuota(relayInfo, summary, tieredQuota, tieredRes) } @@ -451,7 +453,7 @@ func PostTextConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, us // prompt/cache fields here, otherwise old upstream payloads may be double-counted. other["input_tokens_total"] = usage.InputTokens } - if tieredResult != nil { + if tieredBillingApplied { InjectTieredBillingInfo(other, relayInfo, tieredResult) } diff --git a/service/tiered_settle.go b/service/tiered_settle.go index 9a55cb7b..fd168ab2 100644 --- a/service/tiered_settle.go +++ b/service/tiered_settle.go @@ -22,8 +22,14 @@ func BuildTieredTokenParams(usage *dto.Usage, isClaudeUsageSemantic bool, usedVa p := float64(usage.PromptTokens) c := float64(usage.CompletionTokens) cr := float64(usage.PromptTokensDetails.CachedTokens) - ccTotal := float64(usage.PromptTokensDetails.CachedCreationTokens) - cc1h := float64(usage.ClaudeCacheCreation1hTokens) + cc5m := float64(usage.PromptTokensDetails.CachedCreationTokens) + cc1h := float64(0) + + if usage.UsageSemantic == "anthropic" { + cc1h = float64(usage.ClaudeCacheCreation1hTokens) + cc5m = float64(usage.ClaudeCacheCreation5mTokens) + } + img := float64(usage.PromptTokensDetails.ImageTokens) ai := float64(usage.PromptTokensDetails.AudioTokens) imgO := float64(usage.CompletionTokenDetails.ImageTokens) @@ -33,8 +39,11 @@ func BuildTieredTokenParams(usage *dto.Usage, isClaudeUsageSemantic bool, usedVa if usedVars["cr"] { p -= cr } - if usedVars["cc"] || usedVars["cc1h"] { - p -= ccTotal + if usedVars["cc"] { + p -= cc5m + } + if usedVars["cc1h"] { + p -= cc1h } if usedVars["img"] { p -= img @@ -61,7 +70,7 @@ func BuildTieredTokenParams(usage *dto.Usage, isClaudeUsageSemantic bool, usedVa P: p, C: c, CR: cr, - CC: ccTotal - cc1h, + CC: cc5m, CC1h: cc1h, Img: img, ImgO: imgO, diff --git a/web/src/pages/Setting/Ratio/hooks/useModelPricingEditorState.js b/web/src/pages/Setting/Ratio/hooks/useModelPricingEditorState.js index 8712a686..f389ec9e 100644 --- a/web/src/pages/Setting/Ratio/hooks/useModelPricingEditorState.js +++ b/web/src/pages/Setting/Ratio/hooks/useModelPricingEditorState.js @@ -1041,12 +1041,12 @@ export function useModelPricingEditorState({ for (const model of models) { if (model.billingMode === 'tiered_expr') { - tieredOutput['billing_setting.billing_mode'][model.name] = 'tiered_expr'; const finalBillingExpr = combineBillingExpr( model.billingExpr, model.requestRuleExpr, ); if (finalBillingExpr) { + tieredOutput['billing_setting.billing_mode'][model.name] = 'tiered_expr'; tieredOutput['billing_setting.billing_expr'][model.name] = finalBillingExpr; } }