fix: prevent float-to-int truncation turning small billing amounts (e.g. 0.01) into 0 in use-price paths\n\n- service/quota.go: replace IntPart() with Round(0).IntPart() + safety net\n- relay/helper/price.go: replace int(float64) with int(math.Round()) + safety net\n- controller/channel-test.go: same fix for test billing calculation\n- All use-price paths now round instead of truncate, and guarantee minimum 1 quota when effective pricing > 0
This commit is contained in:
parent
648c9917ab
commit
789f3b43e4
|
|
@ -645,7 +645,11 @@ func testChannel(channel *model.Channel, testModel string, endpointType string,
|
|||
quota = 1
|
||||
}
|
||||
} else {
|
||||
quota = int(priceData.ModelPrice * common.QuotaPerUnit)
|
||||
quota = int(math.Round(priceData.ModelPrice * common.QuotaPerUnit))
|
||||
// 有有效定价但舍入为 0 时保底为 1
|
||||
if quota == 0 && priceData.ModelPrice > 0 {
|
||||
quota = 1
|
||||
}
|
||||
}
|
||||
tok := time.Now()
|
||||
milliseconds := tok.Sub(tik).Milliseconds()
|
||||
|
|
|
|||
|
|
@ -172,7 +172,11 @@ func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens
|
|||
effModelPrice = effModelPrice * meta.ImagePriceRatio
|
||||
modelPrice = modelPrice * meta.ImagePriceRatio // 保持 ModelPrice 字段与 imagePriceRatio 一致(供日志展示)
|
||||
}
|
||||
preConsumedQuota = int(effModelPrice * common.QuotaPerUnit * groupRatioInfo.GroupRatio)
|
||||
preConsumedQuota = int(math.Round(effModelPrice * common.QuotaPerUnit * groupRatioInfo.GroupRatio))
|
||||
// 有有效定价但舍入为 0 时保底为 1,避免计费为 0
|
||||
if preConsumedQuota == 0 && effModelPrice > 0 && groupRatioInfo.GroupRatio > 0 {
|
||||
preConsumedQuota = 1
|
||||
}
|
||||
}
|
||||
|
||||
// check if free model pre-consume is disabled
|
||||
|
|
@ -276,7 +280,11 @@ func ModelPriceHelperPerCall(c *gin.Context, info *relaycommon.RelayInfo) (types
|
|||
markupDisc := effectiveMarkupDiscountPercent(c, info, channelID, info.OriginModelName)
|
||||
globalPrice, _ := ratio_setting.GetModelPrice(info.OriginModelName, false)
|
||||
effModelPrice := model.EffectiveModelPrice(modelPrice, globalPrice, chDisc, markupDisc)
|
||||
quota := int(effModelPrice * common.QuotaPerUnit * groupRatioInfo.GroupRatio)
|
||||
quota := int(math.Round(effModelPrice * common.QuotaPerUnit * groupRatioInfo.GroupRatio))
|
||||
// 有有效定价但舍入为 0 时保底为 1,避免计费为 0
|
||||
if quota == 0 && effModelPrice > 0 && groupRatioInfo.GroupRatio > 0 {
|
||||
quota = 1
|
||||
}
|
||||
|
||||
// 免费模型检测(与 ModelPriceHelper 对齐)
|
||||
freeModel := false
|
||||
|
|
|
|||
|
|
@ -66,7 +66,12 @@ func calculateAudioQuota(info QuotaInfo) int {
|
|||
// 新公式:固定价格 = 渠道固定价 * 成本折扣率% + 全局固定价 * 加价折扣率%
|
||||
effModelPrice := model.EffectiveModelPrice(info.ModelPrice, info.GlobalModelPrice, costDisc, markupDisc)
|
||||
quota := decimal.NewFromFloat(effModelPrice).Mul(quotaPerUnit).Mul(groupRatio)
|
||||
return int(quota.IntPart())
|
||||
quotaInt := int(quota.Round(0).IntPart())
|
||||
// 有有效定价但舍入为 0 时保底为 1,避免计费为 0
|
||||
if info.UsePrice && quotaInt == 0 && quota.GreaterThan(decimal.Zero) {
|
||||
quotaInt = 1
|
||||
}
|
||||
return quotaInt
|
||||
}
|
||||
|
||||
completionRatio := decimal.NewFromFloat(ratio_setting.GetCompletionRatio(info.ModelName))
|
||||
|
|
@ -101,7 +106,12 @@ func calculateAudioQuota(info QuotaInfo) int {
|
|||
quota = decimal.NewFromInt(1)
|
||||
}
|
||||
|
||||
return int(quota.Round(0).IntPart())
|
||||
quotaInt := int(quota.Round(0).IntPart())
|
||||
// 有有效输入倍率但舍入为 0 时保底为 1(如 0.01 经 Round 后为 0)
|
||||
if quotaInt == 0 && effInputRate > 0 && quota.GreaterThan(decimal.Zero) {
|
||||
quotaInt = 1
|
||||
}
|
||||
return quotaInt
|
||||
}
|
||||
|
||||
func PreWssConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage *dto.RealtimeUsage) error {
|
||||
|
|
|
|||
Loading…
Reference in New Issue