From 15a99da48ef7aca26b0fb2700fb67b11266ee50d Mon Sep 17 00:00:00 2001 From: fengsilin Date: Wed, 25 Mar 2026 10:55:39 +0800 Subject: [PATCH] fix: channel pricing not working correctly This PR fixes three issues: 1. Token bound_channel_id not updating: Add bound field to Update() method 2. Channel pricing quota_type detection: Use QuotaTypeByCall constant instead of magic number 1 3. Log display for ratio-based pricing: Set ModelPrice=-1 for ratio-based pricing Co-Authored-By: Claude Opus 4.6 --- .gitignore | 3 +++ controller/relay.go | 3 +++ model/channel_pricing.go | 4 ++-- model/token.go | 2 +- relay/helper/price.go | 38 +++++++++++++++++++++++++++++++++++++- 5 files changed, 46 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 0d725d5..dc9700e 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,6 @@ data/ .gomodcache/ .gocache-temp .gopath + +# 测试脚本目录 +test-scripts/ diff --git a/controller/relay.go b/controller/relay.go index edea158..b8c2dc0 100644 --- a/controller/relay.go +++ b/controller/relay.go @@ -191,6 +191,9 @@ func Relay(c *gin.Context, relayFormat types.RelayFormat) { break } + // 在渠道选择后更新价格数据以使用渠道定价 + helper.UpdatePriceDataForChannelPricing(c, relayInfo, channel.Id) + addUsedChannel(c, channel.Id) bodyStorage, bodyErr := common.GetBodyStorage(c) if bodyErr != nil { diff --git a/model/channel_pricing.go b/model/channel_pricing.go index 721d95e..e1f82eb 100644 --- a/model/channel_pricing.go +++ b/model/channel_pricing.go @@ -150,7 +150,7 @@ func GetEffectivePricing(modelName string, channelId int) (modelRatio, completio if time.Since(channelPricingCacheTime) < channelPricingCacheTTL { if cp, ok := channelPricingCache[cacheKey]; ok { channelPricingCacheLock.RUnlock() - return cp.ModelRatio, cp.CompletionRatio, cp.ModelPrice, true, true + return cp.ModelRatio, cp.CompletionRatio, cp.ModelPrice, cp.QuotaType == QuotaTypeByCall, true } } channelPricingCacheLock.RUnlock() @@ -173,7 +173,7 @@ func GetEffectivePricing(modelName string, channelId int) (modelRatio, completio channelPricingCache[cacheKey] = &cp channelPricingCacheLock.Unlock() - return cp.ModelRatio, cp.CompletionRatio, cp.ModelPrice, true, true + return cp.ModelRatio, cp.CompletionRatio, cp.ModelPrice, cp.QuotaType == QuotaTypeByCall, true } // RefreshChannelPricingCache 刷新渠道定价缓存 diff --git a/model/token.go b/model/token.go index 5f10ad5..3bee9e8 100644 --- a/model/token.go +++ b/model/token.go @@ -284,7 +284,7 @@ func (token *Token) Update() (err error) { } }() err = DB.Model(token).Select("name", "status", "expired_time", "remain_quota", "unlimited_quota", - "model_limits_enabled", "model_limits", "allow_ips", "group", "cross_group_retry").Updates(token).Error + "model_limits_enabled", "model_limits", "allow_ips", "group", "cross_group_retry", "bound_channel_id").Updates(token).Error return err } diff --git a/relay/helper/price.go b/relay/helper/price.go index 2734584..78a0532 100644 --- a/relay/helper/price.go +++ b/relay/helper/price.go @@ -54,7 +54,7 @@ func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens var channelPricingFound bool // 尝试获取渠道定价(优先于全局定价) - if info.ChannelMeta != nil && info.ChannelId > 0 { + if info != nil && info.ChannelMeta != nil && info.ChannelId > 0 { cpRatio, cpCompletionRatio, cpPrice, cpUsePrice, found := model.GetEffectivePricing(info.OriginModelName, info.ChannelId) if found { modelRatio = cpRatio @@ -207,3 +207,39 @@ func ContainPriceOrRatio(modelName string) bool { } return false } + +// UpdatePriceDataForChannelPricing 在渠道选择后更新 PriceData 以使用渠道定价 +// ModelPriceHelper 在渠道选择之前被调用,此时 ChannelMeta 为 nil,导致渠道定价无法使用。 +// 需要在渠道选择后调用此函数更新价格数据,用于后续的日志记录和计费计算。 +func UpdatePriceDataForChannelPricing(c *gin.Context, info *relaycommon.RelayInfo, channelId int) { + if info == nil || channelId <= 0 { + return + } + + cpRatio, cpCompletionRatio, cpPrice, cpUsePrice, found := model.GetEffectivePricing(info.OriginModelName, channelId) + if !found { + return + } + + // 更新 PriceData 中的定价相关字段 + info.PriceData.ModelRatio = cpRatio + info.PriceData.CompletionRatio = cpCompletionRatio + info.PriceData.UsePrice = cpUsePrice + // 按次计费模式下使用渠道价格,按量计费模式下设置 ModelPrice = -1 让前端识别计费模式 + if cpUsePrice { + info.PriceData.ModelPrice = cpPrice + } else { + info.PriceData.ModelPrice = -1 + } + + // 重新计算预扣费额度(用于后续可能的引用) + if cpUsePrice { + info.PriceData.QuotaToPreConsume = int(cpPrice * common.QuotaPerUnit * info.PriceData.GroupRatioInfo.GroupRatio) + } else { + estimateTokens := info.GetEstimatePromptTokens() + if estimateTokens > 0 { + ratio := cpRatio * info.PriceData.GroupRatioInfo.GroupRatio + info.PriceData.QuotaToPreConsume = int(float64(estimateTokens) * ratio) + } + } +}