2026-01-05 16:48:59 +08:00
|
|
|
|
"""
|
|
|
|
|
|
预定义计费模板
|
|
|
|
|
|
|
|
|
|
|
|
提供常见厂商的计费配置模板,避免重复配置:
|
|
|
|
|
|
- CLAUDE_STANDARD: Claude/Anthropic 标准计费
|
|
|
|
|
|
- OPENAI_STANDARD: OpenAI 标准计费
|
|
|
|
|
|
- DOUBAO_STANDARD: 豆包计费(含缓存存储)
|
|
|
|
|
|
- GEMINI_STANDARD: Gemini 标准计费
|
|
|
|
|
|
- PER_REQUEST: 按次计费
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
from src.services.billing.models import BillingDimension, BillingUnit
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BillingTemplates:
|
|
|
|
|
|
"""预定义的计费模板"""
|
|
|
|
|
|
|
|
|
|
|
|
# =========================================================================
|
|
|
|
|
|
# Claude/Anthropic 标准计费
|
|
|
|
|
|
# - 输入 token
|
|
|
|
|
|
# - 输出 token
|
|
|
|
|
|
# - 缓存创建(创建时收费,约 1.25x 输入价格)
|
|
|
|
|
|
# - 缓存读取(约 0.1x 输入价格)
|
2026-01-07 20:15:30 +08:00
|
|
|
|
# - 按次计费(可选,配置 price_per_request 时生效)
|
2026-01-05 16:48:59 +08:00
|
|
|
|
# =========================================================================
|
2026-01-30 03:10:21 +08:00
|
|
|
|
CLAUDE_STANDARD: list[BillingDimension] = [
|
2026-01-05 16:48:59 +08:00
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="input",
|
|
|
|
|
|
usage_field="input_tokens",
|
|
|
|
|
|
price_field="input_price_per_1m",
|
|
|
|
|
|
),
|
|
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="output",
|
|
|
|
|
|
usage_field="output_tokens",
|
|
|
|
|
|
price_field="output_price_per_1m",
|
|
|
|
|
|
),
|
|
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="cache_creation",
|
|
|
|
|
|
usage_field="cache_creation_tokens",
|
|
|
|
|
|
price_field="cache_creation_price_per_1m",
|
|
|
|
|
|
),
|
|
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="cache_read",
|
|
|
|
|
|
usage_field="cache_read_tokens",
|
|
|
|
|
|
price_field="cache_read_price_per_1m",
|
|
|
|
|
|
),
|
2026-01-07 20:15:30 +08:00
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="request",
|
|
|
|
|
|
usage_field="request_count",
|
|
|
|
|
|
price_field="price_per_request",
|
|
|
|
|
|
unit=BillingUnit.PER_REQUEST,
|
|
|
|
|
|
),
|
2026-01-05 16:48:59 +08:00
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
# =========================================================================
|
|
|
|
|
|
# OpenAI 标准计费
|
|
|
|
|
|
# - 输入 token
|
|
|
|
|
|
# - 输出 token
|
|
|
|
|
|
# - 缓存读取(部分模型支持,无缓存创建费用)
|
2026-01-07 20:15:30 +08:00
|
|
|
|
# - 按次计费(可选,配置 price_per_request 时生效)
|
2026-01-05 16:48:59 +08:00
|
|
|
|
# =========================================================================
|
2026-01-30 03:10:21 +08:00
|
|
|
|
OPENAI_STANDARD: list[BillingDimension] = [
|
2026-01-05 16:48:59 +08:00
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="input",
|
|
|
|
|
|
usage_field="input_tokens",
|
|
|
|
|
|
price_field="input_price_per_1m",
|
|
|
|
|
|
),
|
|
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="output",
|
|
|
|
|
|
usage_field="output_tokens",
|
|
|
|
|
|
price_field="output_price_per_1m",
|
|
|
|
|
|
),
|
|
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="cache_read",
|
|
|
|
|
|
usage_field="cache_read_tokens",
|
|
|
|
|
|
price_field="cache_read_price_per_1m",
|
|
|
|
|
|
),
|
2026-01-07 20:15:30 +08:00
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="request",
|
|
|
|
|
|
usage_field="request_count",
|
|
|
|
|
|
price_field="price_per_request",
|
|
|
|
|
|
unit=BillingUnit.PER_REQUEST,
|
|
|
|
|
|
),
|
2026-01-05 16:48:59 +08:00
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
# =========================================================================
|
|
|
|
|
|
# 豆包计费
|
|
|
|
|
|
# - 推理输入 (input_tokens)
|
|
|
|
|
|
# - 推理输出 (output_tokens)
|
|
|
|
|
|
# - 缓存命中 (cache_read_tokens) - 类似 Claude 的缓存读取
|
|
|
|
|
|
# - 缓存存储 (cache_storage_token_hours) - 按 token 数 * 存储时长计费
|
2026-01-07 20:15:30 +08:00
|
|
|
|
# - 按次计费(可选,配置 price_per_request 时生效)
|
2026-01-05 16:48:59 +08:00
|
|
|
|
#
|
|
|
|
|
|
# 注意:豆包的缓存创建是免费的,但存储需要按时付费
|
|
|
|
|
|
# =========================================================================
|
2026-01-30 03:10:21 +08:00
|
|
|
|
DOUBAO_STANDARD: list[BillingDimension] = [
|
2026-01-05 16:48:59 +08:00
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="input",
|
|
|
|
|
|
usage_field="input_tokens",
|
|
|
|
|
|
price_field="input_price_per_1m",
|
|
|
|
|
|
),
|
|
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="output",
|
|
|
|
|
|
usage_field="output_tokens",
|
|
|
|
|
|
price_field="output_price_per_1m",
|
|
|
|
|
|
),
|
|
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="cache_read",
|
|
|
|
|
|
usage_field="cache_read_tokens",
|
|
|
|
|
|
price_field="cache_read_price_per_1m",
|
|
|
|
|
|
),
|
|
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="cache_storage",
|
|
|
|
|
|
usage_field="cache_storage_token_hours",
|
|
|
|
|
|
price_field="cache_storage_price_per_1m_hour",
|
|
|
|
|
|
unit=BillingUnit.PER_1M_TOKENS_HOUR,
|
|
|
|
|
|
),
|
2026-01-07 20:15:30 +08:00
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="request",
|
|
|
|
|
|
usage_field="request_count",
|
|
|
|
|
|
price_field="price_per_request",
|
|
|
|
|
|
unit=BillingUnit.PER_REQUEST,
|
|
|
|
|
|
),
|
2026-01-05 16:48:59 +08:00
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
# =========================================================================
|
|
|
|
|
|
# Gemini 标准计费
|
|
|
|
|
|
# - 输入 token
|
|
|
|
|
|
# - 输出 token
|
|
|
|
|
|
# - 缓存读取
|
2026-01-07 20:15:30 +08:00
|
|
|
|
# - 按次计费(用于图片生成等模型,需配置 price_per_request)
|
2026-01-05 16:48:59 +08:00
|
|
|
|
# =========================================================================
|
2026-01-30 03:10:21 +08:00
|
|
|
|
GEMINI_STANDARD: list[BillingDimension] = [
|
2026-01-05 16:48:59 +08:00
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="input",
|
|
|
|
|
|
usage_field="input_tokens",
|
|
|
|
|
|
price_field="input_price_per_1m",
|
|
|
|
|
|
),
|
|
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="output",
|
|
|
|
|
|
usage_field="output_tokens",
|
|
|
|
|
|
price_field="output_price_per_1m",
|
|
|
|
|
|
),
|
|
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="cache_read",
|
|
|
|
|
|
usage_field="cache_read_tokens",
|
|
|
|
|
|
price_field="cache_read_price_per_1m",
|
|
|
|
|
|
),
|
2026-01-07 20:15:30 +08:00
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="request",
|
|
|
|
|
|
usage_field="request_count",
|
|
|
|
|
|
price_field="price_per_request",
|
|
|
|
|
|
unit=BillingUnit.PER_REQUEST,
|
|
|
|
|
|
),
|
2026-01-05 16:48:59 +08:00
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
# =========================================================================
|
|
|
|
|
|
# 按次计费
|
|
|
|
|
|
# - 适用于某些图片生成模型、特殊 API 等
|
|
|
|
|
|
# - 仅按请求次数计费,不按 token 计费
|
|
|
|
|
|
# =========================================================================
|
2026-01-30 03:10:21 +08:00
|
|
|
|
PER_REQUEST: list[BillingDimension] = [
|
2026-01-05 16:48:59 +08:00
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="request",
|
|
|
|
|
|
usage_field="request_count",
|
|
|
|
|
|
price_field="price_per_request",
|
|
|
|
|
|
unit=BillingUnit.PER_REQUEST,
|
|
|
|
|
|
),
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
# =========================================================================
|
|
|
|
|
|
# 混合计费(按次 + 按 token)
|
|
|
|
|
|
# - 某些模型既有固定费用又有 token 费用
|
|
|
|
|
|
# =========================================================================
|
2026-01-30 03:10:21 +08:00
|
|
|
|
HYBRID_STANDARD: list[BillingDimension] = [
|
2026-01-05 16:48:59 +08:00
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="input",
|
|
|
|
|
|
usage_field="input_tokens",
|
|
|
|
|
|
price_field="input_price_per_1m",
|
|
|
|
|
|
),
|
|
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="output",
|
|
|
|
|
|
usage_field="output_tokens",
|
|
|
|
|
|
price_field="output_price_per_1m",
|
|
|
|
|
|
),
|
|
|
|
|
|
BillingDimension(
|
|
|
|
|
|
name="request",
|
|
|
|
|
|
usage_field="request_count",
|
|
|
|
|
|
price_field="price_per_request",
|
|
|
|
|
|
unit=BillingUnit.PER_REQUEST,
|
|
|
|
|
|
),
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# =========================================================================
|
|
|
|
|
|
# 模板注册表
|
|
|
|
|
|
# =========================================================================
|
|
|
|
|
|
|
2026-01-30 03:10:21 +08:00
|
|
|
|
BILLING_TEMPLATE_REGISTRY: dict[str, list[BillingDimension]] = {
|
2026-01-05 16:48:59 +08:00
|
|
|
|
# 按厂商名称
|
|
|
|
|
|
"claude": BillingTemplates.CLAUDE_STANDARD,
|
|
|
|
|
|
"anthropic": BillingTemplates.CLAUDE_STANDARD,
|
|
|
|
|
|
"openai": BillingTemplates.OPENAI_STANDARD,
|
|
|
|
|
|
"doubao": BillingTemplates.DOUBAO_STANDARD,
|
|
|
|
|
|
"bytedance": BillingTemplates.DOUBAO_STANDARD,
|
|
|
|
|
|
"gemini": BillingTemplates.GEMINI_STANDARD,
|
|
|
|
|
|
"google": BillingTemplates.GEMINI_STANDARD,
|
|
|
|
|
|
# 按计费模式
|
|
|
|
|
|
"per_request": BillingTemplates.PER_REQUEST,
|
|
|
|
|
|
"hybrid": BillingTemplates.HYBRID_STANDARD,
|
|
|
|
|
|
# 默认
|
|
|
|
|
|
"default": BillingTemplates.CLAUDE_STANDARD,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-01-30 03:10:21 +08:00
|
|
|
|
def get_template(name: str | None) -> list[BillingDimension]:
|
2026-01-05 16:48:59 +08:00
|
|
|
|
"""
|
|
|
|
|
|
获取计费模板
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
name: 模板名称(不区分大小写)
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
计费维度列表
|
|
|
|
|
|
"""
|
|
|
|
|
|
if not name:
|
|
|
|
|
|
return BILLING_TEMPLATE_REGISTRY["default"]
|
|
|
|
|
|
|
|
|
|
|
|
template = BILLING_TEMPLATE_REGISTRY.get(name.lower())
|
|
|
|
|
|
if template is None:
|
|
|
|
|
|
available = ", ".join(sorted(BILLING_TEMPLATE_REGISTRY.keys()))
|
|
|
|
|
|
raise ValueError(f"Unknown billing template: {name!r}. Available: {available}")
|
|
|
|
|
|
|
|
|
|
|
|
return template
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-01-30 03:10:21 +08:00
|
|
|
|
def list_templates() -> list[str]:
|
2026-01-05 16:48:59 +08:00
|
|
|
|
"""列出所有可用的模板名称"""
|
|
|
|
|
|
return list(BILLING_TEMPLATE_REGISTRY.keys())
|