feat(billing): 全局定价解析 input_cost_per_image_token

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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015wcJTKDddxXSQrepSs3wrU
This commit is contained in:
haruka
2026-07-15 09:23:35 -07:00
co-authored by Claude Opus 4.8
parent be6cd1250c
commit 10cb2ca42c
2 changed files with 7 additions and 1 deletions
@@ -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
}
+6 -1
View File
@@ -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
}