mirror of
https://github.com/YFGaia/dify-plus.git
synced 2026-06-04 10:14:00 +08:00
fix: 千问3.5-plus计费不正确修复
This commit is contained in:
@@ -49,3 +49,34 @@ var DefaultAPIBase = map[string]string{
|
||||
|
||||
// CredentialKeyFallback 未知提供商时依次尝试的配置 key
|
||||
var CredentialKeyFallback = []string{ConfigKeyOpenaiAPIKey, ConfigKeyAPIKey, ConfigKeyDashScopeAPIKey}
|
||||
|
||||
// BuiltinModelPricing 内置兜底定价表(当 Dify Console API 未返回该模型定价时使用)。
|
||||
// 价格单位:每千 token(与 ModelPricing.Unit=0.001 对应),货币为各模型实际结算货币。
|
||||
// 通义/百炼模型官方定价(人民币,参考 https://help.aliyun.com/document_detail/2586379.html):
|
||||
// - 输入/输出价格均为「每百万 token」,换算为每千 token 时除以 1000。
|
||||
var BuiltinModelPricing = map[string]ModelPricing{
|
||||
// ──── 通义千问 Qwen3 系列(RMB / 百万 token,128K 档) ────
|
||||
"qwen3-235b-a22b": {Input: 0.4 / 1000, Output: 1.6 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
"qwen3-30b-a3b": {Input: 0.11 / 1000, Output: 0.44 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
"qwen3-32b": {Input: 0.8 / 1000, Output: 3.2 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
"qwen3-14b": {Input: 0.3 / 1000, Output: 1.2 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
"qwen3-8b": {Input: 0.1 / 1000, Output: 0.4 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
"qwen3-4b": {Input: 0.04 / 1000, Output: 0.16 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
"qwen3-1.7b": {Input: 0.02 / 1000, Output: 0.08 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
"qwen3-0.6b": {Input: 0.01 / 1000, Output: 0.04 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
|
||||
// ──── 通义千问 Qwen3.5 系列(RMB / 百万 token,128K 档) ────
|
||||
"qwen3.5-plus": {Input: 0.8 / 1000, Output: 4.8 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
"qwen3.5-turbo": {Input: 0.3 / 1000, Output: 1.2 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
|
||||
// ──── 通义千问 Qwen2.5 系列(RMB / 百万 token) ────
|
||||
"qwen2.5-72b-instruct": {Input: 4.0 / 1000, Output: 12.0 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
"qwen2.5-32b-instruct": {Input: 3.5 / 1000, Output: 7.0 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
"qwen2.5-14b-instruct": {Input: 2.0 / 1000, Output: 6.0 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
"qwen2.5-7b-instruct": {Input: 1.0 / 1000, Output: 2.0 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
"qwen2.5-3b-instruct": {Input: 0.3 / 1000, Output: 0.6 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
"qwen-plus": {Input: 0.8 / 1000, Output: 2.0 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
"qwen-turbo": {Input: 0.3 / 1000, Output: 0.6 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
"qwen-max": {Input: 40.0 / 1000, Output: 120.0 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
"qwen-long": {Input: 0.5 / 1000, Output: 2.0 / 1000, Unit: 0.001, Currency: "RMB"},
|
||||
}
|
||||
|
||||
@@ -152,27 +152,54 @@ func rmbToUSD(rmb float64) float64 {
|
||||
return rmb / rmbToUSDRate
|
||||
}
|
||||
|
||||
// resolvePricing 返回模型定价:优先用从 Dify 拉取的 pricing,
|
||||
// 其次查内置兜底定价表(BuiltinModelPricing),最后返回 nil。
|
||||
func resolvePricing(pricing *gaia.ModelPricing, modelName string) *gaia.ModelPricing {
|
||||
if pricing != nil && pricing.Unit > 0 {
|
||||
return pricing
|
||||
}
|
||||
// 内置定价表精确匹配
|
||||
if p, ok := gaia.BuiltinModelPricing[modelName]; ok {
|
||||
return &p
|
||||
}
|
||||
// 前缀模糊匹配(如 "qwen3.5-plus-xxx" 匹配 "qwen3.5-plus")
|
||||
lower := strings.ToLower(modelName)
|
||||
for k, p := range gaia.BuiltinModelPricing {
|
||||
if strings.HasPrefix(lower, strings.ToLower(k)) {
|
||||
cp := p
|
||||
return &cp
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// calcQuotaDelta 根据定价和 token 用量计算本次消耗的配额金额(统一以 USD 计)。
|
||||
// Dify pricing 字段语义:input/output 为每「unit」个 token 的价格,unit 通常为 0.001(千分之一),
|
||||
// 即 input=0.0014, unit=0.001 表示每千 token 收 $0.0014 × (tokens/1000)。
|
||||
// 即 input=0.0014, unit=0.001 表示每千 token ¥0.0014 × (tokens/1000)。
|
||||
// 公式:cost = tokens × input × unit(因为 unit=1/1000,等价于 tokens/1000 × input)。
|
||||
// 若货币为 RMB,则除以汇率 7.26 换算为 USD,与 account_money_extend.used_quota 存储单位保持一致。
|
||||
// 若未找到定价则回退到合理默认值:$0.001/1000 tokens(即每 token $0.000001)。
|
||||
func calcQuotaDelta(pricing *gaia.ModelPricing, promptTokens, completionTokens int) float64 {
|
||||
if pricing == nil || pricing.Unit == 0 {
|
||||
// 回退:按 $0.001 / 千token 计费(约 GPT-3.5 量级),避免按每 token 计费导致超额扣费
|
||||
// 若货币为 RMB/CNY,则除以汇率 7.26 换算为 USD,与 account_money_extend.used_quota 存储单位保持一致。
|
||||
// 若 Dify 未返回定价则查内置兜底表;均未命中时按极小默认值记账,避免多扣。
|
||||
func calcQuotaDelta(pricing *gaia.ModelPricing, modelName string, promptTokens, completionTokens int) float64 {
|
||||
p := resolvePricing(pricing, modelName)
|
||||
if p == nil {
|
||||
// 兜底:$0.001/千token,仅做记账占位,不应大量触发
|
||||
global.GVA_LOG.Warn("calcQuotaDelta 未找到模型定价,使用兜底值",
|
||||
zap.String("model", modelName),
|
||||
zap.Int("prompt_tokens", promptTokens),
|
||||
zap.Int("completion_tokens", completionTokens),
|
||||
)
|
||||
return float64(promptTokens+completionTokens) * 0.001 * 0.001
|
||||
}
|
||||
inputCost := float64(promptTokens) * pricing.Input * pricing.Unit
|
||||
outputPrice := pricing.Output
|
||||
inputCost := float64(promptTokens) * p.Input * p.Unit
|
||||
outputPrice := p.Output
|
||||
if outputPrice == 0 {
|
||||
outputPrice = pricing.Input
|
||||
outputPrice = p.Input
|
||||
}
|
||||
outputCost := float64(completionTokens) * outputPrice * pricing.Unit
|
||||
outputCost := float64(completionTokens) * outputPrice * p.Unit
|
||||
total := inputCost + outputCost
|
||||
|
||||
// RMB 定价统一换算为 USD 后再扣费,与 used_quota 存储单位保持一致
|
||||
if strings.EqualFold(pricing.Currency, "RMB") || strings.EqualFold(pricing.Currency, "CNY") {
|
||||
// RMB/CNY 定价统一换算为 USD 后再扣费,与 used_quota 存储单位保持一致
|
||||
if strings.EqualFold(p.Currency, "RMB") || strings.EqualFold(p.Currency, "CNY") {
|
||||
total = rmbToUSD(total)
|
||||
}
|
||||
return total
|
||||
@@ -1239,9 +1266,9 @@ func (s *ModelProviderService) ProxyRequest(
|
||||
// 计费:仅成功时扣费
|
||||
if logStatus == "success" {
|
||||
if promptTokens > 0 || completionTokens > 0 {
|
||||
// LLM 类型:按 token 计费
|
||||
pricing, _ := s.fetchModelPricingFromDify(modelOrPath)
|
||||
delta := calcQuotaDelta(pricing, promptTokens, completionTokens)
|
||||
// LLM 类型:按 token 计费
|
||||
pricing, _ := s.fetchModelPricingFromDify(modelOrPath)
|
||||
delta := calcQuotaDelta(pricing, modelOrPath, promptTokens, completionTokens)
|
||||
deductAccountQuota(userID, delta)
|
||||
} else if isImageOrPerRequestPath(path) {
|
||||
// 图片生成等无 usage 的接口:按请求次数计费(固定 0.04 USD/次,约 1 张图片单价)
|
||||
|
||||
Reference in New Issue
Block a user