Files
xiaoxia-saas/packages/domain/points_rules.py
T
saas-backend-agent 4a4b8f4a05
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 4s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m12s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m20s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 3m36s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m27s
AI Code Review / AI Code Review (pull_request) Successful in 7m13s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 11m7s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 14m54s
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Style (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been cancelled
fix(viral-video): 错别字'很近'三保险修复
- 编导prompt加粗强调严禁使用'很近',正确用词'最近'
- _try_gen增加hard fix字符串替换:口播/分镜对白含'很近'自动替换
- 三级重试合格校验:口播含'很近'视为不合格触发重试

refactor(points): 移除ai_video/数字人/配音/改写/标题/封面/抖音解析扣点,仅保留声音克隆

- 删除5个路由的@points_gate装饰器(generation_preview/generation_cover/generation_tasks/scripts_ai/ai_avatar_render)
- 删除tts.py/lipsync.py/narrative_service.py中ai_voice/ai_digital_human手动扣点+refund块
- points_rules.py精简POINTS_SCENES:仅保留voice_clone_train(0积分)和voice_clone_synth(1积分/分钟)
- 删除DAILY_FREE_CLIP_LIMIT免费混剪额度逻辑,get_daily_usage返回unlimited占位
- points_gate.py删除ai_video特殊分支,未知/免费场景calculate_points_cost返回0直接放行
- points.py删除UNKNOWN_SCENE 400校验,任意scene可查
- 更新16个测试文件适配新规则:198个扣点相关单测全绿,viral_video 58个测试无回归
2026-10-02 20:39:16 +08:00

100 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""积分消耗规则配置 (#1895)
v1.6.1: 按产品决策,智能混剪/AI数字人/AI配音/抖音解析/改写/标题/封面 全部免费,
仅保留声音克隆合成(voice_clone_synth)的扣点逻辑;声音克隆训练保持免费。
爆款视频(viral_video)后续走动态定价,暂不加入本文件。
"""
from __future__ import annotations
import math
# ============ 场景定义 ============
# 每个场景: base_points(基础积分), unit(计费单位), name(显示名称)
# 说明:仅保留需要扣点的场景;免费场景不要写入此字典。
POINTS_SCENES: dict[str, dict] = {
"voice_clone_train": {
"base_points": 0,
"unit": "次",
"name": "声音克隆训练",
"description": "声音克隆训练免费(每用户限 1 个声音)",
},
"voice_clone_synth": {
"base_points": 1,
"unit": "分钟",
"name": "声音克隆合成",
"description": "克隆音色合成每分钟消耗 1 积分",
},
}
# 免费用户积分消耗上浮系数(仅对 voice_clone_synth 生效)
FREE_USER_MULTIPLIER = 1.15
# ============ 积分包定义 ============
POINTS_PACKAGES: dict[str, dict] = {
"starter_pack": {"name": "体验包", "points": 100, "price_cents": 990},
"basic_pack": {"name": "基础包", "points": 500, "price_cents": 3900},
"pro_pack": {"name": "专业包", "points": 2000, "price_cents": 12900},
}
# ============ 会员定价 ============
MEMBERSHIP_PRICES: dict[str, dict] = {
"monthly": {"name": "月卡", "price_cents": 1990, "duration_days": 30},
"quarterly": {"name": "季卡", "price_cents": 3990, "duration_days": 90},
"yearly": {"name": "年卡", "price_cents": 15900, "duration_days": 365},
}
# 会员积分折扣(付费会员按此系数打折)
MEMBER_DISCOUNT: dict[str, float] = {
"monthly": 0.9,
"quarterly": 0.87,
"yearly": 0.8,
}
def calculate_points_cost(
scene_key: str,
is_member: bool,
quantity: int = 1,
duration_minutes: float = 0,
member_type: str | None = None,
) -> int:
"""计算指定场景的积分消耗。
Args:
scene_key: 场景标识(当前仅支持 voice_clone_train/voice_clone_synth)
is_member: 是否付费会员
quantity: 数量(按次计费场景)
duration_minutes: 时长分钟数(按时长计费场景)
member_type: 会员类型 (monthly/quarterly/yearly),用于折扣
Returns:
实际消耗积分(已含免费用户 ×1.15 上浮或会员折扣);免费/已下线场景统一返回 0。
"""
scene = POINTS_SCENES.get(scene_key)
if not scene:
# 已下线/未注册的场景统一返回 0(免费),保持向后兼容
return 0
base = scene["base_points"]
if base == 0:
return 0
unit = scene["unit"]
if unit == "分钟":
total_base = base * max(1, math.ceil(duration_minutes))
elif unit in ("次", "张"):
total_base = base * quantity
else:
total_base = base
if is_member and member_type and member_type in MEMBER_DISCOUNT:
total_base = max(1, math.floor(total_base * MEMBER_DISCOUNT[member_type]))
elif not is_member:
total_base = math.ceil(total_base * FREE_USER_MULTIPLIER)
return total_base