| from __future__ import annotations |
|
|
| """MG_SuperSimple: orchestrates a 1..4 step pipeline over CF -> CADE pairs. |
| |
| Step 1: CADE with the "Step 1" preset (denoise is forced to 1.0). |
| Steps 2..N: ControlFusion (CF) with the "Step N" preset, then CADE with the same "Step N" preset. |
| When custom=True: visible CADE controls (seed/steps/cfg/denoise/sampler/scheduler/clipseg_text) override the corresponding Step presets across all steps (Step 1 still uses denoise=1.0). |
| When custom=False: CADE values come from Step presets; node UI values are ignored. CF always uses its Step presets (kept minimal here). |
| Inputs: |
| |
| model/vae/latent/positive/negative: standard Comfy connectors |
| control_net: ControlNet module for CF (required) |
| reference_image/clip_vision: forwarded into CADE (optional) |
| Outputs: |
| |
| (LATENT, IMAGE) from the final executed step |
| """ |
|
|
|
|
| import torch |
|
|
| from .mg_cade25_easy import ComfyAdaptiveDetailEnhancer25 as _CADE |
| from .mg_controlfusion_easy import MG_ControlFusion as _CF |
| from .mg_cade25_easy import _sampler_names as _sampler_names |
| from .mg_cade25_easy import _scheduler_names as _scheduler_names |
| import comfy.model_management as model_management |
| from ..hard.mg_upscale_module import clear_gpu_and_ram_cache |
|
|
|
|
| class MG_SuperSimple: |
| CATEGORY = "MagicNodes/Easy" |
|
|
| @classmethod |
| def INPUT_TYPES(cls): |
| return { |
| "required": { |
| |
| "step_count": ("INT", {"default": 4, "min": 1, "max": 4, "tooltip": "Number of steps to run (1..4)."}), |
| "custom": ("BOOLEAN", {"default": False, "tooltip": "When enabled, CADE UI values below override Step presets across all steps (denoise on Step 1 is still forced to 1.0)."}), |
|
|
| |
| "model": ("MODEL", {}), |
| "positive": ("CONDITIONING", {}), |
| "negative": ("CONDITIONING", {}), |
| "vae": ("VAE", {}), |
| "latent": ("LATENT", {}), |
| "control_net": ("CONTROL_NET", {"tooltip": "ControlNet module used by ControlFusion."}), |
|
|
| |
| "seed": ("INT", {"default": 0, "min": 0, "max": 0xFFFFFFFFFFFFFFFF, "control_after_generate": True, "tooltip": "Seed 0 = SmartSeed (Sobol + light probe). Non-zero = fixed seed (deterministic)."}), |
| "steps": ("INT", {"default": 25, "min": 1, "max": 10000, "tooltip": "KSampler steps for CADE (applies to all steps)."}), |
| "cfg": ("FLOAT", {"default": 4.5, "min": 0.0, "max": 100.0, "step": 0.1}), |
| |
| "denoise": ("FLOAT", {"default": 0.65, "min": 0.35, "max": 0.9, "step": 0.0001}), |
| "sampler_name": (_sampler_names(), {"default": _sampler_names()[0]}), |
| "scheduler": (_scheduler_names(), {"default": "MGHybrid"}), |
| "clipseg_text": ("STRING", {"default": "hand, feet, face", "multiline": False, "tooltip": "Focus terms for CLIPSeg (comma-separated)."}), |
| }, |
| "optional": { |
| "reference_image": ("IMAGE", {}), |
| "clip_vision": ("CLIP_VISION", {}), |
| }, |
| } |
|
|
| RETURN_TYPES = ("LATENT", "IMAGE") |
| RETURN_NAMES = ("LATENT", "IMAGE") |
| FUNCTION = "run" |
|
|
| def _cade(self, |
| preset_step: str, |
| custom_override: bool, |
| model, vae, positive, negative, latent, |
| seed: int, steps: int, cfg: float, denoise: float, |
| sampler_name: str, scheduler: str, |
| clipseg_text: str, |
| reference_image=None, clip_vision=None): |
| |
| lat, img, _s, _c, _d, _mask = _CADE().apply_cade2( |
| model, vae, positive, negative, latent, |
| int(seed), int(steps), float(cfg), float(denoise), |
| str(sampler_name), str(scheduler), 0.0, |
| preset_step=str(preset_step), custom_override=bool(custom_override), |
| clipseg_text=str(clipseg_text), |
| reference_image=reference_image, clip_vision=clip_vision, |
| ) |
| return lat, img |
|
|
| def _cf(self, |
| preset_step: str, |
| image, positive, negative, control_net, vae): |
| |
| |
| pos, neg, _prev = _CF().apply( |
| image=image, positive=positive, negative=negative, |
| control_net=control_net, vae=vae, |
| preset_step=str(preset_step), custom_override=False, |
| ) |
| return pos, neg |
|
|
| def run(self, |
| step_count, custom, |
| model, positive, negative, vae, latent, control_net, |
| seed, steps, cfg, denoise, sampler_name, scheduler, clipseg_text, |
| reference_image=None, clip_vision=None): |
| |
| model_management.throw_exception_if_processing_interrupted() |
|
|
| |
| n = int(max(1, min(4, step_count))) |
|
|
| cur_latent = latent |
| cur_image = None |
| cur_pos = positive |
| cur_neg = negative |
|
|
| try: |
| |
| denoise_step1 = 1.0 |
| lat1, img1 = self._cade( |
| preset_step="Step 1", |
| custom_override=bool(custom), |
| model=model, vae=vae, positive=cur_pos, negative=cur_neg, latent=cur_latent, |
| seed=seed, steps=steps, cfg=cfg, denoise=denoise_step1, |
| sampler_name=sampler_name, scheduler=scheduler, |
| clipseg_text=clipseg_text, |
| reference_image=reference_image, clip_vision=clip_vision, |
| ) |
| cur_latent, cur_image = lat1, img1 |
|
|
| |
| for i in range(2, n + 1): |
| |
| model_management.throw_exception_if_processing_interrupted() |
| |
| cur_pos, cur_neg = self._cf( |
| preset_step=f"Step {i}", |
| image=cur_image, positive=cur_pos, negative=cur_neg, |
| control_net=control_net, vae=vae, |
| ) |
| |
| |
| |
| ref_img = reference_image if (reference_image is not None) else cur_image |
| lat_i, img_i = self._cade( |
| preset_step=f"Step {i}", |
| custom_override=bool(custom), |
| model=model, vae=vae, positive=cur_pos, negative=cur_neg, latent=cur_latent, |
| seed=seed, steps=steps, cfg=cfg, denoise=denoise, |
| sampler_name=sampler_name, scheduler=scheduler, |
| clipseg_text=clipseg_text, |
| reference_image=ref_img, clip_vision=clip_vision, |
| ) |
| cur_latent, cur_image = lat_i, img_i |
| return (cur_latent, cur_image) |
| finally: |
| |
| try: |
| clear_gpu_and_ram_cache() |
| except Exception: |
| pass |
|
|