## 计费体系 - 团队额度从秒数改为金额(余额/冻结/月消费上限) - 用户限额从秒数改为次数(每日50次/每月1500次) - 新增 billing.py 工具模块(分辨率→像素映射 + token/费用计算) - 扣费流程:预扣制→冻结制(提交冻结预估金额,完成按实际tokens扣费,失败释放) - 允许小额透支(实际费用超预估时余额可变负) - 团队加价比例(markup_percentage),创建团队时必填 ## Token 追踪 - GenerationRecord 新增 tokens_consumed/cost_amount/base_cost_amount - 任务完成时从 Seedance API usage.total_tokens 获取精确值 - 生成页显示预估消耗(tokens + 金额),按团队售价计算 ## 管理后台 - 仪表盘新增利润分析板块(总收入/成本/利润/利润率 + 团队利润排行) - 消费记录新增 Tokens/售价/成本/利润列 - 团队管理:充值改为充金额,新增加价比例设置 - 系统设置:默认限额改为次数,新增基础token单价配置 ## Bug 修复 - 登录弹窗:拖选输入框内容不再误关闭(onClick→mousedown+mouseup) - 视频详情弹窗:遮罩层覆盖全视口(left:76px→0),admin/团管侧栏不再露出 ## UI 增强 - 图片大图预览:上传区和视频详情弹窗的图片支持点击查看大图(ImageLightbox) - 移除 adaptive 比例和智能时长选项,确保 token 预估可精确计算 - 视频详情弹窗显示实际消耗 tokens 和费用 ## 前端全量更新 - 所有页面秒数显示替换为金额(元)和次数(次) - TypeScript 类型全量更新 - API 调用参数同步更新 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
70 lines
2.2 KiB
Python
70 lines
2.2 KiB
Python
"""
|
||
计费工具模块 — 分辨率映射 + token/费用计算
|
||
|
||
Token 预估公式(火山官方):(宽 × 高 × 帧率 × 时长) / 1024
|
||
单价:元 / 百万 tokens
|
||
"""
|
||
from decimal import Decimal, ROUND_HALF_UP
|
||
|
||
# 分辨率 → 像素映射(来自 Seedance 2.0 API 文档)
|
||
RESOLUTION_MAP = {
|
||
# 720p
|
||
('720p', '16:9'): (1280, 720),
|
||
('720p', '9:16'): (720, 1280),
|
||
('720p', '4:3'): (1112, 834),
|
||
('720p', '1:1'): (960, 960),
|
||
('720p', '3:4'): (834, 1112),
|
||
('720p', '21:9'): (1470, 630),
|
||
# 480p
|
||
('480p', '16:9'): (864, 496),
|
||
('480p', '9:16'): (496, 864),
|
||
('480p', '4:3'): (752, 560),
|
||
('480p', '1:1'): (640, 640),
|
||
('480p', '3:4'): (560, 752),
|
||
('480p', '21:9'): (992, 432),
|
||
}
|
||
|
||
# 默认帧率
|
||
DEFAULT_FPS = 24
|
||
|
||
|
||
def get_resolution(aspect_ratio: str, tier: str = '720p') -> tuple:
|
||
"""根据宽高比和分辨率档位返回 (width, height) 像素值。"""
|
||
return RESOLUTION_MAP.get((tier, aspect_ratio), (1280, 720))
|
||
|
||
|
||
def estimate_tokens(width: int, height: int, duration: int, fps: int = DEFAULT_FPS) -> int:
|
||
"""预估视频生成消耗的 tokens。"""
|
||
return round(width * height * fps * duration / 1024)
|
||
|
||
|
||
def calculate_cost(tokens: int, base_price, markup_percentage) -> Decimal:
|
||
"""计算用户费用(加价后)。
|
||
|
||
Args:
|
||
tokens: 消耗的 tokens 数
|
||
base_price: 成本价(元/百万tokens)
|
||
markup_percentage: 加价百分比,如 20 表示 20%
|
||
Returns:
|
||
Decimal: 加价后费用,保留 2 位小数
|
||
"""
|
||
base_price = Decimal(str(base_price))
|
||
markup = Decimal(str(markup_percentage))
|
||
team_price = base_price * (1 + markup / 100)
|
||
cost = Decimal(str(tokens)) * team_price / Decimal('1000000')
|
||
return cost.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
|
||
|
||
|
||
def calculate_base_cost(tokens: int, base_price) -> Decimal:
|
||
"""计算平台成本(不加价)。
|
||
|
||
Args:
|
||
tokens: 消耗的 tokens 数
|
||
base_price: 成本价(元/百万tokens)
|
||
Returns:
|
||
Decimal: 成本费用,保留 2 位小数
|
||
"""
|
||
base_price = Decimal(str(base_price))
|
||
cost = Decimal(str(tokens)) * base_price / Decimal('1000000')
|
||
return cost.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
|