import os from typing import Any, Dict, Tuple import torch from shared.utils.hf import build_hf_url from .prompt_enhancers import MAGI_HUMAN_ENHANCED_PROMPT MAGI_HUMAN_REPO = "DeepBeepMeep/MagiHuman" TEXT_ENCODER_FOLDER = "t5gemma-9b-9b-ul2" TEXT_ENCODER_BF16 = "t5gemma-9b-9b-ul2_bf16.safetensors" TEXT_ENCODER_QUANTO = "t5gemma-9b-9b-ul2_quanto_bf16_int8.safetensors" DISTILL_ARCH = "magi_human_distill" BASE_ARCH = "magi_human" SR_MODEL_DEFAULTS = { "sr_cfg_number": 1, "sr_num_inference_steps": 5, "sr_noise_value": 220, "sr_video_txt_guidance_scale": 3.5, "use_cfg_trick": True, "cfg_trick_start_frame": 13, "cfg_trick_value": 2.0, "using_sde_flag": False, "sr_audio_noise_scale": 0.7, } class family_handler: @staticmethod def query_supported_types(): return [BASE_ARCH, DISTILL_ARCH] @staticmethod def query_family_maps() -> Tuple[Dict[str, str], Dict[str, list]]: return {DISTILL_ARCH: BASE_ARCH}, {BASE_ARCH: [DISTILL_ARCH]} @staticmethod def query_model_family(): return "magi_human" @staticmethod def query_family_infos(): return {"magi_human": (62, "Magi Human")} @staticmethod def register_lora_cli_args(parser, lora_root): parser.add_argument( "--lora-dir-magi-human", type=str, default=None, help=f"Path to a directory that contains Magi Human LoRAs (default: {os.path.join(lora_root, 'magi_human')})", ) parser.add_argument( "--lora-dir-magi-human-distill", type=str, default=None, help=f"Path to a directory that contains Magi Human Distill LoRAs (default: {os.path.join(lora_root, 'magi_human_distill')})", ) @staticmethod def get_lora_dir(base_model_type, args, lora_root): if base_model_type == BASE_ARCH: return getattr(args, "lora_dir_magi_human", None) or os.path.join(lora_root, "magi_human") return getattr(args, "lora_dir_magi_human_distill", None) or os.path.join(lora_root, "magi_human_distill") @staticmethod def query_model_def(base_model_type: str, model_def: Dict[str, Any]): is_distill = base_model_type == DISTILL_ARCH extra_model_def = { "returns_audio": True, "any_audio_prompt": True, "audio_prompt_choices": True, "audio_guide_label": "Driving Audio", "audio_guide_window_slicing": True, "audio_prompt_type_sources": { "selection": ["", "A"], "labels": {"": "Generate Video & Soundtrack based on Text Prompt", "A": "Generate Video based on Soundtrack and Text Prompt"}, "show_label": False, }, "multimedia_generation": True, "sample_solvers": [("UniPC", "unipc")], "audio_guidance": not is_distill, "guidance_max_phases": 0 if is_distill else 1, "lock_inference_steps": is_distill, "no_negative_prompt": is_distill, "profiles_dir": [base_model_type], "group": "magi_human", "fps": 25, "frames_minimum": 26, "latent_size": 4, "frames_steps": 4, "sliding_window": True, "sliding_window_defaults": { "overlap_min": 1, "overlap_max": 1, "overlap_step": 1, "overlap_default": 1, "window_min": 25, "window_max": 251, "window_step": 4, "window_default": 101, }, "image_prompt_types_allowed": "SVL", "multiple_images_as_text_prompts": True, "multiple_submodels": False, "text_encoder_folder": TEXT_ENCODER_FOLDER, "text_encoder_URLs": [ build_hf_url(MAGI_HUMAN_REPO, TEXT_ENCODER_FOLDER, TEXT_ENCODER_BF16), build_hf_url(MAGI_HUMAN_REPO, TEXT_ENCODER_FOLDER, TEXT_ENCODER_QUANTO), ], "text_prompt_enhancer_instructions": MAGI_HUMAN_ENHANCED_PROMPT, "video_prompt_enhancer_instructions": MAGI_HUMAN_ENHANCED_PROMPT, "config_file": f"models/magi_human/configs/{base_model_type}.json", "vae_block_size": 32, "guidance_max_phases": 1, "visible_phases": 0 if is_distill else 1, } extra_model_def.update(model_def) if "URLs2" in extra_model_def: for key, value in SR_MODEL_DEFAULTS.items(): extra_model_def.setdefault(key, value) extra_model_def.update({ "multiple_submodels": True, "guidance_max_phases": 2, "lock_guidance_phases": True, }) return extra_model_def @staticmethod def query_model_files(computeList, base_model_type, model_def=None): return [ { "repoId": MAGI_HUMAN_REPO, "sourceFolderList": [TEXT_ENCODER_FOLDER, "stable-audio-open-1.0", "turbo_vae"], "fileList": [ ["config.json", "generation_config.json", "special_tokens_map.json", "tokenizer.json", "tokenizer.model", "tokenizer_config.json"], ["model_config.json", "model.safetensors"], ["TurboV3-Wan22-TinyShallow_7_7.json", "TurboV3-Wan22-TinyShallow_7_7.safetensors"], ], }, { "repoId": "DeepBeepMeep/Wan2.2", "sourceFolderList": [""], "fileList": [["Wan2.2_VAE.safetensors"]], }, ] @staticmethod def load_model( model_filename, model_type, base_model_type, model_def, quantizeTransformer=False, text_encoder_quantization=None, dtype=torch.bfloat16, VAE_dtype=torch.float32, mixed_precision_transformer=False, save_quantized=False, submodel_no_list=None, text_encoder_filename=None, **kwargs, ): from .magi_human_model import MagiHumanModel magi_model = MagiHumanModel( model_filename=model_filename, model_type=model_type, base_model_type=base_model_type, model_def=model_def, text_encoder_filename=text_encoder_filename, quantizeTransformer=quantizeTransformer, dtype=dtype, VAE_dtype=VAE_dtype, mixed_precision_transformer=mixed_precision_transformer, save_quantized=save_quantized, ) pipe = { "transformer": magi_model.transformer, "text_encoder": magi_model.text_encoder.model, "vae": magi_model.vae.model, "audio_vae": magi_model.audio_vae.vae_model, "turbo_vae": magi_model.turbo_vae, } if magi_model.transformer2 is not None: pipe["transformer2"] = magi_model.transformer2 return magi_model, pipe @staticmethod def fix_settings(base_model_type, settings_version, model_def, ui_defaults): pass @staticmethod def validate_generative_settings(base_model_type, model_def, inputs): inputs["sliding_window_overlap"] = 1 if base_model_type != DISTILL_ARCH: return inputs["guidance_scale"] = 1.0 inputs["audio_guidance_scale"] = 1.0 inputs["num_inference_steps"] = 8 @staticmethod def update_default_settings(base_model_type, model_def, ui_defaults): ui_defaults.update({ "sample_solver": "unipc", "flow_shift": 5.0, "multi_prompts_gen_type": "FG", "image_prompt_type": "S", "audio_prompt_type": "", "video_length": 101, "sliding_window_size": 101, "sliding_window_overlap": 1, "sliding_window_discard_last_frames": 0, }) if "URLs2" in model_def: ui_defaults["guidance_phases"] = 2 if base_model_type == BASE_ARCH: ui_defaults.update({ "guidance_scale": 5.0, "audio_guidance_scale": 5.0, "num_inference_steps": 32, }) else: ui_defaults.update({ "guidance_scale": 1.0, "audio_guidance_scale": 1.0, "num_inference_steps": 8, }) @staticmethod def get_rgb_factors(base_model_type): from shared.RGB_factors import get_rgb_factors return get_rgb_factors("wan", "ti2v_2_2")