Spaces:
Configuration error
Configuration error
| from typing import Union | |
| import numpy as np | |
| from collections.abc import Iterable | |
| from .utils import ControlWeights, TimestepKeyframe, TimestepKeyframeGroup, LatentKeyframe, LatentKeyframeGroup, BIGMIN, BIGMAX | |
| from .utils import StrengthInterpolation as SI | |
| from .logger import logger | |
| class TimestepKeyframeNode: | |
| OUTDATED_DUMMY = -39 | |
| def INPUT_TYPES(s): | |
| return { | |
| "required": { | |
| "start_percent": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001}, ), | |
| }, | |
| "optional": { | |
| "prev_timestep_kf": ("TIMESTEP_KEYFRAME", ), | |
| "strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001}, ), | |
| "cn_weights": ("CONTROL_NET_WEIGHTS", ), | |
| "latent_keyframe": ("LATENT_KEYFRAME", ), | |
| "null_latent_kf_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 10.0, "step": 0.001}, ), | |
| "inherit_missing": ("BOOLEAN", {"default": True}, ), | |
| "guarantee_steps": ("INT", {"default": 1, "min": 0, "max": BIGMAX}), | |
| "mask_optional": ("MASK", ), | |
| } | |
| } | |
| RETURN_NAMES = ("TIMESTEP_KF", ) | |
| RETURN_TYPES = ("TIMESTEP_KEYFRAME", ) | |
| FUNCTION = "load_keyframe" | |
| CATEGORY = "Adv-ControlNet ππ π π /keyframes" | |
| def load_keyframe(self, | |
| start_percent: float, | |
| strength: float=1.0, | |
| cn_weights: ControlWeights=None, control_net_weights: ControlWeights=None, # old name | |
| latent_keyframe: LatentKeyframeGroup=None, | |
| prev_timestep_kf: TimestepKeyframeGroup=None, prev_timestep_keyframe: TimestepKeyframeGroup=None, # old name | |
| null_latent_kf_strength: float=0.0, | |
| inherit_missing=True, | |
| guarantee_steps=OUTDATED_DUMMY, | |
| guarantee_usage=True, # old input | |
| mask_optional=None,): | |
| # if using outdated dummy value, means node on workflow is outdated and should appropriately convert behavior | |
| if guarantee_steps == self.OUTDATED_DUMMY: | |
| guarantee_steps = int(guarantee_usage) | |
| control_net_weights = control_net_weights if control_net_weights else cn_weights | |
| prev_timestep_keyframe = prev_timestep_keyframe if prev_timestep_keyframe else prev_timestep_kf | |
| if not prev_timestep_keyframe: | |
| prev_timestep_keyframe = TimestepKeyframeGroup() | |
| else: | |
| prev_timestep_keyframe = prev_timestep_keyframe.clone() | |
| keyframe = TimestepKeyframe(start_percent=start_percent, strength=strength, null_latent_kf_strength=null_latent_kf_strength, | |
| control_weights=control_net_weights, latent_keyframes=latent_keyframe, inherit_missing=inherit_missing, | |
| guarantee_steps=guarantee_steps, mask_hint_orig=mask_optional) | |
| prev_timestep_keyframe.add(keyframe) | |
| return (prev_timestep_keyframe,) | |
| class TimestepKeyframeInterpolationNode: | |
| def INPUT_TYPES(s): | |
| return { | |
| "required": { | |
| "start_percent": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001},), | |
| "end_percent": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}), | |
| "strength_start": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001},), | |
| "strength_end": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001},), | |
| "interpolation": (SI._LIST, ), | |
| "intervals": ("INT", {"default": 50, "min": 2, "max": 100, "step": 1}), | |
| }, | |
| "optional": { | |
| "prev_timestep_kf": ("TIMESTEP_KEYFRAME", ), | |
| "cn_weights": ("CONTROL_NET_WEIGHTS", ), | |
| "latent_keyframe": ("LATENT_KEYFRAME", ), | |
| "null_latent_kf_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 10.0, "step": 0.001},), | |
| "inherit_missing": ("BOOLEAN", {"default": True},), | |
| "mask_optional": ("MASK", ), | |
| "print_keyframes": ("BOOLEAN", {"default": False}), | |
| } | |
| } | |
| RETURN_NAMES = ("TIMESTEP_KF", ) | |
| RETURN_TYPES = ("TIMESTEP_KEYFRAME", ) | |
| FUNCTION = "load_keyframe" | |
| CATEGORY = "Adv-ControlNet ππ π π /keyframes" | |
| def load_keyframe(self, | |
| start_percent: float, end_percent: float, | |
| strength_start: float, strength_end: float, interpolation: str, intervals: int, | |
| cn_weights: ControlWeights=None, | |
| latent_keyframe: LatentKeyframeGroup=None, | |
| prev_timestep_kf: TimestepKeyframeGroup=None, | |
| null_latent_kf_strength: float=0.0, | |
| inherit_missing=True, | |
| guarantee_steps=1, | |
| mask_optional=None, print_keyframes=False): | |
| if not prev_timestep_kf: | |
| prev_timestep_kf = TimestepKeyframeGroup() | |
| else: | |
| prev_timestep_kf = prev_timestep_kf.clone() | |
| percents = SI.get_weights(num_from=start_percent, num_to=end_percent, length=intervals, method=SI.LINEAR) | |
| strengths = SI.get_weights(num_from=strength_start, num_to=strength_end, length=intervals, method=interpolation) | |
| is_first = True | |
| for percent, strength in zip(percents, strengths): | |
| guarantee_steps = 0 | |
| if is_first: | |
| guarantee_steps = 1 | |
| is_first = False | |
| prev_timestep_kf.add(TimestepKeyframe(start_percent=percent, strength=strength, null_latent_kf_strength=null_latent_kf_strength, | |
| control_weights=cn_weights, latent_keyframes=latent_keyframe, inherit_missing=inherit_missing, | |
| guarantee_steps=guarantee_steps, mask_hint_orig=mask_optional)) | |
| if print_keyframes: | |
| logger.info(f"TimestepKeyframe - start_percent:{percent} = {strength}") | |
| return (prev_timestep_kf,) | |
| class TimestepKeyframeFromStrengthListNode: | |
| def INPUT_TYPES(s): | |
| return { | |
| "required": { | |
| "float_strengths": ("FLOAT", {"default": -1, "min": -1, "step": 0.001, "forceInput": True}), | |
| "start_percent": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.001},), | |
| "end_percent": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.001}), | |
| }, | |
| "optional": { | |
| "prev_timestep_kf": ("TIMESTEP_KEYFRAME", ), | |
| "cn_weights": ("CONTROL_NET_WEIGHTS", ), | |
| "latent_keyframe": ("LATENT_KEYFRAME", ), | |
| "null_latent_kf_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 10.0, "step": 0.001},), | |
| "inherit_missing": ("BOOLEAN", {"default": True},), | |
| "mask_optional": ("MASK", ), | |
| "print_keyframes": ("BOOLEAN", {"default": False}), | |
| } | |
| } | |
| RETURN_NAMES = ("TIMESTEP_KF", ) | |
| RETURN_TYPES = ("TIMESTEP_KEYFRAME", ) | |
| FUNCTION = "load_keyframe" | |
| CATEGORY = "Adv-ControlNet ππ π π /keyframes" | |
| def load_keyframe(self, | |
| start_percent: float, end_percent: float, | |
| float_strengths: float, | |
| cn_weights: ControlWeights=None, | |
| latent_keyframe: LatentKeyframeGroup=None, | |
| prev_timestep_kf: TimestepKeyframeGroup=None, | |
| null_latent_kf_strength: float=0.0, | |
| inherit_missing=True, | |
| guarantee_steps=1, | |
| mask_optional=None, print_keyframes=False): | |
| if not prev_timestep_kf: | |
| prev_timestep_kf = TimestepKeyframeGroup() | |
| else: | |
| prev_timestep_kf = prev_timestep_kf.clone() | |
| if type(float_strengths) in (float, int): | |
| float_strengths = [float(float_strengths)] | |
| elif isinstance(float_strengths, Iterable): | |
| pass | |
| else: | |
| raise Exception(f"strengths_float must be either an iterable input or a float, but was {type(float_strengths).__repr__}.") | |
| percents = SI.get_weights(num_from=start_percent, num_to=end_percent, length=len(float_strengths), method=SI.LINEAR) | |
| is_first = True | |
| for percent, strength in zip(percents, float_strengths): | |
| guarantee_steps = 0 | |
| if is_first: | |
| guarantee_steps = 1 | |
| is_first = False | |
| prev_timestep_kf.add(TimestepKeyframe(start_percent=percent, strength=strength, null_latent_kf_strength=null_latent_kf_strength, | |
| control_weights=cn_weights, latent_keyframes=latent_keyframe, inherit_missing=inherit_missing, | |
| guarantee_steps=guarantee_steps, mask_hint_orig=mask_optional)) | |
| if print_keyframes: | |
| logger.info(f"TimestepKeyframe - start_percent:{percent} = {strength}") | |
| return (prev_timestep_kf,) | |
| class LatentKeyframeNode: | |
| def INPUT_TYPES(s): | |
| return { | |
| "required": { | |
| "batch_index": ("INT", {"default": 0, "min": BIGMIN, "max": BIGMAX, "step": 1}), | |
| "strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001}, ), | |
| }, | |
| "optional": { | |
| "prev_latent_kf": ("LATENT_KEYFRAME", ), | |
| } | |
| } | |
| RETURN_NAMES = ("LATENT_KF", ) | |
| RETURN_TYPES = ("LATENT_KEYFRAME", ) | |
| FUNCTION = "load_keyframe" | |
| CATEGORY = "Adv-ControlNet ππ π π /keyframes" | |
| def load_keyframe(self, | |
| batch_index: int, | |
| strength: float, | |
| prev_latent_kf: LatentKeyframeGroup=None, | |
| prev_latent_keyframe: LatentKeyframeGroup=None, # old name | |
| ): | |
| prev_latent_keyframe = prev_latent_keyframe if prev_latent_keyframe else prev_latent_kf | |
| if not prev_latent_keyframe: | |
| prev_latent_keyframe = LatentKeyframeGroup() | |
| else: | |
| prev_latent_keyframe = prev_latent_keyframe.clone() | |
| keyframe = LatentKeyframe(batch_index, strength) | |
| prev_latent_keyframe.add(keyframe) | |
| return (prev_latent_keyframe,) | |
| class LatentKeyframeGroupNode: | |
| def INPUT_TYPES(s): | |
| return { | |
| "required": { | |
| "index_strengths": ("STRING", {"multiline": True, "default": ""}), | |
| }, | |
| "optional": { | |
| "prev_latent_kf": ("LATENT_KEYFRAME", ), | |
| "latent_optional": ("LATENT", ), | |
| "print_keyframes": ("BOOLEAN", {"default": False}) | |
| } | |
| } | |
| RETURN_NAMES = ("LATENT_KF", ) | |
| RETURN_TYPES = ("LATENT_KEYFRAME", ) | |
| FUNCTION = "load_keyframes" | |
| CATEGORY = "Adv-ControlNet ππ π π /keyframes" | |
| def validate_index(self, index: int, latent_count: int = 0, is_range: bool = False, allow_negative = False) -> int: | |
| # if part of range, do nothing | |
| if is_range: | |
| return index | |
| # otherwise, validate index | |
| # validate not out of range - only when latent_count is passed in | |
| if latent_count > 0 and index > latent_count-1: | |
| raise IndexError(f"Index '{index}' out of range for the total {latent_count} latents.") | |
| # if negative, validate not out of range | |
| if index < 0: | |
| if not allow_negative: | |
| raise IndexError(f"Negative indeces not allowed, but was {index}.") | |
| conv_index = latent_count+index | |
| if conv_index < 0: | |
| raise IndexError(f"Index '{index}', converted to '{conv_index}' out of range for the total {latent_count} latents.") | |
| index = conv_index | |
| return index | |
| def convert_to_index_int(self, raw_index: str, latent_count: int = 0, is_range: bool = False, allow_negative = False) -> int: | |
| try: | |
| return self.validate_index(int(raw_index), latent_count=latent_count, is_range=is_range, allow_negative=allow_negative) | |
| except ValueError as e: | |
| raise ValueError(f"index '{raw_index}' must be an integer.", e) | |
| def convert_to_latent_keyframes(self, latent_indeces: str, latent_count: int) -> set[LatentKeyframe]: | |
| if not latent_indeces: | |
| return set() | |
| int_latent_indeces = [i for i in range(0, latent_count)] | |
| allow_negative = latent_count > 0 | |
| chosen_indeces = set() | |
| # parse string - allow positive ints, negative ints, and ranges separated by ':' | |
| groups = latent_indeces.split(",") | |
| groups = [g.strip() for g in groups] | |
| for g in groups: | |
| # parse strengths - default to 1.0 if no strength given | |
| strength = 1.0 | |
| if '=' in g: | |
| g, strength_str = g.split("=", 1) | |
| g = g.strip() | |
| try: | |
| strength = float(strength_str.strip()) | |
| except ValueError as e: | |
| raise ValueError(f"strength '{strength_str}' must be a float.", e) | |
| if strength < 0: | |
| raise ValueError(f"Strength '{strength}' cannot be negative.") | |
| # parse range of indeces (e.g. 2:16) | |
| if ':' in g: | |
| index_range = g.split(":", 1) | |
| index_range = [r.strip() for r in index_range] | |
| start_index = self.convert_to_index_int(index_range[0], latent_count=latent_count, is_range=True, allow_negative=allow_negative) | |
| end_index = self.convert_to_index_int(index_range[1], latent_count=latent_count, is_range=True, allow_negative=allow_negative) | |
| # if latents were passed in, base indeces on known latent count | |
| if len(int_latent_indeces) > 0: | |
| for i in int_latent_indeces[start_index:end_index]: | |
| chosen_indeces.add(LatentKeyframe(i, strength)) | |
| # otherwise, assume indeces are valid | |
| else: | |
| for i in range(start_index, end_index): | |
| chosen_indeces.add(LatentKeyframe(i, strength)) | |
| # parse individual indeces | |
| else: | |
| chosen_indeces.add(LatentKeyframe(self.convert_to_index_int(g, latent_count=latent_count, allow_negative=allow_negative), strength)) | |
| return chosen_indeces | |
| def load_keyframes(self, | |
| index_strengths: str, | |
| prev_latent_kf: LatentKeyframeGroup=None, | |
| prev_latent_keyframe: LatentKeyframeGroup=None, # old name | |
| latent_image_opt=None, | |
| print_keyframes=False): | |
| prev_latent_keyframe = prev_latent_keyframe if prev_latent_keyframe else prev_latent_kf | |
| if not prev_latent_keyframe: | |
| prev_latent_keyframe = LatentKeyframeGroup() | |
| else: | |
| prev_latent_keyframe = prev_latent_keyframe.clone() | |
| curr_latent_keyframe = LatentKeyframeGroup() | |
| latent_count = -1 | |
| if latent_image_opt: | |
| latent_count = latent_image_opt['samples'].size()[0] | |
| latent_keyframes = self.convert_to_latent_keyframes(index_strengths, latent_count=latent_count) | |
| for latent_keyframe in latent_keyframes: | |
| curr_latent_keyframe.add(latent_keyframe) | |
| if print_keyframes: | |
| for keyframe in curr_latent_keyframe.keyframes: | |
| logger.info(f"LatentKeyframe {keyframe.batch_index}={keyframe.strength}") | |
| # replace values with prev_latent_keyframes | |
| for latent_keyframe in prev_latent_keyframe.keyframes: | |
| curr_latent_keyframe.add(latent_keyframe) | |
| return (curr_latent_keyframe,) | |
| class LatentKeyframeInterpolationNode: | |
| def INPUT_TYPES(s): | |
| return { | |
| "required": { | |
| "batch_index_from": ("INT", {"default": 0, "min": BIGMIN, "max": BIGMAX, "step": 1}), | |
| "batch_index_to_excl": ("INT", {"default": 0, "min": BIGMIN, "max": BIGMAX, "step": 1}), | |
| "strength_from": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001}, ), | |
| "strength_to": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001}, ), | |
| "interpolation": (SI._LIST, ), | |
| }, | |
| "optional": { | |
| "prev_latent_kf": ("LATENT_KEYFRAME", ), | |
| "print_keyframes": ("BOOLEAN", {"default": False}) | |
| } | |
| } | |
| RETURN_NAMES = ("LATENT_KF", ) | |
| RETURN_TYPES = ("LATENT_KEYFRAME", ) | |
| FUNCTION = "load_keyframe" | |
| CATEGORY = "Adv-ControlNet ππ π π /keyframes" | |
| def load_keyframe(self, | |
| batch_index_from: int, | |
| strength_from: float, | |
| batch_index_to_excl: int, | |
| strength_to: float, | |
| interpolation: str, | |
| prev_latent_kf: LatentKeyframeGroup=None, | |
| prev_latent_keyframe: LatentKeyframeGroup=None, # old name | |
| print_keyframes=False): | |
| if (batch_index_from > batch_index_to_excl): | |
| raise ValueError("batch_index_from must be less than or equal to batch_index_to.") | |
| if (batch_index_from < 0 and batch_index_to_excl >= 0): | |
| raise ValueError("batch_index_from and batch_index_to must be either both positive or both negative.") | |
| prev_latent_keyframe = prev_latent_keyframe if prev_latent_keyframe else prev_latent_kf | |
| if not prev_latent_keyframe: | |
| prev_latent_keyframe = LatentKeyframeGroup() | |
| else: | |
| prev_latent_keyframe = prev_latent_keyframe.clone() | |
| curr_latent_keyframe = LatentKeyframeGroup() | |
| steps = batch_index_to_excl - batch_index_from | |
| diff = strength_to - strength_from | |
| if interpolation == SI.LINEAR: | |
| weights = np.linspace(strength_from, strength_to, steps) | |
| elif interpolation == SI.EASE_IN: | |
| index = np.linspace(0, 1, steps) | |
| weights = diff * np.power(index, 2) + strength_from | |
| elif interpolation == SI.EASE_OUT: | |
| index = np.linspace(0, 1, steps) | |
| weights = diff * (1 - np.power(1 - index, 2)) + strength_from | |
| elif interpolation == SI.EASE_IN_OUT: | |
| index = np.linspace(0, 1, steps) | |
| weights = diff * ((1 - np.cos(index * np.pi)) / 2) + strength_from | |
| for i in range(steps): | |
| keyframe = LatentKeyframe(batch_index_from + i, float(weights[i])) | |
| curr_latent_keyframe.add(keyframe) | |
| if print_keyframes: | |
| for keyframe in curr_latent_keyframe.keyframes: | |
| logger.info(f"LatentKeyframe {keyframe.batch_index}={keyframe.strength}") | |
| # replace values with prev_latent_keyframes | |
| for latent_keyframe in prev_latent_keyframe.keyframes: | |
| curr_latent_keyframe.add(latent_keyframe) | |
| return (curr_latent_keyframe,) | |
| class LatentKeyframeBatchedGroupNode: | |
| def INPUT_TYPES(s): | |
| return { | |
| "required": { | |
| "float_strengths": ("FLOAT", {"default": -1, "min": -1, "step": 0.001, "forceInput": True}), | |
| }, | |
| "optional": { | |
| "prev_latent_kf": ("LATENT_KEYFRAME", ), | |
| "print_keyframes": ("BOOLEAN", {"default": False}) | |
| } | |
| } | |
| RETURN_NAMES = ("LATENT_KF", ) | |
| RETURN_TYPES = ("LATENT_KEYFRAME", ) | |
| FUNCTION = "load_keyframe" | |
| CATEGORY = "Adv-ControlNet ππ π π /keyframes" | |
| def load_keyframe(self, float_strengths: Union[float, list[float]], | |
| prev_latent_kf: LatentKeyframeGroup=None, | |
| prev_latent_keyframe: LatentKeyframeGroup=None, # old name | |
| print_keyframes=False): | |
| prev_latent_keyframe = prev_latent_keyframe if prev_latent_keyframe else prev_latent_kf | |
| if not prev_latent_keyframe: | |
| prev_latent_keyframe = LatentKeyframeGroup() | |
| else: | |
| prev_latent_keyframe = prev_latent_keyframe.clone() | |
| curr_latent_keyframe = LatentKeyframeGroup() | |
| # if received a normal float input, do nothing | |
| if type(float_strengths) in (float, int): | |
| logger.info("No batched float_strengths passed into Latent Keyframe Batch Group node; will not create any new keyframes.") | |
| # if iterable, attempt to create LatentKeyframes with chosen strengths | |
| elif isinstance(float_strengths, Iterable): | |
| for idx, strength in enumerate(float_strengths): | |
| keyframe = LatentKeyframe(idx, strength) | |
| curr_latent_keyframe.add(keyframe) | |
| else: | |
| raise ValueError(f"Expected strengths to be an iterable input, but was {type(float_strengths).__repr__}.") | |
| if print_keyframes: | |
| for keyframe in curr_latent_keyframe.keyframes: | |
| logger.info(f"LatentKeyframe {keyframe.batch_index}={keyframe.strength}") | |
| # replace values with prev_latent_keyframes | |
| for latent_keyframe in prev_latent_keyframe.keyframes: | |
| curr_latent_keyframe.add(latent_keyframe) | |
| return (curr_latent_keyframe,) | |