Files
2023-08-29 20:59:10 +02:00

2254 lines
92 KiB
Python

"""
Custom nodes for SDXL in ComfyUI
MIT License
Copyright (c) 2023 Searge
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import datetime
import comfy.samplers
import comfy_extras.nodes_upscale_model
import comfy_extras.nodes_post_processing
import folder_paths
import json
import nodes
import numpy as np
import os
from comfy.cli_args import args
from datetime import datetime
from PIL import Image
from PIL.PngImagePlugin import PngInfo
# from ._experimental import SeargeSamplerAdvanced
from .custom_sdxl_ksampler import sdxl_ksampler
# ====================================================================================================
# SDXL Sampler with base and refiner support
# ====================================================================================================
class SeargeSDXLSampler:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"base_model": ("MODEL",),
"base_positive": ("CONDITIONING",),
"base_negative": ("CONDITIONING",),
"refiner_model": ("MODEL",),
"refiner_positive": ("CONDITIONING",),
"refiner_negative": ("CONDITIONING",),
"latent_image": ("LATENT",),
"noise_seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
"steps": ("INT", {"default": 30, "min": 1, "max": 1000}),
"cfg": ("FLOAT", {"default": 7.0, "min": 0.0, "max": 100.0, "step": 0.5}),
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, {"default": "dpmpp_2m"}),
"scheduler": (comfy.samplers.KSampler.SCHEDULERS, {"default": "karras"}),
"base_ratio": ("FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0, "step": 0.01}),
"denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
},
}
RETURN_TYPES = ("LATENT",)
RETURN_NAMES = ("",)
FUNCTION = "sample"
CATEGORY = "Searge/_deprecated_/Sampling"
def sample(self, base_model, base_positive, base_negative, refiner_model, refiner_positive, refiner_negative,
latent_image, noise_seed, steps, cfg, sampler_name, scheduler, base_ratio, denoise):
base_steps = int(steps * base_ratio)
if denoise < 0.01:
return (latent_image,)
if base_steps >= steps:
return nodes.common_ksampler(base_model, noise_seed, steps, cfg, sampler_name, scheduler, base_positive,
base_negative, latent_image, denoise=denoise, disable_noise=False,
start_step=0, last_step=steps, force_full_denoise=True)
base_result = nodes.common_ksampler(base_model, noise_seed, steps, cfg, sampler_name, scheduler, base_positive,
base_negative, latent_image, denoise=denoise, disable_noise=False,
start_step=0, last_step=base_steps, force_full_denoise=False)
return nodes.common_ksampler(refiner_model, noise_seed, steps, cfg, sampler_name, scheduler, refiner_positive,
refiner_negative, base_result[0], denoise=1.0, disable_noise=True,
start_step=base_steps, last_step=steps, force_full_denoise=True)
# ====================================================================================================
# SDXL Sampler with base and refiner support
# ====================================================================================================
class SeargeSDXLSamplerV3:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"base_model": ("MODEL",),
"base_positive": ("CONDITIONING",),
"base_negative": ("CONDITIONING",),
"refiner_model": ("MODEL",),
"refiner_positive": ("CONDITIONING",),
"refiner_negative": ("CONDITIONING",),
"latent_image": ("LATENT",),
"noise_seed": ("INT", {"default": 0, "min": 0, "max": 0xfffffffffffffff0}),
"steps": ("INT", {"default": 20, "min": 1, "max": 200}),
"cfg": ("FLOAT", {"default": 7.0, "min": 0.0, "max": 30.0, "step": 0.5}),
"sampler_name": ("SAMPLER_NAME", {"default": "ddim"}),
"scheduler": ("SCHEDULER_NAME", {"default": "ddim_uniform"}),
"base_ratio": ("FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0, "step": 0.01}),
"denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
},
"optional": {
"refiner_prep_steps": ("INT", {"default": 0, "min": 0, "max": 10}),
},
}
RETURN_TYPES = ("LATENT",)
FUNCTION = "sample"
CATEGORY = "Searge/_deprecated_/Sampling"
def sample(self, base_model, base_positive, base_negative, refiner_model, refiner_positive, refiner_negative,
latent_image, noise_seed, steps, cfg, sampler_name, scheduler, base_ratio, denoise,
refiner_prep_steps=None):
base_steps = int(steps * (base_ratio + 0.0001))
refiner_steps = max(0, steps - base_steps)
if denoise < 0.01:
return (latent_image,)
start_at_step = 0
input_latent = latent_image
if refiner_prep_steps is not None:
if refiner_prep_steps >= base_steps:
refiner_prep_steps = base_steps - 1
if refiner_prep_steps > 0:
start_at_step = refiner_prep_steps
precondition_result = nodes.common_ksampler(refiner_model, noise_seed + 2, steps, cfg, sampler_name,
scheduler, refiner_positive, refiner_negative,
latent_image, denoise=denoise, disable_noise=False,
start_step=steps - refiner_prep_steps, last_step=steps,
force_full_denoise=False)
input_latent = precondition_result[0]
if base_steps >= steps:
return nodes.common_ksampler(base_model, noise_seed, steps, cfg, sampler_name, scheduler, base_positive,
base_negative, input_latent, denoise=denoise, disable_noise=False,
start_step=start_at_step, last_step=steps, force_full_denoise=True)
return sdxl_ksampler(base_model, refiner_model, noise_seed, base_steps, refiner_steps, cfg, sampler_name,
scheduler, base_positive, base_negative, refiner_positive, refiner_negative, input_latent,
denoise=denoise, disable_noise=False, start_step=start_at_step, last_step=steps,
force_full_denoise=True)
# ====================================================================================================
# SDXL Image2Image Sampler (incl. HiRes Fix)
# ====================================================================================================
class SeargeSDXLImage2ImageSampler:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"base_model": ("MODEL",),
"base_positive": ("CONDITIONING",),
"base_negative": ("CONDITIONING",),
"refiner_model": ("MODEL",),
"refiner_positive": ("CONDITIONING",),
"refiner_negative": ("CONDITIONING",),
"image": ("IMAGE",),
"vae": ("VAE",),
"noise_seed": ("INT", {"default": 0, "min": 0, "max": 0xfffffffffffffff0}),
"steps": ("INT", {"default": 20, "min": 0, "max": 200}),
"cfg": ("FLOAT", {"default": 7.0, "min": 0.0, "max": 30.0, "step": 0.5}),
"sampler_name": ("SAMPLER_NAME", {"default": "ddim"}),
"scheduler": ("SCHEDULER_NAME", {"default": "ddim_uniform"}),
"base_ratio": ("FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0, "step": 0.01}),
"denoise": ("FLOAT", {"default": 0.25, "min": 0.0, "max": 1.0, "step": 0.01}),
},
"optional": {
"upscale_model": ("UPSCALE_MODEL",),
"scaled_width": ("INT", {"default": 1536, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"scaled_height": ("INT", {"default": 1536, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"noise_offset": ("INT", {"default": 1, "min": 0, "max": 1}),
"refiner_strength": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 1.0, "step": 0.05}),
"softness": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.05}),
},
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "sample"
CATEGORY = "Searge/_deprecated_/Sampling"
def sample(self, base_model, base_positive, base_negative, refiner_model, refiner_positive, refiner_negative,
image, vae, noise_seed, steps, cfg, sampler_name, scheduler, base_ratio, denoise, softness,
upscale_model=None, scaled_width=None, scaled_height=None, noise_offset=None, refiner_strength=None):
base_steps = int(steps * (base_ratio + 0.0001))
if noise_offset is None:
noise_offset = 1
if refiner_strength is None:
refiner_strength = 1.0
if refiner_strength < 0.01:
refiner_strength = 0.01
if steps < 1:
return (image,)
scaled_image = image
use_upscale_model = upscale_model is not None and softness < 0.9999
if use_upscale_model:
upscale_result = comfy_extras.nodes_upscale_model.ImageUpscaleWithModel().upscale(upscale_model, image)
scaled_image = upscale_result[0]
if scaled_width is not None and scaled_height is not None:
upscale_result = nodes.ImageScale().upscale(scaled_image, "bicubic", scaled_width,
scaled_height, "center")
scaled_image = upscale_result[0]
if use_upscale_model and softness > 0.0001:
upscale_result = nodes.ImageScale().upscale(image, "bicubic", scaled_width, scaled_height,
"center")
scaled_original = upscale_result[0]
blend_result = comfy_extras.nodes_post_processing.Blend().blend_images(scaled_image, scaled_original,
softness, "normal")
scaled_image = blend_result[0]
if denoise < 0.01:
return (scaled_image,)
vae_encode_result = nodes.VAEEncode().encode(vae, scaled_image)
input_latent = vae_encode_result[0]
if base_steps >= steps:
result_latent = nodes.common_ksampler(base_model, noise_seed, steps, cfg, sampler_name, scheduler,
base_positive, base_negative, input_latent, denoise=denoise,
disable_noise=False, start_step=0, last_step=steps,
force_full_denoise=True)
else:
base_result = nodes.common_ksampler(base_model, noise_seed, steps, cfg, sampler_name, scheduler,
base_positive, base_negative, input_latent, denoise=denoise,
disable_noise=False, start_step=0, last_step=base_steps,
force_full_denoise=True)
result_latent = nodes.common_ksampler(refiner_model, noise_seed + noise_offset, steps, cfg, sampler_name,
scheduler, refiner_positive, refiner_negative, base_result[0],
denoise=denoise * refiner_strength, disable_noise=False,
start_step=base_steps, last_step=steps, force_full_denoise=True)
vae_decode_result = nodes.VAEDecode().decode(vae, result_latent[0])
output_image = vae_decode_result[0]
return (output_image,)
# ====================================================================================================
# SDXL Sampler with base and refiner support
# ====================================================================================================
class SeargeSDXLSampler2:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"base_model": ("MODEL",),
"base_positive": ("CONDITIONING",),
"base_negative": ("CONDITIONING",),
"refiner_model": ("MODEL",),
"refiner_positive": ("CONDITIONING",),
"refiner_negative": ("CONDITIONING",),
"latent_image": ("LATENT",),
"noise_seed": ("INT", {"default": 0, "min": 0, "max": 0xfffffffffffffff0}),
"steps": ("INT", {"default": 20, "min": 1, "max": 200}),
"cfg": ("FLOAT", {"default": 7.0, "min": 0.0, "max": 30.0, "step": 0.5}),
"sampler_name": ("SAMPLER_NAME", {"default": "ddim"}),
"scheduler": ("SCHEDULER_NAME", {"default": "ddim_uniform"}),
"base_ratio": ("FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0, "step": 0.01}),
"denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
},
"optional": {
"refiner_prep_steps": ("INT", {"default": 0, "min": 0, "max": 10}),
"noise_offset": ("INT", {"default": 1, "min": 0, "max": 1}),
"refiner_strength": ("FLOAT", {"default": 1.0, "min": 0.01, "max": 1.0, "step": 0.05}),
},
}
RETURN_TYPES = ("LATENT",)
FUNCTION = "sample"
CATEGORY = "Searge/_deprecated_/Sampling"
def sample(self, base_model, base_positive, base_negative, refiner_model, refiner_positive, refiner_negative,
latent_image, noise_seed, steps, cfg, sampler_name, scheduler, base_ratio, denoise,
refiner_prep_steps=None, noise_offset=None, refiner_strength=None):
base_steps = int(steps * (base_ratio + 0.0001))
if noise_offset is None:
noise_offset = 1
if refiner_strength is None:
refiner_strength = 1.0
if refiner_strength < 0.01:
refiner_strength = 0.01
if denoise < 0.01:
return (latent_image,)
start_at_step = 0
input_latent = latent_image
if refiner_prep_steps is not None:
if refiner_prep_steps >= base_steps:
refiner_prep_steps = base_steps - 1
if refiner_prep_steps > 0:
start_at_step = refiner_prep_steps
precondition_result = nodes.common_ksampler(refiner_model, noise_seed + 2, steps, cfg, sampler_name,
scheduler, refiner_positive, refiner_negative,
latent_image, denoise=denoise, disable_noise=False,
start_step=steps - refiner_prep_steps, last_step=steps,
force_full_denoise=False)
input_latent = precondition_result[0]
if base_steps >= steps:
return nodes.common_ksampler(base_model, noise_seed, steps, cfg, sampler_name, scheduler, base_positive,
base_negative, input_latent, denoise=denoise, disable_noise=False,
start_step=start_at_step, last_step=steps, force_full_denoise=True)
base_result = nodes.common_ksampler(base_model, noise_seed, steps, cfg, sampler_name, scheduler, base_positive,
base_negative, input_latent, denoise=denoise, disable_noise=False,
start_step=start_at_step, last_step=base_steps, force_full_denoise=True)
return nodes.common_ksampler(refiner_model, noise_seed + noise_offset, steps, cfg, sampler_name, scheduler,
refiner_positive, refiner_negative, base_result[0],
denoise=denoise * refiner_strength, disable_noise=False, start_step=base_steps,
last_step=steps, force_full_denoise=True)
# ====================================================================================================
# SDXL Image2Image Sampler (incl. HiRes Fix)
# ====================================================================================================
class SeargeSDXLImage2ImageSampler2:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"base_model": ("MODEL",),
"base_positive": ("CONDITIONING",),
"base_negative": ("CONDITIONING",),
"refiner_model": ("MODEL",),
"refiner_positive": ("CONDITIONING",),
"refiner_negative": ("CONDITIONING",),
"image": ("IMAGE",),
"vae": ("VAE",),
"noise_seed": ("INT", {"default": 0, "min": 0, "max": 0xfffffffffffffff0}),
"steps": ("INT", {"default": 20, "min": 0, "max": 200}),
"cfg": ("FLOAT", {"default": 7.0, "min": 0.0, "max": 30.0, "step": 0.5}),
"sampler_name": ("SAMPLER_NAME", {"default": "ddim"}),
"scheduler": ("SCHEDULER_NAME", {"default": "ddim_uniform"}),
"base_ratio": ("FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0, "step": 0.01}),
"denoise": ("FLOAT", {"default": 0.25, "min": 0.0, "max": 1.0, "step": 0.01}),
},
"optional": {
"upscale_model": ("UPSCALE_MODEL",),
"scaled_width": ("INT", {"default": 1536, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"scaled_height": ("INT", {"default": 1536, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"noise_offset": ("INT", {"default": 1, "min": 0, "max": 1}),
"refiner_strength": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 1.0, "step": 0.05}),
"softness": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.05}),
},
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "sample"
CATEGORY = "Searge/_deprecated_/Sampling"
def sample(self, base_model, base_positive, base_negative, refiner_model, refiner_positive, refiner_negative,
image, vae, noise_seed, steps, cfg, sampler_name, scheduler, base_ratio, denoise, softness,
upscale_model=None, scaled_width=None, scaled_height=None, noise_offset=None, refiner_strength=None):
base_steps = int(steps * (base_ratio + 0.0001))
if noise_offset is None:
noise_offset = 1
if refiner_strength is None:
refiner_strength = 1.0
if refiner_strength < 0.01:
refiner_strength = 0.01
if steps < 1:
return (image,)
scaled_image = image
use_upscale_model = upscale_model is not None and softness < 0.9999
if use_upscale_model:
upscale_result = comfy_extras.nodes_upscale_model.ImageUpscaleWithModel().upscale(upscale_model, image)
scaled_image = upscale_result[0]
if scaled_width is not None and scaled_height is not None:
upscale_result = nodes.ImageScale().upscale(scaled_image, "bicubic", scaled_width,
scaled_height, "center")
scaled_image = upscale_result[0]
if use_upscale_model and softness > 0.0001:
upscale_result = nodes.ImageScale().upscale(image, "bicubic", scaled_width, scaled_height,
"center")
scaled_original = upscale_result[0]
blend_result = comfy_extras.nodes_post_processing.Blend().blend_images(scaled_image, scaled_original,
softness, "normal")
scaled_image = blend_result[0]
if denoise < 0.01:
return (scaled_image,)
vae_encode_result = nodes.VAEEncode().encode(vae, scaled_image)
input_latent = vae_encode_result[0]
if base_steps >= steps:
result_latent = nodes.common_ksampler(base_model, noise_seed, steps, cfg, sampler_name, scheduler,
base_positive, base_negative, input_latent, denoise=denoise,
disable_noise=False, start_step=0, last_step=steps,
force_full_denoise=True)
else:
base_result = nodes.common_ksampler(base_model, noise_seed, steps, cfg, sampler_name, scheduler,
base_positive, base_negative, input_latent, denoise=denoise,
disable_noise=False, start_step=0, last_step=base_steps,
force_full_denoise=True)
result_latent = nodes.common_ksampler(refiner_model, noise_seed + noise_offset, steps, cfg, sampler_name,
scheduler, refiner_positive, refiner_negative, base_result[0],
denoise=denoise * refiner_strength, disable_noise=False,
start_step=base_steps, last_step=steps, force_full_denoise=True)
vae_decode_result = nodes.VAEDecode().decode(vae, result_latent[0])
output_image = vae_decode_result[0]
return (output_image,)
# ====================================================================================================
# UI: Parameter Processor
# ====================================================================================================
class SeargeParameterProcessor:
# hard - refiner uses same seed as base | soft - refiner uses different seed from base
REFINER_INTENSITY = ["hard", "soft"]
# same - HRF uses same seed as image generation | distinct - HRF uses different seed than image generation
HRF_SEED_OFFSET = ["same", "distinct"]
# simple "boolean"-like type
STATES = ["disabled", "enabled"]
# operating modes, determine if the latent source is empty or from a source image, inpainting also uses mask
OPERATION_MODE = ["text to image", "image to image", "inpainting"]
# sorted from easy-to-use to harder-to-use
PROMPT_STYLE = ["simple", "3 prompts G+L-N", "subject focus", "style focus", "weighted", "overlay",
"subject - style", "style - subject", "style only", "weighted - overlay", "overlay - weighted"]
# (work in progress)
STYLE_TEMPLATE = ["none", "from preprocessor", "test"]
# save folder for generated images
SAVE_TO = ["output folder", "input folder"]
@classmethod
def INPUT_TYPES(s):
return {"required": {
"inputs": ("PARAMETER_INPUTS",),
},
}
RETURN_TYPES = ("PARAMETERS",)
RETURN_NAMES = ("parameters",)
FUNCTION = "process"
CATEGORY = "Searge/_deprecated_/UI"
def process(self, inputs):
if inputs is None:
parameters = {}
else:
parameters = inputs
if parameters["denoise"] is None:
parameters["denoise"] = 1.0
saturation = parameters["refiner_intensity"]
if saturation is not None:
# "soft"
if saturation == SeargeParameterProcessor.REFINER_INTENSITY[1]:
parameters["noise_offset"] = 1
# incl. SeargeParameterProcessor.REFINER_INTENSITY[1] -> "hard"
else:
parameters["noise_offset"] = 0
hires_fix = parameters["hires_fix"]
# "disabled"
if hires_fix is not None and hires_fix == SeargeParameterProcessor.STATES[0]:
parameters["hrf_steps"] = 0
hrf_saturation = parameters["hrf_intensity"]
if hrf_saturation is not None:
# "soft"
if hrf_saturation == SeargeParameterProcessor.REFINER_INTENSITY[1]:
parameters["hrf_noise_offset"] = 1
# incl. SeargeParameterProcessor.REFINER_INTENSITY[0] -> "hard"
else:
parameters["hrf_noise_offset"] = 0
seed_offset = parameters["hrf_seed_offset"]
if seed_offset is not None:
seed = parameters["seed"] if parameters["seed"] is not None else 0
# "distinct"
if seed_offset == SeargeParameterProcessor.HRF_SEED_OFFSET[1]:
parameters["hrf_seed"] = seed + 3
# incl. SeargeParameterProcessor.HRF_SEED_OFFSET[0] -> "same"
else:
parameters["hrf_seed"] = seed
style_template = parameters["style_template"]
if style_template is not None:
# "from preprocessor"
if style_template == SeargeParameterProcessor.STYLE_TEMPLATE[1]:
# this does nothing here, but will be used in the preprocessor
pass
# "test"
if style_template == SeargeParameterProcessor.STYLE_TEMPLATE[2]:
if parameters["noise_offset"] is not None:
parameters["noise_offset"] = 1 - parameters["hrf_noise_offset"]
if parameters["hrf_noise_offset"] is not None:
parameters["hrf_noise_offset"] = 1 - parameters["hrf_noise_offset"]
# incl. SeargeParameterProcessor.STYLE_TEMPLATE[0] -> "none"
else:
# TODO: apply style based on its name here...
pass
operation_mode = parameters["operation_mode"]
if operation_mode is not None:
# "image to image":
if operation_mode == SeargeParameterProcessor.OPERATION_MODE[1]:
parameters["operation_selector"] = 1
# "inpainting":
elif operation_mode == SeargeParameterProcessor.OPERATION_MODE[2]:
parameters["operation_selector"] = 2
# incl. SeargeParameterProcessor.OPERATION_MODE[0] -> "text to image":
else:
parameters["operation_selector"] = 0
# always fully denoise in img2img mode
parameters["denoise"] = 1.0
prompt_style = parameters["prompt_style"]
if prompt_style is not None:
# "simple"
if prompt_style == SeargeParameterProcessor.PROMPT_STYLE[0]:
parameters["prompt_style_selector"] = 0
parameters["prompt_style_group"] = 0
main_prompt = parameters["main_prompt"]
parameters["secondary_prompt"] = main_prompt
parameters["style_prompt"] = ""
parameters["negative_style"] = ""
# "subject focus"
elif prompt_style == SeargeParameterProcessor.PROMPT_STYLE[2]:
parameters["prompt_style_selector"] = 1
parameters["prompt_style_group"] = 0
# "style focus"
elif prompt_style == SeargeParameterProcessor.PROMPT_STYLE[3]:
parameters["prompt_style_selector"] = 2
parameters["prompt_style_group"] = 0
# "weighted"
elif prompt_style == SeargeParameterProcessor.PROMPT_STYLE[4]:
parameters["prompt_style_selector"] = 3
parameters["prompt_style_group"] = 0
# "overlay"
elif prompt_style == SeargeParameterProcessor.PROMPT_STYLE[5]:
parameters["prompt_style_selector"] = 4
parameters["prompt_style_group"] = 0
# "subject - style"
elif prompt_style == SeargeParameterProcessor.PROMPT_STYLE[6]:
parameters["prompt_style_selector"] = 0
parameters["prompt_style_group"] = 1
# "style - subject"
elif prompt_style == SeargeParameterProcessor.PROMPT_STYLE[7]:
parameters["prompt_style_selector"] = 1
parameters["prompt_style_group"] = 1
# "style only"
elif prompt_style == SeargeParameterProcessor.PROMPT_STYLE[8]:
parameters["prompt_style_selector"] = 2
parameters["prompt_style_group"] = 1
# "weighted - overlay"
elif prompt_style == SeargeParameterProcessor.PROMPT_STYLE[9]:
parameters["prompt_style_selector"] = 3
parameters["prompt_style_group"] = 1
# "overlay - weighted"
elif prompt_style == SeargeParameterProcessor.PROMPT_STYLE[10]:
parameters["prompt_style_selector"] = 4
parameters["prompt_style_group"] = 1
# incl. SeargeParameterProcessor.PROMPT_STYLE[1] -> "3 prompts G+L-N"
else:
parameters["prompt_style_selector"] = 0
parameters["prompt_style_group"] = 0
parameters["style_prompt"] = ""
parameters["negative_style"] = ""
# TODO: replace this special logic and the dirty hacks by creating new generated parameters for saving
save_image = parameters["save_image"]
if save_image is not None:
# "disabled"
if save_image == SeargeParameterProcessor.STATES[0]:
# when image saving is disabled, we also don't want to save the upscaled image, even if that's enabled
parameters["save_upscaled_image"] = SeargeParameterProcessor.STATES[0]
# HACK: this is a bit dirty, but the variable hires_fix determines if the image should be saved
# but when image saving is disabled, we don't want that to happen
parameters["hires_fix"] = SeargeParameterProcessor.STATES[0]
# "enabled"
else:
# in case we are saving to the input folder, we need to enable saving after the hires fix, even
# if that's disabled in the settings
if parameters["save_directory"] == SeargeParameterProcessor.SAVE_TO[1]:
parameters["hires_fix"] = SeargeParameterProcessor.STATES[1]
return (parameters,)
# ====================================================================================================
# UI: Style Processor
# ====================================================================================================
class SeargeStylePreprocessor:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"inputs": ("PARAMETER_INPUTS",),
"active_style_name": ("STRING", {"multiline": False, "default": ""}),
"style_definitions": ("STRING", {"multiline": True, "default": "[unfinished work in progress]"}),
},
}
RETURN_TYPES = ("PARAMETER_INPUTS",)
RETURN_NAMES = ("inputs",)
FUNCTION = "process"
CATEGORY = "Searge/_deprecated_/UI"
def process(self, inputs, active_style_name, style_definitions):
if inputs is None:
inputs = {}
style_template = inputs["style_template"]
# not "from preprocessor"
if style_template is None or style_template != SeargeParameterProcessor.STYLE_TEMPLATE[1]:
return (inputs,)
# TODO: do what needs to be done to apply the selected style
return (inputs,)
# ====================================================================================================
# UI: Prompt Inputs
# ====================================================================================================
class SeargeInput1:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"main_prompt": ("STRING", {"multiline": True, "default": ""}),
"secondary_prompt": ("STRING", {"multiline": True, "default": ""}),
"style_prompt": ("STRING", {"multiline": True, "default": ""}),
"negative_prompt": ("STRING", {"multiline": True, "default": ""}),
"negative_style": ("STRING", {"multiline": True, "default": ""}),
},
"optional": {
"inputs": ("PARAMETER_INPUTS",),
"image": ("IMAGE",),
"mask": ("MASK",),
},
}
RETURN_TYPES = ("PARAMETER_INPUTS",)
RETURN_NAMES = ("inputs",)
FUNCTION = "mux"
CATEGORY = "Searge/_deprecated_/UI/Inputs"
def mux(self, main_prompt, secondary_prompt, style_prompt, negative_prompt, negative_style, inputs=None,
image=None, mask=None):
if inputs is None:
parameters = {}
else:
parameters = inputs
parameters["main_prompt"] = main_prompt
parameters["secondary_prompt"] = secondary_prompt
parameters["style_prompt"] = style_prompt
parameters["negative_prompt"] = negative_prompt
parameters["negative_style"] = negative_style
parameters["image"] = image
parameters["mask"] = mask
return (parameters,)
# ====================================================================================================
# UI: Generation Parameters Input
# ====================================================================================================
class SeargeInput2:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
"image_width": ("INT", {"default": 1024, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"image_height": ("INT", {"default": 1024, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"steps": ("INT", {"default": 20, "min": 0, "max": 200}),
"cfg": ("FLOAT", {"default": 7.0, "min": 0.0, "max": 30.0, "step": 0.5}),
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, {"default": "ddim"}),
"scheduler": (comfy.samplers.KSampler.SCHEDULERS, {"default": "ddim_uniform"}),
"save_image": (SeargeParameterProcessor.STATES, {"default": SeargeParameterProcessor.STATES[1]}),
"save_directory": (SeargeParameterProcessor.SAVE_TO,
{"default": SeargeParameterProcessor.SAVE_TO[0]}),
},
"optional": {
"inputs": ("PARAMETER_INPUTS",),
},
}
RETURN_TYPES = ("PARAMETER_INPUTS",)
RETURN_NAMES = ("inputs",)
FUNCTION = "mux"
CATEGORY = "Searge/_deprecated_/UI/Inputs"
def mux(self, seed, image_width, image_height, steps, cfg, sampler_name, scheduler, save_image, save_directory,
inputs=None):
if inputs is None:
parameters = {}
else:
parameters = inputs
parameters["seed"] = seed
parameters["image_width"] = image_width
parameters["image_height"] = image_height
parameters["steps"] = steps
parameters["cfg"] = cfg
parameters["sampler_name"] = sampler_name
parameters["scheduler"] = scheduler
parameters["save_image"] = save_image
parameters["save_directory"] = save_directory
return (parameters,)
# ====================================================================================================
# UI: Advanced Parameters Input
# ====================================================================================================
class SeargeInput3:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"base_ratio": ("FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0, "step": 0.01}),
"refiner_strength": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 1.0, "step": 0.05}),
"refiner_intensity": (SeargeParameterProcessor.REFINER_INTENSITY,
{"default": SeargeParameterProcessor.REFINER_INTENSITY[1]}),
"precondition_steps": ("INT", {"default": 0, "min": 0, "max": 10}),
"batch_size": ("INT", {"default": 1, "min": 1, "max": 4}),
"upscale_resolution_factor": ("FLOAT", {"default": 2.0, "min": 0.25, "max": 4.0, "step": 0.25}),
"save_upscaled_image": (SeargeParameterProcessor.STATES, {"default": SeargeParameterProcessor.STATES[1]}),
},
"optional": {
"inputs": ("PARAMETER_INPUTS",),
"denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
},
}
RETURN_TYPES = ("PARAMETER_INPUTS",)
RETURN_NAMES = ("inputs",)
FUNCTION = "mux"
CATEGORY = "Searge/_deprecated_/UI/Inputs"
def mux(self, base_ratio, refiner_strength, refiner_intensity, precondition_steps, batch_size,
upscale_resolution_factor, save_upscaled_image, inputs=None, denoise=None):
if inputs is None:
parameters = {}
else:
parameters = inputs
parameters["denoise"] = denoise
parameters["base_ratio"] = base_ratio
parameters["refiner_strength"] = refiner_strength
parameters["refiner_intensity"] = refiner_intensity
parameters["precondition_steps"] = precondition_steps
parameters["batch_size"] = batch_size
parameters["upscale_resolution_factor"] = upscale_resolution_factor
parameters["save_upscaled_image"] = save_upscaled_image
return (parameters,)
# ====================================================================================================
# UI: Model Selector Input
# ====================================================================================================
class SeargeInput4:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"base_model": (folder_paths.get_filename_list("checkpoints"),),
"refiner_model": (folder_paths.get_filename_list("checkpoints"),),
"vae_model": (folder_paths.get_filename_list("vae"),),
"main_upscale_model": (folder_paths.get_filename_list("upscale_models"),),
"support_upscale_model": (folder_paths.get_filename_list("upscale_models"),),
"lora_model": (folder_paths.get_filename_list("loras"),),
},
"optional": {
"model_settings": ("MODEL_SETTINGS",),
},
}
RETURN_TYPES = ("MODEL_NAMES",)
RETURN_NAMES = ("model_names",)
FUNCTION = "mux"
CATEGORY = "Searge/_deprecated_/UI/Inputs"
def mux(self, base_model, refiner_model, vae_model, main_upscale_model, support_upscale_model, lora_model,
model_settings=None):
if model_settings is None:
model_names = {}
else:
model_names = model_settings
model_names["base_model"] = base_model
model_names["refiner_model"] = refiner_model
model_names["vae_model"] = vae_model
model_names["main_upscale_model"] = main_upscale_model
model_names["support_upscale_model"] = support_upscale_model
model_names["lora_model"] = lora_model
return (model_names,)
# ====================================================================================================
# UI: Prompt Processing Input
# ====================================================================================================
class SeargeInput5:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"base_conditioning_scale": ("FLOAT", {"default": 2.0, "min": 0.25, "max": 4.0, "step": 0.25}),
"refiner_conditioning_scale": ("FLOAT", {"default": 2.0, "min": 0.25, "max": 4.0, "step": 0.25}),
"style_prompt_power": ("FLOAT", {"default": 0.33, "min": 0.0, "max": 1.0, "step": 0.01}),
"negative_style_power": ("FLOAT", {"default": 0.67, "min": 0.0, "max": 1.0, "step": 0.01}),
"style_template": (SeargeParameterProcessor.STYLE_TEMPLATE,
{"default": SeargeParameterProcessor.STYLE_TEMPLATE[0]}),
},
"optional": {
"inputs": ("PARAMETER_INPUTS",),
},
}
RETURN_TYPES = ("PARAMETER_INPUTS",)
RETURN_NAMES = ("inputs",)
FUNCTION = "mux"
CATEGORY = "Searge/_deprecated_/UI/Inputs"
def mux(self, base_conditioning_scale, refiner_conditioning_scale, style_prompt_power, negative_style_power,
style_template, inputs=None):
if inputs is None:
parameters = {}
else:
parameters = inputs
parameters["base_conditioning_scale"] = base_conditioning_scale
parameters["refiner_conditioning_scale"] = refiner_conditioning_scale
parameters["style_prompt_power"] = style_prompt_power
parameters["negative_style_power"] = negative_style_power
parameters["style_template"] = style_template
return (parameters,)
# ====================================================================================================
# UI: HiResFix Parameters Input
# ====================================================================================================
class SeargeInput6:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"hires_fix": (SeargeParameterProcessor.STATES, {"default": SeargeParameterProcessor.STATES[1]}),
"hrf_steps": ("INT", {"default": 0, "min": 0, "max": 100}),
"hrf_denoise": ("FLOAT", {"default": 0.1, "min": 0.0, "max": 1.0, "step": 0.01}),
"hrf_upscale_factor": ("FLOAT", {"default": 1.5, "min": 0.25, "max": 4.0, "step": 0.25}),
"hrf_intensity": (SeargeParameterProcessor.REFINER_INTENSITY,
{"default": SeargeParameterProcessor.REFINER_INTENSITY[1]}),
"hrf_seed_offset": (SeargeParameterProcessor.HRF_SEED_OFFSET,
{"default": SeargeParameterProcessor.HRF_SEED_OFFSET[1]}),
"hrf_smoothness": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.05}),
},
"optional": {
"inputs": ("PARAMETER_INPUTS",),
},
}
RETURN_TYPES = ("PARAMETER_INPUTS",)
RETURN_NAMES = ("inputs",)
FUNCTION = "mux"
CATEGORY = "Searge/_deprecated_/UI/Inputs"
def mux(self, hires_fix, hrf_steps, hrf_denoise, hrf_upscale_factor, hrf_intensity, hrf_seed_offset,
hrf_smoothness, inputs=None):
if inputs is None:
parameters = {}
else:
parameters = inputs
parameters["hires_fix"] = hires_fix
parameters["hrf_steps"] = hrf_steps
parameters["hrf_denoise"] = hrf_denoise
parameters["hrf_upscale_factor"] = hrf_upscale_factor
parameters["hrf_intensity"] = hrf_intensity
parameters["hrf_seed_offset"] = hrf_seed_offset
parameters["hrf_smoothness"] = hrf_smoothness
return (parameters,)
# ====================================================================================================
# UI: Misc Inputs
# ====================================================================================================
class SeargeInput7:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"lora_strength": ("FLOAT", {"default": 0.2, "min": -10.0, "max": 10.0, "step": 0.05}),
"operation_mode": (SeargeParameterProcessor.OPERATION_MODE,
{"default": SeargeParameterProcessor.OPERATION_MODE[0]}),
"prompt_style": (SeargeParameterProcessor.PROMPT_STYLE,
{"default": SeargeParameterProcessor.PROMPT_STYLE[0]}),
},
"optional": {
"inputs": ("PARAMETER_INPUTS",),
},
}
RETURN_TYPES = ("PARAMETER_INPUTS",)
RETURN_NAMES = ("inputs",)
FUNCTION = "mux"
CATEGORY = "Searge/_deprecated_/UI/Inputs"
def mux(self, lora_strength, operation_mode, prompt_style, inputs=None):
if inputs is None:
parameters = {}
else:
parameters = inputs
parameters["lora_strength"] = lora_strength
parameters["operation_mode"] = operation_mode
parameters["prompt_style"] = prompt_style
return (parameters,)
# ====================================================================================================
# UI: Prompt Outputs
# ====================================================================================================
class SeargeOutput1:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"parameters": ("PARAMETERS",),
},
}
RETURN_TYPES = ("PARAMETERS", "STRING", "STRING", "STRING", "STRING", "STRING", "IMAGE", "MASK",)
RETURN_NAMES = ("parameters", "main_prompt", "secondary_prompt", "style_prompt", "negative_prompt",
"negative_style", "image", "mask",)
FUNCTION = "demux"
CATEGORY = "Searge/_deprecated_/UI/Outputs"
def demux(self, parameters):
main_prompt = parameters["main_prompt"]
secondary_prompt = parameters["secondary_prompt"]
style_prompt = parameters["style_prompt"]
negative_prompt = parameters["negative_prompt"]
negative_style = parameters["negative_style"]
image = parameters["image"]
mask = parameters["mask"]
return (parameters, main_prompt, secondary_prompt, style_prompt, negative_prompt, negative_style, image, mask,)
# ====================================================================================================
# UI: Generation Parameters Output
# ====================================================================================================
class SeargeOutput2:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"parameters": ("PARAMETERS",),
},
}
RETURN_TYPES = ("PARAMETERS", "INT", "INT", "INT", "INT", "FLOAT", "SAMPLER_NAME", "SCHEDULER_NAME",
"ENABLE_STATE", "SAVE_FOLDER",)
RETURN_NAMES = ("parameters", "seed", "image_width", "image_height", "steps", "cfg", "sampler_name", "scheduler",
"save_image", "save_directory",)
FUNCTION = "demux"
CATEGORY = "Searge/_deprecated_/UI/Outputs"
def demux(self, parameters):
seed = parameters["seed"]
image_width = parameters["image_width"]
image_height = parameters["image_height"]
steps = parameters["steps"]
cfg = parameters["cfg"]
sampler_name = parameters["sampler_name"]
scheduler = parameters["scheduler"]
save_image = parameters["save_image"]
save_directory = parameters["save_directory"]
return (parameters, seed, image_width, image_height, steps, cfg, sampler_name, scheduler, save_image,
save_directory,)
# ====================================================================================================
# UI: Advanced Parameters Output
# ====================================================================================================
class SeargeOutput3:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"parameters": ("PARAMETERS",),
},
}
RETURN_TYPES = ("PARAMETERS", "FLOAT", "FLOAT", "FLOAT", "INT", "INT", "INT", "FLOAT", "ENABLE_STATE",)
RETURN_NAMES = ("parameters", "denoise", "base_ratio", "refiner_strength", "noise_offset", "precondition_steps",
"batch_size", "upscale_resolution_factor", "save_upscaled_image",)
FUNCTION = "demux"
CATEGORY = "Searge/_deprecated_/UI/Outputs"
def demux(self, parameters):
denoise = parameters["denoise"]
base_ratio = parameters["base_ratio"]
refiner_strength = parameters["refiner_strength"]
noise_offset = parameters["noise_offset"]
precondition_steps = parameters["precondition_steps"]
batch_size = parameters["batch_size"]
upscale_resolution_factor = parameters["upscale_resolution_factor"]
save_upscaled_image = parameters["save_upscaled_image"]
return (parameters, denoise, base_ratio, refiner_strength, noise_offset, precondition_steps, batch_size,
upscale_resolution_factor, save_upscaled_image,)
# ====================================================================================================
# UI: Model Selector
# ====================================================================================================
class SeargeOutput4:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"model_names": ("MODEL_NAMES",),
},
}
RETURN_TYPES = ("MODEL_NAMES", "CHECKPOINT_NAME", "CHECKPOINT_NAME", "VAE_NAME", "UPSCALER_NAME", "UPSCALER_NAME",
"LORA_NAME",)
RETURN_NAMES = ("model_names", "base_model", "refiner_model", "vae_model", "main_upscale_model",
"support_upscale_model", "lora_model",)
FUNCTION = "demux"
CATEGORY = "Searge/_deprecated_/UI/Outputs"
def demux(self, model_names):
base_model = model_names["base_model"]
refiner_model = model_names["refiner_model"]
vae_model = model_names["vae_model"]
main_upscale_model = model_names["main_upscale_model"]
support_upscale_model = model_names["support_upscale_model"]
lora_model = model_names["lora_model"]
return (model_names, base_model, refiner_model, vae_model, main_upscale_model, support_upscale_model,
lora_model,)
# ====================================================================================================
# UI: Prompt Processing Output
# ====================================================================================================
class SeargeOutput5:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"parameters": ("PARAMETERS",),
},
}
RETURN_TYPES = ("PARAMETERS", "FLOAT", "FLOAT", "FLOAT", "FLOAT",)
RETURN_NAMES = ("parameters", "base_conditioning_scale", "refiner_conditioning_scale", "style_prompt_power",
"negative_style_power",)
FUNCTION = "demux"
CATEGORY = "Searge/_deprecated_/UI/Outputs"
def demux(self, parameters):
base_conditioning_scale = parameters["base_conditioning_scale"]
refiner_conditioning_scale = parameters["refiner_conditioning_scale"]
style_prompt_power = parameters["style_prompt_power"]
negative_style_power = parameters["negative_style_power"]
return (parameters, base_conditioning_scale, refiner_conditioning_scale, style_prompt_power,
negative_style_power,)
# ====================================================================================================
# UI: HiResFix Parameters Output
# ====================================================================================================
class SeargeOutput6:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"parameters": ("PARAMETERS",),
},
}
RETURN_TYPES = ("PARAMETERS", "INT", "FLOAT", "FLOAT", "INT", "INT", "ENABLE_STATE", "FLOAT",)
RETURN_NAMES = ("parameters", "hrf_steps", "hrf_denoise", "hrf_upscale_factor", "hrf_noise_offset",
"hrf_seed", "hires_fix", "hrf_smoothness",)
FUNCTION = "demux"
CATEGORY = "Searge/_deprecated_/UI/Outputs"
def demux(self, parameters):
hrf_steps = parameters["hrf_steps"]
hrf_denoise = parameters["hrf_denoise"]
hrf_upscale_factor = parameters["hrf_upscale_factor"]
hrf_noise_offset = parameters["hrf_noise_offset"]
hrf_seed = parameters["hrf_seed"]
hires_fix = parameters["hires_fix"]
hrf_smoothness = parameters["hrf_smoothness"]
return (parameters, hrf_steps, hrf_denoise, hrf_upscale_factor, hrf_noise_offset, hrf_seed, hires_fix,
hrf_smoothness,)
# ====================================================================================================
# UI: Misc Outputs
# ====================================================================================================
class SeargeOutput7:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"parameters": ("PARAMETERS",),
},
}
RETURN_TYPES = ("PARAMETERS", "FLOAT",)
RETURN_NAMES = ("parameters", "lora_strength",)
FUNCTION = "demux"
CATEGORY = "Searge/_deprecated_/UI/Outputs"
def demux(self, parameters):
lora_strength = parameters["lora_strength"]
return (parameters, lora_strength,)
# ====================================================================================================
# UI: Generated outputs for flow control
# ====================================================================================================
class SeargeGenerated1:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"parameters": ("PARAMETERS",),
},
}
RETURN_TYPES = ("PARAMETERS", "INT", "INT", "INT",)
RETURN_NAMES = ("parameters", "operation_selector", "prompt_style_selector", "prompt_style_group",)
FUNCTION = "demux"
CATEGORY = "Searge/_deprecated_/UI/Generated"
def demux(self, parameters):
operation_selector = parameters["operation_selector"]
prompt_style_selector = parameters["prompt_style_selector"]
prompt_style_group = parameters["prompt_style_group"]
return (parameters, operation_selector, prompt_style_selector, prompt_style_group,)
# ====================================================================================================
# SDXL CLIP Text Encoder for prompts with base and refiner support
# ====================================================================================================
class SeargeSDXLPromptEncoder:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"base_clip": ("CLIP",),
"refiner_clip": ("CLIP",),
"pos_g": ("STRING", {"multiline": True, "default": "POS_G"}),
"pos_l": ("STRING", {"multiline": True, "default": "POS_L"}),
"pos_r": ("STRING", {"multiline": True, "default": "POS_R"}),
"neg_g": ("STRING", {"multiline": True, "default": "NEG_G"}),
"neg_l": ("STRING", {"multiline": True, "default": "NEG_L"}),
"neg_r": ("STRING", {"multiline": True, "default": "NEG_R"}),
"base_width": ("INT", {"default": 4096, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"base_height": ("INT", {"default": 4096, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"crop_w": ("INT", {"default": 0, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"crop_h": ("INT", {"default": 0, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"target_width": ("INT", {"default": 4096, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"target_height": ("INT", {"default": 4096, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"pos_ascore": ("FLOAT", {"default": 6.0, "min": 0.0, "max": 1000.0, "step": 0.01}),
"neg_ascore": ("FLOAT", {"default": 2.5, "min": 0.0, "max": 1000.0, "step": 0.01}),
"refiner_width": ("INT", {"default": 2048, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"refiner_height": ("INT", {"default": 2048, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
},
}
RETURN_TYPES = ("CONDITIONING", "CONDITIONING", "CONDITIONING", "CONDITIONING",)
RETURN_NAMES = ("base_positive", "base_negative", "refiner_positive", "refiner_negative",)
FUNCTION = "encode"
CATEGORY = "Searge/_deprecated_/ClipEncoding"
def encode(self, base_clip, refiner_clip, pos_g, pos_l, pos_r, neg_g, neg_l, neg_r, base_width, base_height,
crop_w, crop_h, target_width, target_height, pos_ascore, neg_ascore, refiner_width, refiner_height):
empty = base_clip.tokenize("")
# positive base prompt
tokens1 = base_clip.tokenize(pos_g)
tokens1["l"] = base_clip.tokenize(pos_l)["l"]
if len(tokens1["l"]) != len(tokens1["g"]):
while len(tokens1["l"]) < len(tokens1["g"]):
tokens1["l"] += empty["l"]
while len(tokens1["l"]) > len(tokens1["g"]):
tokens1["g"] += empty["g"]
cond1, pooled1 = base_clip.encode_from_tokens(tokens1, return_pooled=True)
res1 = [[cond1, {"pooled_output": pooled1, "width": base_width, "height": base_height, "crop_w": crop_w,
"crop_h": crop_h, "target_width": target_width, "target_height": target_height}]]
# negative base prompt
tokens2 = base_clip.tokenize(neg_g)
tokens2["l"] = base_clip.tokenize(neg_l)["l"]
if len(tokens2["l"]) != len(tokens2["g"]):
while len(tokens2["l"]) < len(tokens2["g"]):
tokens2["l"] += empty["l"]
while len(tokens2["l"]) > len(tokens2["g"]):
tokens2["g"] += empty["g"]
cond2, pooled2 = base_clip.encode_from_tokens(tokens2, return_pooled=True)
res2 = [[cond2, {"pooled_output": pooled2, "width": base_width, "height": base_height, "crop_w": crop_w,
"crop_h": crop_h, "target_width": target_width, "target_height": target_height}]]
# positive refiner prompt
tokens3 = refiner_clip.tokenize(pos_r)
cond3, pooled3 = refiner_clip.encode_from_tokens(tokens3, return_pooled=True)
res3 = [[cond3, {"pooled_output": pooled3, "aesthetic_score": pos_ascore, "width": refiner_width,
"height": refiner_height}]]
# negative refiner prompt
tokens4 = refiner_clip.tokenize(neg_r)
cond4, pooled4 = refiner_clip.encode_from_tokens(tokens4, return_pooled=True)
res4 = [[cond4, {"pooled_output": pooled4, "aesthetic_score": neg_ascore, "width": refiner_width,
"height": refiner_height}]]
return (res1, res2, res3, res4,)
# ====================================================================================================
# SDXL CLIP Text Encoder for base prompts
# ====================================================================================================
class SeargeSDXLBasePromptEncoder:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"base_clip": ("CLIP",),
"pos_g": ("STRING", {"multiline": True, "default": "POS_G"}),
"pos_l": ("STRING", {"multiline": True, "default": "POS_L"}),
"neg_g": ("STRING", {"multiline": True, "default": "NEG_G"}),
"neg_l": ("STRING", {"multiline": True, "default": "NEG_L"}),
"base_width": ("INT", {"default": 4096, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"base_height": ("INT", {"default": 4096, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"crop_w": ("INT", {"default": 0, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"crop_h": ("INT", {"default": 0, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"target_width": ("INT", {"default": 4096, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"target_height": ("INT", {"default": 4096, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
},
}
RETURN_TYPES = ("CONDITIONING", "CONDITIONING",)
RETURN_NAMES = ("base_positive", "base_negative",)
FUNCTION = "encode"
CATEGORY = "Searge/_deprecated_/ClipEncoding"
def encode(self, base_clip, pos_g, pos_l, neg_g, neg_l, base_width, base_height, crop_w, crop_h, target_width,
target_height):
empty = base_clip.tokenize("")
# positive base prompt
tokens1 = base_clip.tokenize(pos_g)
tokens1["l"] = base_clip.tokenize(pos_l)["l"]
if len(tokens1["l"]) != len(tokens1["g"]):
while len(tokens1["l"]) < len(tokens1["g"]):
tokens1["l"] += empty["l"]
while len(tokens1["l"]) > len(tokens1["g"]):
tokens1["g"] += empty["g"]
cond1, pooled1 = base_clip.encode_from_tokens(tokens1, return_pooled=True)
res1 = [[cond1, {"pooled_output": pooled1, "width": base_width, "height": base_height, "crop_w": crop_w,
"crop_h": crop_h, "target_width": target_width, "target_height": target_height}]]
# negative base prompt
tokens2 = base_clip.tokenize(neg_g)
tokens2["l"] = base_clip.tokenize(neg_l)["l"]
if len(tokens2["l"]) != len(tokens2["g"]):
while len(tokens2["l"]) < len(tokens2["g"]):
tokens2["l"] += empty["l"]
while len(tokens2["l"]) > len(tokens2["g"]):
tokens2["g"] += empty["g"]
cond2, pooled2 = base_clip.encode_from_tokens(tokens2, return_pooled=True)
res2 = [[cond2, {"pooled_output": pooled2, "width": base_width, "height": base_height, "crop_w": crop_w,
"crop_h": crop_h, "target_width": target_width, "target_height": target_height}]]
return (res1, res2,)
# ====================================================================================================
# SDXL CLIP Text Encoder for prompts with base and refiner support
# ====================================================================================================
class SeargeSDXLRefinerPromptEncoder:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"refiner_clip": ("CLIP",),
"pos_r": ("STRING", {"multiline": True, "default": "POS_R"}),
"neg_r": ("STRING", {"multiline": True, "default": "NEG_R"}),
"pos_ascore": ("FLOAT", {"default": 6.0, "min": 0.0, "max": 1000.0, "step": 0.01}),
"neg_ascore": ("FLOAT", {"default": 2.5, "min": 0.0, "max": 1000.0, "step": 0.01}),
"refiner_width": ("INT", {"default": 2048, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"refiner_height": ("INT", {"default": 2048, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
},
}
RETURN_TYPES = ("CONDITIONING", "CONDITIONING",)
RETURN_NAMES = ("refiner_positive", "refiner_negative",)
FUNCTION = "encode"
CATEGORY = "Searge/_deprecated_/ClipEncoding"
def encode(self, refiner_clip, pos_r, neg_r, pos_ascore, neg_ascore, refiner_width, refiner_height):
# positive refiner prompt
tokens1 = refiner_clip.tokenize(pos_r)
cond1, pooled1 = refiner_clip.encode_from_tokens(tokens1, return_pooled=True)
res1 = [[cond1, {"pooled_output": pooled1, "aesthetic_score": pos_ascore, "width": refiner_width,
"height": refiner_height}]]
# negative refiner prompt
tokens2 = refiner_clip.tokenize(neg_r)
cond2, pooled2 = refiner_clip.encode_from_tokens(tokens2, return_pooled=True)
res2 = [[cond2, {"pooled_output": pooled2, "aesthetic_score": neg_ascore, "width": refiner_width,
"height": refiner_height}]]
return (res1, res2,)
# ====================================================================================================
# Tool: text input node for prompt text
# ====================================================================================================
class SeargePromptText:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"prompt": ("STRING", {"default": "", "multiline": True}),
},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("prompt",)
FUNCTION = "get_value"
CATEGORY = "Searge/_deprecated_/Prompting"
def get_value(self, prompt):
return (prompt,)
# Tool: text input node for prompt text
class SeargePromptCombiner:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"prompt1": ("STRING", {"default": "", "multiline": True}),
"separator": ("STRING", {"default": ", ", "multiline": False}),
"prompt2": ("STRING", {"default": "", "multiline": True}),
},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("combined prompt",)
FUNCTION = "get_value"
CATEGORY = "Searge/_deprecated_/Prompting"
def get_value(self, prompt1, separator, prompt2):
len1 = len(prompt1)
len2 = len(prompt2)
prompt = ""
if len1 > 0 and len2 > 0:
prompt = prompt1 + separator + prompt2
elif len1 > 0:
prompt = prompt1
elif len2 > 0:
prompt = prompt2
return (prompt,)
# ====================================================================================================
# Input: sampler inputs
# ====================================================================================================
class SeargeSamplerInputs:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, {"default": "ddim"}),
"scheduler": (comfy.samplers.KSampler.SCHEDULERS, {"default": "ddim_uniform"}),
},
}
RETURN_TYPES = ("SAMPLER_NAME", "SCHEDULER_NAME",)
RETURN_NAMES = ("sampler_name", "scheduler",)
FUNCTION = "get_value"
CATEGORY = "Searge/_deprecated_/Inputs"
def get_value(self, sampler_name, scheduler):
return (sampler_name, scheduler,)
# ====================================================================================================
# Input: enabler inputs
# ====================================================================================================
class SeargeEnablerInputs:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"state": (SeargeParameterProcessor.STATES, {"default": SeargeParameterProcessor.STATES[1]}),
},
}
RETURN_TYPES = ("ENABLE_STATE",)
RETURN_NAMES = ("state",)
FUNCTION = "get_value"
CATEGORY = "Searge/_deprecated_/Inputs"
def get_value(self, state):
return (state,)
# ====================================================================================================
# Input: save folder inputs
# ====================================================================================================
class SeargeSaveFolderInputs:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"save_to": (SeargeParameterProcessor.SAVE_TO, {"default": SeargeParameterProcessor.SAVE_TO[0]}),
},
}
RETURN_TYPES = ("SAVE_FOLDER",)
RETURN_NAMES = ("save_to",)
FUNCTION = "get_value"
CATEGORY = "Searge/_deprecated_/Inputs"
def get_value(self, save_to):
return (save_to,)
# ====================================================================================================
# Tool: integer constant
# ====================================================================================================
class SeargeIntegerConstant:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"value": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
},
}
RETURN_TYPES = ("INT",)
RETURN_NAMES = ("value",)
FUNCTION = "get_value"
CATEGORY = "Searge/_deprecated_/Integers"
def get_value(self, value):
return (value,)
# ====================================================================================================
# Tool: integer pair
# ====================================================================================================
class SeargeIntegerPair:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"value1": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
"value2": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
},
}
RETURN_TYPES = ("INT", "INT",)
RETURN_NAMES = ("value 1", "value 2",)
FUNCTION = "get_value"
CATEGORY = "Searge/_deprecated_/Integers"
def get_value(self, value1, value2):
return (value1, value2,)
# ====================================================================================================
# Tool: integer math
# ====================================================================================================
class SeargeIntegerMath:
OPERATIONS = ["a * b + c", "a + c", "a - c", "a * b", "a / b"]
@classmethod
def INPUT_TYPES(s):
return {"required": {
"op": (SeargeIntegerMath.OPERATIONS, {"default": "a * b + c"}),
"a": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
"b": ("INT", {"default": 1, "min": 0, "max": 0xffffffffffffffff}),
"c": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
},
}
RETURN_TYPES = ("INT",)
RETURN_NAMES = ("result",)
FUNCTION = "get_value"
CATEGORY = "Searge/_deprecated_/Integers"
def get_value(self, op, a, b, c):
res = 0
if op == "a * b + c":
res = a * b + c
elif op == "a + c":
res = a + c
elif op == "a - c":
res = a - c
elif op == "a * b":
res = a * b
elif op == "a / b":
res = a // b
return (int(res),)
# ====================================================================================================
# Tool: integer scaler
# ====================================================================================================
class SeargeIntegerScaler:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"value": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
"factor": ("FLOAT", {"default": 1.0, "step": 0.01}),
"multiple_of": ("INT", {"default": 1, "min": 0, "max": 65536}),
},
}
RETURN_TYPES = ("INT",)
RETURN_NAMES = ("value",)
FUNCTION = "get_value"
CATEGORY = "Searge/_deprecated_/Integers"
def get_value(self, value, factor, multiple_of):
return (int(value * factor // multiple_of) * multiple_of,)
# ====================================================================================================
# Tool: float constant
# ====================================================================================================
class SeargeFloatConstant:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"value": ("FLOAT", {"default": 0.0, "step": 0.01}),
},
}
RETURN_TYPES = ("FLOAT",)
RETURN_NAMES = ("value",)
FUNCTION = "get_value"
CATEGORY = "Searge/_deprecated_/Floats"
def get_value(self, value):
return (value,)
# ====================================================================================================
# Tool: float pair
# ====================================================================================================
class SeargeFloatPair:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"value1": ("FLOAT", {"default": 0.0, "step": 0.01}),
"value2": ("FLOAT", {"default": 0.0, "step": 0.01}),
},
}
RETURN_TYPES = ("FLOAT", "FLOAT",)
RETURN_NAMES = ("value 1", "value 2",)
FUNCTION = "get_value"
CATEGORY = "Searge/_deprecated_/Floats"
def get_value(self, value1, value2):
return (value1, value2,)
# ====================================================================================================
# Tool: float math
# ====================================================================================================
class SeargeFloatMath:
OPERATIONS = ["a * b + c", "a + c", "a - c", "a * b", "a / b"]
@classmethod
def INPUT_TYPES(s):
return {"required": {
"op": (SeargeFloatMath.OPERATIONS, {"default": "a * b + c"}),
"a": ("FLOAT", {"default": 0.0, "step": 0.01}),
"b": ("FLOAT", {"default": 1.0, "step": 0.01}),
"c": ("FLOAT", {"default": 0.0, "step": 0.01}),
},
}
RETURN_TYPES = ("FLOAT",)
RETURN_NAMES = ("result",)
FUNCTION = "get_value"
CATEGORY = "Searge/_deprecated_/Floats"
def get_value(self, op, a, b, c):
res = 0.0
if op == "a * b + c":
res = a * b + c
elif op == "a + c":
res = a + c
elif op == "a - c":
res = a - c
elif op == "a * b":
res = a * b
elif op == "a / b":
res = a / b
return (res,)
# ====================================================================================================
# Util: custom save node (without preview)
# ====================================================================================================
class SeargeImageSave:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"images": ("IMAGE",),
"filename_prefix": ("STRING", {"default": "SeargeSDXL-%date%/Image"}),
"state": ("ENABLE_STATE", {"default": SeargeParameterProcessor.STATES[1]}),
"save_to": ("SAVE_FOLDER", {"default": SeargeParameterProcessor.SAVE_TO[0]}),
},
"hidden": {
"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"
},
}
RETURN_TYPES = ()
FUNCTION = "save_images"
OUTPUT_NODE = True
CATEGORY = "Searge/_deprecated_/Files"
def save_images(self, images, filename_prefix, state, save_to, prompt=None, extra_pnginfo=None):
# "disabled"
if state == SeargeParameterProcessor.STATES[0]:
return {}
# "input folder"
if save_to == SeargeParameterProcessor.SAVE_TO[1]:
output_dir = folder_paths.get_input_directory()
filename_prefix = "output-%date%"
# incl. SeargeParameterProcessor.SAVE_TO[0] -> "output folder"
else:
output_dir = folder_paths.get_output_directory()
filename_prefix = filename_prefix.replace("%date%", datetime.now().strftime("%Y-%m-%d"))
full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(
filename_prefix, output_dir, images[0].shape[1], images[0].shape[0])
for image in images:
i = 255. * image.cpu().numpy()
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
metadata = None
if args.disable_metadata is None or not args.disable_metadata:
metadata = PngInfo()
if prompt is not None:
metadata.add_text("prompt", json.dumps(prompt))
if extra_pnginfo is not None:
for x in extra_pnginfo:
metadata.add_text(x, json.dumps(extra_pnginfo[x]))
file = f"{filename}_{counter:05}_.png"
img.save(os.path.join(full_output_folder, file), pnginfo=metadata, compress_level=4)
counter += 1
return {}
# ====================================================================================================
# Util: custom checkpoint loader
# ====================================================================================================
class SeargeCheckpointLoader:
def __init__(self):
self.chkp_loader = nodes.CheckpointLoaderSimple()
@classmethod
def INPUT_TYPES(s):
return {"required": {
"ckpt_name": ("CHECKPOINT_NAME",),
},
}
RETURN_TYPES = ("MODEL", "CLIP", "VAE",)
FUNCTION = "load_checkpoint"
CATEGORY = "Searge/_deprecated_/Files"
def load_checkpoint(self, ckpt_name):
return self.chkp_loader.load_checkpoint(ckpt_name)
# ====================================================================================================
# Util: custom vae loader
# ====================================================================================================
class SeargeVAELoader:
def __init__(self):
self.vae_loader = nodes.VAELoader()
@classmethod
def INPUT_TYPES(s):
return {"required": {
"vae_name": ("VAE_NAME",),
},
}
RETURN_TYPES = ("VAE",)
FUNCTION = "load_vae"
CATEGORY = "Searge/_deprecated_/Files"
def load_vae(self, vae_name):
return self.vae_loader.load_vae(vae_name)
# ====================================================================================================
# Util: custom upscale model loader
# ====================================================================================================
class SeargeUpscaleModelLoader:
def __init__(self):
self.upscale_model_loader = comfy_extras.nodes_upscale_model.UpscaleModelLoader()
@classmethod
def INPUT_TYPES(s):
return {"required": {
"upscaler_name": ("UPSCALER_NAME",),
},
}
RETURN_TYPES = ("UPSCALE_MODEL",)
FUNCTION = "load_upscaler"
CATEGORY = "Searge/_deprecated_/Files"
def load_upscaler(self, upscaler_name):
return self.upscale_model_loader.load_model(upscaler_name)
# ====================================================================================================
# Util: custom upscale model loader
# ====================================================================================================
class SeargeLoraLoader:
def __init__(self):
self.lora_loader = nodes.LoraLoader()
@classmethod
def INPUT_TYPES(s):
return {"required": {
"model": ("MODEL",),
"clip": ("CLIP",),
"lora_name": ("LORA_NAME",),
"strength_model": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
"strength_clip": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
},
}
RETURN_TYPES = ("MODEL", "CLIP",)
FUNCTION = "load_lora"
CATEGORY = "Searge/_deprecated_/Files"
def load_lora(self, model, clip, lora_name, strength_model, strength_clip):
return self.lora_loader.load_lora(model, clip, lora_name, strength_model, strength_clip)
# ====================================================================================================
# Tool: Muxer for selecting between 3 latent inputs
# ====================================================================================================
class SeargeLatentMuxer3:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"input0": ("LATENT",),
"input1": ("LATENT",),
"input2": ("LATENT",),
"input_selector": ("INT", {"default": 0, "min": 0, "max": 2}),
},
}
RETURN_TYPES = ("LATENT",)
RETURN_NAMES = ("output",)
FUNCTION = "mux"
CATEGORY = "Searge/_deprecated_/FlowControl"
def mux(self, input0, input1, input2, input_selector):
if input_selector == 1:
return (input1,)
elif input_selector == 2:
return (input2,)
else:
return (input0,)
# ====================================================================================================
# Tool: Muxer for selecting between 5 conditioning inputs
# ====================================================================================================
class SeargeConditioningMuxer2:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"input0": ("CONDITIONING",),
"input1": ("CONDITIONING",),
"input_selector": ("INT", {"default": 0, "min": 0, "max": 1}),
},
}
RETURN_TYPES = ("CONDITIONING",)
RETURN_NAMES = ("output",)
FUNCTION = "mux"
CATEGORY = "Searge/_deprecated_/FlowControl"
def mux(self, input0, input1, input_selector):
if input_selector == 1:
return (input1,)
else:
return (input0,)
# ====================================================================================================
# Tool: Muxer for selecting between 5 conditioning inputs
# ====================================================================================================
class SeargeConditioningMuxer5:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"input0": ("CONDITIONING",),
"input1": ("CONDITIONING",),
"input2": ("CONDITIONING",),
"input3": ("CONDITIONING",),
"input4": ("CONDITIONING",),
"input_selector": ("INT", {"default": 0, "min": 0, "max": 4}),
},
}
RETURN_TYPES = ("CONDITIONING",)
RETURN_NAMES = ("output",)
FUNCTION = "mux"
CATEGORY = "Searge/_deprecated_/FlowControl"
def mux(self, input0, input1, input2, input3, input4, input_selector):
if input_selector == 1:
return (input1,)
elif input_selector == 2:
return (input2,)
elif input_selector == 3:
return (input3,)
elif input_selector == 4:
return (input4,)
else:
return (input0,)
# ====================================================================================================
# Register nodes in ComfyUI
# ====================================================================================================
LEGACY_CLASS_MAPPINGS = {
"SeargeSDXLSampler": SeargeSDXLSampler,
"SeargeSDXLSampler2": SeargeSDXLSampler2,
"SeargeSDXLSamplerV3": SeargeSDXLSamplerV3,
"SeargeSDXLImage2ImageSampler": SeargeSDXLImage2ImageSampler,
"SeargeSDXLImage2ImageSampler2": SeargeSDXLImage2ImageSampler2,
"SeargeSamplerInputs": SeargeSamplerInputs,
"SeargeEnablerInputs": SeargeEnablerInputs,
"SeargeSaveFolderInputs": SeargeSaveFolderInputs,
"SeargeSDXLPromptEncoder": SeargeSDXLPromptEncoder,
"SeargeSDXLBasePromptEncoder": SeargeSDXLBasePromptEncoder,
"SeargeSDXLRefinerPromptEncoder": SeargeSDXLRefinerPromptEncoder,
"SeargePromptText": SeargePromptText,
"SeargePromptCombiner": SeargePromptCombiner,
"SeargeIntegerConstant": SeargeIntegerConstant,
"SeargeIntegerPair": SeargeIntegerPair,
"SeargeIntegerMath": SeargeIntegerMath,
"SeargeIntegerScaler": SeargeIntegerScaler,
"SeargeFloatConstant": SeargeFloatConstant,
"SeargeFloatPair": SeargeFloatPair,
"SeargeFloatMath": SeargeFloatMath,
"SeargeImageSave": SeargeImageSave,
"SeargeCheckpointLoader": SeargeCheckpointLoader,
"SeargeVAELoader": SeargeVAELoader,
"SeargeUpscaleModelLoader": SeargeUpscaleModelLoader,
"SeargeLoraLoader": SeargeLoraLoader,
"SeargeLatentMuxer3": SeargeLatentMuxer3,
"SeargeConditioningMuxer2": SeargeConditioningMuxer2,
"SeargeConditioningMuxer5": SeargeConditioningMuxer5,
"SeargeParameterProcessor": SeargeParameterProcessor,
"SeargeStylePreprocessor": SeargeStylePreprocessor,
"SeargeInput1": SeargeInput1,
"SeargeInput2": SeargeInput2,
"SeargeInput3": SeargeInput3,
"SeargeInput4": SeargeInput4,
"SeargeInput5": SeargeInput5,
"SeargeInput6": SeargeInput6,
"SeargeInput7": SeargeInput7,
"SeargeOutput1": SeargeOutput1,
"SeargeOutput2": SeargeOutput2,
"SeargeOutput3": SeargeOutput3,
"SeargeOutput4": SeargeOutput4,
"SeargeOutput5": SeargeOutput5,
"SeargeOutput6": SeargeOutput6,
"SeargeOutput7": SeargeOutput7,
"SeargeGenerated1": SeargeGenerated1,
# "SeargeSamplerAdvanced": SeargeSamplerAdvanced,
}
# ====================================================================================================
# Human readable names for the nodes
# ====================================================================================================
LEGACY_DISPLAY_NAME_MAPPINGS = {
"SeargeSDXLSampler": "SDXL Sampler v1 (Searge)",
"SeargeSDXLSampler2": "SDXL Sampler v2 (Searge)",
"SeargeSDXLSamplerV3": "SDXL Sampler v3 (Searge)",
"SeargeSDXLImage2ImageSampler": "Image2Image Sampler v1 (Searge)",
"SeargeSDXLImage2ImageSampler2": "Image2Image Sampler v2 (Searge)",
"SeargeSamplerInputs": "Sampler Settings",
"SeargeEnablerInputs": "Enable / Disable",
"SeargeSaveFolderInputs": "Save Folder",
"SeargeSDXLPromptEncoder": "SDXL Prompt Encoder (Searge)",
"SeargeSDXLBasePromptEncoder": "SDXL Base Prompt Encoder (Searge)",
"SeargeSDXLRefinerPromptEncoder": "SDXL Refiner Prompt Encoder (Searge)",
"SeargePromptText": "Prompt text input",
"SeargePromptCombiner": "Prompt combiner",
"SeargeIntegerConstant": "Integer Constant",
"SeargeIntegerPair": "Integer Pair",
"SeargeIntegerMath": "Integer Math",
"SeargeIntegerScaler": "Integer Scaler",
"SeargeFloatConstant": "Float Constant",
"SeargeFloatPair": "Float Pair",
"SeargeFloatMath": "Float Math",
"SeargeImageSave": "Save Image (Searge)",
"SeargeCheckpointLoader": "Checkpoint Loader (Searge)",
"SeargeVAELoader": "VAE Loader (Searge)",
"SeargeUpscaleModelLoader": "Upscale Model Loader (Searge)",
"SeargeLoraLoader": "Lora Loader (Searge)",
"SeargeLatentMuxer3": "3-Way Muxer for Latents",
"SeargeConditioningMuxer2": "2-Way Muxer for Conditioning",
"SeargeConditioningMuxer5": "5-Way Muxer for Conditioning",
"SeargeParameterProcessor": "Parameter Processor",
"SeargeStylePreprocessor": "Style Preprocessor (wip)",
"SeargeInput1": "Prompts",
"SeargeInput2": "Generation Parameters",
"SeargeInput3": "Advanced Parameters",
"SeargeInput4": "Model Names",
"SeargeInput5": "Prompt Processing",
"SeargeInput6": "HiResFix Parameters",
"SeargeInput7": "Misc Parameters",
"SeargeOutput1": "Prompts",
"SeargeOutput2": "Generation Parameters",
"SeargeOutput3": "Advanced Parameters",
"SeargeOutput4": "Model Names",
"SeargeOutput5": "Prompt Processing",
"SeargeOutput6": "HiResFix Parameters",
"SeargeOutput7": "Misc Parameters",
"SeargeGenerated1": "Flow Control Parameters",
# "SeargeSamplerAdvanced": "Experimental Sampler"
}
"""
# ====================================================================================================
# SDXL Image2Image Sampler (incl. HiRes Fix)
# ====================================================================================================
class SeargeSDXLImage2ImageSamplerV3:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"base_model": ("MODEL",),
"base_positive": ("CONDITIONING", ),
"base_negative": ("CONDITIONING", ),
"refiner_model": ("MODEL",),
"refiner_positive": ("CONDITIONING",),
"refiner_negative": ("CONDITIONING",),
"image": ("IMAGE", ),
"vae": ("VAE",),
"noise_seed": ("INT", {"default": 0, "min": 0, "max": 0xfffffffffffffff0}),
"steps": ("INT", {"default": 20, "min": 0, "max": 200}),
"cfg": ("FLOAT", {"default": 7.0, "min": 0.0, "max": 30.0, "step": 0.5}),
"sampler_name": ("SAMPLER_NAME", {"default": "ddim"}),
"scheduler": ("SCHEDULER_NAME", {"default": "ddim_uniform"}),
"base_ratio": ("FLOAT", {"default": 0.8, "min": 0.0, "max": 1.0, "step": 0.01}),
"denoise": ("FLOAT", {"default": 0.25, "min": 0.0, "max": 1.0, "step": 0.01}),
},
"optional": {
"upscale_model": ("UPSCALE_MODEL",),
"scaled_width": ("INT", {"default": 1536, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"scaled_height": ("INT", {"default": 1536, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"softness": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.05}),
"parameters": ("PARAMETERS",),
# "noise_offset": ("INT", {"default": 1, "min": 0, "max": 1}),
# "refiner_strength": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 1.0, "step": 0.05}),
},
}
RETURN_TYPES = ("IMAGE", )
FUNCTION = "sample"
CATEGORY = "Searge/_deprecated_/Sampling"
# def sample(self, base_model, base_positive, base_negative, refiner_model, refiner_positive, refiner_negative,
image, vae, noise_seed, steps, cfg, sampler_name, scheduler, base_ratio, denoise, softness,
upscale_model=None, scaled_width=None, scaled_height=None, noise_offset=None, refiner_strength=None):
def sample(self, base_model, base_positive, base_negative, refiner_model, refiner_positive, refiner_negative,
image, vae, noise_seed, steps, cfg, sampler_name, scheduler, base_ratio, denoise, upscale_model=None,
scaled_width=None, scaled_height=None, softness=0.0, parameters=None):
base_steps = int(steps * (base_ratio + 0.0001))
refiner_steps = max(0, steps - base_steps)
# if noise_offset is None:
# noise_offset = 1
# if refiner_strength is None:
# refiner_strength = 1.0
# if refiner_strength < 0.01:
# refiner_strength = 0.01
if steps < 1:
return (image, )
scaled_image = image
use_upscale_model = upscale_model is not None and softness < 0.9999
if use_upscale_model:
upscale_result = comfy_extras.nodes_upscale_model.ImageUpscaleWithModel().upscale(upscale_model, image)
scaled_image = upscale_result[0]
if scaled_width is not None and scaled_height is not None:
upscale_result = nodes.ImageScale().upscale(scaled_image, "bicubic", scaled_width, scaled_height, "center")
scaled_image = upscale_result[0]
if use_upscale_model and softness > 0.0001:
upscale_result = nodes.ImageScale().upscale(image, "bicubic", scaled_width, scaled_height, "center")
scaled_original = upscale_result[0]
blend_result = comfy_extras.nodes_post_processing.Blend().blend_images(scaled_image, scaled_original,
softness, "normal")
scaled_image = blend_result[0]
if denoise < 0.01:
return (scaled_image, )
vae_encode_result = nodes.VAEEncode().encode(vae, scaled_image)
input_latent = vae_encode_result[0]
if base_steps >= steps:
result_latent = nodes.common_ksampler(base_model, noise_seed, steps, cfg, sampler_name, scheduler,
base_positive, base_negative, input_latent, denoise=denoise,
disable_noise=False, start_step=0, last_step=steps,
force_full_denoise=True)
else:
result_latent = sdxl_ksampler(base_model, refiner_model, noise_seed, base_steps, refiner_steps, cfg,
sampler_name, scheduler, base_positive, base_negative, refiner_positive,
refiner_negative, input_latent, denoise=denoise, disable_noise=False,
start_step=0, last_step=steps, force_full_denoise=True)
# base_result = nodes.common_ksampler(base_model, noise_seed, steps, cfg, sampler_name, scheduler,
# base_positive, base_negative, input_latent, denoise=denoise,
# disable_noise=False, start_step=0, last_step=base_steps,
# force_full_denoise=True)
# result_latent = nodes.common_ksampler(refiner_model, noise_seed + noise_offset, steps, cfg, sampler_name,
# scheduler, refiner_positive, refiner_negative, base_result[0],
# denoise=denoise * refiner_strength, disable_noise=False,
# start_step=base_steps, last_step=steps, force_full_denoise=True)
vae_decode_result = nodes.VAEDecode().decode(vae, result_latent[0])
output_image = vae_decode_result[0]
return (output_image, )
"""