feat: support free model setting

This commit is contained in:
CaIon
2025-10-12 13:31:03 +08:00
parent 6c7795238f
commit ede47ef014
6 changed files with 89 additions and 27 deletions

View File

@@ -140,9 +140,13 @@ func Relay(c *gin.Context, relayFormat types.RelayFormat) {
// common.SetContextKey(c, constant.ContextKeyTokenCountMeta, meta) // common.SetContextKey(c, constant.ContextKeyTokenCountMeta, meta)
newAPIError = service.PreConsumeQuota(c, priceData.ShouldPreConsumedQuota, relayInfo) if priceData.FreeModel {
if newAPIError != nil { logger.LogInfo(c, fmt.Sprintf("模型 %s 免费,跳过预扣费", relayInfo.OriginModelName))
return } else {
newAPIError = service.PreConsumeQuota(c, priceData.QuotaToPreConsume, relayInfo)
if newAPIError != nil {
return
}
} }
defer func() { defer func() {

View File

@@ -5,6 +5,7 @@ import (
"github.com/QuantumNous/new-api/common" "github.com/QuantumNous/new-api/common"
relaycommon "github.com/QuantumNous/new-api/relay/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/setting/ratio_setting"
"github.com/QuantumNous/new-api/types" "github.com/QuantumNous/new-api/types"
@@ -55,6 +56,7 @@ func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens
var cacheCreationRatio float64 var cacheCreationRatio float64
var audioRatio float64 var audioRatio float64
var audioCompletionRatio float64 var audioCompletionRatio float64
var freeModel bool
if !usePrice { if !usePrice {
preConsumedTokens := common.Max(promptTokens, common.PreConsumedQuota) preConsumedTokens := common.Max(promptTokens, common.PreConsumedQuota)
if meta.MaxTokens != 0 { if meta.MaxTokens != 0 {
@@ -87,18 +89,35 @@ func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens
preConsumedQuota = int(modelPrice * common.QuotaPerUnit * groupRatioInfo.GroupRatio) 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{ priceData := types.PriceData{
ModelPrice: modelPrice, FreeModel: freeModel,
ModelRatio: modelRatio, ModelPrice: modelPrice,
CompletionRatio: completionRatio, ModelRatio: modelRatio,
GroupRatioInfo: groupRatioInfo, CompletionRatio: completionRatio,
UsePrice: usePrice, GroupRatioInfo: groupRatioInfo,
CacheRatio: cacheRatio, UsePrice: usePrice,
ImageRatio: imageRatio, CacheRatio: cacheRatio,
AudioRatio: audioRatio, ImageRatio: imageRatio,
AudioCompletionRatio: audioCompletionRatio, AudioRatio: audioRatio,
CacheCreationRatio: cacheCreationRatio, AudioCompletionRatio: audioCompletionRatio,
ShouldPreConsumedQuota: preConsumedQuota, CacheCreationRatio: cacheCreationRatio,
QuotaToPreConsume: preConsumedQuota,
} }
if common.DebugEnabled { if common.DebugEnabled {

View File

@@ -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", &quotaSetting)
}
func GetQuotaSetting() *QuotaSetting {
return &quotaSetting
}

View File

@@ -9,18 +9,19 @@ type GroupRatioInfo struct {
} }
type PriceData struct { type PriceData struct {
ModelPrice float64 FreeModel bool
ModelRatio float64 ModelPrice float64
CompletionRatio float64 ModelRatio float64
CacheRatio float64 CompletionRatio float64
CacheCreationRatio float64 CacheRatio float64
ImageRatio float64 CacheCreationRatio float64
AudioRatio float64 ImageRatio float64
AudioCompletionRatio float64 AudioRatio float64
OtherRatios map[string]float64 AudioCompletionRatio float64
UsePrice bool OtherRatios map[string]float64
ShouldPreConsumedQuota int UsePrice bool
GroupRatioInfo GroupRatioInfo QuotaToPreConsume int // 预消耗额度
GroupRatioInfo GroupRatioInfo
} }
type PerCallPriceData struct { type PerCallPriceData struct {
@@ -30,5 +31,5 @@ type PerCallPriceData struct {
} }
func (p PriceData) ToSetting() string { 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)
} }

View File

@@ -35,6 +35,7 @@ const OperationSetting = () => {
PreConsumedQuota: 0, PreConsumedQuota: 0,
QuotaForInviter: 0, QuotaForInviter: 0,
QuotaForInvitee: 0, QuotaForInvitee: 0,
'quota_setting.enable_free_model_pre_consume': true,
/* 通用设置 */ /* 通用设置 */
TopUpLink: '', TopUpLink: '',

View File

@@ -36,6 +36,7 @@ export default function SettingsCreditLimit(props) {
PreConsumedQuota: '', PreConsumedQuota: '',
QuotaForInviter: '', QuotaForInviter: '',
QuotaForInvitee: '', QuotaForInvitee: '',
'quota_setting.enable_free_model_pre_consume': true,
}); });
const refForm = useRef(); const refForm = useRef();
const [inputsRow, setInputsRow] = useState(inputs); const [inputsRow, setInputsRow] = useState(inputs);
@@ -166,6 +167,21 @@ export default function SettingsCreditLimit(props) {
/> />
</Col> </Col>
</Row> </Row>
<Row>
<Col>
<Form.Switch
label={t('对免费模型启用预消耗')}
field={'quota_setting.enable_free_model_pre_consume'}
extraText={t('开启后对免费模型倍率为0或者价格为0的模型也会预消耗额度')}
onChange={(value) =>
setInputs({
...inputs,
'quota_setting.enable_free_model_pre_consume': value,
})
}
/>
</Col>
</Row>
<Row> <Row>
<Button size='default' onClick={onSubmit}> <Button size='default' onClick={onSubmit}>