From 9177cfd8959c18b2525860c8deffd64f84f5b49b Mon Sep 17 00:00:00 2001 From: Jedrzej Kosinski Date: Wed, 30 Jul 2025 12:48:54 -0700 Subject: [PATCH] Removed v3 extras nodes - will live in v3-nodes branch until needed --- comfy_extras/v3/nodes_ace.py | 57 - comfy_extras/v3/nodes_advanced_samplers.py | 128 -- comfy_extras/v3/nodes_align_your_steps.py | 84 -- comfy_extras/v3/nodes_apg.py | 98 -- comfy_extras/v3/nodes_attention_multiply.py | 139 --- comfy_extras/v3/nodes_audio.py | 290 ----- comfy_extras/v3/nodes_camera_trajectory.py | 217 ---- comfy_extras/v3/nodes_canny.py | 32 - comfy_extras/v3/nodes_cfg.py | 89 -- comfy_extras/v3/nodes_clip_sdxl.py | 79 -- comfy_extras/v3/nodes_compositing.py | 226 ---- comfy_extras/v3/nodes_cond.py | 60 - comfy_extras/v3/nodes_controlnet.py | 141 --- comfy_extras/v3/nodes_cosmos.py | 146 --- comfy_extras/v3/nodes_custom_sampler.py | 1035 ----------------- .../v3/nodes_differential_diffusion.py | 50 - comfy_extras/v3/nodes_edit_model.py | 34 - comfy_extras/v3/nodes_flux.py | 122 -- comfy_extras/v3/nodes_freelunch.py | 131 --- comfy_extras/v3/nodes_fresca.py | 110 -- comfy_extras/v3/nodes_gits.py | 376 ------ comfy_extras/v3/nodes_hidream.py | 71 -- comfy_extras/v3/nodes_hunyuan.py | 169 --- comfy_extras/v3/nodes_hunyuan3d.py | 672 ----------- comfy_extras/v3/nodes_hypernetwork.py | 136 --- comfy_extras/v3/nodes_hypertile.py | 95 -- comfy_extras/v3/nodes_images.py | 727 ------------ comfy_extras/v3/nodes_ip2p.py | 56 - comfy_extras/v3/nodes_latent.py | 340 ------ comfy_extras/v3/nodes_load_3d.py | 180 --- comfy_extras/v3/nodes_lora_extract.py | 138 --- comfy_extras/v3/nodes_lotus.py | 34 - comfy_extras/v3/nodes_lt.py | 528 --------- comfy_extras/v3/nodes_lumina2.py | 116 -- comfy_extras/v3/nodes_mahiro.py | 51 - comfy_extras/v3/nodes_mask.py | 437 ------- comfy_extras/v3/nodes_mochi.py | 38 - comfy_extras/v3/nodes_model_advanced.py | 387 ------ comfy_extras/v3/nodes_model_downscale.py | 68 -- comfy_extras/v3/nodes_model_merging.py | 422 ------- .../v3/nodes_model_merging_model_specific.py | 399 ------- comfy_extras/v3/nodes_morphology.py | 108 -- comfy_extras/v3/nodes_optimalsteps.py | 64 - comfy_extras/v3/nodes_pag.py | 62 - comfy_extras/v3/nodes_perpneg.py | 114 -- comfy_extras/v3/nodes_photomaker.py | 205 ---- comfy_extras/v3/nodes_pixart.py | 33 - comfy_extras/v3/nodes_post_processing.py | 255 ---- comfy_extras/v3/nodes_preview_any.py | 47 - comfy_extras/v3/nodes_primitive.py | 104 -- comfy_extras/v3/nodes_rebatch.py | 148 --- comfy_extras/v3/nodes_sag.py | 191 --- comfy_extras/v3/nodes_sd3.py | 145 --- comfy_extras/v3/nodes_sdupscale.py | 58 - comfy_extras/v3/nodes_slg.py | 173 --- comfy_extras/v3/nodes_stable3d.py | 165 --- comfy_extras/v3/nodes_stable_cascade.py | 143 --- comfy_extras/v3/nodes_string.py | 380 ------ comfy_extras/v3/nodes_tcfg.py | 70 -- comfy_extras/v3/nodes_tomesd.py | 190 --- comfy_extras/v3/nodes_torch_compile.py | 32 - comfy_extras/v3/nodes_train.py | 666 ----------- comfy_extras/v3/nodes_upscale_model.py | 106 -- comfy_extras/v3/nodes_video.py | 212 ---- comfy_extras/v3/nodes_video_model.py | 232 ---- comfy_extras/v3/nodes_wan.py | 437 ------- comfy_extras/v3/nodes_webcam.py | 92 -- nodes.py | 72 +- 68 files changed, 2 insertions(+), 13210 deletions(-) delete mode 100644 comfy_extras/v3/nodes_ace.py delete mode 100644 comfy_extras/v3/nodes_advanced_samplers.py delete mode 100644 comfy_extras/v3/nodes_align_your_steps.py delete mode 100644 comfy_extras/v3/nodes_apg.py delete mode 100644 comfy_extras/v3/nodes_attention_multiply.py delete mode 100644 comfy_extras/v3/nodes_audio.py delete mode 100644 comfy_extras/v3/nodes_camera_trajectory.py delete mode 100644 comfy_extras/v3/nodes_canny.py delete mode 100644 comfy_extras/v3/nodes_cfg.py delete mode 100644 comfy_extras/v3/nodes_clip_sdxl.py delete mode 100644 comfy_extras/v3/nodes_compositing.py delete mode 100644 comfy_extras/v3/nodes_cond.py delete mode 100644 comfy_extras/v3/nodes_controlnet.py delete mode 100644 comfy_extras/v3/nodes_cosmos.py delete mode 100644 comfy_extras/v3/nodes_custom_sampler.py delete mode 100644 comfy_extras/v3/nodes_differential_diffusion.py delete mode 100644 comfy_extras/v3/nodes_edit_model.py delete mode 100644 comfy_extras/v3/nodes_flux.py delete mode 100644 comfy_extras/v3/nodes_freelunch.py delete mode 100644 comfy_extras/v3/nodes_fresca.py delete mode 100644 comfy_extras/v3/nodes_gits.py delete mode 100644 comfy_extras/v3/nodes_hidream.py delete mode 100644 comfy_extras/v3/nodes_hunyuan.py delete mode 100644 comfy_extras/v3/nodes_hunyuan3d.py delete mode 100644 comfy_extras/v3/nodes_hypernetwork.py delete mode 100644 comfy_extras/v3/nodes_hypertile.py delete mode 100644 comfy_extras/v3/nodes_images.py delete mode 100644 comfy_extras/v3/nodes_ip2p.py delete mode 100644 comfy_extras/v3/nodes_latent.py delete mode 100644 comfy_extras/v3/nodes_load_3d.py delete mode 100644 comfy_extras/v3/nodes_lora_extract.py delete mode 100644 comfy_extras/v3/nodes_lotus.py delete mode 100644 comfy_extras/v3/nodes_lt.py delete mode 100644 comfy_extras/v3/nodes_lumina2.py delete mode 100644 comfy_extras/v3/nodes_mahiro.py delete mode 100644 comfy_extras/v3/nodes_mask.py delete mode 100644 comfy_extras/v3/nodes_mochi.py delete mode 100644 comfy_extras/v3/nodes_model_advanced.py delete mode 100644 comfy_extras/v3/nodes_model_downscale.py delete mode 100644 comfy_extras/v3/nodes_model_merging.py delete mode 100644 comfy_extras/v3/nodes_model_merging_model_specific.py delete mode 100644 comfy_extras/v3/nodes_morphology.py delete mode 100644 comfy_extras/v3/nodes_optimalsteps.py delete mode 100644 comfy_extras/v3/nodes_pag.py delete mode 100644 comfy_extras/v3/nodes_perpneg.py delete mode 100644 comfy_extras/v3/nodes_photomaker.py delete mode 100644 comfy_extras/v3/nodes_pixart.py delete mode 100644 comfy_extras/v3/nodes_post_processing.py delete mode 100644 comfy_extras/v3/nodes_preview_any.py delete mode 100644 comfy_extras/v3/nodes_primitive.py delete mode 100644 comfy_extras/v3/nodes_rebatch.py delete mode 100644 comfy_extras/v3/nodes_sag.py delete mode 100644 comfy_extras/v3/nodes_sd3.py delete mode 100644 comfy_extras/v3/nodes_sdupscale.py delete mode 100644 comfy_extras/v3/nodes_slg.py delete mode 100644 comfy_extras/v3/nodes_stable3d.py delete mode 100644 comfy_extras/v3/nodes_stable_cascade.py delete mode 100644 comfy_extras/v3/nodes_string.py delete mode 100644 comfy_extras/v3/nodes_tcfg.py delete mode 100644 comfy_extras/v3/nodes_tomesd.py delete mode 100644 comfy_extras/v3/nodes_torch_compile.py delete mode 100644 comfy_extras/v3/nodes_train.py delete mode 100644 comfy_extras/v3/nodes_upscale_model.py delete mode 100644 comfy_extras/v3/nodes_video.py delete mode 100644 comfy_extras/v3/nodes_video_model.py delete mode 100644 comfy_extras/v3/nodes_wan.py delete mode 100644 comfy_extras/v3/nodes_webcam.py diff --git a/comfy_extras/v3/nodes_ace.py b/comfy_extras/v3/nodes_ace.py deleted file mode 100644 index fdad8f800..000000000 --- a/comfy_extras/v3/nodes_ace.py +++ /dev/null @@ -1,57 +0,0 @@ -from __future__ import annotations - -import torch - -import comfy.model_management -import node_helpers -from comfy_api.latest import io - - -class TextEncodeAceStepAudio(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="TextEncodeAceStepAudio_V3", - category="conditioning", - inputs=[ - io.Clip.Input("clip"), - io.String.Input("tags", multiline=True, dynamic_prompts=True), - io.String.Input("lyrics", multiline=True, dynamic_prompts=True), - io.Float.Input("lyrics_strength", default=1.0, min=0.0, max=10.0, step=0.01), - ], - outputs=[io.Conditioning.Output()], - ) - - @classmethod - def execute(cls, clip, tags, lyrics, lyrics_strength) -> io.NodeOutput: - conditioning = clip.encode_from_tokens_scheduled(clip.tokenize(tags, lyrics=lyrics)) - conditioning = node_helpers.conditioning_set_values(conditioning, {"lyrics_strength": lyrics_strength}) - return io.NodeOutput(conditioning) - - -class EmptyAceStepLatentAudio(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="EmptyAceStepLatentAudio_V3", - category="latent/audio", - inputs=[ - io.Float.Input("seconds", default=120.0, min=1.0, max=1000.0, step=0.1), - io.Int.Input( - "batch_size", default=1, min=1, max=4096, tooltip="The number of latent images in the batch." - ), - ], - outputs=[io.Latent.Output()], - ) - - @classmethod - def execute(cls, seconds, batch_size) -> io.NodeOutput: - length = int(seconds * 44100 / 512 / 8) - latent = torch.zeros([batch_size, 8, 16, length], device=comfy.model_management.intermediate_device()) - return io.NodeOutput({"samples": latent, "type": "audio"}) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - EmptyAceStepLatentAudio, - TextEncodeAceStepAudio, -] diff --git a/comfy_extras/v3/nodes_advanced_samplers.py b/comfy_extras/v3/nodes_advanced_samplers.py deleted file mode 100644 index ecbe7094f..000000000 --- a/comfy_extras/v3/nodes_advanced_samplers.py +++ /dev/null @@ -1,128 +0,0 @@ -import numpy as np -import torch -from tqdm.auto import trange - -import comfy.model_patcher -import comfy.samplers -import comfy.utils -from comfy.k_diffusion.sampling import to_d -from comfy_api.latest import io - - -@torch.no_grad() -def sample_lcm_upscale( - model, x, sigmas, extra_args=None, callback=None, disable=None, total_upscale=2.0, upscale_method="bislerp", upscale_steps=None -): - extra_args = {} if extra_args is None else extra_args - - if upscale_steps is None: - upscale_steps = max(len(sigmas) // 2 + 1, 2) - else: - upscale_steps += 1 - upscale_steps = min(upscale_steps, len(sigmas) + 1) - - upscales = np.linspace(1.0, total_upscale, upscale_steps)[1:] - - orig_shape = x.size() - s_in = x.new_ones([x.shape[0]]) - for i in trange(len(sigmas) - 1, disable=disable): - denoised = model(x, sigmas[i] * s_in, **extra_args) - if callback is not None: - callback({"x": x, "i": i, "sigma": sigmas[i], "sigma_hat": sigmas[i], "denoised": denoised}) - - x = denoised - if i < len(upscales): - x = comfy.utils.common_upscale( - x, round(orig_shape[-1] * upscales[i]), round(orig_shape[-2] * upscales[i]), upscale_method, "disabled" - ) - - if sigmas[i + 1] > 0: - x += sigmas[i + 1] * torch.randn_like(x) - return x - - -class SamplerLCMUpscale(io.ComfyNode): - UPSCALE_METHODS = ["bislerp", "nearest-exact", "bilinear", "area", "bicubic"] - - @classmethod - def define_schema(cls) -> io.Schema: - return io.Schema( - node_id="SamplerLCMUpscale_V3", - category="sampling/custom_sampling/samplers", - inputs=[ - io.Float.Input("scale_ratio", default=1.0, min=0.1, max=20.0, step=0.01), - io.Int.Input("scale_steps", default=-1, min=-1, max=1000, step=1), - io.Combo.Input("upscale_method", options=cls.UPSCALE_METHODS), - ], - outputs=[io.Sampler.Output()], - ) - - @classmethod - def execute(cls, scale_ratio, scale_steps, upscale_method) -> io.NodeOutput: - if scale_steps < 0: - scale_steps = None - sampler = comfy.samplers.KSAMPLER( - sample_lcm_upscale, - extra_options={ - "total_upscale": scale_ratio, - "upscale_steps": scale_steps, - "upscale_method": upscale_method, - }, - ) - return io.NodeOutput(sampler) - - -@torch.no_grad() -def sample_euler_pp(model, x, sigmas, extra_args=None, callback=None, disable=None): - extra_args = {} if extra_args is None else extra_args - - temp = [0] - - def post_cfg_function(args): - temp[0] = args["uncond_denoised"] - return args["denoised"] - - model_options = extra_args.get("model_options", {}).copy() - extra_args["model_options"] = comfy.model_patcher.set_model_options_post_cfg_function( - model_options, post_cfg_function, disable_cfg1_optimization=True - ) - - s_in = x.new_ones([x.shape[0]]) - for i in trange(len(sigmas) - 1, disable=disable): - sigma_hat = sigmas[i] - denoised = model(x, sigma_hat * s_in, **extra_args) - d = to_d(x - denoised + temp[0], sigmas[i], denoised) - if callback is not None: - callback({"x": x, "i": i, "sigma": sigmas[i], "sigma_hat": sigma_hat, "denoised": denoised}) - dt = sigmas[i + 1] - sigma_hat - x = x + d * dt - return x - - -class SamplerEulerCFGpp(io.ComfyNode): - @classmethod - def define_schema(cls) -> io.Schema: - return io.Schema( - node_id="SamplerEulerCFGpp_V3", - display_name="SamplerEulerCFG++ _V3", - category="_for_testing", - inputs=[ - io.Combo.Input("version", options=["regular", "alternative"]), - ], - outputs=[io.Sampler.Output()], - is_experimental=True, - ) - - @classmethod - def execute(cls, version) -> io.NodeOutput: - if version == "alternative": - sampler = comfy.samplers.KSAMPLER(sample_euler_pp) - else: - sampler = comfy.samplers.ksampler("euler_cfg_pp") - return io.NodeOutput(sampler) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - SamplerEulerCFGpp, - SamplerLCMUpscale, -] diff --git a/comfy_extras/v3/nodes_align_your_steps.py b/comfy_extras/v3/nodes_align_your_steps.py deleted file mode 100644 index acb71c631..000000000 --- a/comfy_extras/v3/nodes_align_your_steps.py +++ /dev/null @@ -1,84 +0,0 @@ -# from: https://research.nvidia.com/labs/toronto-ai/AlignYourSteps/howto.html - -import numpy as np -import torch - -from comfy_api.latest import io - - -def loglinear_interp(t_steps, num_steps): - """Performs log-linear interpolation of a given array of decreasing numbers.""" - xs = np.linspace(0, 1, len(t_steps)) - ys = np.log(t_steps[::-1]) - - new_xs = np.linspace(0, 1, num_steps) - new_ys = np.interp(new_xs, xs, ys) - - return np.exp(new_ys)[::-1].copy() - - -NOISE_LEVELS = { - "SD1": [ - 14.6146412293, - 6.4745760956, - 3.8636745985, - 2.6946151520, - 1.8841921177, - 1.3943805092, - 0.9642583904, - 0.6523686016, - 0.3977456272, - 0.1515232662, - 0.0291671582, - ], - "SDXL": [ - 14.6146412293, - 6.3184485287, - 3.7681790315, - 2.1811480769, - 1.3405244945, - 0.8620721141, - 0.5550693289, - 0.3798540708, - 0.2332364134, - 0.1114188177, - 0.0291671582, - ], - "SVD": [700.00, 54.5, 15.886, 7.977, 4.248, 1.789, 0.981, 0.403, 0.173, 0.034, 0.002], -} - - -class AlignYourStepsScheduler(io.ComfyNode): - @classmethod - def define_schema(cls) -> io.Schema: - return io.Schema( - node_id="AlignYourStepsScheduler_V3", - category="sampling/custom_sampling/schedulers", - inputs=[ - io.Combo.Input("model_type", options=["SD1", "SDXL", "SVD"]), - io.Int.Input("steps", default=10, min=1, max=10000), - io.Float.Input("denoise", default=1.0, min=0.0, max=1.0, step=0.01), - ], - outputs=[io.Sigmas.Output()], - ) - - @classmethod - def execute(cls, model_type, steps, denoise) -> io.NodeOutput: - total_steps = steps - if denoise < 1.0: - if denoise <= 0.0: - return io.NodeOutput(torch.FloatTensor([])) - total_steps = round(steps * denoise) - - sigmas = NOISE_LEVELS[model_type][:] - if (steps + 1) != len(sigmas): - sigmas = loglinear_interp(sigmas, steps + 1) - - sigmas = sigmas[-(total_steps + 1) :] - sigmas[-1] = 0 - return io.NodeOutput(torch.FloatTensor(sigmas)) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - AlignYourStepsScheduler, -] diff --git a/comfy_extras/v3/nodes_apg.py b/comfy_extras/v3/nodes_apg.py deleted file mode 100644 index f9fc208d0..000000000 --- a/comfy_extras/v3/nodes_apg.py +++ /dev/null @@ -1,98 +0,0 @@ -import torch - -from comfy_api.latest import io - - -def project(v0, v1): - v1 = torch.nn.functional.normalize(v1, dim=[-1, -2, -3]) - v0_parallel = (v0 * v1).sum(dim=[-1, -2, -3], keepdim=True) * v1 - v0_orthogonal = v0 - v0_parallel - return v0_parallel, v0_orthogonal - - -class APG(io.ComfyNode): - @classmethod - def define_schema(cls) -> io.Schema: - return io.Schema( - node_id="APG_V3", - display_name="Adaptive Projected Guidance _V3", - category="sampling/custom_sampling", - inputs=[ - io.Model.Input("model"), - io.Float.Input( - "eta", - default=1.0, - min=-10.0, - max=10.0, - step=0.01, - tooltip="Controls the scale of the parallel guidance vector. Default CFG behavior at a setting of 1.", - ), - io.Float.Input( - "norm_threshold", - default=5.0, - min=0.0, - max=50.0, - step=0.1, - tooltip="Normalize guidance vector to this value, normalization disable at a setting of 0.", - ), - io.Float.Input( - "momentum", - default=0.0, - min=-5.0, - max=1.0, - step=0.01, - tooltip="Controls a running average of guidance during diffusion, disabled at a setting of 0.", - ), - ], - outputs=[io.Model.Output()], - ) - - @classmethod - def execute(cls, model, eta, norm_threshold, momentum) -> io.NodeOutput: - running_avg = 0 - prev_sigma = None - - def pre_cfg_function(args): - nonlocal running_avg, prev_sigma - - if len(args["conds_out"]) == 1: - return args["conds_out"] - - cond = args["conds_out"][0] - uncond = args["conds_out"][1] - sigma = args["sigma"][0] - cond_scale = args["cond_scale"] - - if prev_sigma is not None and sigma > prev_sigma: - running_avg = 0 - prev_sigma = sigma - - guidance = cond - uncond - - if momentum != 0: - if not torch.is_tensor(running_avg): - running_avg = guidance - else: - running_avg = momentum * running_avg + guidance - guidance = running_avg - - if norm_threshold > 0: - guidance_norm = guidance.norm(p=2, dim=[-1, -2, -3], keepdim=True) - scale = torch.minimum(torch.ones_like(guidance_norm), norm_threshold / guidance_norm) - guidance = guidance * scale - - guidance_parallel, guidance_orthogonal = project(guidance, cond) - modified_guidance = guidance_orthogonal + eta * guidance_parallel - - modified_cond = (uncond + modified_guidance) + (cond - uncond) / cond_scale - - return [modified_cond, uncond] + args["conds_out"][2:] - - m = model.clone() - m.set_model_sampler_pre_cfg_function(pre_cfg_function) - return io.NodeOutput(m) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - APG, -] diff --git a/comfy_extras/v3/nodes_attention_multiply.py b/comfy_extras/v3/nodes_attention_multiply.py deleted file mode 100644 index dfcb85568..000000000 --- a/comfy_extras/v3/nodes_attention_multiply.py +++ /dev/null @@ -1,139 +0,0 @@ -from comfy_api.latest import io - - -def attention_multiply(attn, model, q, k, v, out): - m = model.clone() - sd = model.model_state_dict() - - for key in sd: - if key.endswith("{}.to_q.bias".format(attn)) or key.endswith("{}.to_q.weight".format(attn)): - m.add_patches({key: (None,)}, 0.0, q) - if key.endswith("{}.to_k.bias".format(attn)) or key.endswith("{}.to_k.weight".format(attn)): - m.add_patches({key: (None,)}, 0.0, k) - if key.endswith("{}.to_v.bias".format(attn)) or key.endswith("{}.to_v.weight".format(attn)): - m.add_patches({key: (None,)}, 0.0, v) - if key.endswith("{}.to_out.0.bias".format(attn)) or key.endswith("{}.to_out.0.weight".format(attn)): - m.add_patches({key: (None,)}, 0.0, out) - return m - - -class UNetSelfAttentionMultiply(io.ComfyNode): - @classmethod - def define_schema(cls) -> io.Schema: - return io.Schema( - node_id="UNetSelfAttentionMultiply_V3", - category="_for_testing/attention_experiments", - inputs=[ - io.Model.Input("model"), - io.Float.Input("q", default=1.0, min=0.0, max=10.0, step=0.01), - io.Float.Input("k", default=1.0, min=0.0, max=10.0, step=0.01), - io.Float.Input("v", default=1.0, min=0.0, max=10.0, step=0.01), - io.Float.Input("out", default=1.0, min=0.0, max=10.0, step=0.01), - ], - outputs=[io.Model.Output()], - is_experimental=True, - ) - - @classmethod - def execute(cls, model, q, k, v, out) -> io.NodeOutput: - return io.NodeOutput(attention_multiply("attn1", model, q, k, v, out)) - - -class UNetCrossAttentionMultiply(io.ComfyNode): - @classmethod - def define_schema(cls) -> io.Schema: - return io.Schema( - node_id="UNetCrossAttentionMultiply_V3", - category="_for_testing/attention_experiments", - inputs=[ - io.Model.Input("model"), - io.Float.Input("q", default=1.0, min=0.0, max=10.0, step=0.01), - io.Float.Input("k", default=1.0, min=0.0, max=10.0, step=0.01), - io.Float.Input("v", default=1.0, min=0.0, max=10.0, step=0.01), - io.Float.Input("out", default=1.0, min=0.0, max=10.0, step=0.01), - ], - outputs=[io.Model.Output()], - is_experimental=True, - ) - - @classmethod - def execute(cls, model, q, k, v, out) -> io.NodeOutput: - return io.NodeOutput(attention_multiply("attn2", model, q, k, v, out)) - - -class CLIPAttentionMultiply(io.ComfyNode): - @classmethod - def define_schema(cls) -> io.Schema: - return io.Schema( - node_id="CLIPAttentionMultiply_V3", - category="_for_testing/attention_experiments", - inputs=[ - io.Clip.Input("clip"), - io.Float.Input("q", default=1.0, min=0.0, max=10.0, step=0.01), - io.Float.Input("k", default=1.0, min=0.0, max=10.0, step=0.01), - io.Float.Input("v", default=1.0, min=0.0, max=10.0, step=0.01), - io.Float.Input("out", default=1.0, min=0.0, max=10.0, step=0.01), - ], - outputs=[io.Clip.Output()], - is_experimental=True, - ) - - @classmethod - def execute(cls, clip, q, k, v, out) -> io.NodeOutput: - m = clip.clone() - sd = m.patcher.model_state_dict() - - for key in sd: - if key.endswith("self_attn.q_proj.weight") or key.endswith("self_attn.q_proj.bias"): - m.add_patches({key: (None,)}, 0.0, q) - if key.endswith("self_attn.k_proj.weight") or key.endswith("self_attn.k_proj.bias"): - m.add_patches({key: (None,)}, 0.0, k) - if key.endswith("self_attn.v_proj.weight") or key.endswith("self_attn.v_proj.bias"): - m.add_patches({key: (None,)}, 0.0, v) - if key.endswith("self_attn.out_proj.weight") or key.endswith("self_attn.out_proj.bias"): - m.add_patches({key: (None,)}, 0.0, out) - return io.NodeOutput(m) - - -class UNetTemporalAttentionMultiply(io.ComfyNode): - @classmethod - def define_schema(cls) -> io.Schema: - return io.Schema( - node_id="UNetTemporalAttentionMultiply_V3", - category="_for_testing/attention_experiments", - inputs=[ - io.Model.Input("model"), - io.Float.Input("self_structural", default=1.0, min=0.0, max=10.0, step=0.01), - io.Float.Input("self_temporal", default=1.0, min=0.0, max=10.0, step=0.01), - io.Float.Input("cross_structural", default=1.0, min=0.0, max=10.0, step=0.01), - io.Float.Input("cross_temporal", default=1.0, min=0.0, max=10.0, step=0.01), - ], - outputs=[io.Model.Output()], - is_experimental=True, - ) - - @classmethod - def execute(cls, model, self_structural, self_temporal, cross_structural, cross_temporal) -> io.NodeOutput: - m = model.clone() - sd = model.model_state_dict() - - for k in sd: - if (k.endswith("attn1.to_out.0.bias") or k.endswith("attn1.to_out.0.weight")): - if '.time_stack.' in k: - m.add_patches({k: (None,)}, 0.0, self_temporal) - else: - m.add_patches({k: (None,)}, 0.0, self_structural) - elif (k.endswith("attn2.to_out.0.bias") or k.endswith("attn2.to_out.0.weight")): - if '.time_stack.' in k: - m.add_patches({k: (None,)}, 0.0, cross_temporal) - else: - m.add_patches({k: (None,)}, 0.0, cross_structural) - return io.NodeOutput(m) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - CLIPAttentionMultiply, - UNetCrossAttentionMultiply, - UNetSelfAttentionMultiply, - UNetTemporalAttentionMultiply, -] diff --git a/comfy_extras/v3/nodes_audio.py b/comfy_extras/v3/nodes_audio.py deleted file mode 100644 index 089c2cb73..000000000 --- a/comfy_extras/v3/nodes_audio.py +++ /dev/null @@ -1,290 +0,0 @@ -from __future__ import annotations - -import hashlib -import os - -import av -import torch -import torchaudio - -import comfy.model_management -import folder_paths -import node_helpers -from comfy_api.latest import io, ui - - -class EmptyLatentAudio(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="EmptyLatentAudio_V3", - category="latent/audio", - inputs=[ - io.Float.Input("seconds", default=47.6, min=1.0, max=1000.0, step=0.1), - io.Int.Input( - "batch_size", default=1, min=1, max=4096, tooltip="The number of latent images in the batch." - ), - ], - outputs=[io.Latent.Output()], - ) - - @classmethod - def execute(cls, seconds, batch_size) -> io.NodeOutput: - length = round((seconds * 44100 / 2048) / 2) * 2 - latent = torch.zeros([batch_size, 64, length], device=comfy.model_management.intermediate_device()) - return io.NodeOutput({"samples": latent, "type": "audio"}) - - -class ConditioningStableAudio(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="ConditioningStableAudio_V3", - category="conditioning", - inputs=[ - io.Conditioning.Input("positive"), - io.Conditioning.Input("negative"), - io.Float.Input("seconds_start", default=0.0, min=0.0, max=1000.0, step=0.1), - io.Float.Input("seconds_total", default=47.0, min=0.0, max=1000.0, step=0.1), - ], - outputs=[ - io.Conditioning.Output(display_name="positive"), - io.Conditioning.Output(display_name="negative"), - ], - ) - - @classmethod - def execute(cls, positive, negative, seconds_start, seconds_total) -> io.NodeOutput: - return io.NodeOutput( - node_helpers.conditioning_set_values( - positive, {"seconds_start": seconds_start, "seconds_total": seconds_total} - ), - node_helpers.conditioning_set_values( - negative, {"seconds_start": seconds_start, "seconds_total": seconds_total} - ), - ) - - -class VAEEncodeAudio(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="VAEEncodeAudio_V3", - category="latent/audio", - inputs=[ - io.Audio.Input("audio"), - io.Vae.Input("vae"), - ], - outputs=[io.Latent.Output()], - ) - - @classmethod - def execute(cls, vae, audio) -> io.NodeOutput: - sample_rate = audio["sample_rate"] - if 44100 != sample_rate: - waveform = torchaudio.functional.resample(audio["waveform"], sample_rate, 44100) - else: - waveform = audio["waveform"] - return io.NodeOutput({"samples": vae.encode(waveform.movedim(1, -1))}) - - -class VAEDecodeAudio(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="VAEDecodeAudio_V3", - category="latent/audio", - inputs=[ - io.Latent.Input("samples"), - io.Vae.Input("vae"), - ], - outputs=[io.Audio.Output()], - ) - - @classmethod - def execute(cls, vae, samples) -> io.NodeOutput: - audio = vae.decode(samples["samples"]).movedim(-1, 1) - std = torch.std(audio, dim=[1, 2], keepdim=True) * 5.0 - std[std < 1.0] = 1.0 - audio /= std - return io.NodeOutput({"waveform": audio, "sample_rate": 44100}) - - -class SaveAudio(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SaveAudio_V3", # frontend expects "SaveAudio" to work - display_name="Save Audio _V3", # frontend ignores "display_name" for this node - category="audio", - inputs=[ - io.Audio.Input("audio"), - io.String.Input("filename_prefix", default="audio/ComfyUI"), - ], - hidden=[io.Hidden.prompt, io.Hidden.extra_pnginfo], - is_output_node=True, - ) - - @classmethod - def execute(cls, audio, filename_prefix="ComfyUI", format="flac") -> io.NodeOutput: - return io.NodeOutput( - ui=ui.AudioSaveHelper.get_save_audio_ui(audio, filename_prefix=filename_prefix, cls=cls, format=format) - ) - - -class SaveAudioMP3(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SaveAudioMP3_V3", # frontend expects "SaveAudioMP3" to work - display_name="Save Audio(MP3) _V3", # frontend ignores "display_name" for this node - category="audio", - inputs=[ - io.Audio.Input("audio"), - io.String.Input("filename_prefix", default="audio/ComfyUI"), - io.Combo.Input("quality", options=["V0", "128k", "320k"], default="V0"), - ], - hidden=[io.Hidden.prompt, io.Hidden.extra_pnginfo], - is_output_node=True, - ) - - @classmethod - def execute(cls, audio, filename_prefix="ComfyUI", format="mp3", quality="V0") -> io.NodeOutput: - return io.NodeOutput( - ui=ui.AudioSaveHelper.get_save_audio_ui( - audio, filename_prefix=filename_prefix, cls=cls, format=format, quality=quality - ) - ) - - -class SaveAudioOpus(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SaveAudioOpus_V3", # frontend expects "SaveAudioOpus" to work - display_name="Save Audio(Opus) _V3", # frontend ignores "display_name" for this node - category="audio", - inputs=[ - io.Audio.Input("audio"), - io.String.Input("filename_prefix", default="audio/ComfyUI"), - io.Combo.Input("quality", options=["64k", "96k", "128k", "192k", "320k"], default="128k"), - ], - hidden=[io.Hidden.prompt, io.Hidden.extra_pnginfo], - is_output_node=True, - ) - - @classmethod - def execute(cls, audio, filename_prefix="ComfyUI", format="opus", quality="128k") -> io.NodeOutput: - return io.NodeOutput( - ui=ui.AudioSaveHelper.get_save_audio_ui( - audio, filename_prefix=filename_prefix, cls=cls, format=format, quality=quality - ) - ) - - -class PreviewAudio(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="PreviewAudio_V3", # frontend expects "PreviewAudio" to work - display_name="Preview Audio _V3", # frontend ignores "display_name" for this node - category="audio", - inputs=[ - io.Audio.Input("audio"), - ], - hidden=[io.Hidden.prompt, io.Hidden.extra_pnginfo], - is_output_node=True, - ) - - @classmethod - def execute(cls, audio) -> io.NodeOutput: - return io.NodeOutput(ui=ui.PreviewAudio(audio, cls=cls)) - - -class LoadAudio(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="LoadAudio_V3", # frontend expects "LoadAudio" to work - display_name="Load Audio _V3", # frontend ignores "display_name" for this node - category="audio", - inputs=[ - io.Combo.Input("audio", upload=io.UploadType.audio, options=cls.get_files_options()), - ], - outputs=[io.Audio.Output()], - ) - - @classmethod - def get_files_options(cls) -> list[str]: - input_dir = folder_paths.get_input_directory() - return sorted(folder_paths.filter_files_content_types(os.listdir(input_dir), ["audio", "video"])) - - @classmethod - def load(cls, filepath: str) -> tuple[torch.Tensor, int]: - with av.open(filepath) as af: - if not af.streams.audio: - raise ValueError("No audio stream found in the file.") - - stream = af.streams.audio[0] - sr = stream.codec_context.sample_rate - n_channels = stream.channels - - frames = [] - length = 0 - for frame in af.decode(streams=stream.index): - buf = torch.from_numpy(frame.to_ndarray()) - if buf.shape[0] != n_channels: - buf = buf.view(-1, n_channels).t() - - frames.append(buf) - length += buf.shape[1] - - if not frames: - raise ValueError("No audio frames decoded.") - - wav = torch.cat(frames, dim=1) - wav = cls.f32_pcm(wav) - return wav, sr - - @classmethod - def f32_pcm(cls, wav: torch.Tensor) -> torch.Tensor: - """Convert audio to float 32 bits PCM format.""" - if wav.dtype.is_floating_point: - return wav - elif wav.dtype == torch.int16: - return wav.float() / (2 ** 15) - elif wav.dtype == torch.int32: - return wav.float() / (2 ** 31) - raise ValueError(f"Unsupported wav dtype: {wav.dtype}") - - @classmethod - def execute(cls, audio) -> io.NodeOutput: - waveform, sample_rate = cls.load(folder_paths.get_annotated_filepath(audio)) - return io.NodeOutput({"waveform": waveform.unsqueeze(0), "sample_rate": sample_rate}) - - @classmethod - def fingerprint_inputs(s, audio): - image_path = folder_paths.get_annotated_filepath(audio) - m = hashlib.sha256() - with open(image_path, "rb") as f: - m.update(f.read()) - return m.digest().hex() - - @classmethod - def validate_inputs(s, audio): - if not folder_paths.exists_annotated_filepath(audio): - return "Invalid audio file: {}".format(audio) - return True - - -NODES_LIST: list[type[io.ComfyNode]] = [ - ConditioningStableAudio, - EmptyLatentAudio, - LoadAudio, - PreviewAudio, - SaveAudio, - SaveAudioMP3, - SaveAudioOpus, - VAEDecodeAudio, - VAEEncodeAudio, -] diff --git a/comfy_extras/v3/nodes_camera_trajectory.py b/comfy_extras/v3/nodes_camera_trajectory.py deleted file mode 100644 index 40fb1dcf9..000000000 --- a/comfy_extras/v3/nodes_camera_trajectory.py +++ /dev/null @@ -1,217 +0,0 @@ -from __future__ import annotations - -import numpy as np -import torch -from einops import rearrange - -import comfy.model_management -import nodes -from comfy_api.latest import io - -CAMERA_DICT = { - "base_T_norm": 1.5, - "base_angle": np.pi / 3, - "Static": {"angle": [0.0, 0.0, 0.0], "T": [0.0, 0.0, 0.0]}, - "Pan Up": {"angle": [0.0, 0.0, 0.0], "T": [0.0, -1.0, 0.0]}, - "Pan Down": {"angle": [0.0, 0.0, 0.0], "T": [0.0, 1.0, 0.0]}, - "Pan Left": {"angle": [0.0, 0.0, 0.0], "T": [-1.0, 0.0, 0.0]}, - "Pan Right": {"angle": [0.0, 0.0, 0.0], "T": [1.0, 0.0, 0.0]}, - "Zoom In": {"angle": [0.0, 0.0, 0.0], "T": [0.0, 0.0, 2.0]}, - "Zoom Out": {"angle": [0.0, 0.0, 0.0], "T": [0.0, 0.0, -2.0]}, - "Anti Clockwise (ACW)": {"angle": [0.0, 0.0, -1.0], "T": [0.0, 0.0, 0.0]}, - "ClockWise (CW)": {"angle": [0.0, 0.0, 1.0], "T": [0.0, 0.0, 0.0]}, -} - - -def process_pose_params(cam_params, width=672, height=384, original_pose_width=1280, original_pose_height=720, device="cpu"): - def get_relative_pose(cam_params): - """Copied from https://github.com/hehao13/CameraCtrl/blob/main/inference.py""" - abs_w2cs = [cam_param.w2c_mat for cam_param in cam_params] - abs_c2ws = [cam_param.c2w_mat for cam_param in cam_params] - cam_to_origin = 0 - target_cam_c2w = np.array([[1, 0, 0, 0], [0, 1, 0, -cam_to_origin], [0, 0, 1, 0], [0, 0, 0, 1]]) - abs2rel = target_cam_c2w @ abs_w2cs[0] - ret_poses = [target_cam_c2w] + [abs2rel @ abs_c2w for abs_c2w in abs_c2ws[1:]] - return np.array(ret_poses, dtype=np.float32) - - """Modified from https://github.com/hehao13/CameraCtrl/blob/main/inference.py""" - cam_params = [Camera(cam_param) for cam_param in cam_params] - - sample_wh_ratio = width / height - pose_wh_ratio = original_pose_width / original_pose_height # Assuming placeholder ratios, change as needed - - if pose_wh_ratio > sample_wh_ratio: - resized_ori_w = height * pose_wh_ratio - for cam_param in cam_params: - cam_param.fx = resized_ori_w * cam_param.fx / width - else: - resized_ori_h = width / pose_wh_ratio - for cam_param in cam_params: - cam_param.fy = resized_ori_h * cam_param.fy / height - - intrinsic = np.asarray( - [[cam_param.fx * width, cam_param.fy * height, cam_param.cx * width, cam_param.cy * height] for cam_param in cam_params], - dtype=np.float32, - ) - - K = torch.as_tensor(intrinsic)[None] # [1, 1, 4] - c2ws = get_relative_pose(cam_params) # Assuming this function is defined elsewhere - c2ws = torch.as_tensor(c2ws)[None] # [1, n_frame, 4, 4] - plucker_embedding = ray_condition(K, c2ws, height, width, device=device)[0].permute(0, 3, 1, 2).contiguous() # V, 6, H, W - plucker_embedding = plucker_embedding[None] - return rearrange(plucker_embedding, "b f c h w -> b f h w c")[0] - - -class Camera: - """Copied from https://github.com/hehao13/CameraCtrl/blob/main/inference.py""" - - def __init__(self, entry): - fx, fy, cx, cy = entry[1:5] - self.fx = fx - self.fy = fy - self.cx = cx - self.cy = cy - c2w_mat = np.array(entry[7:]).reshape(4, 4) - self.c2w_mat = c2w_mat - self.w2c_mat = np.linalg.inv(c2w_mat) - - -def ray_condition(K, c2w, H, W, device): - """Copied from https://github.com/hehao13/CameraCtrl/blob/main/inference.py""" - # c2w: B, V, 4, 4 - # K: B, V, 4 - - B = K.shape[0] - - j, i = torch.meshgrid( - torch.linspace(0, H - 1, H, device=device, dtype=c2w.dtype), - torch.linspace(0, W - 1, W, device=device, dtype=c2w.dtype), - indexing="ij", - ) - i = i.reshape([1, 1, H * W]).expand([B, 1, H * W]) + 0.5 # [B, HxW] - j = j.reshape([1, 1, H * W]).expand([B, 1, H * W]) + 0.5 # [B, HxW] - - fx, fy, cx, cy = K.chunk(4, dim=-1) # B,V, 1 - - zs = torch.ones_like(i) # [B, HxW] - xs = (i - cx) / fx * zs - ys = (j - cy) / fy * zs - zs = zs.expand_as(ys) - - directions = torch.stack((xs, ys, zs), dim=-1) # B, V, HW, 3 - directions = directions / directions.norm(dim=-1, keepdim=True) # B, V, HW, 3 - - rays_d = directions @ c2w[..., :3, :3].transpose(-1, -2) # B, V, 3, HW - rays_o = c2w[..., :3, 3] # B, V, 3 - rays_o = rays_o[:, :, None].expand_as(rays_d) # B, V, 3, HW - # c2w @ dirctions - rays_dxo = torch.cross(rays_o, rays_d) - plucker = torch.cat([rays_dxo, rays_d], dim=-1) - plucker = plucker.reshape(B, c2w.shape[1], H, W, 6) # B, V, H, W, 6 - # plucker = plucker.permute(0, 1, 4, 2, 3) - return plucker - - -def get_camera_motion(angle, T, speed, n=81): - def compute_R_form_rad_angle(angles): - theta_x, theta_y, theta_z = angles - Rx = np.array([[1, 0, 0], [0, np.cos(theta_x), -np.sin(theta_x)], [0, np.sin(theta_x), np.cos(theta_x)]]) - - Ry = np.array([[np.cos(theta_y), 0, np.sin(theta_y)], [0, 1, 0], [-np.sin(theta_y), 0, np.cos(theta_y)]]) - - Rz = np.array([[np.cos(theta_z), -np.sin(theta_z), 0], [np.sin(theta_z), np.cos(theta_z), 0], [0, 0, 1]]) - - R = np.dot(Rz, np.dot(Ry, Rx)) - return R - - RT = [] - for i in range(n): - _angle = (i / n) * speed * (CAMERA_DICT["base_angle"]) * angle - R = compute_R_form_rad_angle(_angle) - _T = (i / n) * speed * (CAMERA_DICT["base_T_norm"]) * (T.reshape(3, 1)) - _RT = np.concatenate([R, _T], axis=1) - RT.append(_RT) - RT = np.stack(RT) - return RT - - -class WanCameraEmbedding(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="WanCameraEmbedding_V3", - category="camera", - inputs=[ - io.Combo.Input( - "camera_pose", - options=[ - "Static", - "Pan Up", - "Pan Down", - "Pan Left", - "Pan Right", - "Zoom In", - "Zoom Out", - "Anti Clockwise (ACW)", - "ClockWise (CW)", - ], - default="Static", - ), - io.Int.Input("width", default=832, min=16, max=nodes.MAX_RESOLUTION, step=16), - io.Int.Input("height", default=480, min=16, max=nodes.MAX_RESOLUTION, step=16), - io.Int.Input("length", default=81, min=1, max=nodes.MAX_RESOLUTION, step=4), - io.Float.Input("speed", default=1.0, min=0, max=10.0, step=0.1, optional=True), - io.Float.Input("fx", default=0.5, min=0, max=1, step=0.000000001, optional=True), - io.Float.Input("fy", default=0.5, min=0, max=1, step=0.000000001, optional=True), - io.Float.Input("cx", default=0.5, min=0, max=1, step=0.01, optional=True), - io.Float.Input("cy", default=0.5, min=0, max=1, step=0.01, optional=True), - ], - outputs=[ - io.WanCameraEmbedding.Output(display_name="camera_embedding"), - io.Int.Output(display_name="width"), - io.Int.Output(display_name="height"), - io.Int.Output(display_name="length"), - ], - ) - - @classmethod - def execute(cls, camera_pose, width, height, length, speed=1.0, fx=0.5, fy=0.5, cx=0.5, cy=0.5) -> io.NodeOutput: - """ - Use Camera trajectory as extrinsic parameters to calculate Plücker embeddings (Sitzmannet al., 2021) - Adapted from https://github.com/aigc-apps/VideoX-Fun/blob/main/comfyui/comfyui_nodes.py - """ - motion_list = [camera_pose] - speed = speed - angle = np.array(CAMERA_DICT[motion_list[0]]["angle"]) - T = np.array(CAMERA_DICT[motion_list[0]]["T"]) - RT = get_camera_motion(angle, T, speed, length) - - trajs = [] - for cp in RT.tolist(): - traj = [fx, fy, cx, cy, 0, 0] - traj.extend(cp[0]) - traj.extend(cp[1]) - traj.extend(cp[2]) - traj.extend([0, 0, 0, 1]) - trajs.append(traj) - - cam_params = np.array([[float(x) for x in pose] for pose in trajs]) - cam_params = np.concatenate([np.zeros_like(cam_params[:, :1]), cam_params], 1) - control_camera_video = process_pose_params(cam_params, width=width, height=height) - control_camera_video = control_camera_video.permute([3, 0, 1, 2]).unsqueeze(0).to(device=comfy.model_management.intermediate_device()) - - control_camera_video = torch.concat( - [torch.repeat_interleave(control_camera_video[:, :, 0:1], repeats=4, dim=2), control_camera_video[:, :, 1:]], dim=2 - ).transpose(1, 2) - - # Reshape, transpose, and view into desired shape - b, f, c, h, w = control_camera_video.shape - control_camera_video = control_camera_video.contiguous().view(b, f // 4, 4, c, h, w).transpose(2, 3) - control_camera_video = control_camera_video.contiguous().view(b, f // 4, c * 4, h, w).transpose(1, 2) - - return io.NodeOutput(control_camera_video, width, height, length) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - WanCameraEmbedding, -] diff --git a/comfy_extras/v3/nodes_canny.py b/comfy_extras/v3/nodes_canny.py deleted file mode 100644 index 0b68db381..000000000 --- a/comfy_extras/v3/nodes_canny.py +++ /dev/null @@ -1,32 +0,0 @@ -from __future__ import annotations - -from kornia.filters import canny - -import comfy.model_management -from comfy_api.latest import io - - -class Canny(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="Canny_V3", - category="image/preprocessors", - inputs=[ - io.Image.Input("image"), - io.Float.Input("low_threshold", default=0.4, min=0.01, max=0.99, step=0.01), - io.Float.Input("high_threshold", default=0.8, min=0.01, max=0.99, step=0.01), - ], - outputs=[io.Image.Output()], - ) - - @classmethod - def execute(cls, image, low_threshold, high_threshold) -> io.NodeOutput: - output = canny(image.to(comfy.model_management.get_torch_device()).movedim(-1, 1), low_threshold, high_threshold) - img_out = output[1].to(comfy.model_management.intermediate_device()).repeat(1, 3, 1, 1).movedim(1, -1) - return io.NodeOutput(img_out) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - Canny, -] diff --git a/comfy_extras/v3/nodes_cfg.py b/comfy_extras/v3/nodes_cfg.py deleted file mode 100644 index e8e84a2bd..000000000 --- a/comfy_extras/v3/nodes_cfg.py +++ /dev/null @@ -1,89 +0,0 @@ -from __future__ import annotations - -import torch - -from comfy_api.latest import io - - -# https://github.com/WeichenFan/CFG-Zero-star -def optimized_scale(positive, negative): - positive_flat = positive.reshape(positive.shape[0], -1) - negative_flat = negative.reshape(negative.shape[0], -1) - - # Calculate dot production - dot_product = torch.sum(positive_flat * negative_flat, dim=1, keepdim=True) - - # Squared norm of uncondition - squared_norm = torch.sum(negative_flat ** 2, dim=1, keepdim=True) + 1e-8 - - # st_star = v_cond^T * v_uncond / ||v_uncond||^2 - st_star = dot_product / squared_norm - - return st_star.reshape([positive.shape[0]] + [1] * (positive.ndim - 1)) - - -class CFGZeroStar(io.ComfyNode): - @classmethod - def define_schema(cls) -> io.Schema: - return io.Schema( - node_id="CFGZeroStar_V3", - category="advanced/guidance", - inputs=[ - io.Model.Input("model"), - ], - outputs=[io.Model.Output(display_name="patched_model")], - ) - - @classmethod - def execute(cls, model) -> io.NodeOutput: - m = model.clone() - - def cfg_zero_star(args): - guidance_scale = args['cond_scale'] - x = args['input'] - cond_p = args['cond_denoised'] - uncond_p = args['uncond_denoised'] - out = args["denoised"] - alpha = optimized_scale(x - cond_p, x - uncond_p) - - return out + uncond_p * (alpha - 1.0) + guidance_scale * uncond_p * (1.0 - alpha) - - m.set_model_sampler_post_cfg_function(cfg_zero_star) - return io.NodeOutput(m) - - -class CFGNorm(io.ComfyNode): - @classmethod - def define_schema(cls) -> io.Schema: - return io.Schema( - node_id="CFGNorm_V3", - category="advanced/guidance", - inputs=[ - io.Model.Input("model"), - io.Float.Input("strength", default=1.0, min=0.0, max=100.0, step=0.01), - ], - outputs=[io.Model.Output(display_name="patched_model")], - is_experimental=True, - ) - - @classmethod - def execute(cls, model, strength) -> io.NodeOutput: - m = model.clone() - - def cfg_norm(args): - cond_p = args['cond_denoised'] - pred_text_ = args["denoised"] - - norm_full_cond = torch.norm(cond_p, dim=1, keepdim=True) - norm_pred_text = torch.norm(pred_text_, dim=1, keepdim=True) - scale = (norm_full_cond / (norm_pred_text + 1e-8)).clamp(min=0.0, max=1.0) - return pred_text_ * scale * strength - - m.set_model_sampler_post_cfg_function(cfg_norm) - return io.NodeOutput(m) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - CFGNorm, - CFGZeroStar, -] diff --git a/comfy_extras/v3/nodes_clip_sdxl.py b/comfy_extras/v3/nodes_clip_sdxl.py deleted file mode 100644 index 3d05b7595..000000000 --- a/comfy_extras/v3/nodes_clip_sdxl.py +++ /dev/null @@ -1,79 +0,0 @@ -from __future__ import annotations - -import nodes -from comfy_api.latest import io - - -class CLIPTextEncodeSDXLRefiner(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="CLIPTextEncodeSDXLRefiner_V3", - category="advanced/conditioning", - inputs=[ - io.Float.Input("ascore", default=6.0, min=0.0, max=1000.0, step=0.01), - io.Int.Input("width", default=1024, min=0, max=nodes.MAX_RESOLUTION), - io.Int.Input("height", default=1024, min=0, max=nodes.MAX_RESOLUTION), - io.String.Input("text", multiline=True, dynamic_prompts=True), - io.Clip.Input("clip"), - ], - outputs=[io.Conditioning.Output()], - ) - - @classmethod - def execute(cls, ascore, width, height, text, clip) -> io.NodeOutput: - tokens = clip.tokenize(text) - conditioning = clip.encode_from_tokens_scheduled( - tokens, add_dict={"aesthetic_score": ascore, "width": width, "height": height} - ) - return io.NodeOutput(conditioning) - - -class CLIPTextEncodeSDXL(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="CLIPTextEncodeSDXL_V3", - category="advanced/conditioning", - inputs=[ - io.Clip.Input("clip"), - io.Int.Input("width", default=1024, min=0, max=nodes.MAX_RESOLUTION), - io.Int.Input("height", default=1024, min=0, max=nodes.MAX_RESOLUTION), - io.Int.Input("crop_w", default=0, min=0, max=nodes.MAX_RESOLUTION), - io.Int.Input("crop_h", default=0, min=0, max=nodes.MAX_RESOLUTION), - io.Int.Input("target_width", default=1024, min=0, max=nodes.MAX_RESOLUTION), - io.Int.Input("target_height", default=1024, min=0, max=nodes.MAX_RESOLUTION), - io.String.Input("text_g", multiline=True, dynamic_prompts=True), - io.String.Input("text_l", multiline=True, dynamic_prompts=True), - ], - outputs=[io.Conditioning.Output()], - ) - - @classmethod - def execute(cls, clip, width, height, crop_w, crop_h, target_width, target_height, text_g, text_l) -> io.NodeOutput: - tokens = clip.tokenize(text_g) - tokens["l"] = clip.tokenize(text_l)["l"] - if len(tokens["l"]) != len(tokens["g"]): - empty = clip.tokenize("") - while len(tokens["l"]) < len(tokens["g"]): - tokens["l"] += empty["l"] - while len(tokens["l"]) > len(tokens["g"]): - tokens["g"] += empty["g"] - conditioning = clip.encode_from_tokens_scheduled( - tokens, - add_dict={ - "width": width, - "height": height, - "crop_w": crop_w, - "crop_h": crop_h, - "target_width": target_width, - "target_height": target_height, - }, - ) - return io.NodeOutput(conditioning) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - CLIPTextEncodeSDXL, - CLIPTextEncodeSDXLRefiner, -] diff --git a/comfy_extras/v3/nodes_compositing.py b/comfy_extras/v3/nodes_compositing.py deleted file mode 100644 index b1e59ec78..000000000 --- a/comfy_extras/v3/nodes_compositing.py +++ /dev/null @@ -1,226 +0,0 @@ -from __future__ import annotations - -from enum import Enum - -import torch - -import comfy.utils -from comfy_api.latest import io - - -def resize_mask(mask, shape): - return torch.nn.functional.interpolate( - mask.reshape((-1, 1, mask.shape[-2], mask.shape[-1])), size=(shape[0], shape[1]), mode="bilinear" - ).squeeze(1) - - -class PorterDuffMode(Enum): - ADD = 0 - CLEAR = 1 - DARKEN = 2 - DST = 3 - DST_ATOP = 4 - DST_IN = 5 - DST_OUT = 6 - DST_OVER = 7 - LIGHTEN = 8 - MULTIPLY = 9 - OVERLAY = 10 - SCREEN = 11 - SRC = 12 - SRC_ATOP = 13 - SRC_IN = 14 - SRC_OUT = 15 - SRC_OVER = 16 - XOR = 17 - - -def porter_duff_composite( - src_image: torch.Tensor, src_alpha: torch.Tensor, dst_image: torch.Tensor, dst_alpha: torch.Tensor, mode: PorterDuffMode -): - # convert mask to alpha - src_alpha = 1 - src_alpha - dst_alpha = 1 - dst_alpha - # premultiply alpha - src_image = src_image * src_alpha - dst_image = dst_image * dst_alpha - - # composite ops below assume alpha-premultiplied images - if mode == PorterDuffMode.ADD: - out_alpha = torch.clamp(src_alpha + dst_alpha, 0, 1) - out_image = torch.clamp(src_image + dst_image, 0, 1) - elif mode == PorterDuffMode.CLEAR: - out_alpha = torch.zeros_like(dst_alpha) - out_image = torch.zeros_like(dst_image) - elif mode == PorterDuffMode.DARKEN: - out_alpha = src_alpha + dst_alpha - src_alpha * dst_alpha - out_image = (1 - dst_alpha) * src_image + (1 - src_alpha) * dst_image + torch.min(src_image, dst_image) - elif mode == PorterDuffMode.DST: - out_alpha = dst_alpha - out_image = dst_image - elif mode == PorterDuffMode.DST_ATOP: - out_alpha = src_alpha - out_image = src_alpha * dst_image + (1 - dst_alpha) * src_image - elif mode == PorterDuffMode.DST_IN: - out_alpha = src_alpha * dst_alpha - out_image = dst_image * src_alpha - elif mode == PorterDuffMode.DST_OUT: - out_alpha = (1 - src_alpha) * dst_alpha - out_image = (1 - src_alpha) * dst_image - elif mode == PorterDuffMode.DST_OVER: - out_alpha = dst_alpha + (1 - dst_alpha) * src_alpha - out_image = dst_image + (1 - dst_alpha) * src_image - elif mode == PorterDuffMode.LIGHTEN: - out_alpha = src_alpha + dst_alpha - src_alpha * dst_alpha - out_image = (1 - dst_alpha) * src_image + (1 - src_alpha) * dst_image + torch.max(src_image, dst_image) - elif mode == PorterDuffMode.MULTIPLY: - out_alpha = src_alpha * dst_alpha - out_image = src_image * dst_image - elif mode == PorterDuffMode.OVERLAY: - out_alpha = src_alpha + dst_alpha - src_alpha * dst_alpha - out_image = torch.where(2 * dst_image < dst_alpha, 2 * src_image * dst_image, - src_alpha * dst_alpha - 2 * (dst_alpha - src_image) * (src_alpha - dst_image)) - elif mode == PorterDuffMode.SCREEN: - out_alpha = src_alpha + dst_alpha - src_alpha * dst_alpha - out_image = src_image + dst_image - src_image * dst_image - elif mode == PorterDuffMode.SRC: - out_alpha = src_alpha - out_image = src_image - elif mode == PorterDuffMode.SRC_ATOP: - out_alpha = dst_alpha - out_image = dst_alpha * src_image + (1 - src_alpha) * dst_image - elif mode == PorterDuffMode.SRC_IN: - out_alpha = src_alpha * dst_alpha - out_image = src_image * dst_alpha - elif mode == PorterDuffMode.SRC_OUT: - out_alpha = (1 - dst_alpha) * src_alpha - out_image = (1 - dst_alpha) * src_image - elif mode == PorterDuffMode.SRC_OVER: - out_alpha = src_alpha + (1 - src_alpha) * dst_alpha - out_image = src_image + (1 - src_alpha) * dst_image - elif mode == PorterDuffMode.XOR: - out_alpha = (1 - dst_alpha) * src_alpha + (1 - src_alpha) * dst_alpha - out_image = (1 - dst_alpha) * src_image + (1 - src_alpha) * dst_image - else: - return None, None - - # back to non-premultiplied alpha - out_image = torch.where(out_alpha > 1e-5, out_image / out_alpha, torch.zeros_like(out_image)) - out_image = torch.clamp(out_image, 0, 1) - # convert alpha to mask - out_alpha = 1 - out_alpha - return out_image, out_alpha - - -class PorterDuffImageComposite(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="PorterDuffImageComposite_V3", - display_name="Porter-Duff Image Composite _V3", - category="mask/compositing", - inputs=[ - io.Image.Input("source"), - io.Mask.Input("source_alpha"), - io.Image.Input("destination"), - io.Mask.Input("destination_alpha"), - io.Combo.Input("mode", options=[mode.name for mode in PorterDuffMode], default=PorterDuffMode.DST.name), - ], - outputs=[io.Image.Output(), io.Mask.Output()], - ) - - @classmethod - def execute( - cls, source: torch.Tensor, source_alpha: torch.Tensor, destination: torch.Tensor, destination_alpha: torch.Tensor, mode - ) -> io.NodeOutput: - batch_size = min(len(source), len(source_alpha), len(destination), len(destination_alpha)) - out_images = [] - out_alphas = [] - - for i in range(batch_size): - src_image = source[i] - dst_image = destination[i] - - assert src_image.shape[2] == dst_image.shape[2] # inputs need to have same number of channels - - src_alpha = source_alpha[i].unsqueeze(2) - dst_alpha = destination_alpha[i].unsqueeze(2) - - if dst_alpha.shape[:2] != dst_image.shape[:2]: - upscale_input = dst_alpha.unsqueeze(0).permute(0, 3, 1, 2) - upscale_output = comfy.utils.common_upscale( - upscale_input, dst_image.shape[1], dst_image.shape[0], upscale_method='bicubic', crop='center' - ) - dst_alpha = upscale_output.permute(0, 2, 3, 1).squeeze(0) - if src_image.shape != dst_image.shape: - upscale_input = src_image.unsqueeze(0).permute(0, 3, 1, 2) - upscale_output = comfy.utils.common_upscale( - upscale_input, dst_image.shape[1], dst_image.shape[0], upscale_method='bicubic', crop='center' - ) - src_image = upscale_output.permute(0, 2, 3, 1).squeeze(0) - if src_alpha.shape != dst_alpha.shape: - upscale_input = src_alpha.unsqueeze(0).permute(0, 3, 1, 2) - upscale_output = comfy.utils.common_upscale( - upscale_input, dst_alpha.shape[1], dst_alpha.shape[0], upscale_method='bicubic', crop='center' - ) - src_alpha = upscale_output.permute(0, 2, 3, 1).squeeze(0) - - out_image, out_alpha = porter_duff_composite(src_image, src_alpha, dst_image, dst_alpha, PorterDuffMode[mode]) - - out_images.append(out_image) - out_alphas.append(out_alpha.squeeze(2)) - - return io.NodeOutput(torch.stack(out_images), torch.stack(out_alphas)) - - -class SplitImageWithAlpha(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SplitImageWithAlpha_V3", - display_name="Split Image with Alpha _V3", - category="mask/compositing", - inputs=[ - io.Image.Input("image"), - ], - outputs=[io.Image.Output(), io.Mask.Output()], - ) - - @classmethod - def execute(cls, image: torch.Tensor) -> io.NodeOutput: - out_images = [i[:, :, :3] for i in image] - out_alphas = [i[:, :, 3] if i.shape[2] > 3 else torch.ones_like(i[:, :, 0]) for i in image] - return io.NodeOutput(torch.stack(out_images), 1.0 - torch.stack(out_alphas)) - - -class JoinImageWithAlpha(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="JoinImageWithAlpha_V3", - display_name="Join Image with Alpha _V3", - category="mask/compositing", - inputs=[ - io.Image.Input("image"), - io.Mask.Input("alpha"), - ], - outputs=[io.Image.Output()], - ) - - @classmethod - def execute(cls, image: torch.Tensor, alpha: torch.Tensor) -> io.NodeOutput: - batch_size = min(len(image), len(alpha)) - out_images = [] - - alpha = 1.0 - resize_mask(alpha, image.shape[1:]) - for i in range(batch_size): - out_images.append(torch.cat((image[i][:, :, :3], alpha[i].unsqueeze(2)), dim=2)) - - return io.NodeOutput(torch.stack(out_images)) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - JoinImageWithAlpha, - PorterDuffImageComposite, - SplitImageWithAlpha, -] diff --git a/comfy_extras/v3/nodes_cond.py b/comfy_extras/v3/nodes_cond.py deleted file mode 100644 index 2ce343500..000000000 --- a/comfy_extras/v3/nodes_cond.py +++ /dev/null @@ -1,60 +0,0 @@ -from __future__ import annotations - -from comfy_api.latest import io - - -class CLIPTextEncodeControlnet(io.ComfyNode): - @classmethod - def define_schema(cls) -> io.Schema: - return io.Schema( - node_id="CLIPTextEncodeControlnet_V3", - category="_for_testing/conditioning", - inputs=[ - io.Clip.Input("clip"), - io.Conditioning.Input("conditioning"), - io.String.Input("text", multiline=True, dynamic_prompts=True), - ], - outputs=[io.Conditioning.Output()], - ) - - @classmethod - def execute(cls, clip, conditioning, text) -> io.NodeOutput: - tokens = clip.tokenize(text) - cond, pooled = clip.encode_from_tokens(tokens, return_pooled=True) - c = [] - for t in conditioning: - n = [t[0], t[1].copy()] - n[1]['cross_attn_controlnet'] = cond - n[1]['pooled_output_controlnet'] = pooled - c.append(n) - return io.NodeOutput(c) - - -class T5TokenizerOptions(io.ComfyNode): - @classmethod - def define_schema(cls) -> io.Schema: - return io.Schema( - node_id="T5TokenizerOptions_V3", - category="_for_testing/conditioning", - inputs=[ - io.Clip.Input("clip"), - io.Int.Input("min_padding", default=0, min=0, max=10000, step=1), - io.Int.Input("min_length", default=0, min=0, max=10000, step=1), - ], - outputs=[io.Clip.Output()], - ) - - @classmethod - def execute(cls, clip, min_padding, min_length) -> io.NodeOutput: - clip = clip.clone() - for t5_type in ["t5xxl", "pile_t5xl", "t5base", "mt5xl", "umt5xxl"]: - clip.set_tokenizer_option("{}_min_padding".format(t5_type), min_padding) - clip.set_tokenizer_option("{}_min_length".format(t5_type), min_length) - - return io.NodeOutput(clip) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - CLIPTextEncodeControlnet, - T5TokenizerOptions, -] diff --git a/comfy_extras/v3/nodes_controlnet.py b/comfy_extras/v3/nodes_controlnet.py deleted file mode 100644 index a4656fad2..000000000 --- a/comfy_extras/v3/nodes_controlnet.py +++ /dev/null @@ -1,141 +0,0 @@ -import comfy.utils -from comfy.cldm.control_types import UNION_CONTROLNET_TYPES -from comfy_api.latest import io - - -class SetUnionControlNetType(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SetUnionControlNetType_V3", - category="conditioning/controlnet", - inputs=[ - io.ControlNet.Input("control_net"), - io.Combo.Input("type", options=["auto"] + list(UNION_CONTROLNET_TYPES.keys())), - ], - outputs=[ - io.ControlNet.Output(), - ], - ) - - @classmethod - def execute(cls, control_net, type) -> io.NodeOutput: - control_net = control_net.copy() - type_number = UNION_CONTROLNET_TYPES.get(type, -1) - if type_number >= 0: - control_net.set_extra_arg("control_type", [type_number]) - else: - control_net.set_extra_arg("control_type", []) - - return io.NodeOutput(control_net) - - -class ControlNetApplyAdvanced(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="ControlNetApplyAdvanced_V3", - display_name="Apply ControlNet _V3", - category="conditioning/controlnet", - inputs=[ - io.Conditioning.Input("positive"), - io.Conditioning.Input("negative"), - io.ControlNet.Input("control_net"), - io.Image.Input("image"), - io.Float.Input("strength", default=1.0, min=0.0, max=10.0, step=0.01), - io.Float.Input("start_percent", default=0.0, min=0.0, max=1.0, step=0.001), - io.Float.Input("end_percent", default=1.0, min=0.0, max=1.0, step=0.001), - io.Vae.Input("vae", optional=True), - ], - outputs=[ - io.Conditioning.Output(display_name="positive"), - io.Conditioning.Output(display_name="negative"), - ], - ) - - @classmethod - def execute( - cls, positive, negative, control_net, image, strength, start_percent, end_percent, vae=None, extra_concat=[] - ) -> io.NodeOutput: - if strength == 0: - return io.NodeOutput(positive, negative) - - control_hint = image.movedim(-1, 1) - cnets = {} - - out = [] - for conditioning in [positive, negative]: - c = [] - 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: - c_net = control_net.copy().set_cond_hint( - control_hint, strength, (start_percent, end_percent), vae=vae, extra_concat=extra_concat - ) - c_net.set_previous_controlnet(prev_cnet) - cnets[prev_cnet] = c_net - - d["control"] = c_net - d["control_apply_to_uncond"] = False - n = [t[0], d] - c.append(n) - out.append(c) - return io.NodeOutput(out[0], out[1]) - - -class ControlNetInpaintingAliMamaApply(ControlNetApplyAdvanced): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="ControlNetInpaintingAliMamaApply_V3", - category="conditioning/controlnet", - inputs=[ - io.Conditioning.Input("positive"), - io.Conditioning.Input("negative"), - io.ControlNet.Input("control_net"), - io.Vae.Input("vae"), - io.Image.Input("image"), - io.Mask.Input("mask"), - io.Float.Input("strength", default=1.0, min=0.0, max=10.0, step=0.01), - io.Float.Input("start_percent", default=0.0, min=0.0, max=1.0, step=0.001), - io.Float.Input("end_percent", default=1.0, min=0.0, max=1.0, step=0.001), - ], - outputs=[ - io.Conditioning.Output(display_name="positive"), - io.Conditioning.Output(display_name="negative"), - ], - ) - - @classmethod - def execute( - cls, positive, negative, control_net, vae, image, mask, strength, start_percent, end_percent - ) -> io.NodeOutput: - extra_concat = [] - if control_net.concat_mask: - mask = 1.0 - mask.reshape((-1, 1, mask.shape[-2], mask.shape[-1])) - mask_apply = comfy.utils.common_upscale(mask, image.shape[2], image.shape[1], "bilinear", "center").round() - image = image * mask_apply.movedim(1, -1).repeat(1, 1, 1, image.shape[3]) - extra_concat = [mask] - - return super().execute( - positive, - negative, - control_net, - image, - strength, - start_percent, - end_percent, - vae=vae, - extra_concat=extra_concat, - ) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - ControlNetApplyAdvanced, - SetUnionControlNetType, - ControlNetInpaintingAliMamaApply, -] diff --git a/comfy_extras/v3/nodes_cosmos.py b/comfy_extras/v3/nodes_cosmos.py deleted file mode 100644 index a32c192e8..000000000 --- a/comfy_extras/v3/nodes_cosmos.py +++ /dev/null @@ -1,146 +0,0 @@ -from __future__ import annotations - -import torch - -import comfy.latent_formats -import comfy.model_management -import comfy.utils -import nodes -from comfy_api.latest import io - - -class EmptyCosmosLatentVideo(io.ComfyNode): - @classmethod - def define_schema(cls) -> io.Schema: - return io.Schema( - node_id="EmptyCosmosLatentVideo_V3", - category="latent/video", - inputs=[ - io.Int.Input("width", default=1280, min=16, max=nodes.MAX_RESOLUTION, step=16), - io.Int.Input("height", default=704, min=16, max=nodes.MAX_RESOLUTION, step=16), - io.Int.Input("length", default=121, min=1, max=nodes.MAX_RESOLUTION, step=8), - io.Int.Input("batch_size", default=1, min=1, max=4096), - ], - outputs=[io.Latent.Output()], - ) - - @classmethod - def execute(cls, width, height, length, batch_size) -> io.NodeOutput: - latent = torch.zeros( - [batch_size, 16, ((length - 1) // 8) + 1, height // 8, width // 8], device=comfy.model_management.intermediate_device() - ) - return io.NodeOutput({"samples": latent}) - - -def vae_encode_with_padding(vae, image, width, height, length, padding=0): - pixels = comfy.utils.common_upscale(image[..., :3].movedim(-1, 1), width, height, "bilinear", "center").movedim(1, -1) - pixel_len = min(pixels.shape[0], length) - padded_length = min(length, (((pixel_len - 1) // 8) + 1 + padding) * 8 - 7) - padded_pixels = torch.ones((padded_length, height, width, 3)) * 0.5 - padded_pixels[:pixel_len] = pixels[:pixel_len] - latent_len = ((pixel_len - 1) // 8) + 1 - latent_temp = vae.encode(padded_pixels) - return latent_temp[:, :, :latent_len] - - -class CosmosImageToVideoLatent(io.ComfyNode): - @classmethod - def define_schema(cls) -> io.Schema: - return io.Schema( - node_id="CosmosImageToVideoLatent_V3", - category="conditioning/inpaint", - inputs=[ - io.Vae.Input("vae"), - io.Int.Input("width", default=1280, min=16, max=nodes.MAX_RESOLUTION, step=16), - io.Int.Input("height", default=704, min=16, max=nodes.MAX_RESOLUTION, step=16), - io.Int.Input("length", default=121, min=1, max=nodes.MAX_RESOLUTION, step=8), - io.Int.Input("batch_size", default=1, min=1, max=4096), - io.Image.Input("start_image", optional=True), - io.Image.Input("end_image", optional=True), - ], - outputs=[io.Latent.Output()], - ) - - @classmethod - def execute(cls, vae, width, height, length, batch_size, start_image=None, end_image=None) -> io.NodeOutput: - latent = torch.zeros([1, 16, ((length - 1) // 8) + 1, height // 8, width // 8], device=comfy.model_management.intermediate_device()) - if start_image is None and end_image is None: - out_latent = {} - out_latent["samples"] = latent - return io.NodeOutput(out_latent) - - mask = torch.ones( - [latent.shape[0], 1, ((length - 1) // 8) + 1, latent.shape[-2], latent.shape[-1]], - device=comfy.model_management.intermediate_device(), - ) - - if start_image is not None: - latent_temp = vae_encode_with_padding(vae, start_image, width, height, length, padding=1) - latent[:, :, :latent_temp.shape[-3]] = latent_temp - mask[:, :, :latent_temp.shape[-3]] *= 0.0 - - if end_image is not None: - latent_temp = vae_encode_with_padding(vae, end_image, width, height, length, padding=0) - latent[:, :, -latent_temp.shape[-3]:] = latent_temp - mask[:, :, -latent_temp.shape[-3]:] *= 0.0 - - out_latent = {} - out_latent["samples"] = latent.repeat((batch_size, ) + (1,) * (latent.ndim - 1)) - out_latent["noise_mask"] = mask.repeat((batch_size, ) + (1,) * (mask.ndim - 1)) - return io.NodeOutput(out_latent) - - -class CosmosPredict2ImageToVideoLatent(io.ComfyNode): - @classmethod - def define_schema(cls) -> io.Schema: - return io.Schema( - node_id="CosmosPredict2ImageToVideoLatent_V3", - category="conditioning/inpaint", - inputs=[ - io.Vae.Input("vae"), - io.Int.Input("width", default=848, min=16, max=nodes.MAX_RESOLUTION, step=16), - io.Int.Input("height", default=480, min=16, max=nodes.MAX_RESOLUTION, step=16), - io.Int.Input("length", default=93, min=1, max=nodes.MAX_RESOLUTION, step=4), - io.Int.Input("batch_size", default=1, min=1, max=4096), - io.Image.Input("start_image", optional=True), - io.Image.Input("end_image", optional=True), - ], - outputs=[io.Latent.Output()], - ) - - @classmethod - def execute(cls, vae, width, height, length, batch_size, start_image=None, end_image=None) -> io.NodeOutput: - latent = torch.zeros([1, 16, ((length - 1) // 4) + 1, height // 8, width // 8], device=comfy.model_management.intermediate_device()) - if start_image is None and end_image is None: - out_latent = {} - out_latent["samples"] = latent - return io.NodeOutput(out_latent) - - mask = torch.ones( - [latent.shape[0], 1, ((length - 1) // 4) + 1, latent.shape[-2], latent.shape[-1]], - device=comfy.model_management.intermediate_device(), - ) - - if start_image is not None: - latent_temp = vae_encode_with_padding(vae, start_image, width, height, length, padding=1) - latent[:, :, :latent_temp.shape[-3]] = latent_temp - mask[:, :, :latent_temp.shape[-3]] *= 0.0 - - if end_image is not None: - latent_temp = vae_encode_with_padding(vae, end_image, width, height, length, padding=0) - latent[:, :, -latent_temp.shape[-3]:] = latent_temp - mask[:, :, -latent_temp.shape[-3]:] *= 0.0 - - out_latent = {} - latent_format = comfy.latent_formats.Wan21() - latent = latent_format.process_out(latent) * mask + latent * (1.0 - mask) - out_latent["samples"] = latent.repeat((batch_size, ) + (1,) * (latent.ndim - 1)) - out_latent["noise_mask"] = mask.repeat((batch_size, ) + (1,) * (mask.ndim - 1)) - return io.NodeOutput(out_latent) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - CosmosImageToVideoLatent, - CosmosPredict2ImageToVideoLatent, - EmptyCosmosLatentVideo, -] diff --git a/comfy_extras/v3/nodes_custom_sampler.py b/comfy_extras/v3/nodes_custom_sampler.py deleted file mode 100644 index dca18b6ad..000000000 --- a/comfy_extras/v3/nodes_custom_sampler.py +++ /dev/null @@ -1,1035 +0,0 @@ -from __future__ import annotations - -import math - -import torch - -import comfy.sample -import comfy.samplers -import comfy.utils -import latent_preview -import node_helpers -from comfy.k_diffusion import sa_solver -from comfy.k_diffusion import sampling as k_diffusion_sampling -from comfy_api.latest import io - - -class BasicScheduler(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="BasicScheduler_V3", - category="sampling/custom_sampling/schedulers", - inputs=[ - io.Model.Input("model"), - io.Combo.Input("scheduler", options=comfy.samplers.SCHEDULER_NAMES), - io.Int.Input("steps", default=20, min=1, max=10000), - io.Float.Input("denoise", default=1.0, min=0.0, max=1.0, step=0.01), - ], - outputs=[ - io.Sigmas.Output(), - ] - ) - - @classmethod - def execute(cls, model, scheduler, steps, denoise): - total_steps = steps - if denoise < 1.0: - if denoise <= 0.0: - return io.NodeOutput(torch.FloatTensor([])) - total_steps = int(steps/denoise) - - sigmas = comfy.samplers.calculate_sigmas(model.get_model_object("model_sampling"), scheduler, total_steps).cpu() - sigmas = sigmas[-(steps + 1):] - return io.NodeOutput(sigmas) - - -class KarrasScheduler(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="KarrasScheduler_V3", - category="sampling/custom_sampling/schedulers", - inputs=[ - io.Int.Input("steps", default=20, min=1, max=10000), - io.Float.Input("sigma_max", default=14.614642, min=0.0, max=5000.0, step=0.01, round=False), - io.Float.Input("sigma_min", default=0.0291675, min=0.0, max=5000.0, step=0.01, round=False), - io.Float.Input("rho", default=7.0, min=0.0, max=100.0, step=0.01, round=False), - ], - outputs=[ - io.Sigmas.Output(), - ] - ) - - @classmethod - def execute(cls, steps, sigma_max, sigma_min, rho): - sigmas = k_diffusion_sampling.get_sigmas_karras(n=steps, sigma_min=sigma_min, sigma_max=sigma_max, rho=rho) - return io.NodeOutput(sigmas) - - -class ExponentialScheduler(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="ExponentialScheduler_V3", - category="sampling/custom_sampling/schedulers", - inputs=[ - io.Int.Input("steps", default=20, min=1, max=10000), - io.Float.Input("sigma_max", default=14.614642, min=0.0, max=5000.0, step=0.01, round=False), - io.Float.Input("sigma_min", default=0.0291675, min=0.0, max=5000.0, step=0.01, round=False), - ], - outputs=[ - io.Sigmas.Output(), - ] - ) - - @classmethod - def execute(cls, steps, sigma_max, sigma_min): - sigmas = k_diffusion_sampling.get_sigmas_exponential(n=steps, sigma_min=sigma_min, sigma_max=sigma_max) - return io.NodeOutput(sigmas) - - -class PolyexponentialScheduler(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="PolyexponentialScheduler_V3", - category="sampling/custom_sampling/schedulers", - inputs=[ - io.Int.Input("steps", default=20, min=1, max=10000), - io.Float.Input("sigma_max", default=14.614642, min=0.0, max=5000.0, step=0.01, round=False), - io.Float.Input("sigma_min", default=0.0291675, min=0.0, max=5000.0, step=0.01, round=False), - io.Float.Input("rho", default=1.0, min=0.0, max=100.0, step=0.01, round=False), - ], - outputs=[ - io.Sigmas.Output(), - ] - ) - - @classmethod - def execute(cls, steps, sigma_max, sigma_min, rho): - sigmas = k_diffusion_sampling.get_sigmas_polyexponential(n=steps, sigma_min=sigma_min, sigma_max=sigma_max, rho=rho) - return io.NodeOutput(sigmas) - - -class LaplaceScheduler(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="LaplaceScheduler_V3", - category="sampling/custom_sampling/schedulers", - inputs=[ - io.Int.Input("steps", default=20, min=1, max=10000), - io.Float.Input("sigma_max", default=14.614642, min=0.0, max=5000.0, step=0.01, round=False), - io.Float.Input("sigma_min", default=0.0291675, min=0.0, max=5000.0, step=0.01, round=False), - io.Float.Input("mu", default=0.0, min=-10.0, max=10.0, step=0.1, round=False), - io.Float.Input("beta", default=0.5, min=0.0, max=10.0, step=0.1, round=False), - ], - outputs=[ - io.Sigmas.Output(), - ] - ) - - @classmethod - def execute(cls, steps, sigma_max, sigma_min, mu, beta): - sigmas = k_diffusion_sampling.get_sigmas_laplace(n=steps, sigma_min=sigma_min, sigma_max=sigma_max, mu=mu, beta=beta) - return io.NodeOutput(sigmas) - - -class SDTurboScheduler(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SDTurboScheduler_V3", - category="sampling/custom_sampling/schedulers", - inputs=[ - io.Model.Input("model"), - io.Int.Input("steps", default=1, min=1, max=10), - io.Float.Input("denoise", default=1.0, min=0, max=1.0, step=0.01), - ], - outputs=[ - io.Sigmas.Output(), - ] - ) - - @classmethod - def execute(cls, model, steps, denoise): - start_step = 10 - int(10 * denoise) - timesteps = torch.flip(torch.arange(1, 11) * 100 - 1, (0,))[start_step:start_step + steps] - sigmas = model.get_model_object("model_sampling").sigma(timesteps) - sigmas = torch.cat([sigmas, sigmas.new_zeros([1])]) - return io.NodeOutput(sigmas) - - -class BetaSamplingScheduler(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="BetaSamplingScheduler_V3", - category="sampling/custom_sampling/schedulers", - inputs=[ - io.Model.Input("model"), - io.Int.Input("steps", default=20, min=1, max=10000), - io.Float.Input("alpha", default=0.6, min=0.0, max=50.0, step=0.01, round=False), - io.Float.Input("beta", default=0.6, min=0.0, max=50.0, step=0.01, round=False), - ], - outputs=[ - io.Sigmas.Output(), - ] - ) - - @classmethod - def execute(cls, model, steps, alpha, beta): - sigmas = comfy.samplers.beta_scheduler(model.get_model_object("model_sampling"), steps, alpha=alpha, beta=beta) - return io.NodeOutput(sigmas) - - -class VPScheduler(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="VPScheduler_V3", - category="sampling/custom_sampling/schedulers", - inputs=[ - io.Int.Input("steps", default=20, min=1, max=10000), - io.Float.Input("beta_d", default=19.9, min=0.0, max=5000.0, step=0.01, round=False), - io.Float.Input("beta_min", default=0.1, min=0.0, max=5000.0, step=0.01, round=False), - io.Float.Input("eps_s", default=0.001, min=0.0, max=1.0, step=0.0001, round=False), - ], - outputs=[ - io.Sigmas.Output(), - ] - ) - - @classmethod - def execute(cls, steps, beta_d, beta_min, eps_s): - sigmas = k_diffusion_sampling.get_sigmas_vp(n=steps, beta_d=beta_d, beta_min=beta_min, eps_s=eps_s) - return io.NodeOutput(sigmas) - - -class SplitSigmas(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SplitSigmas_V3", - category="sampling/custom_sampling/sigmas", - inputs=[ - io.Sigmas.Input("sigmas"), - io.Int.Input("step", default=0, min=0, max=10000), - ], - outputs=[ - io.Sigmas.Output(display_name="high_sigmas"), - io.Sigmas.Output(display_name="low_sigmas"), - ] - ) - - @classmethod - def execute(cls, sigmas, step): - sigmas1 = sigmas[:step + 1] - sigmas2 = sigmas[step:] - return io.NodeOutput(sigmas1, sigmas2) - - -class SplitSigmasDenoise(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SplitSigmasDenoise_V3", - category="sampling/custom_sampling/sigmas", - inputs=[ - io.Sigmas.Input("sigmas"), - io.Float.Input("denoise", default=1.0, min=0.0, max=1.0, step=0.01), - ], - outputs=[ - io.Sigmas.Output(display_name="high_sigmas"), - io.Sigmas.Output(display_name="low_sigmas"), - ] - ) - - @classmethod - def execute(cls, sigmas, denoise): - steps = max(sigmas.shape[-1] - 1, 0) - total_steps = round(steps * denoise) - sigmas1 = sigmas[:-(total_steps)] - sigmas2 = sigmas[-(total_steps + 1):] - return io.NodeOutput(sigmas1, sigmas2) - - -class FlipSigmas(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="FlipSigmas_V3", - category="sampling/custom_sampling/sigmas", - inputs=[ - io.Sigmas.Input("sigmas"), - ], - outputs=[ - io.Sigmas.Output(), - ] - ) - - @classmethod - def execute(cls, sigmas): - if len(sigmas) == 0: - return io.NodeOutput(sigmas) - - sigmas = sigmas.flip(0) - if sigmas[0] == 0: - sigmas[0] = 0.0001 - return io.NodeOutput(sigmas) - - -class SetFirstSigma(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SetFirstSigma_V3", - category="sampling/custom_sampling/sigmas", - inputs=[ - io.Sigmas.Input("sigmas"), - io.Float.Input("sigma", default=136.0, min=0.0, max=20000.0, step=0.001, round=False), - ], - outputs=[ - io.Sigmas.Output(), - ] - ) - - @classmethod - def execute(cls, sigmas, sigma): - sigmas = sigmas.clone() - sigmas[0] = sigma - return io.NodeOutput(sigmas) - - -class ExtendIntermediateSigmas(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="ExtendIntermediateSigmas_V3", - category="sampling/custom_sampling/sigmas", - inputs=[ - io.Sigmas.Input("sigmas"), - io.Int.Input("steps", default=2, min=1, max=100), - io.Float.Input("start_at_sigma", default=-1.0, min=-1.0, max=20000.0, step=0.01, round=False), - io.Float.Input("end_at_sigma", default=12.0, min=0.0, max=20000.0, step=0.01, round=False), - io.Combo.Input("spacing", options=['linear', 'cosine', 'sine']), - ], - outputs=[ - io.Sigmas.Output(), - ] - ) - - @classmethod - def execute(cls, sigmas: torch.Tensor, steps: int, start_at_sigma: float, end_at_sigma: float, spacing: str): - if start_at_sigma < 0: - start_at_sigma = float("inf") - - interpolator = { - 'linear': lambda x: x, - 'cosine': lambda x: torch.sin(x*math.pi/2), - 'sine': lambda x: 1 - torch.cos(x*math.pi/2) - }[spacing] - - # linear space for our interpolation function - x = torch.linspace(0, 1, steps + 1, device=sigmas.device)[1:-1] - computed_spacing = interpolator(x) - - extended_sigmas = [] - for i in range(len(sigmas) - 1): - sigma_current = sigmas[i] - sigma_next = sigmas[i+1] - - extended_sigmas.append(sigma_current) - - if end_at_sigma <= sigma_current <= start_at_sigma: - interpolated_steps = computed_spacing * (sigma_next - sigma_current) + sigma_current - extended_sigmas.extend(interpolated_steps.tolist()) - - # Add the last sigma value - if len(sigmas) > 0: - extended_sigmas.append(sigmas[-1]) - - extended_sigmas = torch.FloatTensor(extended_sigmas) - - return io.NodeOutput(extended_sigmas) - - -class SamplingPercentToSigma(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SamplingPercentToSigma_V3", - category="sampling/custom_sampling/sigmas", - inputs=[ - io.Model.Input("model"), - io.Float.Input("sampling_percent", default=0.0, min=0.0, max=1.0, step=0.0001), - io.Boolean.Input("return_actual_sigma", default=False, tooltip="Return the actual sigma value instead of the value used for interval checks.\nThis only affects results at 0.0 and 1.0."), - ], - outputs=[ - io.Float.Output(display_name="sigma_value"), - ] - ) - - @classmethod - def execute(cls, model, sampling_percent, return_actual_sigma): - model_sampling = model.get_model_object("model_sampling") - sigma_val = model_sampling.percent_to_sigma(sampling_percent) - if return_actual_sigma: - if sampling_percent == 0.0: - sigma_val = model_sampling.sigma_max.item() - elif sampling_percent == 1.0: - sigma_val = model_sampling.sigma_min.item() - return io.NodeOutput(sigma_val) - - -class KSamplerSelect(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="KSamplerSelect_V3", - category="sampling/custom_sampling/samplers", - inputs=[ - io.Combo.Input("sampler_name", options=comfy.samplers.SAMPLER_NAMES), - ], - outputs=[ - io.Sampler.Output(), - ] - ) - - @classmethod - def execute(cls, sampler_name): - sampler = comfy.samplers.sampler_object(sampler_name) - return io.NodeOutput(sampler) - - -class SamplerDPMPP_3M_SDE(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SamplerDPMPP_3M_SDE_V3", - category="sampling/custom_sampling/samplers", - inputs=[ - io.Float.Input("eta", default=1.0, min=0.0, max=100.0, step=0.01, round=False), - io.Float.Input("s_noise", default=1.0, min=0.0, max=100.0, step=0.01, round=False), - io.Combo.Input("noise_device", options=['gpu', 'cpu']), - ], - outputs=[ - io.Sampler.Output(), - ] - ) - - @classmethod - def execute(cls, eta, s_noise, noise_device): - if noise_device == 'cpu': - sampler_name = "dpmpp_3m_sde" - else: - sampler_name = "dpmpp_3m_sde_gpu" - sampler = comfy.samplers.ksampler(sampler_name, {"eta": eta, "s_noise": s_noise}) - return io.NodeOutput(sampler) - - -class SamplerDPMPP_2M_SDE(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SamplerDPMPP_2M_SDE_V3", - category="sampling/custom_sampling/samplers", - inputs=[ - io.Combo.Input("solver_type", options=['midpoint', 'heun']), - io.Float.Input("eta", default=1.0, min=0.0, max=100.0, step=0.01, round=False), - io.Float.Input("s_noise", default=1.0, min=0.0, max=100.0, step=0.01, round=False), - io.Combo.Input("noise_device", options=['gpu', 'cpu']), - ], - outputs=[ - io.Sampler.Output(), - ] - ) - - @classmethod - def execute(cls, solver_type, eta, s_noise, noise_device): - if noise_device == 'cpu': - sampler_name = "dpmpp_2m_sde" - else: - sampler_name = "dpmpp_2m_sde_gpu" - sampler = comfy.samplers.ksampler(sampler_name, {"eta": eta, "s_noise": s_noise, "solver_type": solver_type}) - return io.NodeOutput(sampler) - - -class SamplerDPMPP_SDE(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SamplerDPMPP_SDE_V3", - category="sampling/custom_sampling/samplers", - inputs=[ - io.Float.Input("eta", default=1.0, min=0.0, max=100.0, step=0.01, round=False), - io.Float.Input("s_noise", default=1.0, min=0.0, max=100.0, step=0.01, round=False), - io.Float.Input("r", default=0.5, min=0.0, max=100.0, step=0.01, round=False), - io.Combo.Input("noise_device", options=['gpu', 'cpu']), - ], - outputs=[ - io.Sampler.Output(), - ] - ) - - @classmethod - def execute(cls, eta, s_noise, r, noise_device): - if noise_device == 'cpu': - sampler_name = "dpmpp_sde" - else: - sampler_name = "dpmpp_sde_gpu" - sampler = comfy.samplers.ksampler(sampler_name, {"eta": eta, "s_noise": s_noise, "r": r}) - return io.NodeOutput(sampler) - - -class SamplerDPMPP_2S_Ancestral(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SamplerDPMPP_2S_Ancestral_V3", - category="sampling/custom_sampling/samplers", - inputs=[ - io.Float.Input("eta", default=1.0, min=0.0, max=100.0, step=0.01, round=False), - io.Float.Input("s_noise", default=1.0, min=0.0, max=100.0, step=0.01, round=False), - ], - outputs=[ - io.Sampler.Output(), - ] - ) - - @classmethod - def execute(cls, eta, s_noise): - sampler = comfy.samplers.ksampler("dpmpp_2s_ancestral", {"eta": eta, "s_noise": s_noise}) - return io.NodeOutput(sampler) - - -class SamplerEulerAncestral(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SamplerEulerAncestral_V3", - category="sampling/custom_sampling/samplers", - inputs=[ - io.Float.Input("eta", default=1.0, min=0.0, max=100.0, step=0.01, round=False), - io.Float.Input("s_noise", default=1.0, min=0.0, max=100.0, step=0.01, round=False), - ], - outputs=[ - io.Sampler.Output(), - ] - ) - - @classmethod - def execute(cls, eta, s_noise): - sampler = comfy.samplers.ksampler("euler_ancestral", {"eta": eta, "s_noise": s_noise}) - return io.NodeOutput(sampler) - - -class SamplerEulerAncestralCFGPP(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SamplerEulerAncestralCFGPP_V3", - display_name="SamplerEulerAncestralCFG++ _V3", - category="sampling/custom_sampling/samplers", - inputs=[ - io.Float.Input("eta", default=1.0, min=0.0, max=1.0, step=0.01, round=False), - io.Float.Input("s_noise", default=1.0, min=0.0, max=10.0, step=0.01, round=False), - ], - outputs=[ - io.Sampler.Output(), - ] - ) - - @classmethod - def execute(cls, eta, s_noise): - sampler = comfy.samplers.ksampler( - "euler_ancestral_cfg_pp", - {"eta": eta, "s_noise": s_noise}) - return io.NodeOutput(sampler) - - -class SamplerLMS(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SamplerLMS_V3", - category="sampling/custom_sampling/samplers", - inputs=[ - io.Int.Input("order", default=4, min=1, max=100), - ], - outputs=[ - io.Sampler.Output() - ] - ) - - @classmethod - def execute(cls, order): - sampler = comfy.samplers.ksampler("lms", {"order": order}) - return io.NodeOutput(sampler) - - -class SamplerDPMAdaptative(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SamplerDPMAdaptative_V3", - category="sampling/custom_sampling/samplers", - inputs=[ - io.Int.Input("order", default=3, min=2, max=3), - io.Float.Input("rtol", default=0.05, min=0.0, max=100.0, step=0.01, round=False), - io.Float.Input("atol", default=0.0078, min=0.0, max=100.0, step=0.01, round=False), - io.Float.Input("h_init", default=0.05, min=0.0, max=100.0, step=0.01, round=False), - io.Float.Input("pcoeff", default=0.0, min=0.0, max=100.0, step=0.01, round=False), - io.Float.Input("icoeff", default=1.0, min=0.0, max=100.0, step=0.01, round=False), - io.Float.Input("dcoeff", default=0.0, min=0.0, max=100.0, step=0.01, round=False), - io.Float.Input("accept_safety", default=0.81, min=0.0, max=100.0, step=0.01, round=False), - io.Float.Input("eta", default=0.0, min=0.0, max=100.0, step=0.01, round=False), - io.Float.Input("s_noise", default=1.0, min=0.0, max=100.0, step=0.01, round=False), - ], - outputs=[ - io.Sampler.Output(), - ] - ) - - @classmethod - def execute(cls, order, rtol, atol, h_init, pcoeff, icoeff, dcoeff, accept_safety, eta, s_noise): - sampler = comfy.samplers.ksampler("dpm_adaptive", {"order": order, "rtol": rtol, "atol": atol, "h_init": h_init, "pcoeff": pcoeff, - "icoeff": icoeff, "dcoeff": dcoeff, "accept_safety": accept_safety, "eta": eta, - "s_noise":s_noise }) - return io.NodeOutput(sampler) - - -class SamplerER_SDE(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SamplerER_SDE_V3", - category="sampling/custom_sampling/samplers", - inputs=[ - io.Combo.Input("solver_type", options=["ER-SDE", "Reverse-time SDE", "ODE"]), - io.Int.Input("max_stage", default=3, min=1, max=3), - io.Float.Input("eta", default=1.0, min=0.0, max=100.0, step=0.01, round=False, tooltip="Stochastic strength of reverse-time SDE.\nWhen eta=0, it reduces to deterministic ODE. This setting doesn't apply to ER-SDE solver type."), - io.Float.Input("s_noise", default=1.0, min=0.0, max=100.0, step=0.01, round=False), - ], - outputs=[ - io.Sampler.Output(), - ] - ) - - @classmethod - def execute(cls, solver_type, max_stage, eta, s_noise): - if solver_type == "ODE" or (solver_type == "Reverse-time SDE" and eta == 0): - eta = 0 - s_noise = 0 - - def reverse_time_sde_noise_scaler(x): - return x ** (eta + 1) - - if solver_type == "ER-SDE": - # Use the default one in sample_er_sde() - noise_scaler = None - else: - noise_scaler = reverse_time_sde_noise_scaler - - sampler_name = "er_sde" - sampler = comfy.samplers.ksampler(sampler_name, {"s_noise": s_noise, "noise_scaler": noise_scaler, "max_stage": max_stage}) - return io.NodeOutput(sampler) - - -class SamplerSASolver(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SamplerSASolver_V3", - category="sampling/custom_sampling/samplers", - inputs=[ - io.Model.Input("model"), - io.Float.Input("eta", default=1.0, min=0.0, max=10.0, step=0.01, round=False), - io.Float.Input("sde_start_percent", default=0.2, min=0.0, max=1.0, step=0.001), - io.Float.Input("sde_end_percent", default=0.8, min=0.0, max=1.0, step=0.001), - io.Float.Input("s_noise", default=1.0, min=0.0, max=100.0, step=0.01, round=False), - io.Int.Input("predictor_order", default=3, min=1, max=6), - io.Int.Input("corrector_order", default=4, min=0, max=6), - io.Boolean.Input("use_pece"), - io.Boolean.Input("simple_order_2"), - ], - outputs=[ - io.Sampler.Output(), - ] - ) - - @classmethod - def execute(cls, model, eta, sde_start_percent, sde_end_percent, s_noise, predictor_order, corrector_order, use_pece, simple_order_2): - model_sampling = model.get_model_object("model_sampling") - start_sigma = model_sampling.percent_to_sigma(sde_start_percent) - end_sigma = model_sampling.percent_to_sigma(sde_end_percent) - tau_func = sa_solver.get_tau_interval_func(start_sigma, end_sigma, eta=eta) - - sampler_name = "sa_solver" - sampler = comfy.samplers.ksampler( - sampler_name, - { - "tau_func": tau_func, - "s_noise": s_noise, - "predictor_order": predictor_order, - "corrector_order": corrector_order, - "use_pece": use_pece, - "simple_order_2": simple_order_2, - }, - ) - return io.NodeOutput(sampler) - - -class Noise_EmptyNoise: - def __init__(self): - self.seed = 0 - - def generate_noise(self, input_latent): - latent_image = input_latent["samples"] - return torch.zeros(latent_image.shape, dtype=latent_image.dtype, layout=latent_image.layout, device="cpu") - - -class Noise_RandomNoise: - def __init__(self, seed): - self.seed = seed - - def generate_noise(self, input_latent): - latent_image = input_latent["samples"] - batch_inds = input_latent["batch_index"] if "batch_index" in input_latent else None - return comfy.sample.prepare_noise(latent_image, self.seed, batch_inds) - - -class SamplerCustom(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SamplerCustom_V3", - category="sampling/custom_sampling", - inputs=[ - io.Model.Input("model"), - io.Boolean.Input("add_noise", default=True), - io.Int.Input("noise_seed", default=0, min=0, max=0xffffffffffffffff, control_after_generate=True), - io.Float.Input("cfg", default=8.0, min=0.0, max=100.0, step=0.1, round=0.01), - io.Conditioning.Input("positive"), - io.Conditioning.Input("negative"), - io.Sampler.Input("sampler"), - io.Sigmas.Input("sigmas"), - io.Latent.Input("latent_image"), - ], - outputs=[ - io.Latent.Output(display_name="output"), - io.Latent.Output(display_name="denoised_output"), - ] - ) - - @classmethod - def execute(cls, model, add_noise, noise_seed, cfg, positive, negative, sampler, sigmas, latent_image): - latent = latent_image - latent_image = latent["samples"] - latent = latent.copy() - latent_image = comfy.sample.fix_empty_latent_channels(model, latent_image) - latent["samples"] = latent_image - - if not add_noise: - noise = Noise_EmptyNoise().generate_noise(latent) - else: - noise = Noise_RandomNoise(noise_seed).generate_noise(latent) - - noise_mask = None - if "noise_mask" in latent: - noise_mask = latent["noise_mask"] - - x0_output = {} - callback = latent_preview.prepare_callback(model, sigmas.shape[-1] - 1, x0_output) - - disable_pbar = not comfy.utils.PROGRESS_BAR_ENABLED - samples = comfy.sample.sample_custom(model, noise, cfg, sampler, sigmas, positive, negative, latent_image, noise_mask=noise_mask, callback=callback, disable_pbar=disable_pbar, seed=noise_seed) - - out = latent.copy() - out["samples"] = samples - if "x0" in x0_output: - out_denoised = latent.copy() - out_denoised["samples"] = model.model.process_latent_out(x0_output["x0"].cpu()) - else: - out_denoised = out - return io.NodeOutput(out, out_denoised) - - -class Guider_Basic(comfy.samplers.CFGGuider): - def set_conds(self, positive): - self.inner_set_conds({"positive": positive}) - - -class BasicGuider(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="BasicGuider_V3", - category="sampling/custom_sampling/guiders", - inputs=[ - io.Model.Input("model"), - io.Conditioning.Input("conditioning"), - ], - outputs=[ - io.Guider.Output(), - ] - ) - - @classmethod - def execute(cls, model, conditioning): - guider = Guider_Basic(model) - guider.set_conds(conditioning) - return io.NodeOutput(guider) - - -class CFGGuider(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="CFGGuider_V3", - category="sampling/custom_sampling/guiders", - inputs=[ - io.Model.Input("model"), - io.Conditioning.Input("positive"), - io.Conditioning.Input("negative"), - io.Float.Input("cfg", default=8.0, min=0.0, max=100.0, step=0.1, round=0.01), - ], - outputs=[ - io.Guider.Output(), - ] - ) - - @classmethod - def execute(cls, model, positive, negative, cfg): - guider = comfy.samplers.CFGGuider(model) - guider.set_conds(positive, negative) - guider.set_cfg(cfg) - return io.NodeOutput(guider) - - -class Guider_DualCFG(comfy.samplers.CFGGuider): - def set_cfg(self, cfg1, cfg2, nested=False): - self.cfg1 = cfg1 - self.cfg2 = cfg2 - self.nested = nested - - def set_conds(self, positive, middle, negative): - middle = node_helpers.conditioning_set_values(middle, {"prompt_type": "negative"}) - self.inner_set_conds({"positive": positive, "middle": middle, "negative": negative}) - - def predict_noise(self, x, timestep, model_options={}, seed=None): - negative_cond = self.conds.get("negative", None) - middle_cond = self.conds.get("middle", None) - positive_cond = self.conds.get("positive", None) - - if self.nested: - out = comfy.samplers.calc_cond_batch(self.inner_model, [negative_cond, middle_cond, positive_cond], x, timestep, model_options) - pred_text = comfy.samplers.cfg_function(self.inner_model, out[2], out[1], self.cfg1, x, timestep, model_options=model_options, cond=positive_cond, uncond=middle_cond) - return out[0] + self.cfg2 * (pred_text - out[0]) - else: - if model_options.get("disable_cfg1_optimization", False) is False: - if math.isclose(self.cfg2, 1.0): - negative_cond = None - if math.isclose(self.cfg1, 1.0): - middle_cond = None - - out = comfy.samplers.calc_cond_batch(self.inner_model, [negative_cond, middle_cond, positive_cond], x, timestep, model_options) - return comfy.samplers.cfg_function(self.inner_model, out[1], out[0], self.cfg2, x, timestep, model_options=model_options, cond=middle_cond, uncond=negative_cond) + (out[2] - out[1]) * self.cfg1 - - -class DualCFGGuider(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="DualCFGGuider_V3", - category="sampling/custom_sampling/guiders", - inputs=[ - io.Model.Input("model"), - io.Conditioning.Input("cond1"), - io.Conditioning.Input("cond2"), - io.Conditioning.Input("negative"), - io.Float.Input("cfg_conds", default=8.0, min=0.0, max=100.0, step=0.1, round=0.01), - io.Float.Input("cfg_cond2_negative", default=8.0, min=0.0, max=100.0, step=0.1, round=0.01), - io.Combo.Input("style", options=["regular", "nested"]), - ], - outputs=[ - io.Guider.Output(), - ] - ) - - @classmethod - def execute(cls, model, cond1, cond2, negative, cfg_conds, cfg_cond2_negative, style): - guider = Guider_DualCFG(model) - guider.set_conds(cond1, cond2, negative) - guider.set_cfg(cfg_conds, cfg_cond2_negative, nested=(style == "nested")) - return io.NodeOutput(guider) - - -class DisableNoise(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="DisableNoise_V3", - category="sampling/custom_sampling/noise", - inputs=[], - outputs=[ - io.Noise.Output(), - ] - ) - - @classmethod - def execute(cls): - return io.NodeOutput(Noise_EmptyNoise()) - - -class RandomNoise(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="RandomNoise_V3", - category="sampling/custom_sampling/noise", - inputs=[ - io.Int.Input("noise_seed", default=0, min=0, max=0xffffffffffffffff, control_after_generate=True), - ], - outputs=[ - io.Noise.Output(), - ] - ) - - @classmethod - def execute(cls, noise_seed): - return io.NodeOutput(Noise_RandomNoise(noise_seed)) - - -class SamplerCustomAdvanced(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="SamplerCustomAdvanced_V3", - category="sampling/custom_sampling", - inputs=[ - io.Noise.Input("noise"), - io.Guider.Input("guider"), - io.Sampler.Input("sampler"), - io.Sigmas.Input("sigmas"), - io.Latent.Input("latent_image"), - ], - outputs=[ - io.Latent.Output(display_name="output"), - io.Latent.Output(display_name="denoised_output"), - ] - ) - - @classmethod - def execute(cls, noise, guider, sampler, sigmas, latent_image): - latent = latent_image - latent_image = latent["samples"] - latent = latent.copy() - latent_image = comfy.sample.fix_empty_latent_channels(guider.model_patcher, latent_image) - latent["samples"] = latent_image - - noise_mask = None - if "noise_mask" in latent: - noise_mask = latent["noise_mask"] - - x0_output = {} - callback = latent_preview.prepare_callback(guider.model_patcher, sigmas.shape[-1] - 1, x0_output) - - disable_pbar = not comfy.utils.PROGRESS_BAR_ENABLED - samples = guider.sample(noise.generate_noise(latent), latent_image, sampler, sigmas, denoise_mask=noise_mask, callback=callback, disable_pbar=disable_pbar, seed=noise.seed) - samples = samples.to(comfy.model_management.intermediate_device()) - - out = latent.copy() - out["samples"] = samples - if "x0" in x0_output: - out_denoised = latent.copy() - out_denoised["samples"] = guider.model_patcher.model.process_latent_out(x0_output["x0"].cpu()) - else: - out_denoised = out - return io.NodeOutput(out, out_denoised) - - -class AddNoise(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="AddNoise_V3", - category="_for_testing/custom_sampling/noise", - is_experimental=True, - inputs=[ - io.Model.Input("model"), - io.Noise.Input("noise"), - io.Sigmas.Input("sigmas"), - io.Latent.Input("latent_image"), - ], - outputs=[ - io.Latent.Output(), - ] - ) - - @classmethod - def execute(cls, model, noise, sigmas, latent_image): - if len(sigmas) == 0: - return io.NodeOutput(latent_image) - - latent = latent_image - latent_image = latent["samples"] - - noisy = noise.generate_noise(latent) - - model_sampling = model.get_model_object("model_sampling") - process_latent_out = model.get_model_object("process_latent_out") - process_latent_in = model.get_model_object("process_latent_in") - - if len(sigmas) > 1: - scale = torch.abs(sigmas[0] - sigmas[-1]) - else: - scale = sigmas[0] - - if torch.count_nonzero(latent_image) > 0: #Don't shift the empty latent image. - latent_image = process_latent_in(latent_image) - noisy = model_sampling.noise_scaling(scale, noisy, latent_image) - noisy = process_latent_out(noisy) - noisy = torch.nan_to_num(noisy, nan=0.0, posinf=0.0, neginf=0.0) - - out = latent.copy() - out["samples"] = noisy - return io.NodeOutput(out) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - AddNoise, - BasicGuider, - BasicScheduler, - BetaSamplingScheduler, - CFGGuider, - DisableNoise, - DualCFGGuider, - ExponentialScheduler, - ExtendIntermediateSigmas, - FlipSigmas, - KarrasScheduler, - KSamplerSelect, - LaplaceScheduler, - PolyexponentialScheduler, - RandomNoise, - SamplerCustom, - SamplerCustomAdvanced, - SamplerDPMAdaptative, - SamplerDPMPP_2M_SDE, - SamplerDPMPP_2S_Ancestral, - SamplerDPMPP_3M_SDE, - SamplerDPMPP_SDE, - SamplerER_SDE, - SamplerEulerAncestral, - SamplerEulerAncestralCFGPP, - SamplerLMS, - SamplerSASolver, - SamplingPercentToSigma, - SDTurboScheduler, - SetFirstSigma, - SplitSigmas, - SplitSigmasDenoise, - VPScheduler, -] diff --git a/comfy_extras/v3/nodes_differential_diffusion.py b/comfy_extras/v3/nodes_differential_diffusion.py deleted file mode 100644 index b4e5ecdc5..000000000 --- a/comfy_extras/v3/nodes_differential_diffusion.py +++ /dev/null @@ -1,50 +0,0 @@ -from __future__ import annotations - -import torch - -from comfy_api.latest import io - - -class DifferentialDiffusion(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="DifferentialDiffusion_V3", - display_name="Differential Diffusion _V3", - category="_for_testing", - inputs=[ - io.Model.Input("model"), - ], - outputs=[ - io.Model.Output(), - ], - is_experimental=True, - ) - - @classmethod - def execute(cls, model): - model = model.clone() - model.set_model_denoise_mask_function(cls.forward) - return io.NodeOutput(model) - - @classmethod - def forward(cls, sigma: torch.Tensor, denoise_mask: torch.Tensor, extra_options: dict): - model = extra_options["model"] - step_sigmas = extra_options["sigmas"] - sigma_to = model.inner_model.model_sampling.sigma_min - if step_sigmas[-1] > sigma_to: - sigma_to = step_sigmas[-1] - sigma_from = step_sigmas[0] - - ts_from = model.inner_model.model_sampling.timestep(sigma_from) - ts_to = model.inner_model.model_sampling.timestep(sigma_to) - current_ts = model.inner_model.model_sampling.timestep(sigma[0]) - - threshold = (current_ts - ts_to) / (ts_from - ts_to) - - return (denoise_mask >= threshold).to(denoise_mask.dtype) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - DifferentialDiffusion, -] diff --git a/comfy_extras/v3/nodes_edit_model.py b/comfy_extras/v3/nodes_edit_model.py deleted file mode 100644 index b6164dc6a..000000000 --- a/comfy_extras/v3/nodes_edit_model.py +++ /dev/null @@ -1,34 +0,0 @@ -from __future__ import annotations - -import node_helpers -from comfy_api.latest import io - - -class ReferenceLatent(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="ReferenceLatent_V3", - category="advanced/conditioning/edit_models", - description="This node sets the guiding latent for an edit model. If the model supports it you can chain multiple to set multiple reference images.", - inputs=[ - io.Conditioning.Input("conditioning"), - io.Latent.Input("latent", optional=True), - ], - outputs=[ - io.Conditioning.Output(), - ] - ) - - @classmethod - def execute(cls, conditioning, latent=None): - if latent is not None: - conditioning = node_helpers.conditioning_set_values( - conditioning, {"reference_latents": [latent["samples"]]}, append=True - ) - return io.NodeOutput(conditioning) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - ReferenceLatent, -] diff --git a/comfy_extras/v3/nodes_flux.py b/comfy_extras/v3/nodes_flux.py deleted file mode 100644 index f068f7b98..000000000 --- a/comfy_extras/v3/nodes_flux.py +++ /dev/null @@ -1,122 +0,0 @@ -from __future__ import annotations - -import comfy.utils -import node_helpers -from comfy_api.latest import io - -PREFERED_KONTEXT_RESOLUTIONS = [ - (672, 1568), - (688, 1504), - (720, 1456), - (752, 1392), - (800, 1328), - (832, 1248), - (880, 1184), - (944, 1104), - (1024, 1024), - (1104, 944), - (1184, 880), - (1248, 832), - (1328, 800), - (1392, 752), - (1456, 720), - (1504, 688), - (1568, 672), -] - - -class CLIPTextEncodeFlux(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="CLIPTextEncodeFlux_V3", - category="advanced/conditioning/flux", - inputs=[ - io.Clip.Input("clip"), - io.String.Input("clip_l", multiline=True, dynamic_prompts=True), - io.String.Input("t5xxl", multiline=True, dynamic_prompts=True), - io.Float.Input("guidance", default=3.5, min=0.0, max=100.0, step=0.1), - ], - outputs=[ - io.Conditioning.Output(), - ], - ) - - @classmethod - def execute(cls, clip, clip_l, t5xxl, guidance): - tokens = clip.tokenize(clip_l) - tokens["t5xxl"] = clip.tokenize(t5xxl)["t5xxl"] - - return io.NodeOutput(clip.encode_from_tokens_scheduled(tokens, add_dict={"guidance": guidance})) - -class FluxGuidance(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="FluxGuidance_V3", - category="advanced/conditioning/flux", - inputs=[ - io.Conditioning.Input("conditioning"), - io.Float.Input("guidance", default=3.5, min=0.0, max=100.0, step=0.1), - ], - outputs=[ - io.Conditioning.Output(), - ], - ) - - @classmethod - def execute(cls, conditioning, guidance): - c = node_helpers.conditioning_set_values(conditioning, {"guidance": guidance}) - return io.NodeOutput(c) - -class FluxDisableGuidance(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="FluxDisableGuidance_V3", - category="advanced/conditioning/flux", - description="This node completely disables the guidance embed on Flux and Flux like models", - inputs=[ - io.Conditioning.Input("conditioning"), - ], - outputs=[ - io.Conditioning.Output(), - ], - ) - - @classmethod - def execute(cls, conditioning): - c = node_helpers.conditioning_set_values(conditioning, {"guidance": None}) - return io.NodeOutput(c) - -class FluxKontextImageScale(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="FluxKontextImageScale_V3", - category="advanced/conditioning/flux", - description="This node resizes the image to one that is more optimal for flux kontext.", - inputs=[ - io.Image.Input("image"), - ], - outputs=[ - io.Image.Output(), - ], - ) - - @classmethod - def execute(cls, image): - width = image.shape[2] - height = image.shape[1] - aspect_ratio = width / height - _, width, height = min((abs(aspect_ratio - w / h), w, h) for w, h in PREFERED_KONTEXT_RESOLUTIONS) - image = comfy.utils.common_upscale(image.movedim(-1, 1), width, height, "lanczos", "center").movedim(1, -1) - return io.NodeOutput(image) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - CLIPTextEncodeFlux, - FluxDisableGuidance, - FluxGuidance, - FluxKontextImageScale, -] diff --git a/comfy_extras/v3/nodes_freelunch.py b/comfy_extras/v3/nodes_freelunch.py deleted file mode 100644 index 7467a1f88..000000000 --- a/comfy_extras/v3/nodes_freelunch.py +++ /dev/null @@ -1,131 +0,0 @@ -#code originally taken from: https://github.com/ChenyangSi/FreeU (under MIT License) - -from __future__ import annotations - -import logging - -import torch - -from comfy_api.latest import io - - -def Fourier_filter(x, threshold, scale): - # FFT - x_freq = torch.fft.fftn(x.float(), dim=(-2, -1)) - x_freq = torch.fft.fftshift(x_freq, dim=(-2, -1)) - - B, C, H, W = x_freq.shape - mask = torch.ones((B, C, H, W), device=x.device) - - crow, ccol = H // 2, W //2 - mask[..., crow - threshold:crow + threshold, ccol - threshold:ccol + threshold] = scale - x_freq = x_freq * mask - - # IFFT - x_freq = torch.fft.ifftshift(x_freq, dim=(-2, -1)) - x_filtered = torch.fft.ifftn(x_freq, dim=(-2, -1)).real - - return x_filtered.to(x.dtype) - - -class FreeU(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="FreeU_V3", - category="model_patches/unet", - inputs=[ - io.Model.Input("model"), - io.Float.Input("b1", default=1.1, min=0.0, max=10.0, step=0.01), - io.Float.Input("b2", default=1.2, min=0.0, max=10.0, step=0.01), - io.Float.Input("s1", default=0.9, min=0.0, max=10.0, step=0.01), - io.Float.Input("s2", default=0.2, min=0.0, max=10.0, step=0.01), - ], - outputs=[ - io.Model.Output(), - ], - ) - - @classmethod - def execute(cls, model, b1, b2, s1, s2): - model_channels = model.model.model_config.unet_config["model_channels"] - scale_dict = {model_channels * 4: (b1, s1), model_channels * 2: (b2, s2)} - on_cpu_devices = {} - - def output_block_patch(h, hsp, transformer_options): - scale = scale_dict.get(int(h.shape[1]), None) - if scale is not None: - h[:,:h.shape[1] // 2] = h[:,:h.shape[1] // 2] * scale[0] - if hsp.device not in on_cpu_devices: - try: - hsp = Fourier_filter(hsp, threshold=1, scale=scale[1]) - except Exception: - logging.warning("Device {} does not support the torch.fft functions used in the FreeU node, switching to CPU.".format(hsp.device)) - on_cpu_devices[hsp.device] = True - hsp = Fourier_filter(hsp.cpu(), threshold=1, scale=scale[1]).to(hsp.device) - else: - hsp = Fourier_filter(hsp.cpu(), threshold=1, scale=scale[1]).to(hsp.device) - - return h, hsp - - m = model.clone() - m.set_model_output_block_patch(output_block_patch) - return io.NodeOutput(m) - - -class FreeU_V2(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="FreeU_V2_V3", - category="model_patches/unet", - inputs=[ - io.Model.Input("model"), - io.Float.Input("b1", default=1.3, min=0.0, max=10.0, step=0.01), - io.Float.Input("b2", default=1.4, min=0.0, max=10.0, step=0.01), - io.Float.Input("s1", default=0.9, min=0.0, max=10.0, step=0.01), - io.Float.Input("s2", default=0.2, min=0.0, max=10.0, step=0.01), - ], - outputs=[ - io.Model.Output(), - ], - ) - - @classmethod - def execute(cls, model, b1, b2, s1, s2): - model_channels = model.model.model_config.unet_config["model_channels"] - scale_dict = {model_channels * 4: (b1, s1), model_channels * 2: (b2, s2)} - on_cpu_devices = {} - - def output_block_patch(h, hsp, transformer_options): - scale = scale_dict.get(int(h.shape[1]), None) - if scale is not None: - hidden_mean = h.mean(1).unsqueeze(1) - B = hidden_mean.shape[0] - hidden_max, _ = torch.max(hidden_mean.view(B, -1), dim=-1, keepdim=True) - hidden_min, _ = torch.min(hidden_mean.view(B, -1), dim=-1, keepdim=True) - hidden_mean = (hidden_mean - hidden_min.unsqueeze(2).unsqueeze(3)) / (hidden_max - hidden_min).unsqueeze(2).unsqueeze(3) - - h[:,:h.shape[1] // 2] = h[:,:h.shape[1] // 2] * ((scale[0] - 1 ) * hidden_mean + 1) - - if hsp.device not in on_cpu_devices: - try: - hsp = Fourier_filter(hsp, threshold=1, scale=scale[1]) - except Exception: - logging.warning("Device {} does not support the torch.fft functions used in the FreeU node, switching to CPU.".format(hsp.device)) - on_cpu_devices[hsp.device] = True - hsp = Fourier_filter(hsp.cpu(), threshold=1, scale=scale[1]).to(hsp.device) - else: - hsp = Fourier_filter(hsp.cpu(), threshold=1, scale=scale[1]).to(hsp.device) - - return h, hsp - - m = model.clone() - m.set_model_output_block_patch(output_block_patch) - return io.NodeOutput(m) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - FreeU, - FreeU_V2, -] diff --git a/comfy_extras/v3/nodes_fresca.py b/comfy_extras/v3/nodes_fresca.py deleted file mode 100644 index c4115c84c..000000000 --- a/comfy_extras/v3/nodes_fresca.py +++ /dev/null @@ -1,110 +0,0 @@ -# Code based on https://github.com/WikiChao/FreSca (MIT License) - -from __future__ import annotations - -import torch -import torch.fft as fft - -from comfy_api.latest import io - - -def Fourier_filter(x, scale_low=1.0, scale_high=1.5, freq_cutoff=20): - """ - Apply frequency-dependent scaling to an image tensor using Fourier transforms. - - Parameters: - x: Input tensor of shape (B, C, H, W) - scale_low: Scaling factor for low-frequency components (default: 1.0) - scale_high: Scaling factor for high-frequency components (default: 1.5) - freq_cutoff: Number of frequency indices around center to consider as low-frequency (default: 20) - - Returns: - x_filtered: Filtered version of x in spatial domain with frequency-specific scaling applied. - """ - # Preserve input dtype and device - dtype, device = x.dtype, x.device - - # Convert to float32 for FFT computations - x = x.to(torch.float32) - - # 1) Apply FFT and shift low frequencies to center - x_freq = fft.fftn(x, dim=(-2, -1)) - x_freq = fft.fftshift(x_freq, dim=(-2, -1)) - - # Initialize mask with high-frequency scaling factor - mask = torch.ones(x_freq.shape, device=device) * scale_high - m = mask - for d in range(len(x_freq.shape) - 2): - dim = d + 2 - cc = x_freq.shape[dim] // 2 - f_c = min(freq_cutoff, cc) - m = m.narrow(dim, cc - f_c, f_c * 2) - - # Apply low-frequency scaling factor to center region - m[:] = scale_low - - # 3) Apply frequency-specific scaling - x_freq = x_freq * mask - - # 4) Convert back to spatial domain - x_freq = fft.ifftshift(x_freq, dim=(-2, -1)) - x_filtered = fft.ifftn(x_freq, dim=(-2, -1)).real - - # 5) Restore original dtype - x_filtered = x_filtered.to(dtype) - - return x_filtered - - -class FreSca(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="FreSca_V3", - display_name="FreSca _V3", - category="_for_testing", - description="Applies frequency-dependent scaling to the guidance", - inputs=[ - io.Model.Input("model"), - io.Float.Input("scale_low", default=1.0, min=0, max=10, step=0.01, - tooltip="Scaling factor for low-frequency components"), - io.Float.Input("scale_high", default=1.25, min=0, max=10, step=0.01, - tooltip="Scaling factor for high-frequency components"), - io.Int.Input("freq_cutoff", default=20, min=1, max=10000, step=1, - tooltip="Number of frequency indices around center to consider as low-frequency"), - ], - outputs=[ - io.Model.Output(), - ], - is_experimental=True, - ) - - @classmethod - def execute(cls, model, scale_low, scale_high, freq_cutoff): - def custom_cfg_function(args): - conds_out = args["conds_out"] - if len(conds_out) <= 1 or None in args["conds"][:2]: - return conds_out - cond = conds_out[0] - uncond = conds_out[1] - - guidance = cond - uncond - filtered_guidance = Fourier_filter( - guidance, - scale_low=scale_low, - scale_high=scale_high, - freq_cutoff=freq_cutoff, - ) - filtered_cond = filtered_guidance + uncond - - return [filtered_cond, uncond] + conds_out[2:] - - m = model.clone() - m.set_model_sampler_pre_cfg_function(custom_cfg_function) - - return io.NodeOutput(m) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - FreSca, -] diff --git a/comfy_extras/v3/nodes_gits.py b/comfy_extras/v3/nodes_gits.py deleted file mode 100644 index 4d500d789..000000000 --- a/comfy_extras/v3/nodes_gits.py +++ /dev/null @@ -1,376 +0,0 @@ -from __future__ import annotations - -import numpy as np -import torch - -from comfy_api.latest import io - - -def loglinear_interp(t_steps, num_steps): - """Performs log-linear interpolation of a given array of decreasing numbers.""" - xs = np.linspace(0, 1, len(t_steps)) - ys = np.log(t_steps[::-1]) - - new_xs = np.linspace(0, 1, num_steps) - new_ys = np.interp(new_xs, xs, ys) - - return np.exp(new_ys)[::-1].copy() - - -NOISE_LEVELS = { - 0.80: [ - [14.61464119, 7.49001646, 0.02916753], - [14.61464119, 11.54541874, 6.77309084, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 3.07277966, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 5.85520077, 2.05039096, 0.02916753], - [14.61464119, 12.2308979, 8.75849152, 7.49001646, 5.85520077, 2.05039096, 0.02916753], - [14.61464119, 12.2308979, 8.75849152, 7.49001646, 5.85520077, 3.07277966, 1.56271636, 0.02916753], - [14.61464119, 12.96784878, 11.54541874, 8.75849152, 7.49001646, 5.85520077, 3.07277966, 1.56271636, 0.02916753], - [14.61464119, 13.76078796, 12.2308979, 10.90732002, 8.75849152, 7.49001646, 5.85520077, 3.07277966, 1.56271636, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 10.90732002, 8.75849152, 7.49001646, 5.85520077, 3.07277966, 1.56271636, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 10.90732002, 9.24142551, 8.30717278, 7.49001646, 5.85520077, 3.07277966, 1.56271636, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 10.90732002, 9.24142551, 8.30717278, 7.49001646, 6.14220476, 4.86714602, 3.07277966, 1.56271636, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.31284904, 9.24142551, 8.30717278, 7.49001646, 6.14220476, 4.86714602, 3.07277966, 1.56271636, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.90732002, 10.31284904, 9.24142551, 8.30717278, 7.49001646, 6.14220476, 4.86714602, 3.07277966, 1.56271636, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.90732002, 10.31284904, 9.24142551, 8.75849152, 8.30717278, 7.49001646, 6.14220476, 4.86714602, 3.07277966, 1.56271636, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.90732002, 10.31284904, 9.24142551, 8.75849152, 8.30717278, 7.49001646, 6.14220476, 4.86714602, 3.1956799, 1.98035145, 0.86115354, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.90732002, 10.31284904, 9.75859547, 9.24142551, 8.75849152, 8.30717278, 7.49001646, 6.14220476, 4.86714602, 3.1956799, 1.98035145, 0.86115354, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.90732002, 10.31284904, 9.75859547, 9.24142551, 8.75849152, 8.30717278, 7.49001646, 6.77309084, 5.85520077, 4.65472794, 3.07277966, 1.84880662, 0.83188516, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.90732002, 10.31284904, 9.75859547, 9.24142551, 8.75849152, 8.30717278, 7.88507891, 7.49001646, 6.77309084, 5.85520077, 4.65472794, 3.07277966, 1.84880662, 0.83188516, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.90732002, 10.31284904, 9.75859547, 9.24142551, 8.75849152, 8.30717278, 7.88507891, 7.49001646, 6.77309084, 5.85520077, 4.86714602, 3.75677586, 2.84484982, 1.78698075, 0.803307, 0.02916753], - ], - 0.85: [ - [14.61464119, 7.49001646, 0.02916753], - [14.61464119, 7.49001646, 1.84880662, 0.02916753], - [14.61464119, 11.54541874, 6.77309084, 1.56271636, 0.02916753], - [14.61464119, 11.54541874, 7.11996698, 3.07277966, 1.24153244, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 5.09240818, 2.84484982, 0.95350921, 0.02916753], - [14.61464119, 12.2308979, 8.75849152, 7.49001646, 5.09240818, 2.84484982, 0.95350921, 0.02916753], - [14.61464119, 12.2308979, 8.75849152, 7.49001646, 5.58536053, 3.1956799, 1.84880662, 0.803307, 0.02916753], - [14.61464119, 12.96784878, 11.54541874, 8.75849152, 7.49001646, 5.58536053, 3.1956799, 1.84880662, 0.803307, 0.02916753], - [14.61464119, 12.96784878, 11.54541874, 8.75849152, 7.49001646, 6.14220476, 4.65472794, 3.07277966, 1.84880662, 0.803307, 0.02916753], - [14.61464119, 13.76078796, 12.2308979, 10.90732002, 8.75849152, 7.49001646, 6.14220476, 4.65472794, 3.07277966, 1.84880662, 0.803307, 0.02916753], - [14.61464119, 13.76078796, 12.2308979, 10.90732002, 9.24142551, 8.30717278, 7.49001646, 6.14220476, 4.65472794, 3.07277966, 1.84880662, 0.803307, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 10.90732002, 9.24142551, 8.30717278, 7.49001646, 6.14220476, 4.65472794, 3.07277966, 1.84880662, 0.803307, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.31284904, 9.24142551, 8.30717278, 7.49001646, 6.14220476, 4.65472794, 3.07277966, 1.84880662, 0.803307, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.31284904, 9.24142551, 8.30717278, 7.49001646, 6.14220476, 4.86714602, 3.60512662, 2.6383388, 1.56271636, 0.72133851, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.31284904, 9.24142551, 8.30717278, 7.49001646, 6.77309084, 5.85520077, 4.65472794, 3.46139455, 2.45070267, 1.56271636, 0.72133851, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.31284904, 9.24142551, 8.75849152, 8.30717278, 7.49001646, 6.77309084, 5.85520077, 4.65472794, 3.46139455, 2.45070267, 1.56271636, 0.72133851, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.90732002, 10.31284904, 9.24142551, 8.75849152, 8.30717278, 7.49001646, 6.77309084, 5.85520077, 4.65472794, 3.46139455, 2.45070267, 1.56271636, 0.72133851, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.90732002, 10.31284904, 9.75859547, 9.24142551, 8.75849152, 8.30717278, 7.49001646, 6.77309084, 5.85520077, 4.65472794, 3.46139455, 2.45070267, 1.56271636, 0.72133851, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.90732002, 10.31284904, 9.75859547, 9.24142551, 8.75849152, 8.30717278, 7.88507891, 7.49001646, 6.77309084, 5.85520077, 4.65472794, 3.46139455, 2.45070267, 1.56271636, 0.72133851, 0.02916753], - ], - 0.90: [ - [14.61464119, 6.77309084, 0.02916753], - [14.61464119, 7.49001646, 1.56271636, 0.02916753], - [14.61464119, 7.49001646, 3.07277966, 0.95350921, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 2.54230714, 0.89115214, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 4.86714602, 2.54230714, 0.89115214, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 5.09240818, 3.07277966, 1.61558151, 0.69515091, 0.02916753], - [14.61464119, 12.2308979, 8.75849152, 7.11996698, 4.86714602, 3.07277966, 1.61558151, 0.69515091, 0.02916753], - [14.61464119, 12.2308979, 8.75849152, 7.49001646, 5.85520077, 4.45427561, 2.95596409, 1.61558151, 0.69515091, 0.02916753], - [14.61464119, 12.2308979, 8.75849152, 7.49001646, 5.85520077, 4.45427561, 3.1956799, 2.19988537, 1.24153244, 0.57119018, 0.02916753], - [14.61464119, 12.96784878, 10.90732002, 8.75849152, 7.49001646, 5.85520077, 4.45427561, 3.1956799, 2.19988537, 1.24153244, 0.57119018, 0.02916753], - [14.61464119, 12.96784878, 11.54541874, 9.24142551, 8.30717278, 7.49001646, 5.85520077, 4.45427561, 3.1956799, 2.19988537, 1.24153244, 0.57119018, 0.02916753], - [14.61464119, 12.96784878, 11.54541874, 9.24142551, 8.30717278, 7.49001646, 6.14220476, 4.86714602, 3.75677586, 2.84484982, 1.84880662, 1.08895338, 0.52423614, 0.02916753], - [14.61464119, 13.76078796, 12.2308979, 10.90732002, 9.24142551, 8.30717278, 7.49001646, 6.14220476, 4.86714602, 3.75677586, 2.84484982, 1.84880662, 1.08895338, 0.52423614, 0.02916753], - [14.61464119, 13.76078796, 12.2308979, 10.90732002, 9.24142551, 8.30717278, 7.49001646, 6.44769001, 5.58536053, 4.45427561, 3.32507086, 2.45070267, 1.61558151, 0.95350921, 0.45573691, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 10.90732002, 9.24142551, 8.30717278, 7.49001646, 6.44769001, 5.58536053, 4.45427561, 3.32507086, 2.45070267, 1.61558151, 0.95350921, 0.45573691, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 10.90732002, 9.24142551, 8.30717278, 7.49001646, 6.77309084, 5.85520077, 4.86714602, 3.91689563, 3.07277966, 2.27973175, 1.56271636, 0.95350921, 0.45573691, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.31284904, 9.24142551, 8.30717278, 7.49001646, 6.77309084, 5.85520077, 4.86714602, 3.91689563, 3.07277966, 2.27973175, 1.56271636, 0.95350921, 0.45573691, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.31284904, 9.24142551, 8.75849152, 8.30717278, 7.49001646, 6.77309084, 5.85520077, 4.86714602, 3.91689563, 3.07277966, 2.27973175, 1.56271636, 0.95350921, 0.45573691, 0.02916753], - [14.61464119, 13.76078796, 12.96784878, 12.2308979, 11.54541874, 10.31284904, 9.24142551, 8.75849152, 8.30717278, 7.49001646, 6.77309084, 5.85520077, 5.09240818, 4.45427561, 3.60512662, 2.95596409, 2.19988537, 1.51179266, 0.89115214, 0.43325692, 0.02916753], - ], - 0.95: [ - [14.61464119, 6.77309084, 0.02916753], - [14.61464119, 6.77309084, 1.56271636, 0.02916753], - [14.61464119, 7.49001646, 2.84484982, 0.89115214, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 2.36326075, 0.803307, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 2.95596409, 1.56271636, 0.64427125, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 4.86714602, 2.95596409, 1.56271636, 0.64427125, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 4.86714602, 3.07277966, 1.91321158, 1.08895338, 0.50118381, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 5.85520077, 4.45427561, 3.07277966, 1.91321158, 1.08895338, 0.50118381, 0.02916753], - [14.61464119, 12.2308979, 8.75849152, 7.49001646, 5.85520077, 4.45427561, 3.07277966, 1.91321158, 1.08895338, 0.50118381, 0.02916753], - [14.61464119, 12.2308979, 8.75849152, 7.49001646, 5.85520077, 4.45427561, 3.1956799, 2.19988537, 1.41535246, 0.803307, 0.38853383, 0.02916753], - [14.61464119, 12.2308979, 8.75849152, 7.49001646, 5.85520077, 4.65472794, 3.46139455, 2.6383388, 1.84880662, 1.24153244, 0.72133851, 0.34370604, 0.02916753], - [14.61464119, 12.96784878, 10.90732002, 8.75849152, 7.49001646, 5.85520077, 4.65472794, 3.46139455, 2.6383388, 1.84880662, 1.24153244, 0.72133851, 0.34370604, 0.02916753], - [14.61464119, 12.96784878, 10.90732002, 8.75849152, 7.49001646, 6.14220476, 4.86714602, 3.75677586, 2.95596409, 2.19988537, 1.56271636, 1.05362725, 0.64427125, 0.32104823, 0.02916753], - [14.61464119, 12.96784878, 10.90732002, 8.75849152, 7.49001646, 6.44769001, 5.58536053, 4.65472794, 3.60512662, 2.95596409, 2.19988537, 1.56271636, 1.05362725, 0.64427125, 0.32104823, 0.02916753], - [14.61464119, 12.96784878, 11.54541874, 9.24142551, 8.30717278, 7.49001646, 6.44769001, 5.58536053, 4.65472794, 3.60512662, 2.95596409, 2.19988537, 1.56271636, 1.05362725, 0.64427125, 0.32104823, 0.02916753], - [14.61464119, 12.96784878, 11.54541874, 9.24142551, 8.30717278, 7.49001646, 6.44769001, 5.58536053, 4.65472794, 3.75677586, 3.07277966, 2.45070267, 1.78698075, 1.24153244, 0.83188516, 0.50118381, 0.22545385, 0.02916753], - [14.61464119, 12.96784878, 11.54541874, 9.24142551, 8.30717278, 7.49001646, 6.77309084, 5.85520077, 5.09240818, 4.45427561, 3.60512662, 2.95596409, 2.36326075, 1.72759056, 1.24153244, 0.83188516, 0.50118381, 0.22545385, 0.02916753], - [14.61464119, 13.76078796, 12.2308979, 10.90732002, 9.24142551, 8.30717278, 7.49001646, 6.77309084, 5.85520077, 5.09240818, 4.45427561, 3.60512662, 2.95596409, 2.36326075, 1.72759056, 1.24153244, 0.83188516, 0.50118381, 0.22545385, 0.02916753], - [14.61464119, 13.76078796, 12.2308979, 10.90732002, 9.24142551, 8.30717278, 7.49001646, 6.77309084, 5.85520077, 5.09240818, 4.45427561, 3.75677586, 3.07277966, 2.45070267, 1.91321158, 1.46270394, 1.05362725, 0.72133851, 0.43325692, 0.19894916, 0.02916753], - ], - 1.00: [ - [14.61464119, 1.56271636, 0.02916753], - [14.61464119, 6.77309084, 0.95350921, 0.02916753], - [14.61464119, 6.77309084, 2.36326075, 0.803307, 0.02916753], - [14.61464119, 7.11996698, 3.07277966, 1.56271636, 0.59516323, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 2.84484982, 1.41535246, 0.57119018, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 2.84484982, 1.61558151, 0.86115354, 0.38853383, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 4.86714602, 2.84484982, 1.61558151, 0.86115354, 0.38853383, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 4.86714602, 3.07277966, 1.98035145, 1.24153244, 0.72133851, 0.34370604, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 5.85520077, 4.45427561, 3.07277966, 1.98035145, 1.24153244, 0.72133851, 0.34370604, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 5.85520077, 4.45427561, 3.1956799, 2.27973175, 1.51179266, 0.95350921, 0.54755926, 0.25053367, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 5.85520077, 4.45427561, 3.1956799, 2.36326075, 1.61558151, 1.08895338, 0.72133851, 0.41087446, 0.17026083, 0.02916753], - [14.61464119, 11.54541874, 8.75849152, 7.49001646, 5.85520077, 4.45427561, 3.1956799, 2.36326075, 1.61558151, 1.08895338, 0.72133851, 0.41087446, 0.17026083, 0.02916753], - [14.61464119, 11.54541874, 8.75849152, 7.49001646, 5.85520077, 4.65472794, 3.60512662, 2.84484982, 2.12350607, 1.56271636, 1.08895338, 0.72133851, 0.41087446, 0.17026083, 0.02916753], - [14.61464119, 11.54541874, 8.75849152, 7.49001646, 5.85520077, 4.65472794, 3.60512662, 2.84484982, 2.19988537, 1.61558151, 1.162866, 0.803307, 0.50118381, 0.27464288, 0.09824532, 0.02916753], - [14.61464119, 11.54541874, 8.75849152, 7.49001646, 5.85520077, 4.65472794, 3.75677586, 3.07277966, 2.45070267, 1.84880662, 1.36964464, 1.01931262, 0.72133851, 0.45573691, 0.25053367, 0.09824532, 0.02916753], - [14.61464119, 11.54541874, 8.75849152, 7.49001646, 6.14220476, 5.09240818, 4.26497746, 3.46139455, 2.84484982, 2.19988537, 1.67050016, 1.24153244, 0.92192322, 0.64427125, 0.43325692, 0.25053367, 0.09824532, 0.02916753], - [14.61464119, 11.54541874, 8.75849152, 7.49001646, 6.14220476, 5.09240818, 4.26497746, 3.60512662, 2.95596409, 2.45070267, 1.91321158, 1.51179266, 1.12534678, 0.83188516, 0.59516323, 0.38853383, 0.22545385, 0.09824532, 0.02916753], - [14.61464119, 12.2308979, 9.24142551, 8.30717278, 7.49001646, 6.14220476, 5.09240818, 4.26497746, 3.60512662, 2.95596409, 2.45070267, 1.91321158, 1.51179266, 1.12534678, 0.83188516, 0.59516323, 0.38853383, 0.22545385, 0.09824532, 0.02916753], - [14.61464119, 12.2308979, 9.24142551, 8.30717278, 7.49001646, 6.77309084, 5.85520077, 5.09240818, 4.26497746, 3.60512662, 2.95596409, 2.45070267, 1.91321158, 1.51179266, 1.12534678, 0.83188516, 0.59516323, 0.38853383, 0.22545385, 0.09824532, 0.02916753], - ], - 1.05: [ - [14.61464119, 0.95350921, 0.02916753], - [14.61464119, 6.77309084, 0.89115214, 0.02916753], - [14.61464119, 6.77309084, 2.05039096, 0.72133851, 0.02916753], - [14.61464119, 6.77309084, 2.84484982, 1.28281462, 0.52423614, 0.02916753], - [14.61464119, 6.77309084, 3.07277966, 1.61558151, 0.803307, 0.34370604, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 2.84484982, 1.56271636, 0.803307, 0.34370604, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 2.84484982, 1.61558151, 0.95350921, 0.52423614, 0.22545385, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 3.07277966, 1.98035145, 1.24153244, 0.74807048, 0.41087446, 0.17026083, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 3.1956799, 2.27973175, 1.51179266, 0.95350921, 0.59516323, 0.34370604, 0.13792117, 0.02916753], - [14.61464119, 7.49001646, 5.09240818, 3.46139455, 2.45070267, 1.61558151, 1.08895338, 0.72133851, 0.45573691, 0.25053367, 0.09824532, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 5.09240818, 3.46139455, 2.45070267, 1.61558151, 1.08895338, 0.72133851, 0.45573691, 0.25053367, 0.09824532, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 5.85520077, 4.45427561, 3.1956799, 2.36326075, 1.61558151, 1.08895338, 0.72133851, 0.45573691, 0.25053367, 0.09824532, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 5.85520077, 4.45427561, 3.1956799, 2.45070267, 1.72759056, 1.24153244, 0.86115354, 0.59516323, 0.38853383, 0.22545385, 0.09824532, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 5.85520077, 4.65472794, 3.60512662, 2.84484982, 2.19988537, 1.61558151, 1.162866, 0.83188516, 0.59516323, 0.38853383, 0.22545385, 0.09824532, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 5.85520077, 4.65472794, 3.60512662, 2.84484982, 2.19988537, 1.67050016, 1.28281462, 0.95350921, 0.72133851, 0.52423614, 0.34370604, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 5.85520077, 4.65472794, 3.60512662, 2.95596409, 2.36326075, 1.84880662, 1.41535246, 1.08895338, 0.83188516, 0.61951244, 0.45573691, 0.32104823, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 5.85520077, 4.65472794, 3.60512662, 2.95596409, 2.45070267, 1.91321158, 1.51179266, 1.20157266, 0.95350921, 0.74807048, 0.57119018, 0.43325692, 0.29807833, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 11.54541874, 8.30717278, 7.11996698, 5.85520077, 4.65472794, 3.60512662, 2.95596409, 2.45070267, 1.91321158, 1.51179266, 1.20157266, 0.95350921, 0.74807048, 0.57119018, 0.43325692, 0.29807833, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 11.54541874, 8.30717278, 7.11996698, 5.85520077, 4.65472794, 3.60512662, 2.95596409, 2.45070267, 1.98035145, 1.61558151, 1.32549286, 1.08895338, 0.86115354, 0.69515091, 0.54755926, 0.41087446, 0.29807833, 0.19894916, 0.09824532, 0.02916753], - ], - 1.10: [ - [14.61464119, 0.89115214, 0.02916753], - [14.61464119, 2.36326075, 0.72133851, 0.02916753], - [14.61464119, 5.85520077, 1.61558151, 0.57119018, 0.02916753], - [14.61464119, 6.77309084, 2.45070267, 1.08895338, 0.45573691, 0.02916753], - [14.61464119, 6.77309084, 2.95596409, 1.56271636, 0.803307, 0.34370604, 0.02916753], - [14.61464119, 6.77309084, 3.07277966, 1.61558151, 0.89115214, 0.4783645, 0.19894916, 0.02916753], - [14.61464119, 6.77309084, 3.07277966, 1.84880662, 1.08895338, 0.64427125, 0.34370604, 0.13792117, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 2.84484982, 1.61558151, 0.95350921, 0.54755926, 0.27464288, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 2.95596409, 1.91321158, 1.24153244, 0.803307, 0.4783645, 0.25053367, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 3.07277966, 2.05039096, 1.41535246, 0.95350921, 0.64427125, 0.41087446, 0.22545385, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 3.1956799, 2.27973175, 1.61558151, 1.12534678, 0.803307, 0.54755926, 0.36617002, 0.22545385, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 3.32507086, 2.45070267, 1.72759056, 1.24153244, 0.89115214, 0.64427125, 0.45573691, 0.32104823, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 5.09240818, 3.60512662, 2.84484982, 2.05039096, 1.51179266, 1.08895338, 0.803307, 0.59516323, 0.43325692, 0.29807833, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 5.09240818, 3.60512662, 2.84484982, 2.12350607, 1.61558151, 1.24153244, 0.95350921, 0.72133851, 0.54755926, 0.41087446, 0.29807833, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 5.85520077, 4.45427561, 3.1956799, 2.45070267, 1.84880662, 1.41535246, 1.08895338, 0.83188516, 0.64427125, 0.50118381, 0.36617002, 0.25053367, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 5.85520077, 4.45427561, 3.1956799, 2.45070267, 1.91321158, 1.51179266, 1.20157266, 0.95350921, 0.74807048, 0.59516323, 0.45573691, 0.34370604, 0.25053367, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 5.85520077, 4.45427561, 3.46139455, 2.84484982, 2.19988537, 1.72759056, 1.36964464, 1.08895338, 0.86115354, 0.69515091, 0.54755926, 0.43325692, 0.34370604, 0.25053367, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 5.85520077, 4.45427561, 3.46139455, 2.84484982, 2.19988537, 1.72759056, 1.36964464, 1.08895338, 0.86115354, 0.69515091, 0.54755926, 0.43325692, 0.34370604, 0.25053367, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 11.54541874, 7.49001646, 5.85520077, 4.45427561, 3.46139455, 2.84484982, 2.19988537, 1.72759056, 1.36964464, 1.08895338, 0.89115214, 0.72133851, 0.59516323, 0.4783645, 0.38853383, 0.29807833, 0.22545385, 0.17026083, 0.09824532, 0.02916753], - ], - 1.15: [ - [14.61464119, 0.83188516, 0.02916753], - [14.61464119, 1.84880662, 0.59516323, 0.02916753], - [14.61464119, 5.85520077, 1.56271636, 0.52423614, 0.02916753], - [14.61464119, 5.85520077, 1.91321158, 0.83188516, 0.34370604, 0.02916753], - [14.61464119, 5.85520077, 2.45070267, 1.24153244, 0.59516323, 0.25053367, 0.02916753], - [14.61464119, 5.85520077, 2.84484982, 1.51179266, 0.803307, 0.41087446, 0.17026083, 0.02916753], - [14.61464119, 5.85520077, 2.84484982, 1.56271636, 0.89115214, 0.50118381, 0.25053367, 0.09824532, 0.02916753], - [14.61464119, 6.77309084, 3.07277966, 1.84880662, 1.12534678, 0.72133851, 0.43325692, 0.22545385, 0.09824532, 0.02916753], - [14.61464119, 6.77309084, 3.07277966, 1.91321158, 1.24153244, 0.803307, 0.52423614, 0.34370604, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 2.95596409, 1.91321158, 1.24153244, 0.803307, 0.52423614, 0.34370604, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 3.07277966, 2.05039096, 1.36964464, 0.95350921, 0.69515091, 0.4783645, 0.32104823, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 3.07277966, 2.12350607, 1.51179266, 1.08895338, 0.803307, 0.59516323, 0.43325692, 0.29807833, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 3.07277966, 2.12350607, 1.51179266, 1.08895338, 0.803307, 0.59516323, 0.45573691, 0.34370604, 0.25053367, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 3.07277966, 2.19988537, 1.61558151, 1.24153244, 0.95350921, 0.74807048, 0.59516323, 0.45573691, 0.34370604, 0.25053367, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 3.1956799, 2.45070267, 1.78698075, 1.32549286, 1.01931262, 0.803307, 0.64427125, 0.50118381, 0.38853383, 0.29807833, 0.22545385, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 3.1956799, 2.45070267, 1.78698075, 1.32549286, 1.01931262, 0.803307, 0.64427125, 0.52423614, 0.41087446, 0.32104823, 0.25053367, 0.19894916, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 3.1956799, 2.45070267, 1.84880662, 1.41535246, 1.12534678, 0.89115214, 0.72133851, 0.59516323, 0.4783645, 0.38853383, 0.32104823, 0.25053367, 0.19894916, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 3.1956799, 2.45070267, 1.84880662, 1.41535246, 1.12534678, 0.89115214, 0.72133851, 0.59516323, 0.50118381, 0.41087446, 0.34370604, 0.27464288, 0.22545385, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.86714602, 3.1956799, 2.45070267, 1.84880662, 1.41535246, 1.12534678, 0.89115214, 0.72133851, 0.59516323, 0.50118381, 0.41087446, 0.34370604, 0.29807833, 0.25053367, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - ], - 1.20: [ - [14.61464119, 0.803307, 0.02916753], - [14.61464119, 1.56271636, 0.52423614, 0.02916753], - [14.61464119, 2.36326075, 0.92192322, 0.36617002, 0.02916753], - [14.61464119, 2.84484982, 1.24153244, 0.59516323, 0.25053367, 0.02916753], - [14.61464119, 5.85520077, 2.05039096, 0.95350921, 0.45573691, 0.17026083, 0.02916753], - [14.61464119, 5.85520077, 2.45070267, 1.24153244, 0.64427125, 0.29807833, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.45070267, 1.36964464, 0.803307, 0.45573691, 0.25053367, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.84484982, 1.61558151, 0.95350921, 0.59516323, 0.36617002, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.84484982, 1.67050016, 1.08895338, 0.74807048, 0.50118381, 0.32104823, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.95596409, 1.84880662, 1.24153244, 0.83188516, 0.59516323, 0.41087446, 0.27464288, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 3.07277966, 1.98035145, 1.36964464, 0.95350921, 0.69515091, 0.50118381, 0.36617002, 0.25053367, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 6.77309084, 3.46139455, 2.36326075, 1.56271636, 1.08895338, 0.803307, 0.59516323, 0.45573691, 0.34370604, 0.25053367, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 6.77309084, 3.46139455, 2.45070267, 1.61558151, 1.162866, 0.86115354, 0.64427125, 0.50118381, 0.38853383, 0.29807833, 0.22545385, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.65472794, 3.07277966, 2.12350607, 1.51179266, 1.08895338, 0.83188516, 0.64427125, 0.50118381, 0.38853383, 0.29807833, 0.22545385, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.65472794, 3.07277966, 2.12350607, 1.51179266, 1.08895338, 0.83188516, 0.64427125, 0.50118381, 0.41087446, 0.32104823, 0.25053367, 0.19894916, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.65472794, 3.07277966, 2.12350607, 1.51179266, 1.08895338, 0.83188516, 0.64427125, 0.50118381, 0.41087446, 0.34370604, 0.27464288, 0.22545385, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.65472794, 3.07277966, 2.19988537, 1.61558151, 1.20157266, 0.92192322, 0.72133851, 0.57119018, 0.45573691, 0.36617002, 0.29807833, 0.25053367, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.65472794, 3.07277966, 2.19988537, 1.61558151, 1.24153244, 0.95350921, 0.74807048, 0.59516323, 0.4783645, 0.38853383, 0.32104823, 0.27464288, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 7.49001646, 4.65472794, 3.07277966, 2.19988537, 1.61558151, 1.24153244, 0.95350921, 0.74807048, 0.59516323, 0.50118381, 0.41087446, 0.34370604, 0.29807833, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - ], - 1.25: [ - [14.61464119, 0.72133851, 0.02916753], - [14.61464119, 1.56271636, 0.50118381, 0.02916753], - [14.61464119, 2.05039096, 0.803307, 0.32104823, 0.02916753], - [14.61464119, 2.36326075, 0.95350921, 0.43325692, 0.17026083, 0.02916753], - [14.61464119, 2.84484982, 1.24153244, 0.59516323, 0.27464288, 0.09824532, 0.02916753], - [14.61464119, 3.07277966, 1.51179266, 0.803307, 0.43325692, 0.22545385, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.36326075, 1.24153244, 0.72133851, 0.41087446, 0.22545385, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.45070267, 1.36964464, 0.83188516, 0.52423614, 0.34370604, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.84484982, 1.61558151, 0.98595673, 0.64427125, 0.43325692, 0.27464288, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.84484982, 1.67050016, 1.08895338, 0.74807048, 0.52423614, 0.36617002, 0.25053367, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.84484982, 1.72759056, 1.162866, 0.803307, 0.59516323, 0.45573691, 0.34370604, 0.25053367, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.95596409, 1.84880662, 1.24153244, 0.86115354, 0.64427125, 0.4783645, 0.36617002, 0.27464288, 0.19894916, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.95596409, 1.84880662, 1.28281462, 0.92192322, 0.69515091, 0.52423614, 0.41087446, 0.32104823, 0.25053367, 0.19894916, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.95596409, 1.91321158, 1.32549286, 0.95350921, 0.72133851, 0.54755926, 0.43325692, 0.34370604, 0.27464288, 0.22545385, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.95596409, 1.91321158, 1.32549286, 0.95350921, 0.72133851, 0.57119018, 0.45573691, 0.36617002, 0.29807833, 0.25053367, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.95596409, 1.91321158, 1.32549286, 0.95350921, 0.74807048, 0.59516323, 0.4783645, 0.38853383, 0.32104823, 0.27464288, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 3.07277966, 2.05039096, 1.41535246, 1.05362725, 0.803307, 0.61951244, 0.50118381, 0.41087446, 0.34370604, 0.29807833, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 3.07277966, 2.05039096, 1.41535246, 1.05362725, 0.803307, 0.64427125, 0.52423614, 0.43325692, 0.36617002, 0.32104823, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 3.07277966, 2.05039096, 1.46270394, 1.08895338, 0.83188516, 0.66947293, 0.54755926, 0.45573691, 0.38853383, 0.34370604, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - ], - 1.30: [ - [14.61464119, 0.72133851, 0.02916753], - [14.61464119, 1.24153244, 0.43325692, 0.02916753], - [14.61464119, 1.56271636, 0.59516323, 0.22545385, 0.02916753], - [14.61464119, 1.84880662, 0.803307, 0.36617002, 0.13792117, 0.02916753], - [14.61464119, 2.36326075, 1.01931262, 0.52423614, 0.25053367, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.36964464, 0.74807048, 0.41087446, 0.22545385, 0.09824532, 0.02916753], - [14.61464119, 3.07277966, 1.56271636, 0.89115214, 0.54755926, 0.34370604, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 3.07277966, 1.61558151, 0.95350921, 0.61951244, 0.41087446, 0.27464288, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.45070267, 1.36964464, 0.83188516, 0.54755926, 0.36617002, 0.25053367, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.45070267, 1.41535246, 0.92192322, 0.64427125, 0.45573691, 0.34370604, 0.25053367, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.6383388, 1.56271636, 1.01931262, 0.72133851, 0.50118381, 0.36617002, 0.27464288, 0.19894916, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.84484982, 1.61558151, 1.05362725, 0.74807048, 0.54755926, 0.41087446, 0.32104823, 0.25053367, 0.19894916, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.84484982, 1.61558151, 1.08895338, 0.77538133, 0.57119018, 0.43325692, 0.34370604, 0.27464288, 0.22545385, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.84484982, 1.61558151, 1.08895338, 0.803307, 0.59516323, 0.45573691, 0.36617002, 0.29807833, 0.25053367, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.84484982, 1.61558151, 1.08895338, 0.803307, 0.59516323, 0.4783645, 0.38853383, 0.32104823, 0.27464288, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.84484982, 1.72759056, 1.162866, 0.83188516, 0.64427125, 0.50118381, 0.41087446, 0.34370604, 0.29807833, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.84484982, 1.72759056, 1.162866, 0.83188516, 0.64427125, 0.52423614, 0.43325692, 0.36617002, 0.32104823, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.84484982, 1.78698075, 1.24153244, 0.92192322, 0.72133851, 0.57119018, 0.45573691, 0.38853383, 0.34370604, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.84484982, 1.78698075, 1.24153244, 0.92192322, 0.72133851, 0.57119018, 0.4783645, 0.41087446, 0.36617002, 0.32104823, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - ], - 1.35: [ - [14.61464119, 0.69515091, 0.02916753], - [14.61464119, 0.95350921, 0.34370604, 0.02916753], - [14.61464119, 1.56271636, 0.57119018, 0.19894916, 0.02916753], - [14.61464119, 1.61558151, 0.69515091, 0.29807833, 0.09824532, 0.02916753], - [14.61464119, 1.84880662, 0.83188516, 0.43325692, 0.22545385, 0.09824532, 0.02916753], - [14.61464119, 2.45070267, 1.162866, 0.64427125, 0.36617002, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.36964464, 0.803307, 0.50118381, 0.32104823, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.41535246, 0.83188516, 0.54755926, 0.36617002, 0.25053367, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.56271636, 0.95350921, 0.64427125, 0.45573691, 0.32104823, 0.22545385, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.56271636, 0.95350921, 0.64427125, 0.45573691, 0.34370604, 0.25053367, 0.19894916, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 3.07277966, 1.61558151, 1.01931262, 0.72133851, 0.52423614, 0.38853383, 0.29807833, 0.22545385, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 3.07277966, 1.61558151, 1.01931262, 0.72133851, 0.52423614, 0.41087446, 0.32104823, 0.25053367, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 3.07277966, 1.61558151, 1.05362725, 0.74807048, 0.54755926, 0.43325692, 0.34370604, 0.27464288, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 3.07277966, 1.72759056, 1.12534678, 0.803307, 0.59516323, 0.45573691, 0.36617002, 0.29807833, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 3.07277966, 1.72759056, 1.12534678, 0.803307, 0.59516323, 0.4783645, 0.38853383, 0.32104823, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.45070267, 1.51179266, 1.01931262, 0.74807048, 0.57119018, 0.45573691, 0.36617002, 0.32104823, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.6383388, 1.61558151, 1.08895338, 0.803307, 0.61951244, 0.50118381, 0.41087446, 0.34370604, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.6383388, 1.61558151, 1.08895338, 0.803307, 0.64427125, 0.52423614, 0.43325692, 0.36617002, 0.32104823, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 5.85520077, 2.6383388, 1.61558151, 1.08895338, 0.803307, 0.64427125, 0.52423614, 0.45573691, 0.38853383, 0.34370604, 0.32104823, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - ], - 1.40: [ - [14.61464119, 0.59516323, 0.02916753], - [14.61464119, 0.95350921, 0.34370604, 0.02916753], - [14.61464119, 1.08895338, 0.43325692, 0.13792117, 0.02916753], - [14.61464119, 1.56271636, 0.64427125, 0.27464288, 0.09824532, 0.02916753], - [14.61464119, 1.61558151, 0.803307, 0.43325692, 0.22545385, 0.09824532, 0.02916753], - [14.61464119, 2.05039096, 0.95350921, 0.54755926, 0.34370604, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 2.45070267, 1.24153244, 0.72133851, 0.43325692, 0.27464288, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 2.45070267, 1.24153244, 0.74807048, 0.50118381, 0.34370604, 0.25053367, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 2.45070267, 1.28281462, 0.803307, 0.52423614, 0.36617002, 0.27464288, 0.19894916, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.45070267, 1.28281462, 0.803307, 0.54755926, 0.38853383, 0.29807833, 0.22545385, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.41535246, 0.86115354, 0.59516323, 0.43325692, 0.32104823, 0.25053367, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.51179266, 0.95350921, 0.64427125, 0.45573691, 0.34370604, 0.27464288, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.51179266, 0.95350921, 0.64427125, 0.4783645, 0.36617002, 0.29807833, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.56271636, 0.98595673, 0.69515091, 0.52423614, 0.41087446, 0.34370604, 0.29807833, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.56271636, 1.01931262, 0.72133851, 0.54755926, 0.43325692, 0.36617002, 0.32104823, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.61558151, 1.05362725, 0.74807048, 0.57119018, 0.45573691, 0.38853383, 0.34370604, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.61558151, 1.08895338, 0.803307, 0.61951244, 0.50118381, 0.41087446, 0.36617002, 0.32104823, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.61558151, 1.08895338, 0.803307, 0.61951244, 0.50118381, 0.43325692, 0.38853383, 0.34370604, 0.32104823, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.61558151, 1.08895338, 0.803307, 0.64427125, 0.52423614, 0.45573691, 0.41087446, 0.36617002, 0.34370604, 0.32104823, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - ], - 1.45: [ - [14.61464119, 0.59516323, 0.02916753], - [14.61464119, 0.803307, 0.25053367, 0.02916753], - [14.61464119, 0.95350921, 0.34370604, 0.09824532, 0.02916753], - [14.61464119, 1.24153244, 0.54755926, 0.25053367, 0.09824532, 0.02916753], - [14.61464119, 1.56271636, 0.72133851, 0.36617002, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 1.61558151, 0.803307, 0.45573691, 0.27464288, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 1.91321158, 0.95350921, 0.57119018, 0.36617002, 0.25053367, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 2.19988537, 1.08895338, 0.64427125, 0.41087446, 0.27464288, 0.19894916, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.45070267, 1.24153244, 0.74807048, 0.50118381, 0.34370604, 0.25053367, 0.19894916, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.45070267, 1.24153244, 0.74807048, 0.50118381, 0.36617002, 0.27464288, 0.22545385, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.45070267, 1.28281462, 0.803307, 0.54755926, 0.41087446, 0.32104823, 0.25053367, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.45070267, 1.28281462, 0.803307, 0.57119018, 0.43325692, 0.34370604, 0.27464288, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.45070267, 1.28281462, 0.83188516, 0.59516323, 0.45573691, 0.36617002, 0.29807833, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.45070267, 1.28281462, 0.83188516, 0.59516323, 0.45573691, 0.36617002, 0.32104823, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.51179266, 0.95350921, 0.69515091, 0.52423614, 0.41087446, 0.34370604, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.51179266, 0.95350921, 0.69515091, 0.52423614, 0.43325692, 0.36617002, 0.32104823, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.56271636, 0.98595673, 0.72133851, 0.54755926, 0.45573691, 0.38853383, 0.34370604, 0.32104823, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.56271636, 1.01931262, 0.74807048, 0.57119018, 0.4783645, 0.41087446, 0.36617002, 0.34370604, 0.32104823, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.84484982, 1.56271636, 1.01931262, 0.74807048, 0.59516323, 0.50118381, 0.43325692, 0.38853383, 0.36617002, 0.34370604, 0.32104823, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - ], - 1.50: [ - [14.61464119, 0.54755926, 0.02916753], - [14.61464119, 0.803307, 0.25053367, 0.02916753], - [14.61464119, 0.86115354, 0.32104823, 0.09824532, 0.02916753], - [14.61464119, 1.24153244, 0.54755926, 0.25053367, 0.09824532, 0.02916753], - [14.61464119, 1.56271636, 0.72133851, 0.36617002, 0.19894916, 0.09824532, 0.02916753], - [14.61464119, 1.61558151, 0.803307, 0.45573691, 0.27464288, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 1.61558151, 0.83188516, 0.52423614, 0.34370604, 0.25053367, 0.17026083, 0.09824532, 0.02916753], - [14.61464119, 1.84880662, 0.95350921, 0.59516323, 0.38853383, 0.27464288, 0.19894916, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 1.84880662, 0.95350921, 0.59516323, 0.41087446, 0.29807833, 0.22545385, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 1.84880662, 0.95350921, 0.61951244, 0.43325692, 0.32104823, 0.25053367, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.19988537, 1.12534678, 0.72133851, 0.50118381, 0.36617002, 0.27464288, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.19988537, 1.12534678, 0.72133851, 0.50118381, 0.36617002, 0.29807833, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.36326075, 1.24153244, 0.803307, 0.57119018, 0.43325692, 0.34370604, 0.29807833, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.36326075, 1.24153244, 0.803307, 0.57119018, 0.43325692, 0.34370604, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.36326075, 1.24153244, 0.803307, 0.59516323, 0.45573691, 0.36617002, 0.32104823, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.36326075, 1.24153244, 0.803307, 0.59516323, 0.45573691, 0.38853383, 0.34370604, 0.32104823, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.45070267, 1.32549286, 0.86115354, 0.64427125, 0.50118381, 0.41087446, 0.36617002, 0.34370604, 0.32104823, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.45070267, 1.36964464, 0.92192322, 0.69515091, 0.54755926, 0.45573691, 0.41087446, 0.36617002, 0.34370604, 0.32104823, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - [14.61464119, 2.45070267, 1.41535246, 0.95350921, 0.72133851, 0.57119018, 0.4783645, 0.43325692, 0.38853383, 0.36617002, 0.34370604, 0.32104823, 0.29807833, 0.27464288, 0.25053367, 0.22545385, 0.19894916, 0.17026083, 0.13792117, 0.09824532, 0.02916753], - ], -} - - -class GITSScheduler(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="GITSScheduler_V3", - category="sampling/custom_sampling/schedulers", - inputs=[ - io.Float.Input("coeff", default=1.20, min=0.80, max=1.50, step=0.05), - io.Int.Input("steps", default=10, min=2, max=1000), - io.Float.Input("denoise", default=1.0, min=0.0, max=1.0, step=0.01), - ], - outputs=[ - io.Sigmas.Output(), - ], - ) - - @classmethod - def execute(cls, coeff, steps, denoise): - total_steps = steps - if denoise < 1.0: - if denoise <= 0.0: - return io.NodeOutput(torch.FloatTensor([])) - total_steps = round(steps * denoise) - - if steps <= 20: - sigmas = NOISE_LEVELS[round(coeff, 2)][steps-2][:] - else: - sigmas = NOISE_LEVELS[round(coeff, 2)][-1][:] - sigmas = loglinear_interp(sigmas, steps + 1) - - sigmas = sigmas[-(total_steps + 1):] - sigmas[-1] = 0 - return io.NodeOutput(torch.FloatTensor(sigmas)) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - GITSScheduler, -] diff --git a/comfy_extras/v3/nodes_hidream.py b/comfy_extras/v3/nodes_hidream.py deleted file mode 100644 index a7c733774..000000000 --- a/comfy_extras/v3/nodes_hidream.py +++ /dev/null @@ -1,71 +0,0 @@ -from __future__ import annotations - -import comfy.model_management -import comfy.sd -import folder_paths -from comfy_api.latest import io - - -class QuadrupleCLIPLoader(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="QuadrupleCLIPLoader_V3", - category="advanced/loaders", - description="[Recipes]\n\nhidream: long clip-l, long clip-g, t5xxl, llama_8b_3.1_instruct", - inputs=[ - io.Combo.Input("clip_name1", options=folder_paths.get_filename_list("text_encoders")), - io.Combo.Input("clip_name2", options=folder_paths.get_filename_list("text_encoders")), - io.Combo.Input("clip_name3", options=folder_paths.get_filename_list("text_encoders")), - io.Combo.Input("clip_name4", options=folder_paths.get_filename_list("text_encoders")), - ], - outputs=[ - io.Clip.Output(), - ] - ) - - @classmethod - def execute(cls, clip_name1, clip_name2, clip_name3, clip_name4): - clip_path1 = folder_paths.get_full_path_or_raise("text_encoders", clip_name1) - clip_path2 = folder_paths.get_full_path_or_raise("text_encoders", clip_name2) - clip_path3 = folder_paths.get_full_path_or_raise("text_encoders", clip_name3) - clip_path4 = folder_paths.get_full_path_or_raise("text_encoders", clip_name4) - return io.NodeOutput( - comfy.sd.load_clip( - ckpt_paths=[clip_path1, clip_path2, clip_path3, clip_path4], - embedding_directory=folder_paths.get_folder_paths("embeddings"), - ) - ) - - -class CLIPTextEncodeHiDream(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="CLIPTextEncodeHiDream_V3", - category="advanced/conditioning", - inputs=[ - io.Clip.Input("clip"), - io.String.Input("clip_l", multiline=True, dynamic_prompts=True), - io.String.Input("clip_g", multiline=True, dynamic_prompts=True), - io.String.Input("t5xxl", multiline=True, dynamic_prompts=True), - io.String.Input("llama", multiline=True, dynamic_prompts=True), - ], - outputs=[ - io.Conditioning.Output(), - ] - ) - - @classmethod - def execute(cls, clip, clip_l, clip_g, t5xxl, llama): - tokens = clip.tokenize(clip_g) - tokens["l"] = clip.tokenize(clip_l)["l"] - tokens["t5xxl"] = clip.tokenize(t5xxl)["t5xxl"] - tokens["llama"] = clip.tokenize(llama)["llama"] - return io.NodeOutput(clip.encode_from_tokens_scheduled(tokens)) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - CLIPTextEncodeHiDream, - QuadrupleCLIPLoader, -] diff --git a/comfy_extras/v3/nodes_hunyuan.py b/comfy_extras/v3/nodes_hunyuan.py deleted file mode 100644 index 4ad737d7b..000000000 --- a/comfy_extras/v3/nodes_hunyuan.py +++ /dev/null @@ -1,169 +0,0 @@ -from __future__ import annotations - -import torch - -import comfy.model_management -import node_helpers -import nodes -from comfy_api.latest import io - - -class CLIPTextEncodeHunyuanDiT(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="CLIPTextEncodeHunyuanDiT_V3", - category="advanced/conditioning", - inputs=[ - io.Clip.Input("clip"), - io.String.Input("bert", multiline=True, dynamic_prompts=True), - io.String.Input("mt5xl", multiline=True, dynamic_prompts=True), - ], - outputs=[ - io.Conditioning.Output(), - ], - ) - - @classmethod - def execute(cls, clip, bert, mt5xl): - tokens = clip.tokenize(bert) - tokens["mt5xl"] = clip.tokenize(mt5xl)["mt5xl"] - - return io.NodeOutput(clip.encode_from_tokens_scheduled(tokens)) - - -class EmptyHunyuanLatentVideo(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="EmptyHunyuanLatentVideo_V3", - category="latent/video", - inputs=[ - io.Int.Input("width", default=848, min=16, max=nodes.MAX_RESOLUTION, step=16), - io.Int.Input("height", default=480, min=16, max=nodes.MAX_RESOLUTION, step=16), - io.Int.Input("length", default=25, min=1, max=nodes.MAX_RESOLUTION, step=4), - io.Int.Input("batch_size", default=1, min=1, max=4096), - ], - outputs=[ - io.Latent.Output(), - ], - ) - - @classmethod - def execute(cls, width, height, length, batch_size): - latent = torch.zeros( - [batch_size, 16, ((length - 1) // 4) + 1, height // 8, width // 8], - device=comfy.model_management.intermediate_device(), - ) - return io.NodeOutput({"samples":latent}) - - -PROMPT_TEMPLATE_ENCODE_VIDEO_I2V = ( - "<|start_header_id|>system<|end_header_id|>\n\n\nDescribe the video by detailing the following aspects according to the reference image: " - "1. The main content and theme of the video." - "2. The color, shape, size, texture, quantity, text, and spatial relationships of the objects." - "3. Actions, events, behaviors temporal relationships, physical movement changes of the objects." - "4. background environment, light, style and atmosphere." - "5. camera angles, movements, and transitions used in the video:<|eot_id|>\n\n" - "<|start_header_id|>user<|end_header_id|>\n\n{}<|eot_id|>" - "<|start_header_id|>assistant<|end_header_id|>\n\n" -) - - -class TextEncodeHunyuanVideo_ImageToVideo(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="TextEncodeHunyuanVideo_ImageToVideo_V3", - category="advanced/conditioning", - inputs=[ - io.Clip.Input("clip"), - io.ClipVisionOutput.Input("clip_vision_output"), - io.String.Input("prompt", multiline=True, dynamic_prompts=True), - io.Int.Input( - "image_interleave", - default=2, - min=1, - max=512, - tooltip="How much the image influences things vs the text prompt. Higher number means more influence from the text prompt.", - ), - ], - outputs=[ - io.Conditioning.Output(), - ], - ) - - @classmethod - def execute(cls, clip, clip_vision_output, prompt, image_interleave): - tokens = clip.tokenize( - prompt, llama_template=PROMPT_TEMPLATE_ENCODE_VIDEO_I2V, - image_embeds=clip_vision_output.mm_projected, - image_interleave=image_interleave, - ) - return io.NodeOutput(clip.encode_from_tokens_scheduled(tokens)) - - -class HunyuanImageToVideo(io.ComfyNode): - @classmethod - def define_schema(cls): - return io.Schema( - node_id="HunyuanImageToVideo_V3", - category="conditioning/video_models", - inputs=[ - io.Conditioning.Input("positive"), - io.Vae.Input("vae"), - io.Int.Input("width", default=848, min=16, max=nodes.MAX_RESOLUTION, step=16), - io.Int.Input("height", default=480, min=16, max=nodes.MAX_RESOLUTION, step=16), - io.Int.Input("length", default=53, min=1, max=nodes.MAX_RESOLUTION, step=4), - io.Int.Input("batch_size", default=1, min=1, max=4096), - io.Combo.Input("guidance_type", options=["v1 (concat)", "v2 (replace)", "custom"]), - io.Image.Input("start_image", optional=True), - ], - outputs=[ - io.Conditioning.Output(display_name="positive"), - io.Latent.Output(display_name="latent"), - ], - ) - - @classmethod - def execute(cls, positive, vae, width, height, length, batch_size, guidance_type, start_image=None): - latent = torch.zeros( - [batch_size, 16, ((length - 1) // 4) + 1, height // 8, width // 8], - device=comfy.model_management.intermediate_device(), - ) - out_latent = {} - - if start_image is not None: - start_image = comfy.utils.common_upscale( - start_image[:length, :, :, :3].movedim(-1, 1), width, height, "bilinear", "center" - ).movedim(1, -1) - - concat_latent_image = vae.encode(start_image) - mask = torch.ones( - (1, 1, latent.shape[2], concat_latent_image.shape[-2], concat_latent_image.shape[-1]), - device=start_image.device, - dtype=start_image.dtype, - ) - mask[:, :, :((start_image.shape[0] - 1) // 4) + 1] = 0.0 - - if guidance_type == "v1 (concat)": - cond = {"concat_latent_image": concat_latent_image, "concat_mask": mask} - elif guidance_type == "v2 (replace)": - cond = {'guiding_frame_index': 0} - latent[:, :, :concat_latent_image.shape[2]] = concat_latent_image - out_latent["noise_mask"] = mask - elif guidance_type == "custom": - cond = {"ref_latent": concat_latent_image} - - positive = node_helpers.conditioning_set_values(positive, cond) - - out_latent["samples"] = latent - return io.NodeOutput(positive, out_latent) - - -NODES_LIST: list[type[io.ComfyNode]] = [ - CLIPTextEncodeHunyuanDiT, - EmptyHunyuanLatentVideo, - HunyuanImageToVideo, - TextEncodeHunyuanVideo_ImageToVideo, -] diff --git a/comfy_extras/v3/nodes_hunyuan3d.py b/comfy_extras/v3/nodes_hunyuan3d.py deleted file mode 100644 index a4594c4c2..000000000 --- a/comfy_extras/v3/nodes_hunyuan3d.py +++ /dev/null @@ -1,672 +0,0 @@ -from __future__ import annotations - -import json -import os -import struct - -import numpy as np -import torch - -import comfy.model_management -import folder_paths -from comfy.cli_args import args -from comfy.ldm.modules.diffusionmodules.mmdit import ( - get_1d_sincos_pos_embed_from_grid_torch, -) -from comfy_api.latest import io - - -class VOXEL: - def __init__(self, data): - self.data = data - - -class MESH: - def __init__(self, vertices, faces): - self.vertices = vertices - self.faces = faces - - -def voxel_to_mesh(voxels, threshold=0.5, device=None): - if device is None: - device = torch.device("cpu") - voxels = voxels.to(device) - - binary = (voxels > threshold).float() - padded = torch.nn.functional.pad(binary, (1, 1, 1, 1, 1, 1), 'constant', 0) - - D, H, W = binary.shape - - neighbors = torch.tensor([ - [0, 0, 1], - [0, 0, -1], - [0, 1, 0], - [0, -1, 0], - [1, 0, 0], - [-1, 0, 0] - ], device=device) - - z, y, x = torch.meshgrid( - torch.arange(D, device=device), - torch.arange(H, device=device), - torch.arange(W, device=device), - indexing='ij' - ) - voxel_indices = torch.stack([z.flatten(), y.flatten(), x.flatten()], dim=1) - - solid_mask = binary.flatten() > 0 - solid_indices = voxel_indices[solid_mask] - - corner_offsets = [ - torch.tensor([ - [0, 0, 1], [0, 1, 1], [1, 1, 1], [1, 0, 1] - ], device=device), - torch.tensor([ - [0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0] - ], device=device), - torch.tensor([ - [0, 1, 0], [1, 1, 0], [1, 1, 1], [0, 1, 1] - ], device=device), - torch.tensor([ - [0, 0, 0], [0, 0, 1], [1, 0, 1], [1, 0, 0] - ], device=device), - torch.tensor([ - [1, 0, 1], [1, 1, 1], [1, 1, 0], [1, 0, 0] - ], device=device), - torch.tensor([ - [0, 1, 0], [0, 1, 1], [0, 0, 1], [0, 0, 0] - ], device=device) - ] - - all_vertices = [] - all_indices = [] - - vertex_count = 0 - - for face_idx, offset in enumerate(neighbors): - neighbor_indices = solid_indices + offset - - padded_indices = neighbor_indices + 1 - - is_exposed = padded[ - padded_indices[:, 0], - padded_indices[:, 1], - padded_indices[:, 2] - ] == 0 - - if not is_exposed.any(): - continue - - exposed_indices = solid_indices[is_exposed] - - corners = corner_offsets[face_idx].unsqueeze(0) - - face_vertices = exposed_indices.unsqueeze(1) + corners - - all_vertices.append(face_vertices.reshape(-1, 3)) - - num_faces = exposed_indices.shape[0] - face_indices = torch.arange( - vertex_count, - vertex_count + 4 * num_faces, - device=device - ).reshape(-1, 4) - - all_indices.append(torch.stack([face_indices[:, 0], face_indices[:, 1], face_indices[:, 2]], dim=1)) - all_indices.append(torch.stack([face_indices[:, 0], face_indices[:, 2], face_indices[:, 3]], dim=1)) - - vertex_count += 4 * num_faces - - if len(all_vertices) > 0: - vertices = torch.cat(all_vertices, dim=0) - faces = torch.cat(all_indices, dim=0) - else: - vertices = torch.zeros((1, 3)) - faces = torch.zeros((1, 3)) - - v_min = 0 - v_max = max(voxels.shape) - - vertices = vertices - (v_min + v_max) / 2 - - scale = (v_max - v_min) / 2 - if scale > 0: - vertices = vertices / scale - - vertices = torch.fliplr(vertices) - return vertices, faces - -def voxel_to_mesh_surfnet(voxels, threshold=0.5, device=None): - if device is None: - device = torch.device("cpu") - voxels = voxels.to(device) - - D, H, W = voxels.shape - - padded = torch.nn.functional.pad(voxels, (1, 1, 1, 1, 1, 1), 'constant', 0) - z, y, x = torch.meshgrid( - torch.arange(D, device=device), - torch.arange(H, device=device), - torch.arange(W, device=device), - indexing='ij' - ) - cell_positions = torch.stack([z.flatten(), y.flatten(), x.flatten()], dim=1) - - corner_offsets = torch.tensor([ - [0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0], - [0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1] - ], device=device) - - corner_values = torch.zeros((cell_positions.shape[0], 8), device=device) - for c, (dz, dy, dx) in enumerate(corner_offsets): - corner_values[:, c] = padded[ - cell_positions[:, 0] + dz, - cell_positions[:, 1] + dy, - cell_positions[:, 2] + dx - ] - - corner_signs = corner_values > threshold - has_inside = torch.any(corner_signs, dim=1) - has_outside = torch.any(~corner_signs, dim=1) - contains_surface = has_inside & has_outside - - active_cells = cell_positions[contains_surface] - active_signs = corner_signs[contains_surface] - active_values = corner_values[contains_surface] - - if active_cells.shape[0] == 0: - return torch.zeros((0, 3), device=device), torch.zeros((0, 3), dtype=torch.long, device=device) - - edges = torch.tensor([ - [0, 1], [0, 2], [0, 4], [1, 3], - [1, 5], [2, 3], [2, 6], [3, 7], - [4, 5], [4, 6], [5, 7], [6, 7] - ], device=device) - - cell_vertices = {} - progress = comfy.utils.ProgressBar(100) - - for edge_idx, (e1, e2) in enumerate(edges): - progress.update(1) - crossing = active_signs[:, e1] != active_signs[:, e2] - if not crossing.any(): - continue - - cell_indices = torch.nonzero(crossing, as_tuple=True)[0] - - v1 = active_values[cell_indices, e1] - v2 = active_values[cell_indices, e2] - - t = torch.zeros_like(v1, device=device) - denom = v2 - v1 - valid = denom != 0 - t[valid] = (threshold - v1[valid]) / denom[valid] - t[~valid] = 0.5 - - p1 = corner_offsets[e1].float() - p2 = corner_offsets[e2].float() - - intersection = p1.unsqueeze(0) + t.unsqueeze(1) * (p2.unsqueeze(0) - p1.unsqueeze(0)) - - for i, point in zip(cell_indices.tolist(), intersection): - if i not in cell_vertices: - cell_vertices[i] = [] - cell_vertices[i].append(point) - - # Calculate the final vertices as the average of intersection points for each cell - vertices = [] - vertex_lookup = {} - - vert_progress_mod = round(len(cell_vertices)/50) - - for i, points in cell_vertices.items(): - if not i % vert_progress_mod: - progress.update(1) - - if points: - vertex = torch.stack(points).mean(dim=0) - vertex = vertex + active_cells[i].float() - vertex_lookup[tuple(active_cells[i].tolist())] = len(vertices) - vertices.append(vertex) - - if not vertices: - return torch.zeros((0, 3), device=device), torch.zeros((0, 3), dtype=torch.long, device=device) - - final_vertices = torch.stack(vertices) - - inside_corners_mask = active_signs - outside_corners_mask = ~active_signs - - inside_counts = inside_corners_mask.sum(dim=1, keepdim=True).float() - outside_counts = outside_corners_mask.sum(dim=1, keepdim=True).float() - - inside_pos = torch.zeros((active_cells.shape[0], 3), device=device) - outside_pos = torch.zeros((active_cells.shape[0], 3), device=device) - - for i in range(8): - mask_inside = inside_corners_mask[:, i].unsqueeze(1) - mask_outside = outside_corners_mask[:, i].unsqueeze(1) - inside_pos += corner_offsets[i].float().unsqueeze(0) * mask_inside - outside_pos += corner_offsets[i].float().unsqueeze(0) * mask_outside - - inside_pos /= inside_counts - outside_pos /= outside_counts - gradients = inside_pos - outside_pos - - pos_dirs = torch.tensor([ - [1, 0, 0], - [0, 1, 0], - [0, 0, 1] - ], device=device) - - cross_products = [ - torch.linalg.cross(pos_dirs[i].float(), pos_dirs[j].float()) - for i in range(3) for j in range(i+1, 3) - ] - - faces = [] - all_keys = set(vertex_lookup.keys()) - - face_progress_mod = round(len(active_cells)/38*3) - - for pair_idx, (i, j) in enumerate([(0,1), (0,2), (1,2)]): - dir_i = pos_dirs[i] - dir_j = pos_dirs[j] - cross_product = cross_products[pair_idx] - - ni_positions = active_cells + dir_i - nj_positions = active_cells + dir_j - diag_positions = active_cells + dir_i + dir_j - - alignments = torch.matmul(gradients, cross_product) - - valid_quads = [] - quad_indices = [] - - for idx, active_cell in enumerate(active_cells): - if not idx % face_progress_mod: - progress.update(1) - cell_key = tuple(active_cell.tolist()) - ni_key = tuple(ni_positions[idx].tolist()) - nj_key = tuple(nj_positions[idx].tolist()) - diag_key = tuple(diag_positions[idx].tolist()) - - if cell_key in all_keys and ni_key in all_keys and nj_key in all_keys and diag_key in all_keys: - v0 = vertex_lookup[cell_key] - v1 = vertex_lookup[ni_key] - v2 = vertex_lookup[nj_key] - v3 = vertex_lookup[diag_key] - - valid_quads.append((v0, v1, v2, v3)) - quad_indices.append(idx) - - for q_idx, (v0, v1, v2, v3) in enumerate(valid_quads): - cell_idx = quad_indices[q_idx] - if alignments[cell_idx] > 0: - faces.append(torch.tensor([v0, v1, v3], device=device, dtype=torch.long)) - faces.append(torch.tensor([v0, v3, v2], device=device, dtype=torch.long)) - else: - faces.append(torch.tensor([v0, v3, v1], device=device, dtype=torch.long)) - faces.append(torch.tensor([v0, v2, v3], device=device, dtype=torch.long)) - - if faces: - faces = torch.stack(faces) - else: - faces = torch.zeros((0, 3), dtype=torch.long, device=device) - - v_min = 0 - v_max = max(D, H, W) - - final_vertices = final_vertices - (v_min + v_max) / 2 - - scale = (v_max - v_min) / 2 - if scale > 0: - final_vertices = final_vertices / scale - - final_vertices = torch.fliplr(final_vertices) - - return final_vertices, faces - - -def save_glb(vertices, faces, filepath, metadata=None): - """ - Save PyTorch tensor vertices and faces as a GLB file without external dependencies. - - Parameters: - vertices: torch.Tensor of shape (N, 3) - The vertex coordinates - faces: torch.Tensor of shape (M, 3) - The face indices (triangle faces) - filepath: str - Output filepath (should end with .glb) - """ - - # Convert tensors to numpy arrays - vertices_np = vertices.cpu().numpy().astype(np.float32) - faces_np = faces.cpu().numpy().astype(np.uint32) - - vertices_buffer = vertices_np.tobytes() - indices_buffer = faces_np.tobytes() - - def pad_to_4_bytes(buffer): - padding_length = (4 - (len(buffer) % 4)) % 4 - return buffer + b'\x00' * padding_length - - vertices_buffer_padded = pad_to_4_bytes(vertices_buffer) - indices_buffer_padded = pad_to_4_bytes(indices_buffer) - - buffer_data = vertices_buffer_padded + indices_buffer_padded - - vertices_byte_length = len(vertices_buffer) - vertices_byte_offset = 0 - indices_byte_length = len(indices_buffer) - indices_byte_offset = len(vertices_buffer_padded) - - gltf = { - "asset": {"version": "2.0", "generator": "ComfyUI"}, - "buffers": [ - { - "byteLength": len(buffer_data) - } - ], - "bufferViews": [ - { - "buffer": 0, - "byteOffset": vertices_byte_offset, - "byteLength": vertices_byte_length, - "target": 34962 # ARRAY_BUFFER - }, - { - "buffer": 0, - "byteOffset": indices_byte_offset, - "byteLength": indices_byte_length, - "target": 34963 # ELEMENT_ARRAY_BUFFER - } - ], - "accessors": [ - { - "bufferView": 0, - "byteOffset": 0, - "componentType": 5126, # FLOAT - "count": len(vertices_np), - "type": "VEC3", - "max": vertices_np.max(axis=0).tolist(), - "min": vertices_np.min(axis=0).tolist() - }, - { - "bufferView": 1, - "byteOffset": 0, - "componentType": 5125, # UNSIGNED_INT - "count": faces_np.size, - "type": "SCALAR" - } - ], - "meshes": [ - { - "primitives": [ - { - "attributes": { - "POSITION": 0 - }, - "indices": 1, - "mode": 4 # TRIANGLES - } - ] - } - ], - "nodes": [ - { - "mesh": 0 - } - ], - "scenes": [ - { - "nodes": [0] - } - ], - "scene": 0 - } - - if metadata is not None: - gltf["asset"]["extras"] = metadata - - # Convert the JSON to bytes - gltf_json = json.dumps(gltf).encode('utf8') - - def pad_json_to_4_bytes(buffer): - padding_length = (4 - (len(buffer) % 4)) % 4 - return buffer + b' ' * padding_length - - gltf_json_padded = pad_json_to_4_bytes(gltf_json) - - # Create the GLB header - # Magic glTF - glb_header = struct.pack('<4sII', b'glTF', 2, 12 + 8 + len(gltf_json_padded) + 8 + len(buffer_data)) - - # Create JSON chunk header (chunk type 0) - json_chunk_header = struct.pack('