pipeline-app/app/cost_estimator.py

182 lines
5.7 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.

"""
Video generation cost estimator - multi-model pricing and cost prediction.
Estimates cost for generating scene videos using different models:
- Wan2.2 (local GPU, fast, lower cost)
- Wan2.7 (local GPU, higher quality, medium cost)
- Vidu 2.0 (cloud API, highest quality, premium cost)
Cost factors:
- Scene count from storyboard
- Duration per scene (frames)
- Model pricing (per frame or per second)
- GPU compute cost (for local models)
"""
import logging
from typing import List, Dict, Any
logger = logging.getLogger("pipeline.cost_estimator")
# Model pricing configuration — llmage v1 video models
MODEL_PRICING = {
"wan2.7-t2v": {
"name": "通义万象 WAN 2.7 (T2V) ⭐推荐",
"price_per_second": 0.05,
"quality_score": 8.5,
"generation_speed": "medium",
"description": "最新版文生视频,质量更高",
"features": ["T2V", "I2V", "Ref2V"],
"recommended_for": ["quality", "professional"],
},
"happyhorse-1.0-t2v": {
"name": "快乐马 HappyHorse 1.0 (T2V)",
"price_per_second": 0.03,
"quality_score": 7.5,
"generation_speed": "fast",
"description": "快速文生视频,经济实惠",
"features": ["T2V", "I2V"],
"recommended_for": ["standard", "batch"],
},
"doubao-seedance-2-0-260128": {
"name": "豆包 Seedance 2.0 (T2V)",
"price_per_second": 0.08,
"quality_score": 9.0,
"generation_speed": "slow",
"description": "字节跳动旗舰视频生成,支持音效同步",
"features": ["T2V", "I2V", "Ref2V", "音效"],
"recommended_for": ["premium", "cinematic"],
},
}
def estimate_scene_cost(storyboard: List[Dict[str, Any]], fps: int = 24) -> int:
"""
Estimate total frames needed for all scenes.
Args:
storyboard: List of scene dicts with start_time/end_time
fps: Frames per second (default 24)
Returns:
Total frame count
"""
total_frames = 0
for scene in storyboard:
duration = scene.get("end_time", 10) - scene.get("start_time", 0)
frames = int(duration * fps)
total_frames += frames
return total_frames
def estimate_model_cost(model_id: str, total_frames: int, fps: int = 24) -> Dict[str, Any]:
"""
Estimate cost for a specific model.
Args:
model_id: Model identifier (e.g., wan2.7-t2v, doubao-seedance-2-0-260128)
total_frames: Total frames to generate
Returns:
Cost estimate dict with breakdown
"""
if model_id not in MODEL_PRICING:
raise ValueError(f"Unknown model: {model_id}")
model = MODEL_PRICING[model_id]
return {
"model_id": model_id,
"model_name": model["name"],
"total_frames": total_frames,
"fps": fps,
"price_per_second": model["price_per_second"],
"total_cost": round(total_frames * model["price_per_second"] / fps, 4),
"quality_score": model["quality_score"],
"generation_speed": model["generation_speed"],
"description": model["description"],
"features": model["features"],
"recommended_for": model["recommended_for"],
}
def estimate_all_models(storyboard: List[Dict[str, Any]], fps: int = 24) -> List[Dict[str, Any]]:
"""
Estimate cost for all available models.
Args:
storyboard: List of scene dicts
fps: Frames per second
Returns:
List of cost estimates sorted by total_cost (ascending)
"""
total_frames = estimate_scene_cost(storyboard, fps)
scene_count = len(storyboard)
estimates = []
for model_id in MODEL_PRICING.keys():
try:
estimate = estimate_model_cost(model_id, total_frames, fps)
estimate["scene_count"] = scene_count
estimate["fps"] = fps
estimates.append(estimate)
except Exception as e:
logger.error(f"Failed to estimate cost for {model_id}: {e}")
# Sort by total_cost (cheapest first)
estimates.sort(key=lambda x: x["total_cost"])
# Add recommendation flag
if estimates:
# Recommend middle option (best value)
mid_idx = len(estimates) // 2
estimates[mid_idx]["recommended"] = True
for i, est in enumerate(estimates):
if i != mid_idx:
est["recommended"] = False
return estimates
def format_cost_summary(estimates: List[Dict[str, Any]]) -> str:
"""
Format cost estimates as human-readable summary.
Args:
estimates: List of cost estimate dicts
Returns:
Formatted string summary
"""
lines = []
lines.append("=" * 70)
lines.append("视频生成模型费用预估")
lines.append("=" * 70)
if not estimates:
lines.append("无可用模型")
return "\n".join(lines)
scene_count = estimates[0].get("scene_count", 0)
total_frames = estimates[0].get("total_frames", 0)
fps = estimates[0].get("fps", 24)
lines.append(f"分镜数量: {scene_count}")
lines.append(f"总帧数: {total_frames} (at {fps}fps)")
lines.append("")
for est in estimates:
rec = " ⭐ 推荐" if est.get("recommended") else ""
lines.append(f"{est['model_name']}{rec}")
lines.append(f" 质量评分: {est['quality_score']}/10")
lines.append(f" 生成速度: {est['generation_speed']}")
lines.append(f" 功能: {', '.join(est['features'])}")
lines.append(f" 描述: {est['description']}")
lines.append(f" 费用: 每秒 ${est['price_per_second']:.4f} × {est['total_frames']}帧@{est['fps']}fps = ${est['total_cost']:.4f}")
lines.append("")
lines.append("=" * 70)
return "\n".join(lines)