From ede47ef01447ec2de6df920f4ff2c05561ceb757 Mon Sep 17 00:00:00 2001 From: CaIon Date: Sun, 12 Oct 2025 13:31:03 +0800 Subject: [PATCH] feat: support free model setting --- controller/relay.go | 10 +++-- relay/helper/price.go | 41 ++++++++++++++----- setting/operation_setting/quota_setting.go | 21 ++++++++++ types/price_data.go | 27 ++++++------ .../components/settings/OperationSetting.jsx | 1 + .../Setting/Operation/SettingsCreditLimit.jsx | 16 ++++++++ 6 files changed, 89 insertions(+), 27 deletions(-) create mode 100644 setting/operation_setting/quota_setting.go diff --git a/controller/relay.go b/controller/relay.go index 27ece2872..e8ea1998e 100644 --- a/controller/relay.go +++ b/controller/relay.go @@ -140,9 +140,13 @@ func Relay(c *gin.Context, relayFormat types.RelayFormat) { // common.SetContextKey(c, constant.ContextKeyTokenCountMeta, meta) - newAPIError = service.PreConsumeQuota(c, priceData.ShouldPreConsumedQuota, relayInfo) - if newAPIError != nil { - return + if priceData.FreeModel { + logger.LogInfo(c, fmt.Sprintf("模型 %s 免费,跳过预扣费", relayInfo.OriginModelName)) + } else { + newAPIError = service.PreConsumeQuota(c, priceData.QuotaToPreConsume, relayInfo) + if newAPIError != nil { + return + } } defer func() { diff --git a/relay/helper/price.go b/relay/helper/price.go index 67051eeee..dfbc58640 100644 --- a/relay/helper/price.go +++ b/relay/helper/price.go @@ -5,6 +5,7 @@ import ( "github.com/QuantumNous/new-api/common" relaycommon "github.com/QuantumNous/new-api/relay/common" + "github.com/QuantumNous/new-api/setting/operation_setting" "github.com/QuantumNous/new-api/setting/ratio_setting" "github.com/QuantumNous/new-api/types" @@ -55,6 +56,7 @@ func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens var cacheCreationRatio float64 var audioRatio float64 var audioCompletionRatio float64 + var freeModel bool if !usePrice { preConsumedTokens := common.Max(promptTokens, common.PreConsumedQuota) if meta.MaxTokens != 0 { @@ -87,18 +89,35 @@ func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens preConsumedQuota = int(modelPrice * common.QuotaPerUnit * groupRatioInfo.GroupRatio) } + // check if free model pre-consume is disabled + if !operation_setting.GetQuotaSetting().EnableFreeModelPreConsume { + // if model price or ratio is 0, do not pre-consume quota + if usePrice { + if modelPrice == 0 { + preConsumedQuota = 0 + freeModel = true + } + } else { + if modelRatio == 0 { + preConsumedQuota = 0 + freeModel = true + } + } + } + priceData := types.PriceData{ - ModelPrice: modelPrice, - ModelRatio: modelRatio, - CompletionRatio: completionRatio, - GroupRatioInfo: groupRatioInfo, - UsePrice: usePrice, - CacheRatio: cacheRatio, - ImageRatio: imageRatio, - AudioRatio: audioRatio, - AudioCompletionRatio: audioCompletionRatio, - CacheCreationRatio: cacheCreationRatio, - ShouldPreConsumedQuota: preConsumedQuota, + FreeModel: freeModel, + ModelPrice: modelPrice, + ModelRatio: modelRatio, + CompletionRatio: completionRatio, + GroupRatioInfo: groupRatioInfo, + UsePrice: usePrice, + CacheRatio: cacheRatio, + ImageRatio: imageRatio, + AudioRatio: audioRatio, + AudioCompletionRatio: audioCompletionRatio, + CacheCreationRatio: cacheCreationRatio, + QuotaToPreConsume: preConsumedQuota, } if common.DebugEnabled { diff --git a/setting/operation_setting/quota_setting.go b/setting/operation_setting/quota_setting.go new file mode 100644 index 000000000..dcf0501a9 --- /dev/null +++ b/setting/operation_setting/quota_setting.go @@ -0,0 +1,21 @@ +package operation_setting + +import "github.com/QuantumNous/new-api/setting/config" + +type QuotaSetting struct { + EnableFreeModelPreConsume bool `json:"enable_free_model_pre_consume"` // 是否对免费模型启用预消耗 +} + +// 默认配置 +var quotaSetting = QuotaSetting{ + EnableFreeModelPreConsume: true, +} + +func init() { + // 注册到全局配置管理器 + config.GlobalConfig.Register("quota_setting", "aSetting) +} + +func GetQuotaSetting() *QuotaSetting { + return "aSetting +} diff --git a/types/price_data.go b/types/price_data.go index dd5dad1aa..8f6297408 100644 --- a/types/price_data.go +++ b/types/price_data.go @@ -9,18 +9,19 @@ type GroupRatioInfo struct { } type PriceData struct { - ModelPrice float64 - ModelRatio float64 - CompletionRatio float64 - CacheRatio float64 - CacheCreationRatio float64 - ImageRatio float64 - AudioRatio float64 - AudioCompletionRatio float64 - OtherRatios map[string]float64 - UsePrice bool - ShouldPreConsumedQuota int - GroupRatioInfo GroupRatioInfo + FreeModel bool + ModelPrice float64 + ModelRatio float64 + CompletionRatio float64 + CacheRatio float64 + CacheCreationRatio float64 + ImageRatio float64 + AudioRatio float64 + AudioCompletionRatio float64 + OtherRatios map[string]float64 + UsePrice bool + QuotaToPreConsume int // 预消耗额度 + GroupRatioInfo GroupRatioInfo } type PerCallPriceData struct { @@ -30,5 +31,5 @@ type PerCallPriceData struct { } func (p PriceData) ToSetting() string { - return fmt.Sprintf("ModelPrice: %f, ModelRatio: %f, CompletionRatio: %f, CacheRatio: %f, GroupRatio: %f, UsePrice: %t, CacheCreationRatio: %f, ShouldPreConsumedQuota: %d, ImageRatio: %f, AudioRatio: %f, AudioCompletionRatio: %f", p.ModelPrice, p.ModelRatio, p.CompletionRatio, p.CacheRatio, p.GroupRatioInfo.GroupRatio, p.UsePrice, p.CacheCreationRatio, p.ShouldPreConsumedQuota, p.ImageRatio, p.AudioRatio, p.AudioCompletionRatio) + return fmt.Sprintf("ModelPrice: %f, ModelRatio: %f, CompletionRatio: %f, CacheRatio: %f, GroupRatio: %f, UsePrice: %t, CacheCreationRatio: %f, QuotaToPreConsume: %d, ImageRatio: %f, AudioRatio: %f, AudioCompletionRatio: %f", p.ModelPrice, p.ModelRatio, p.CompletionRatio, p.CacheRatio, p.GroupRatioInfo.GroupRatio, p.UsePrice, p.CacheCreationRatio, p.QuotaToPreConsume, p.ImageRatio, p.AudioRatio, p.AudioCompletionRatio) } diff --git a/web/src/components/settings/OperationSetting.jsx b/web/src/components/settings/OperationSetting.jsx index 51cdb1de6..9f4f584a5 100644 --- a/web/src/components/settings/OperationSetting.jsx +++ b/web/src/components/settings/OperationSetting.jsx @@ -35,6 +35,7 @@ const OperationSetting = () => { PreConsumedQuota: 0, QuotaForInviter: 0, QuotaForInvitee: 0, + 'quota_setting.enable_free_model_pre_consume': true, /* 通用设置 */ TopUpLink: '', diff --git a/web/src/pages/Setting/Operation/SettingsCreditLimit.jsx b/web/src/pages/Setting/Operation/SettingsCreditLimit.jsx index 131ade445..a5208a502 100644 --- a/web/src/pages/Setting/Operation/SettingsCreditLimit.jsx +++ b/web/src/pages/Setting/Operation/SettingsCreditLimit.jsx @@ -36,6 +36,7 @@ export default function SettingsCreditLimit(props) { PreConsumedQuota: '', QuotaForInviter: '', QuotaForInvitee: '', + 'quota_setting.enable_free_model_pre_consume': true, }); const refForm = useRef(); const [inputsRow, setInputsRow] = useState(inputs); @@ -166,6 +167,21 @@ export default function SettingsCreditLimit(props) { /> + + + + setInputs({ + ...inputs, + 'quota_setting.enable_free_model_pre_consume': value, + }) + } + /> + +