From 10cb2ca42cc01b4a9e5cfd47c8c87754dc1c7ee6 Mon Sep 17 00:00:00 2001 From: haruka <1628615876@qq.com> Date: Wed, 15 Jul 2026 09:23:35 -0700 Subject: [PATCH] =?UTF-8?q?feat(billing):=20=E5=85=A8=E5=B1=80=E5=AE=9A?= =?UTF-8?q?=E4=BB=B7=E8=A7=A3=E6=9E=90=20input=5Fcost=5Fper=5Fimage=5Ftoke?= =?UTF-8?q?n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LiteLLM 定价数据中 gpt-image-2 等模型已含 input_cost_per_image_token (图片输入 token 单价),但此前未被解析,导致图片编辑/图生图请求的 图像输入 token 被按文本输入价计费。 - LiteLLMModelPricing / LiteLLMRawEntry 新增 InputCostPerImageToken 字段并解析 - GetModelPricing 将其映射到 ModelPricing.ImageInputPricePerToken 计费拆分算术(computeTokenBreakdown)已支持图/文输入分价,本提交补齐 全局定价路径的数据来源。相关 #4386。 Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_015wcJTKDddxXSQrepSs3wrU --- backend/internal/service/billing_service.go | 1 + backend/internal/service/pricing_service.go | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/backend/internal/service/billing_service.go b/backend/internal/service/billing_service.go index 7fa69d41ea..873773d9f9 100644 --- a/backend/internal/service/billing_service.go +++ b/backend/internal/service/billing_service.go @@ -802,6 +802,7 @@ func (s *BillingService) GetModelPricing(model string) (*ModelPricing, error) { LongContextInputThreshold: litellmPricing.LongContextInputTokenThreshold, LongContextInputMultiplier: litellmPricing.LongContextInputCostMultiplier, LongContextOutputMultiplier: litellmPricing.LongContextOutputCostMultiplier, + ImageInputPricePerToken: litellmPricing.InputCostPerImageToken, ImageOutputPricePerToken: litellmPricing.OutputCostPerImageToken, }), nil } diff --git a/backend/internal/service/pricing_service.go b/backend/internal/service/pricing_service.go index d0ae3c7d96..814d6ddaa1 100644 --- a/backend/internal/service/pricing_service.go +++ b/backend/internal/service/pricing_service.go @@ -125,6 +125,7 @@ type LiteLLMModelPricing struct { SupportsPromptCaching bool `json:"supports_prompt_caching"` OutputCostPerImage float64 `json:"output_cost_per_image"` // 图片生成模型每张图片价格 OutputCostPerImageToken float64 `json:"output_cost_per_image_token"` // 图片输出 token 价格 + InputCostPerImageToken float64 `json:"input_cost_per_image_token"` // 图片输入 token 价格(如 gpt-image-2 图片编辑) // TokenPricingAbsent 表示源数据中 input/output token 价格均缺失(仅有图片价)。 // 此类条目只可用于图片计费,token 计费必须回退到 fallback 或 fail-closed, @@ -158,6 +159,7 @@ type LiteLLMRawEntry struct { SupportsPromptCaching bool `json:"supports_prompt_caching"` OutputCostPerImage *float64 `json:"output_cost_per_image"` OutputCostPerImageToken *float64 `json:"output_cost_per_image_token"` + InputCostPerImageToken *float64 `json:"input_cost_per_image_token"` } // PricingService 动态价格服务 @@ -435,7 +437,7 @@ func (s *PricingService) parsePricingData(body []byte) (map[string]*LiteLLMModel } // 只保留有有效价格的条目 - if entry.InputCostPerToken == nil && entry.OutputCostPerToken == nil && entry.OutputCostPerImage == nil && entry.OutputCostPerImageToken == nil { + if entry.InputCostPerToken == nil && entry.OutputCostPerToken == nil && entry.OutputCostPerImage == nil && entry.OutputCostPerImageToken == nil && entry.InputCostPerImageToken == nil { continue } @@ -489,6 +491,9 @@ func (s *PricingService) parsePricingData(body []byte) (map[string]*LiteLLMModel if entry.OutputCostPerImageToken != nil { pricing.OutputCostPerImageToken = *entry.OutputCostPerImageToken } + if entry.InputCostPerImageToken != nil { + pricing.InputCostPerImageToken = *entry.InputCostPerImageToken + } result[modelName] = pricing }