julius119's picture
Upload folder using huggingface_hub
8ab53f1 verified
Raw History Blame Contribute Delete
3.76 kB
"""
多维度加权决策模型路由器与质量降级漏斗
Author: XiaoZhe (Commercial Contact: janejulius119@gmail.com / WeChat: julius119)
"""
import logging
from dataclasses import dataclass
from typing import Dict, List, Tuple, Optional
logger = logging.getLogger("VerseFlow.Router")
@dataclass
class ModelProfile:
model_id: str
display_name: str
param_count: float
max_resolution: Tuple[int, int]
max_duration: float
fp8_vram_gb: float
has_native_audio: bool
identity_consistency: float
motion_quality: float
face_quality: float
text_compliance: float
audio_sync: float
speed_score: float
@dataclass
class RoutingRequest:
scene_type: str
duration: float
resolution: Tuple[int, int]
requires_audio: bool
requires_text: bool
identity_critical: bool
deadline_s: float
class ModelRouter:
"""6 维度加权决策模型路由器"""
SCENE_WEIGHTS = {
"product_demo": {"identity_consistency": 0.25, "text_compliance": 0.25, "motion_quality": 0.20, "speed_score": 0.30},
"talking_head": {"face_quality": 0.40, "identity_consistency": 0.30, "audio_sync": 0.20, "speed_score": 0.10},
"b_roll": {"speed_score": 0.40, "motion_quality": 0.30, "identity_consistency": 0.30},
"brand_ad": {"text_compliance": 0.30, "identity_consistency": 0.30, "audio_sync": 0.20, "motion_quality": 0.20}
}
def __init__(self, models: Optional[List[ModelProfile]] = None):
self.models = models or self._get_default_profiles()
def _get_default_profiles(self) -> List[ModelProfile]:
return [
ModelProfile("minimax_h3", "MiniMax H3", 33.0, (2560, 1440), 15.0, 38.0, True, 9.0, 8.5, 9.0, 9.5, 9.5, 3.0),[cite: 1]
ModelProfile("wan2.2_14b", "Wan2.2 14B", 14.0, (1280, 720), 10.0, 28.0, False, 8.5, 9.0, 8.5, 7.5, 0.0, 4.0),[cite: 1]
ModelProfile("hunyuan_video_1_5", "Hunyuan 1.5", 8.3, (1280, 720), 12.0, 24.0, False, 8.0, 8.0, 9.5, 7.0, 0.0, 5.0),[cite: 1]
ModelProfile("ltx_2_3", "LTX 2.3", 22.0, (1920, 1080), 10.0, 16.0, True, 7.0, 8.0, 7.5, 6.0, 8.0, 9.0),[cite: 1]
ModelProfile("wan2.2_5b", "Wan2.2 5B", 5.0, (854, 480), 5.0, 8.0, False, 6.0, 7.0, 6.5, 6.0, 0.0, 9.5),[cite: 1]
]
def route(self, request: RoutingRequest) -> List[Tuple[str, float, str]]:
candidates = []
weights = self.SCENE_WEIGHTS.get(request.scene_type, self.SCENE_WEIGHTS["b_roll"])
for model in self.models:
if request.duration > model.max_duration:
continue
if request.resolution[0] > model.max_resolution[0] or request.resolution[1] > model.max_resolution[1]:
continue
score = 0.0
for attr, weight in weights.items():
val = getattr(model, attr, 5.0)
score += val * weight
if request.requires_audio and not model.has_native_audio:
score *= 0.6
reason = f"场景匹配得分: {score:.2f} | Model={model.display_name}"
candidates.append((model.model_id, score, reason))
candidates.sort(key=lambda x: x[1], reverse=True)
return candidates
class QualityFunnelController:
"""三级质量控制漏斗"""
@staticmethod
def get_stage_config(quality_tier: str) -> Dict[str, Any]:
if quality_tier == "draft":
return {"model_id": "wan2.2_5b", "resolution": (854, 480), "max_attempts": 1}[cite: 1]
elif quality_tier == "refine":
return {"model_id": "auto_route", "resolution": (1280, 720), "max_attempts": 3}[cite: 1]
else:
return {"model_id": "minimax_h3", "resolution": (1920, 1080), "max_attempts": 5}[cite: 1]