From 4b439ad3beb8a3404aff3fa4ad2f907a8d0be531 Mon Sep 17 00:00:00 2001 From: Fat Person <58603432@qq.com> Date: Mon, 2 Mar 2026 19:09:48 +0800 Subject: [PATCH] Return error when model price/ratio unset #3079 Change ModelPriceHelperPerCall to return (PriceData, error) and stop silently falling back to a default price. If a model price is not configured the helper now returns an error (unless the user has AcceptUnsetRatioModel enabled and a ratio exists). Propagate this error to callers: Midjourney handlers now return a MidjourneyResponse with Code 4 and the error message, and task submission returns a wrapped task error with HTTP 400. Also extract remix video_id in ResolveOriginTask for remix actions. This enforces explicit model price/ratio configuration and surfaces configuration issues to clients. --- relay/helper/price.go | 23 +++++++++++++++++++---- relay/mjproxy_handler.go | 16 ++++++++++++++-- relay/relay_task.go | 8 +++++++- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/relay/helper/price.go b/relay/helper/price.go index 1cb04166f..8c31c1822 100644 --- a/relay/helper/price.go +++ b/relay/helper/price.go @@ -140,18 +140,33 @@ func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens } // ModelPriceHelperPerCall 按次计费的 PriceHelper (MJ、Task) -func ModelPriceHelperPerCall(c *gin.Context, info *relaycommon.RelayInfo) types.PriceData { +func ModelPriceHelperPerCall(c *gin.Context, info *relaycommon.RelayInfo) (types.PriceData, error) { groupRatioInfo := HandleGroupRatio(c, info) modelPrice, success := ratio_setting.GetModelPrice(info.OriginModelName, true) - // 如果没有配置价格,则使用默认价格 + // 如果没有配置价格,检查模型倍率配置 if !success { + + // 没有配置费用,返回错误 defaultPrice, ok := ratio_setting.GetDefaultModelPriceMap()[info.OriginModelName] if !ok { - modelPrice = 0.1 + // 不再使用默认价格,而是返回错误 + return types.PriceData{}, fmt.Errorf("模型 %s 价格未配置,请联系管理员设置", info.OriginModelName) } else { modelPrice = defaultPrice } + // 没有配置倍率也不接受没配置,那就返回错误 + _, ratioSuccess, matchName := ratio_setting.GetModelRatio(info.OriginModelName) + if !ratioSuccess { + acceptUnsetRatio := false + if info.UserSetting.AcceptUnsetRatioModel { + acceptUnsetRatio = true + } + if !acceptUnsetRatio { + return types.PriceData{}, fmt.Errorf("模型 %s 倍率或价格未配置,请联系管理员设置或开始自用模式;Model %s ratio or price not set, please set or start self-use mode", matchName, matchName) + } + } + } quota := int(modelPrice * common.QuotaPerUnit * groupRatioInfo.GroupRatio) @@ -170,7 +185,7 @@ func ModelPriceHelperPerCall(c *gin.Context, info *relaycommon.RelayInfo) types. Quota: quota, GroupRatioInfo: groupRatioInfo, } - return priceData + return priceData, nil } func ContainPriceOrRatio(modelName string) bool { diff --git a/relay/mjproxy_handler.go b/relay/mjproxy_handler.go index 8e7c61e9c..c2aac9691 100644 --- a/relay/mjproxy_handler.go +++ b/relay/mjproxy_handler.go @@ -186,7 +186,13 @@ func RelaySwapFace(c *gin.Context, info *relaycommon.RelayInfo) *dto.MidjourneyR } modelName := service.CovertMjpActionToModelName(constant.MjActionSwapFace) - priceData := helper.ModelPriceHelperPerCall(c, info) + priceData, err := helper.ModelPriceHelperPerCall(c, info) + if err != nil { + return &dto.MidjourneyResponse{ + Code: 4, + Description: err.Error(), + } + } userQuota, err := model.GetUserQuota(info.UserId, false) if err != nil { @@ -487,7 +493,13 @@ func RelayMidjourneySubmit(c *gin.Context, relayInfo *relaycommon.RelayInfo) *dt modelName := service.CovertMjpActionToModelName(midjRequest.Action) - priceData := helper.ModelPriceHelperPerCall(c, relayInfo) + priceData, err := helper.ModelPriceHelperPerCall(c, relayInfo) + if err != nil { + return &dto.MidjourneyResponse{ + Code: 4, + Description: err.Error(), + } + } userQuota, err := model.GetUserQuota(relayInfo.UserId, false) if err != nil { diff --git a/relay/relay_task.go b/relay/relay_task.go index c740facdb..098e23828 100644 --- a/relay/relay_task.go +++ b/relay/relay_task.go @@ -41,6 +41,8 @@ func ResolveOriginTask(c *gin.Context, info *relaycommon.RelayInfo) *dto.TaskErr if strings.Contains(path, "/v1/videos/") && strings.HasSuffix(path, "/remix") { info.Action = constant.TaskActionRemix } + + // 提取 remix 任务的 video_id if info.Action == constant.TaskActionRemix { videoID := c.Param("video_id") if strings.TrimSpace(videoID) == "" { @@ -176,7 +178,11 @@ func RelayTaskSubmit(c *gin.Context, info *relaycommon.RelayInfo) (*TaskSubmitRe // 4. 价格计算:基础模型价格 info.OriginModelName = modelName - info.PriceData = helper.ModelPriceHelperPerCall(c, info) + priceData, err := helper.ModelPriceHelperPerCall(c, info) + if err != nil { + return nil, service.TaskErrorWrapper(err, "model_price_error", http.StatusBadRequest) + } + info.PriceData = priceData // 5. 计费估算:让适配器根据用户请求提供 OtherRatios(时长、分辨率等) // 必须在 ModelPriceHelperPerCall 之后调用(它会重建 PriceData)。