fix: 管理员自定义价格的任务模型自动按次计费,不再乘 OtherRatios

当管理员为任务模型(如 sora_video2)设置了固定价格时,
之前会错误地将价格乘以 seconds/size 等 OtherRatios,
导致设置 $2/次 实际收费 $8($2 × 4秒)。

新增 IsTaskPerCallBilling() 判断逻辑:
- 模型在 TASK_PRICE_PATCH 环境变量中 → 按次(兼容旧逻辑)
- 模型有管理员配置的价格且不在默认价格表中 → 自动按次
默认价格表中的模型(如 sora-2: $0.3)仍按原逻辑乘 OtherRatios。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-24 17:01:12 +08:00
parent 9ae9040b3c
commit c41ca95a43
4 changed files with 24 additions and 5 deletions

View File

@@ -22,6 +22,7 @@ import (
"github.com/QuantumNous/new-api/service"
"github.com/QuantumNous/new-api/setting"
"github.com/QuantumNous/new-api/setting/operation_setting"
"github.com/QuantumNous/new-api/setting/ratio_setting"
"github.com/QuantumNous/new-api/types"
"github.com/bytedance/gopkg/util/gopool"
@@ -581,7 +582,7 @@ func RelayTask(c *gin.Context) {
ModelRatio: relayInfo.PriceData.ModelRatio,
OtherRatios: relayInfo.PriceData.OtherRatios,
OriginModelName: relayInfo.OriginModelName,
PerCallBilling: common.StringsContains(constant.TaskPricePatches, relayInfo.OriginModelName),
PerCallBilling: ratio_setting.IsTaskPerCallBilling(relayInfo.OriginModelName),
}
task.Quota = result.Quota
task.Data = result.TaskData

View File

@@ -19,6 +19,7 @@ import (
relayconstant "github.com/QuantumNous/new-api/relay/constant"
"github.com/QuantumNous/new-api/relay/helper"
"github.com/QuantumNous/new-api/service"
"github.com/QuantumNous/new-api/setting/ratio_setting"
"github.com/gin-gonic/gin"
)
@@ -194,7 +195,8 @@ func RelayTaskSubmit(c *gin.Context, info *relaycommon.RelayInfo) (*TaskSubmitRe
}
// 6. 将 OtherRatios 应用到基础额度
if !common.StringsContains(constant.TaskPricePatches, modelName) {
// 按次计费模型TaskPricePatches 或管理员自定义价格)跳过 OtherRatios 乘算
if !ratio_setting.IsTaskPerCallBilling(modelName) {
for _, ra := range info.PriceData.OtherRatios {
if ra != 1.0 {
info.PriceData.Quota = int(float64(info.PriceData.Quota) * ra)

View File

@@ -5,8 +5,6 @@ import (
"fmt"
"strings"
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/constant"
"github.com/QuantumNous/new-api/logger"
"github.com/QuantumNous/new-api/model"
relaycommon "github.com/QuantumNous/new-api/relay/common"
@@ -20,7 +18,7 @@ func LogTaskConsumption(c *gin.Context, info *relaycommon.RelayInfo) {
tokenName := c.GetString("token_name")
logContent := fmt.Sprintf("操作 %s", info.Action)
// 支持任务仅按次计费
if common.StringsContains(constant.TaskPricePatches, info.OriginModelName) {
if ratio_setting.IsTaskPerCallBilling(info.OriginModelName) {
logContent = fmt.Sprintf("%s按次计费", logContent)
} else {
if len(info.PriceData.OtherRatios) > 0 {

View File

@@ -4,6 +4,7 @@ import (
"strings"
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/constant"
"github.com/QuantumNous/new-api/setting/operation_setting"
"github.com/QuantumNous/new-api/types"
)
@@ -732,3 +733,20 @@ func GetModelRatioOrPrice(model string) (float64, bool, bool) { // price or rati
}
return 37.5, false, false
}
// IsTaskPerCallBilling 判断任务模型是否按次计费(固定价格,不乘 OtherRatios
// 满足以下任一条件即为按次计费:
// 1. 模型在 TaskPricePatches 列表中(环境变量配置)
// 2. 模型有管理员配置的固定价格(在价格表中但不在默认价格表中)
func IsTaskPerCallBilling(modelName string) bool {
if common.StringsContains(constant.TaskPricePatches, modelName) {
return true
}
// 检查模型是否有管理员配置的固定价格(非默认价格)
_, hasPrice := GetModelPrice(modelName, false)
if !hasPrice {
return false
}
_, isDefault := defaultModelPrice[modelName]
return !isDefault
}