diff --git a/adv_control/nodes.py b/adv_control/nodes.py index 0d6025e..bcd8eb3 100644 --- a/adv_control/nodes.py +++ b/adv_control/nodes.py @@ -7,6 +7,9 @@ from comfy.model_patcher import ModelPatcher from .control import load_controlnet, convert_to_advanced, is_advanced_controlnet, is_sd3_advanced_controlnet from .utils import ControlWeights, LatentKeyframeGroup, TimestepKeyframeGroup, AbstractPreprocWrapper, BIGMAX + +from .nodes_main import (ControlNetLoaderAdvanced, DiffControlNetLoaderAdvanced, + AdvancedControlNetApply, AdvancedControlNetApplySingle) from .nodes_weight import (DefaultWeights, ScaledSoftMaskedUniversalWeights, ScaledSoftUniversalWeights, SoftControlNetWeightsSD15, CustomControlNetWeightsSD15, CustomControlNetWeightsFlux, SoftT2IAdapterWeights, CustomT2IAdapterWeights) @@ -18,7 +21,8 @@ from .nodes_plusplus import PlusPlusLoaderAdvanced, PlusPlusLoaderSingle, PlusPl from .nodes_loosecontrol import ControlNetLoaderWithLoraAdvanced from .nodes_deprecated import (LoadImagesFromDirectory, ScaledSoftUniversalWeightsDeprecated, SoftControlNetWeightsDeprecated, CustomControlNetWeightsDeprecated, - SoftT2IAdapterWeightsDeprecated, CustomT2IAdapterWeightsDeprecated) + SoftT2IAdapterWeightsDeprecated, CustomT2IAdapterWeightsDeprecated, + AdvancedControlNetApplyDEPR, AdvancedControlNetApplySingleDEPR) from .logger import logger from .sampling import acn_sample_factory @@ -27,213 +31,6 @@ comfy.sample.sample = acn_sample_factory(comfy.sample.sample) comfy.sample.sample_custom = acn_sample_factory(comfy.sample.sample_custom, is_custom=True) -class ControlNetLoaderAdvanced: - @classmethod - def INPUT_TYPES(s): - return { - "required": { - "control_net_name": (folder_paths.get_filename_list("controlnet"), ), - }, - "optional": { - "tk_optional": ("TIMESTEP_KEYFRAME", ), - } - } - - RETURN_TYPES = ("CONTROL_NET", ) - FUNCTION = "load_controlnet" - - CATEGORY = "Adv-ControlNet 🛂🅐🅒🅝" - - def load_controlnet(self, control_net_name, - tk_optional: TimestepKeyframeGroup=None, - timestep_keyframe: TimestepKeyframeGroup=None, - ): - if timestep_keyframe is not None: # backwards compatibility - tk_optional = timestep_keyframe - controlnet_path = folder_paths.get_full_path("controlnet", control_net_name) - controlnet = load_controlnet(controlnet_path, tk_optional) - return (controlnet,) - - -class DiffControlNetLoaderAdvanced: - @classmethod - def INPUT_TYPES(s): - return { - "required": { - "model": ("MODEL",), - "control_net_name": (folder_paths.get_filename_list("controlnet"), ) - }, - "optional": { - "tk_optional": ("TIMESTEP_KEYFRAME", ), - "autosize": ("ACNAUTOSIZE", {"padding": 160}), - } - } - - RETURN_TYPES = ("CONTROL_NET", ) - FUNCTION = "load_controlnet" - - CATEGORY = "Adv-ControlNet 🛂🅐🅒🅝" - - def load_controlnet(self, control_net_name, model, - tk_optional: TimestepKeyframeGroup=None, - timestep_keyframe: TimestepKeyframeGroup=None - ): - if timestep_keyframe is not None: # backwards compatibility - tk_optional = timestep_keyframe - controlnet_path = folder_paths.get_full_path("controlnet", control_net_name) - controlnet = load_controlnet(controlnet_path, tk_optional, model) - if is_advanced_controlnet(controlnet): - controlnet.verify_all_weights() - return (controlnet,) - - -class AdvancedControlNetApply: - @classmethod - def INPUT_TYPES(s): - return { - "required": { - "positive": ("CONDITIONING", ), - "negative": ("CONDITIONING", ), - "control_net": ("CONTROL_NET", ), - "image": ("IMAGE", ), - "strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}), - "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": { - "mask_optional": ("MASK", ), - "timestep_kf": ("TIMESTEP_KEYFRAME", ), - "latent_kf_override": ("LATENT_KEYFRAME", ), - "weights_override": ("CONTROL_NET_WEIGHTS", ), - "model_optional": ("MODEL",), - "vae_optional": ("VAE",), - "autosize": ("ACNAUTOSIZE", {"padding": 0}), - } - } - - RETURN_TYPES = ("CONDITIONING","CONDITIONING","MODEL",) - RETURN_NAMES = ("positive", "negative", "model_opt") - FUNCTION = "apply_controlnet" - - CATEGORY = "Adv-ControlNet 🛂🅐🅒🅝" - - def apply_controlnet(self, positive, negative, control_net, image, strength, start_percent, end_percent, - mask_optional: Tensor=None, model_optional: ModelPatcher=None, vae_optional=None, - timestep_kf: TimestepKeyframeGroup=None, latent_kf_override: LatentKeyframeGroup=None, - weights_override: ControlWeights=None, control_apply_to_uncond=False): - if strength == 0: - return (positive, negative, model_optional) - if model_optional: - model_optional = model_optional.clone() - - control_hint = image.movedim(-1,1) - cnets = {} - - out = [] - for conditioning in [positive, negative]: - c = [] - if conditioning is not None: - for t in conditioning: - d = t[1].copy() - - prev_cnet = d.get('control', None) - if prev_cnet in cnets: - c_net = cnets[prev_cnet] - else: - # make sure control_net is not None to avoid confusing error messages - if control_net is None: - raise Exception("Passed in control_net is None; something must have went wrong when loading it from a Load ControlNet node.") - # copy, convert to advanced if needed, and set cond - c_net = convert_to_advanced(control_net.copy()).set_cond_hint(control_hint, strength, (start_percent, end_percent), vae_optional) - if is_advanced_controlnet(c_net): - # disarm node check - c_net.disarm() - # check for allow_condhint_latents where vae_optional can't handle it itself - if c_net.allow_condhint_latents and not c_net.require_vae: - if not isinstance(control_hint, AbstractPreprocWrapper): - raise Exception(f"Type '{type(c_net).__name__}' requires proc_IMAGE input via a corresponding preprocessor, but received a normal Image instead.") - else: - if isinstance(control_hint, AbstractPreprocWrapper) and not c_net.postpone_condhint_latents_check: - raise Exception(f"Type '{type(c_net).__name__}' requires a normal Image input, but received a proc_IMAGE input instead.") - # if vae required, verify vae is passed in - if c_net.require_vae: - # if controlnet can accept preprocced condhint latents and is the case, ignore vae requirement - if c_net.allow_condhint_latents and isinstance(control_hint, AbstractPreprocWrapper): - pass - elif not vae_optional: - # make sure SD3 ControlNet will get a special message instead of generic type mention - if is_sd3_advanced_controlnet: - raise Exception(f"SD3 ControlNet requires vae_optional input, but got None.") - else: - raise Exception(f"Type '{type(c_net).__name__}' requires vae_optional input, but got None.") - # apply optional parameters and overrides, if provided - if timestep_kf is not None: - c_net.set_timestep_keyframes(timestep_kf) - if latent_kf_override is not None: - c_net.latent_keyframe_override = latent_kf_override - if weights_override is not None: - c_net.weights_override = weights_override - # verify weights are compatible - c_net.verify_all_weights() - # set cond hint mask - if mask_optional is not None: - mask_optional = mask_optional.clone() - # if not in the form of a batch, make it so - if len(mask_optional.shape) < 3: - mask_optional = mask_optional.unsqueeze(0) - c_net.set_cond_hint_mask(mask_optional) - c_net.set_previous_controlnet(prev_cnet) - cnets[prev_cnet] = c_net - - d['control'] = c_net - d['control_apply_to_uncond'] = control_apply_to_uncond - n = [t[0], d] - c.append(n) - out.append(c) - return (out[0], out[1], model_optional) - - -class AdvancedControlNetApplySingle: - @classmethod - def INPUT_TYPES(s): - return { - "required": { - "conditioning": ("CONDITIONING", ), - "control_net": ("CONTROL_NET", ), - "image": ("IMAGE", ), - "strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}), - "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": { - "mask_optional": ("MASK", ), - "timestep_kf": ("TIMESTEP_KEYFRAME", ), - "latent_kf_override": ("LATENT_KEYFRAME", ), - "weights_override": ("CONTROL_NET_WEIGHTS", ), - "model_optional": ("MODEL",), - "vae_optional": ("VAE",), - "autosize": ("ACNAUTOSIZE", {"padding": 0}), - } - } - - RETURN_TYPES = ("CONDITIONING","MODEL",) - RETURN_NAMES = ("CONDITIONING", "model_opt") - FUNCTION = "apply_controlnet" - - CATEGORY = "Adv-ControlNet 🛂🅐🅒🅝" - - def apply_controlnet(self, conditioning, control_net, image, strength, start_percent, end_percent, - mask_optional: Tensor=None, model_optional: ModelPatcher=None, vae_optional=None, - timestep_kf: TimestepKeyframeGroup=None, latent_kf_override: LatentKeyframeGroup=None, - weights_override: ControlWeights=None): - values = AdvancedControlNetApply.apply_controlnet(self, positive=conditioning, negative=None, control_net=control_net, image=image, - strength=strength, start_percent=start_percent, end_percent=end_percent, - mask_optional=mask_optional, model_optional=model_optional, vae_optional=vae_optional, - timestep_kf=timestep_kf, latent_kf_override=latent_kf_override, weights_override=weights_override, - control_apply_to_uncond=True) - return (values[0], values[2]) - - # NODE MAPPING NODE_CLASS_MAPPINGS = { # Keyframes @@ -245,8 +42,8 @@ NODE_CLASS_MAPPINGS = { "LatentKeyframeBatchedGroup": LatentKeyframeBatchedGroupNode, "LatentKeyframeGroup": LatentKeyframeGroupNode, # Conditioning - "ACN_AdvancedControlNetApply": AdvancedControlNetApply, - "ACN_AdvancedControlNetApplySingle": AdvancedControlNetApplySingle, + "ACN_AdvancedControlNetApply_v2": AdvancedControlNetApply, + "ACN_AdvancedControlNetApplySingle_v2": AdvancedControlNetApplySingle, # Loaders "ControlNetLoaderAdvanced": ControlNetLoaderAdvanced, "DiffControlNetLoaderAdvanced": DiffControlNetLoaderAdvanced, @@ -283,6 +80,8 @@ NODE_CLASS_MAPPINGS = { "CustomControlNetWeights": CustomControlNetWeightsDeprecated, "SoftT2IAdapterWeights": SoftT2IAdapterWeightsDeprecated, "CustomT2IAdapterWeights": CustomT2IAdapterWeightsDeprecated, + "ACN_AdvancedControlNetApply": AdvancedControlNetApplyDEPR, + "ACN_AdvancedControlNetApplySingle": AdvancedControlNetApplySingleDEPR, } NODE_DISPLAY_NAME_MAPPINGS = { @@ -295,8 +94,8 @@ NODE_DISPLAY_NAME_MAPPINGS = { "LatentKeyframeBatchedGroup": "Latent Keyframe From List 🛂🅐🅒🅝", "LatentKeyframeGroup": "Latent Keyframe Group 🛂🅐🅒🅝", # Conditioning - "ACN_AdvancedControlNetApply": "Apply Advanced ControlNet 🛂🅐🅒🅝", - "ACN_AdvancedControlNetApplySingle": "Apply Advanced ControlNet(1) 🛂🅐🅒🅝", + "ACN_AdvancedControlNetApply_v2": "Apply Advanced ControlNet 🛂🅐🅒🅝", + "ACN_AdvancedControlNetApplySingle_v2": "Apply Advanced ControlNet(1) 🛂🅐🅒🅝", # Loaders "ControlNetLoaderAdvanced": "Load Advanced ControlNet Model 🛂🅐🅒🅝", "DiffControlNetLoaderAdvanced": "Load Advanced ControlNet Model (diff) 🛂🅐🅒🅝", @@ -333,4 +132,6 @@ NODE_DISPLAY_NAME_MAPPINGS = { "CustomControlNetWeights": "ControlNet Custom Weights 🛂🅐🅒🅝", "SoftT2IAdapterWeights": "T2IAdapter Soft Weights 🛂🅐🅒🅝", "CustomT2IAdapterWeights": "T2IAdapter Custom Weights 🛂🅐🅒🅝", + "ACN_AdvancedControlNetApply": "Apply Advanced ControlNet 🛂🅐🅒🅝", + "ACN_AdvancedControlNetApplySingle": "Apply Advanced ControlNet(1) 🛂🅐🅒🅝", } diff --git a/adv_control/nodes_deprecated.py b/adv_control/nodes_deprecated.py index bd1d2f0..838fc99 100644 --- a/adv_control/nodes_deprecated.py +++ b/adv_control/nodes_deprecated.py @@ -4,6 +4,7 @@ import torch import numpy as np from PIL import Image, ImageOps +from .nodes_main import AdvancedControlNetApply from .utils import BIGMAX, ControlWeights, TimestepKeyframeGroup, TimestepKeyframe, get_properly_arranged_t2i_weights from .logger import logger @@ -249,3 +250,87 @@ class CustomT2IAdapterWeightsDeprecated: weights = get_properly_arranged_t2i_weights(weights) weights = ControlWeights.t2iadapter(weights_input=weights, uncond_multiplier=uncond_multiplier, extras=cn_extras) return (weights, TimestepKeyframeGroup.default(TimestepKeyframe(control_weights=weights))) + + +class AdvancedControlNetApplyDEPR: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "positive": ("CONDITIONING", ), + "negative": ("CONDITIONING", ), + "control_net": ("CONTROL_NET", ), + "image": ("IMAGE", ), + "strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}), + "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": { + "mask_optional": ("MASK", ), + "timestep_kf": ("TIMESTEP_KEYFRAME", ), + "latent_kf_override": ("LATENT_KEYFRAME", ), + "weights_override": ("CONTROL_NET_WEIGHTS", ), + "model_optional": ("MODEL",), + "vae_optional": ("VAE",), + "autosize": ("ACNAUTOSIZE", {"padding": 0}), + } + } + + DEPRECATED = True + RETURN_TYPES = ("CONDITIONING","CONDITIONING","MODEL",) + RETURN_NAMES = ("positive", "negative", "model_opt") + FUNCTION = "apply_controlnet" + + CATEGORY = "" + + def apply_controlnet(self, positive, negative, control_net, image, strength, start_percent, end_percent, + mask_optional=None, model_optional=None, vae_optional=None, + timestep_kf: TimestepKeyframeGroup=None, latent_kf_override=None, + weights_override: ControlWeights=None, control_apply_to_uncond=False): + new_positive, new_negative = AdvancedControlNetApply.apply_controlnet(self, positive=positive, negative=negative, control_net=control_net, image=image, + strength=strength, start_percent=start_percent, end_percent=end_percent, + mask_optional=mask_optional, vae_optional=vae_optional, + timestep_kf=timestep_kf, latent_kf_override=latent_kf_override, weights_override=weights_override,) + return (new_positive, new_negative, model_optional) + + +class AdvancedControlNetApplySingleDEPR: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "conditioning": ("CONDITIONING", ), + "control_net": ("CONTROL_NET", ), + "image": ("IMAGE", ), + "strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}), + "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": { + "mask_optional": ("MASK", ), + "timestep_kf": ("TIMESTEP_KEYFRAME", ), + "latent_kf_override": ("LATENT_KEYFRAME", ), + "weights_override": ("CONTROL_NET_WEIGHTS", ), + "model_optional": ("MODEL",), + "vae_optional": ("VAE",), + "autosize": ("ACNAUTOSIZE", {"padding": 0}), + } + } + + DEPRECATED = True + RETURN_TYPES = ("CONDITIONING","MODEL",) + RETURN_NAMES = ("CONDITIONING", "model_opt") + FUNCTION = "apply_controlnet" + + CATEGORY = "" + + def apply_controlnet(self, conditioning, control_net, image, strength, start_percent, end_percent, + mask_optional=None, model_optional=None, vae_optional=None, + timestep_kf: TimestepKeyframeGroup=None, latent_kf_override=None, + weights_override: ControlWeights=None): + values = AdvancedControlNetApply.apply_controlnet(self, positive=conditioning, negative=None, control_net=control_net, image=image, + strength=strength, start_percent=start_percent, end_percent=end_percent, + mask_optional=mask_optional, vae_optional=vae_optional, + timestep_kf=timestep_kf, latent_kf_override=latent_kf_override, weights_override=weights_override, + control_apply_to_uncond=True) + return (values[0], model_optional) diff --git a/adv_control/nodes_main.py b/adv_control/nodes_main.py new file mode 100644 index 0000000..5cdd68d --- /dev/null +++ b/adv_control/nodes_main.py @@ -0,0 +1,213 @@ +from torch import Tensor + +import folder_paths +from comfy.model_patcher import ModelPatcher + +from .control import load_controlnet, convert_to_advanced, is_advanced_controlnet, is_sd3_advanced_controlnet +from .utils import ControlWeights, LatentKeyframeGroup, TimestepKeyframeGroup, AbstractPreprocWrapper, BIGMAX + +from .logger import logger + + +class ControlNetLoaderAdvanced: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "control_net_name": (folder_paths.get_filename_list("controlnet"), ), + }, + "optional": { + "tk_optional": ("TIMESTEP_KEYFRAME", ), + } + } + + RETURN_TYPES = ("CONTROL_NET", ) + FUNCTION = "load_controlnet" + + CATEGORY = "Adv-ControlNet 🛂🅐🅒🅝" + + def load_controlnet(self, control_net_name, + tk_optional: TimestepKeyframeGroup=None, + timestep_keyframe: TimestepKeyframeGroup=None, + ): + if timestep_keyframe is not None: # backwards compatibility + tk_optional = timestep_keyframe + controlnet_path = folder_paths.get_full_path("controlnet", control_net_name) + controlnet = load_controlnet(controlnet_path, tk_optional) + return (controlnet,) + + +class DiffControlNetLoaderAdvanced: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "model": ("MODEL",), + "control_net_name": (folder_paths.get_filename_list("controlnet"), ) + }, + "optional": { + "tk_optional": ("TIMESTEP_KEYFRAME", ), + "autosize": ("ACNAUTOSIZE", {"padding": 160}), + } + } + + RETURN_TYPES = ("CONTROL_NET", ) + FUNCTION = "load_controlnet" + + CATEGORY = "Adv-ControlNet 🛂🅐🅒🅝" + + def load_controlnet(self, control_net_name, model, + tk_optional: TimestepKeyframeGroup=None, + timestep_keyframe: TimestepKeyframeGroup=None + ): + if timestep_keyframe is not None: # backwards compatibility + tk_optional = timestep_keyframe + controlnet_path = folder_paths.get_full_path("controlnet", control_net_name) + controlnet = load_controlnet(controlnet_path, tk_optional, model) + if is_advanced_controlnet(controlnet): + controlnet.verify_all_weights() + return (controlnet,) + + +class AdvancedControlNetApply: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "positive": ("CONDITIONING", ), + "negative": ("CONDITIONING", ), + "control_net": ("CONTROL_NET", ), + "image": ("IMAGE", ), + "strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}), + "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": { + "mask_optional": ("MASK", ), + "timestep_kf": ("TIMESTEP_KEYFRAME", ), + "latent_kf_override": ("LATENT_KEYFRAME", ), + "weights_override": ("CONTROL_NET_WEIGHTS", ), + "vae_optional": ("VAE",), + "autosize": ("ACNAUTOSIZE", {"padding": 0}), + } + } + + RETURN_TYPES = ("CONDITIONING","CONDITIONING",) + RETURN_NAMES = ("positive", "negative") + FUNCTION = "apply_controlnet" + + CATEGORY = "Adv-ControlNet 🛂🅐🅒🅝" + + def apply_controlnet(self, positive, negative, control_net, image, strength, start_percent, end_percent, + mask_optional: Tensor=None, vae_optional=None, + timestep_kf: TimestepKeyframeGroup=None, latent_kf_override: LatentKeyframeGroup=None, + weights_override: ControlWeights=None, control_apply_to_uncond=False): + if strength == 0: + return (positive, negative) + + control_hint = image.movedim(-1,1) + cnets = {} + + out = [] + for conditioning in [positive, negative]: + c = [] + if conditioning is not None: + for t in conditioning: + d = t[1].copy() + + prev_cnet = d.get('control', None) + if prev_cnet in cnets: + c_net = cnets[prev_cnet] + else: + # make sure control_net is not None to avoid confusing error messages + if control_net is None: + raise Exception("Passed in control_net is None; something must have went wrong when loading it from a Load ControlNet node.") + # copy, convert to advanced if needed, and set cond + c_net = convert_to_advanced(control_net.copy()).set_cond_hint(control_hint, strength, (start_percent, end_percent), vae_optional) + if is_advanced_controlnet(c_net): + # disarm node check + c_net.disarm() + # check for allow_condhint_latents where vae_optional can't handle it itself + if c_net.allow_condhint_latents and not c_net.require_vae: + if not isinstance(control_hint, AbstractPreprocWrapper): + raise Exception(f"Type '{type(c_net).__name__}' requires proc_IMAGE input via a corresponding preprocessor, but received a normal Image instead.") + else: + if isinstance(control_hint, AbstractPreprocWrapper) and not c_net.postpone_condhint_latents_check: + raise Exception(f"Type '{type(c_net).__name__}' requires a normal Image input, but received a proc_IMAGE input instead.") + # if vae required, verify vae is passed in + if c_net.require_vae: + # if controlnet can accept preprocced condhint latents and is the case, ignore vae requirement + if c_net.allow_condhint_latents and isinstance(control_hint, AbstractPreprocWrapper): + pass + elif not vae_optional: + # make sure SD3 ControlNet will get a special message instead of generic type mention + if is_sd3_advanced_controlnet: + raise Exception(f"SD3 ControlNet requires vae_optional input, but got None.") + else: + raise Exception(f"Type '{type(c_net).__name__}' requires vae_optional input, but got None.") + # apply optional parameters and overrides, if provided + if timestep_kf is not None: + c_net.set_timestep_keyframes(timestep_kf) + if latent_kf_override is not None: + c_net.latent_keyframe_override = latent_kf_override + if weights_override is not None: + c_net.weights_override = weights_override + # verify weights are compatible + c_net.verify_all_weights() + # set cond hint mask + if mask_optional is not None: + mask_optional = mask_optional.clone() + # if not in the form of a batch, make it so + if len(mask_optional.shape) < 3: + mask_optional = mask_optional.unsqueeze(0) + c_net.set_cond_hint_mask(mask_optional) + c_net.set_previous_controlnet(prev_cnet) + cnets[prev_cnet] = c_net + + d['control'] = c_net + d['control_apply_to_uncond'] = control_apply_to_uncond + n = [t[0], d] + c.append(n) + out.append(c) + return (out[0], out[1]) + + +class AdvancedControlNetApplySingle: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "conditioning": ("CONDITIONING", ), + "control_net": ("CONTROL_NET", ), + "image": ("IMAGE", ), + "strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}), + "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": { + "mask_optional": ("MASK", ), + "timestep_kf": ("TIMESTEP_KEYFRAME", ), + "latent_kf_override": ("LATENT_KEYFRAME", ), + "weights_override": ("CONTROL_NET_WEIGHTS", ), + "model_optional": ("MODEL",), + "vae_optional": ("VAE",), + "autosize": ("ACNAUTOSIZE", {"padding": 0}), + } + } + + RETURN_TYPES = ("CONDITIONING","MODEL",) + RETURN_NAMES = ("CONDITIONING", "model_opt") + FUNCTION = "apply_controlnet" + + CATEGORY = "Adv-ControlNet 🛂🅐🅒🅝" + + def apply_controlnet(self, conditioning, control_net, image, strength, start_percent, end_percent, + mask_optional: Tensor=None, model_optional: ModelPatcher=None, vae_optional=None, + timestep_kf: TimestepKeyframeGroup=None, latent_kf_override: LatentKeyframeGroup=None, + weights_override: ControlWeights=None): + values = AdvancedControlNetApply.apply_controlnet(self, positive=conditioning, negative=None, control_net=control_net, image=image, + strength=strength, start_percent=start_percent, end_percent=end_percent, + mask_optional=mask_optional, model_optional=model_optional, vae_optional=vae_optional, + timestep_kf=timestep_kf, latent_kf_override=latent_kf_override, weights_override=weights_override, + control_apply_to_uncond=True) + return (values[0],)