| from pathlib import Path |
| import torch |
|
|
| import comfy.sample as comfy_sample |
| from comfy.model_patcher import ModelPatcher |
|
|
| from .context import ContextOptions, ContextSchedules, UniformContextOptions |
| from .logger import logger |
| from .model_utils import BetaSchedules, get_available_motion_loras, get_available_motion_models, get_motion_lora_path |
| from .motion_utils import NoiseType |
| from .motion_lora import MotionLoraInfo, MotionLoraList |
| from .model_injection import InjectionParams, ModelPatcherAndInjector, MotionModelSettings, load_motion_module |
| from .sampling import motion_sample_factory |
|
|
| from .nodes_extras import AnimateDiffUnload, EmptyLatentImageLarge, CheckpointLoaderSimpleWithNoiseSelect |
| from .nodes_experimental import AnimateDiffModelSettingsSimple, AnimateDiffModelSettingsAdvanced, AnimateDiffModelSettingsAdvancedAttnStrengths |
| from .nodes_deprecated import AnimateDiffLoader_Deprecated, AnimateDiffLoaderAdvanced_Deprecated, AnimateDiffCombine_Deprecated |
|
|
| |
| comfy_sample.sample = motion_sample_factory(comfy_sample.sample) |
| comfy_sample.sample_custom = motion_sample_factory(comfy_sample.sample_custom) |
|
|
|
|
| class AnimateDiffModelSettings: |
| @classmethod |
| def INPUT_TYPES(s): |
| return { |
| "required": { |
| "min_motion_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "step": 0.001}), |
| "max_motion_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "step": 0.001}), |
| }, |
| "optional": { |
| "mask_motion_scale": ("MASK",), |
| } |
| } |
| |
| RETURN_TYPES = ("MOTION_MODEL_SETTINGS",) |
| CATEGORY = "Animate Diff ππ
π
/motion settings" |
| FUNCTION = "get_motion_model_settings" |
|
|
| def get_motion_model_settings(self, mask_motion_scale: torch.Tensor=None, min_motion_scale: float=1.0, max_motion_scale: float=1.0): |
| motion_model_settings = MotionModelSettings( |
| mask_attn_scale=mask_motion_scale, |
| mask_attn_scale_min=min_motion_scale, |
| mask_attn_scale_max=max_motion_scale, |
| ) |
|
|
| return (motion_model_settings,) |
|
|
|
|
| class AnimateDiffLoraLoader: |
| @classmethod |
| def INPUT_TYPES(s): |
| return { |
| "required": { |
| "lora_name": (get_available_motion_loras(),), |
| "strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001}), |
| }, |
| "optional": { |
| "prev_motion_lora": ("MOTION_LORA",), |
| } |
| } |
| |
| RETURN_TYPES = ("MOTION_LORA",) |
| CATEGORY = "Animate Diff ππ
π
" |
| FUNCTION = "load_motion_lora" |
|
|
| def load_motion_lora(self, lora_name: str, strength: float, prev_motion_lora: MotionLoraList=None): |
| if prev_motion_lora is None: |
| prev_motion_lora = MotionLoraList() |
| else: |
| prev_motion_lora = prev_motion_lora.clone() |
| |
| lora_path = get_motion_lora_path(lora_name) |
| if not Path(lora_path).is_file(): |
| raise FileNotFoundError(f"Motion lora with name '{lora_name}' not found.") |
| |
| lora_info = MotionLoraInfo(name=lora_name, strength=strength) |
| prev_motion_lora.add_lora(lora_info) |
|
|
| return (prev_motion_lora,) |
|
|
|
|
| class AnimateDiffLoaderWithContext: |
| @classmethod |
| def INPUT_TYPES(s): |
| return { |
| "required": { |
| "model": ("MODEL",), |
| "model_name": (get_available_motion_models(),), |
| "beta_schedule": (BetaSchedules.ALIAS_LIST, {"default": BetaSchedules.SQRT_LINEAR}), |
| |
| }, |
| "optional": { |
| "context_options": ("CONTEXT_OPTIONS",), |
| "motion_lora": ("MOTION_LORA",), |
| "motion_model_settings": ("MOTION_MODEL_SETTINGS",), |
| "motion_scale": ("FLOAT", {"default": 1.0, "min": 0.0, "step": 0.001}), |
| "apply_v2_models_properly": ("BOOLEAN", {"default": True}), |
| } |
| } |
| |
| RETURN_TYPES = ("MODEL",) |
| CATEGORY = "Animate Diff ππ
π
" |
| FUNCTION = "load_mm_and_inject_params" |
|
|
|
|
| def load_mm_and_inject_params(self, |
| model: ModelPatcher, |
| model_name: str, beta_schedule: str, |
| context_options: ContextOptions=None, motion_lora: MotionLoraList=None, motion_model_settings: MotionModelSettings=None, |
| motion_scale: float=1.0, apply_v2_models_properly: bool=False, |
| ): |
| |
| motion_model = load_motion_module(model_name, model, motion_lora=motion_lora, motion_model_settings=motion_model_settings) |
| |
| params = InjectionParams( |
| video_length=None, |
| unlimited_area_hack=False, |
| apply_mm_groupnorm_hack=True, |
| beta_schedule=beta_schedule, |
| model_name=model_name, |
| apply_v2_models_properly=apply_v2_models_properly, |
| ) |
| if context_options: |
| |
| if type(context_options) == UniformContextOptions: |
| params.set_context( |
| context_length=context_options.context_length, |
| context_stride=context_options.context_stride, |
| context_overlap=context_options.context_overlap, |
| context_schedule=context_options.context_schedule, |
| closed_loop=context_options.closed_loop, |
| sync_context_to_pe=context_options.sync_context_to_pe, |
| ) |
| params.noise_type = context_options.noise_type |
| if motion_lora: |
| params.set_loras(motion_lora) |
| |
| if not motion_model_settings: |
| motion_model_settings = MotionModelSettings() |
| motion_model_settings.attn_scale = motion_scale |
| params.set_motion_model_settings(motion_model_settings) |
|
|
| |
| motion_model.model.set_scale_multiplier(params.motion_model_settings.attn_scale) |
|
|
| |
| motion_model.model.set_masks( |
| masks=params.motion_model_settings.mask_attn_scale, |
| min_val=params.motion_model_settings.mask_attn_scale_min, |
| max_val=params.motion_model_settings.mask_attn_scale_max |
| ) |
|
|
| model = ModelPatcherAndInjector(model) |
| model.motion_model = motion_model |
| model.motion_injection_params = params |
|
|
| |
| new_model_sampling = BetaSchedules.to_model_sampling(params.beta_schedule, model) |
| if new_model_sampling is not None: |
| model.add_object_patch("model_sampling", new_model_sampling) |
|
|
| del motion_model |
| return (model,) |
|
|
|
|
| class AnimateDiffUniformContextOptions: |
| @classmethod |
| def INPUT_TYPES(s): |
| return { |
| "required": { |
| "context_length": ("INT", {"default": 16, "min": 1, "max": 32}), |
| "context_stride": ("INT", {"default": 1, "min": 1, "max": 32}), |
| "context_overlap": ("INT", {"default": 4, "min": 0, "max": 32}), |
| "context_schedule": (ContextSchedules.CONTEXT_SCHEDULE_LIST,), |
| "closed_loop": ("BOOLEAN", {"default": False},), |
| |
| }, |
| } |
| |
| RETURN_TYPES = ("CONTEXT_OPTIONS",) |
| CATEGORY = "Animate Diff ππ
π
" |
| FUNCTION = "create_options" |
|
|
| def create_options(self, context_length: int, context_stride: int, context_overlap: int, context_schedule: int, closed_loop: bool): |
| context_options = UniformContextOptions( |
| context_length=context_length, |
| context_stride=context_stride, |
| context_overlap=context_overlap, |
| context_schedule=context_schedule, |
| closed_loop=closed_loop |
| ) |
| |
| return (context_options,) |
|
|
|
|
| class AnimateDiffUniformContextOptionsExperimental: |
| @classmethod |
| def INPUT_TYPES(s): |
| return { |
| "required": { |
| "context_length": ("INT", {"default": 16, "min": 1, "max": 32}), |
| "context_stride": ("INT", {"default": 1, "min": 1, "max": 32}), |
| "context_overlap": ("INT", {"default": 0, "min": 0, "max": 32}), |
| "context_schedule": (ContextSchedules.CONTEXT_SCHEDULE_LIST,), |
| "closed_loop": ("BOOLEAN", {"default": False},), |
| "noise_override": (NoiseType.LIST,) |
| |
| }, |
| } |
| |
| RETURN_TYPES = ("CONTEXT_OPTIONS",) |
| CATEGORY = "Animate Diff ππ
π
" |
| FUNCTION = "create_options" |
|
|
| def create_options(self, context_length: int, context_stride: int, context_overlap: int, context_schedule: int, closed_loop: bool, |
| noise_override: str): |
| context_options = UniformContextOptions( |
| context_length=context_length, |
| context_stride=context_stride, |
| context_overlap=context_overlap, |
| context_schedule=context_schedule, |
| closed_loop=closed_loop, |
| ) |
| context_options.set_noise_type(noise_override) |
| |
| return (context_options,) |
|
|
|
|
| NODE_CLASS_MAPPINGS = { |
| "ADE_AnimateDiffUniformContextOptions": AnimateDiffUniformContextOptions, |
| |
| "ADE_AnimateDiffLoaderWithContext": AnimateDiffLoaderWithContext, |
| "ADE_AnimateDiffLoRALoader": AnimateDiffLoraLoader, |
| "ADE_AnimateDiffModelSettings_Release": AnimateDiffModelSettings, |
| |
| "ADE_AnimateDiffModelSettingsSimple": AnimateDiffModelSettingsSimple, |
| "ADE_AnimateDiffModelSettings": AnimateDiffModelSettingsAdvanced, |
| "ADE_AnimateDiffModelSettingsAdvancedAttnStrengths": AnimateDiffModelSettingsAdvancedAttnStrengths, |
| |
| "ADE_AnimateDiffUnload": AnimateDiffUnload, |
| "ADE_EmptyLatentImageLarge": EmptyLatentImageLarge, |
| "CheckpointLoaderSimpleWithNoiseSelect": CheckpointLoaderSimpleWithNoiseSelect, |
| |
| "AnimateDiffLoaderV1": AnimateDiffLoader_Deprecated, |
| "ADE_AnimateDiffLoaderV1Advanced": AnimateDiffLoaderAdvanced_Deprecated, |
| "ADE_AnimateDiffCombine": AnimateDiffCombine_Deprecated, |
| } |
| NODE_DISPLAY_NAME_MAPPINGS = { |
| "ADE_AnimateDiffUniformContextOptions": "Uniform Context Options ππ
π
", |
| |
| "ADE_AnimateDiffLoaderWithContext": "AnimateDiff Loader ππ
π
", |
| "ADE_AnimateDiffLoRALoader": "AnimateDiff LoRA Loader ππ
π
", |
| "ADE_AnimateDiffModelSettings_Release": "Motion Model Settings ππ
π
", |
| |
| "ADE_AnimateDiffModelSettingsSimple": "EXP Motion Model Settings (Simple) ππ
π
", |
| "ADE_AnimateDiffModelSettings": "EXP Motion Model Settings (Advanced) ππ
π
", |
| "ADE_AnimateDiffModelSettingsAdvancedAttnStrengths": "EXP Motion Model Settings (Adv. Attn) ππ
π
", |
| |
| "ADE_AnimateDiffUnload": "AnimateDiff Unload ππ
π
", |
| "ADE_EmptyLatentImageLarge": "Empty Latent Image (Big Batch) ππ
π
", |
| "CheckpointLoaderSimpleWithNoiseSelect": "Load Checkpoint w/ Noise Select ππ
π
", |
| |
| "AnimateDiffLoaderV1": "AnimateDiff Loader [DEPRECATED] ππ
π
", |
| "ADE_AnimateDiffLoaderV1Advanced": "AnimateDiff Loader (Advanced) [DEPRECATED] ππ
π
", |
| "ADE_AnimateDiffCombine": "DO NOT USE, USE VideoCombine from ComfyUI-VideoHelperSuite instead! AnimateDiff Combine [DEPRECATED, DO NOT USE] ππ
π
", |
| } |
|
|