"""积分消耗规则配置 (#1895)""" from __future__ import annotations import math # ============ 场景定义 ============ # 每个场景: base_points(基础积分), unit(计费单位), name(显示名称) POINTS_SCENES: dict[str, dict] = { "ai_voice": { "base_points": 1, "unit": "分钟", "name": "AI 配音", "description": "AI 配音每分钟消耗 1 积分(免费用户上浮 15%,会员 8~9 折)", }, "ai_video": { "base_points": 3, "unit": "条", "name": "智能混剪", "extra_per_30s": 1, "description": "智能混剪每条 3 积分起,视频超过 30 秒后每 30 秒加 1 积分;免费用户每日 2 条免费额度", }, "ai_digital_human": { "base_points": 15, "unit": "分钟", "name": "AI 数字人", "description": "AI 数字人每分钟消耗 15 积分", }, "voice_clone_train": { "base_points": 0, "unit": "次", "name": "声音克隆训练", "description": "声音克隆训练免费(每用户限 1 个声音)", }, "voice_clone_synth": { "base_points": 1, "unit": "分钟", "name": "声音克隆合成", "description": "克隆音色合成每分钟消耗 1 积分", }, "douyin_extract": { "base_points": 1, "unit": "次", "name": "抖音链接提取", "description": "抖音文案提取每次 1 积分", }, "ai_rewrite": {"base_points": 1, "unit": "次", "name": "AI 改写文案", "description": "AI 改写文案每次 1 积分"}, "ai_title": { "base_points": 1, "unit": "次", "name": "AI 标题生成", "description": "AI 生成标题每次 1 积分(免费用户实际上浮后 2 积分/次)", }, "ai_cover": {"base_points": 1, "unit": "张", "name": "AI 封面生成", "description": "AI 封面生成每张 1 积分"}, } # 免费用户积分消耗上浮系数 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, } # 每日免费混剪次数(免费用户) DAILY_FREE_CLIP_LIMIT = 2 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: 场景标识,如 "ai_voice"、"ai_video" is_member: 是否付费会员 quantity: 数量(按次计费场景) duration_minutes: 时长分钟数(按时长计费场景) member_type: 会员类型 (monthly/quarterly/yearly),用于折扣 Returns: 实际消耗积分(已含免费用户 ×1.15 上浮或会员折扣) Raises: ValueError: 未知场景标识 """ scene = POINTS_SCENES.get(scene_key) if not scene: raise ValueError(f"Unknown points scene: {scene_key}") 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 # 混剪特殊逻辑:视频超过 30s 后每 +30s 额外加 1 积分 if scene_key == "ai_video" and duration_minutes > 0.5: extra_segments = math.ceil((duration_minutes * 60 - 30) / 30) if extra_segments > 0: total_base += scene.get("extra_per_30s", 1) * extra_segments 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