Upload folder using huggingface_hub
Browse files- chain_injectors/pid_injector.py +278 -0
- core/pipelines/pipeline_input_processor.py +334 -0
- core/pipelines/sd_image_pipeline.py +253 -618
- core/pipelines/workflow_executor.py +110 -0
- core/pipelines/workflow_recipes/_partials/conditioning/anima.yaml +4 -0
- core/pipelines/workflow_recipes/_partials/conditioning/chroma1.yaml +4 -0
- core/pipelines/workflow_recipes/_partials/conditioning/ernie-image.yaml +4 -0
- core/pipelines/workflow_recipes/_partials/conditioning/flux1.yaml +4 -0
- core/pipelines/workflow_recipes/_partials/conditioning/flux2-kv.yaml +4 -0
- core/pipelines/workflow_recipes/_partials/conditioning/flux2.yaml +4 -0
- core/pipelines/workflow_recipes/_partials/conditioning/hidream-i1.yaml +4 -0
- core/pipelines/workflow_recipes/_partials/conditioning/lens.yaml +4 -0
- core/pipelines/workflow_recipes/_partials/conditioning/longcat-image.yaml +4 -0
- core/pipelines/workflow_recipes/_partials/conditioning/lumina.yaml +4 -0
- core/pipelines/workflow_recipes/_partials/conditioning/newbie-image.yaml +4 -0
- core/pipelines/workflow_recipes/_partials/conditioning/omnigen2.yaml +4 -0
- core/pipelines/workflow_recipes/_partials/conditioning/ovis-image.yaml +4 -0
- core/pipelines/workflow_recipes/_partials/conditioning/qwen-image.yaml +4 -0
- core/pipelines/workflow_recipes/_partials/conditioning/sd35.yaml +4 -0
- core/pipelines/workflow_recipes/_partials/conditioning/sdxl.yaml +4 -0
- core/pipelines/workflow_recipes/_partials/conditioning/z-image.yaml +4 -0
- requirements.txt +2 -2
- ui/events/change_handlers.py +5 -3
- ui/events/main.py +8 -3
- ui/events/run_handlers.py +4 -1
- ui/shared/txt2img_ui.py +3 -1
- ui/shared/ui_components.py +19 -2
- yaml/file_list.yaml +21 -0
- yaml/image_gen_features.yaml +100 -89
- yaml/injectors.yaml +4 -1
- yaml/pid.yaml +16 -0
chain_injectors/pid_injector.py
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import yaml
|
| 3 |
+
import random
|
| 4 |
+
|
| 5 |
+
def load_pid_config():
|
| 6 |
+
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| 7 |
+
pid_path = os.path.join(project_root, 'yaml', 'pid.yaml')
|
| 8 |
+
with open(pid_path, 'r', encoding='utf-8') as f:
|
| 9 |
+
return yaml.safe_load(f) or {}
|
| 10 |
+
|
| 11 |
+
def load_model_config():
|
| 12 |
+
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| 13 |
+
model_list_path = os.path.join(project_root, 'yaml', 'model_list.yaml')
|
| 14 |
+
with open(model_list_path, 'r', encoding='utf-8') as f:
|
| 15 |
+
return yaml.safe_load(f) or {}
|
| 16 |
+
|
| 17 |
+
def inject(assembler, chain_definition, chain_items):
|
| 18 |
+
if not chain_items:
|
| 19 |
+
return
|
| 20 |
+
|
| 21 |
+
pid_config = {}
|
| 22 |
+
try:
|
| 23 |
+
pid_config = load_pid_config() or {}
|
| 24 |
+
except Exception as e:
|
| 25 |
+
print(f"Error loading PiD config: {e}")
|
| 26 |
+
|
| 27 |
+
pid_items = pid_config.get("PiD", [])
|
| 28 |
+
architectures_settings = {}
|
| 29 |
+
default_settings = {"unet_name": "pid_flux1_1024_to_4096_4step_mxfp8.safetensors", "latent_format": "flux"}
|
| 30 |
+
|
| 31 |
+
for item in pid_items:
|
| 32 |
+
unet_name = item.get("filepath")
|
| 33 |
+
latent_format = item.get("latent_format")
|
| 34 |
+
archs = item.get("architectures", [])
|
| 35 |
+
for arch in archs:
|
| 36 |
+
architectures_settings[arch] = {
|
| 37 |
+
"unet_name": unet_name,
|
| 38 |
+
"latent_format": latent_format
|
| 39 |
+
}
|
| 40 |
+
if arch == "flux1":
|
| 41 |
+
default_settings = {
|
| 42 |
+
"unet_name": unet_name,
|
| 43 |
+
"latent_format": latent_format
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
ksampler_name = chain_definition.get('ksampler_node', 'ksampler')
|
| 47 |
+
if ksampler_name not in assembler.node_map:
|
| 48 |
+
print(f"Warning: [PiD Injector] KSampler node '{ksampler_name}' not found. Skipping.")
|
| 49 |
+
return
|
| 50 |
+
|
| 51 |
+
original_ksampler_id = assembler.node_map[ksampler_name]
|
| 52 |
+
|
| 53 |
+
original_vae_loader_id = assembler.node_map.get('vae_loader')
|
| 54 |
+
original_vae_decode_id = assembler.node_map.get('vae_decode')
|
| 55 |
+
original_pos_prompt_id = assembler.node_map.get('pos_prompt')
|
| 56 |
+
original_neg_prompt_id = assembler.node_map.get('neg_prompt')
|
| 57 |
+
|
| 58 |
+
if not original_vae_loader_id:
|
| 59 |
+
for node_id, node_data in assembler.workflow.items():
|
| 60 |
+
if node_data.get('class_type') == 'VAELoader':
|
| 61 |
+
original_vae_loader_id = node_id
|
| 62 |
+
break
|
| 63 |
+
|
| 64 |
+
if not original_vae_decode_id:
|
| 65 |
+
for node_id, node_data in assembler.workflow.items():
|
| 66 |
+
if node_data.get('class_type') == 'VAEDecode':
|
| 67 |
+
original_vae_decode_id = node_id
|
| 68 |
+
break
|
| 69 |
+
|
| 70 |
+
if not original_pos_prompt_id or not original_neg_prompt_id:
|
| 71 |
+
for node_id, node_data in assembler.workflow.items():
|
| 72 |
+
if node_data.get('class_type') == 'CLIPTextEncode':
|
| 73 |
+
title = node_data.get('_meta', {}).get('title', '')
|
| 74 |
+
if 'Positive' in title:
|
| 75 |
+
if not original_pos_prompt_id:
|
| 76 |
+
original_pos_prompt_id = node_id
|
| 77 |
+
elif 'Negative' in title:
|
| 78 |
+
if not original_neg_prompt_id:
|
| 79 |
+
original_neg_prompt_id = node_id
|
| 80 |
+
|
| 81 |
+
pos_text = ""
|
| 82 |
+
if original_pos_prompt_id and original_pos_prompt_id in assembler.workflow:
|
| 83 |
+
pos_text = assembler.workflow[original_pos_prompt_id]['inputs'].get('text', '')
|
| 84 |
+
|
| 85 |
+
neg_text = ""
|
| 86 |
+
if original_neg_prompt_id and original_neg_prompt_id in assembler.workflow:
|
| 87 |
+
neg_text = assembler.workflow[original_neg_prompt_id]['inputs'].get('text', '')
|
| 88 |
+
|
| 89 |
+
clip_loader_id = assembler._get_unique_id()
|
| 90 |
+
clip_loader_node = assembler._get_node_template("CLIPLoader")
|
| 91 |
+
clip_loader_node['inputs']['clip_name'] = "gemma_2_2b_it_elm_fp8_scaled.safetensors"
|
| 92 |
+
clip_loader_node['inputs']['type'] = "pixeldit"
|
| 93 |
+
clip_loader_node['inputs']['device'] = "default"
|
| 94 |
+
assembler.workflow[clip_loader_id] = clip_loader_node
|
| 95 |
+
|
| 96 |
+
pos_text_encode_id = assembler._get_unique_id()
|
| 97 |
+
pos_text_encode_node = assembler._get_node_template("CLIPTextEncode")
|
| 98 |
+
pos_text_encode_node['inputs']['text'] = pos_text
|
| 99 |
+
pos_text_encode_node['inputs']['clip'] = [clip_loader_id, 0]
|
| 100 |
+
assembler.workflow[pos_text_encode_id] = pos_text_encode_node
|
| 101 |
+
|
| 102 |
+
neg_text_encode_id = assembler._get_unique_id()
|
| 103 |
+
neg_text_encode_node = assembler._get_node_template("CLIPTextEncode")
|
| 104 |
+
neg_text_encode_node['inputs']['text'] = neg_text
|
| 105 |
+
neg_text_encode_node['inputs']['clip'] = [clip_loader_id, 0]
|
| 106 |
+
assembler.workflow[neg_text_encode_id] = neg_text_encode_node
|
| 107 |
+
|
| 108 |
+
active_model_file = None
|
| 109 |
+
for node_id, node_data in assembler.workflow.items():
|
| 110 |
+
class_type = node_data.get('class_type')
|
| 111 |
+
if class_type == 'UNETLoader':
|
| 112 |
+
active_model_file = node_data.get('inputs', {}).get('unet_name')
|
| 113 |
+
if active_model_file:
|
| 114 |
+
break
|
| 115 |
+
elif class_type == 'CheckpointLoaderSimple':
|
| 116 |
+
active_model_file = node_data.get('inputs', {}).get('ckpt_name')
|
| 117 |
+
if active_model_file:
|
| 118 |
+
break
|
| 119 |
+
|
| 120 |
+
architecture = None
|
| 121 |
+
if active_model_file:
|
| 122 |
+
try:
|
| 123 |
+
model_config = load_model_config()
|
| 124 |
+
checkpoints = model_config.get("Checkpoints", {})
|
| 125 |
+
for arch_name, arch_data in checkpoints.items():
|
| 126 |
+
models_list = arch_data.get("models", [])
|
| 127 |
+
for model_entry in models_list:
|
| 128 |
+
if model_entry.get('path') == active_model_file:
|
| 129 |
+
architecture = arch_name
|
| 130 |
+
break
|
| 131 |
+
components_dict = model_entry.get('components', {})
|
| 132 |
+
if active_model_file in components_dict.values():
|
| 133 |
+
architecture = arch_name
|
| 134 |
+
break
|
| 135 |
+
if architecture:
|
| 136 |
+
break
|
| 137 |
+
except Exception as e:
|
| 138 |
+
print(f"Error looking up model architecture in PiD injector: {e}")
|
| 139 |
+
|
| 140 |
+
if architecture:
|
| 141 |
+
architecture = architecture.lower().replace(" ", "-").replace(".", "")
|
| 142 |
+
else:
|
| 143 |
+
file_lower = active_model_file.lower().replace("-", "").replace("_", "").replace(".", "")
|
| 144 |
+
for arch in sorted(architectures_settings.keys(), key=len, reverse=True):
|
| 145 |
+
candidates = [arch]
|
| 146 |
+
if "-image" in arch:
|
| 147 |
+
candidates.append(arch.replace("-image", ""))
|
| 148 |
+
if "-i1" in arch:
|
| 149 |
+
candidates.append(arch.replace("-i1", ""))
|
| 150 |
+
if "-kv" in arch:
|
| 151 |
+
candidates.append(arch.replace("-kv", ""))
|
| 152 |
+
|
| 153 |
+
matched = False
|
| 154 |
+
for cand in candidates:
|
| 155 |
+
if cand.replace("-", "").replace(".", "") in file_lower:
|
| 156 |
+
architecture = arch
|
| 157 |
+
matched = True
|
| 158 |
+
break
|
| 159 |
+
if matched:
|
| 160 |
+
break
|
| 161 |
+
|
| 162 |
+
unet_name = default_settings.get("unet_name")
|
| 163 |
+
latent_format = default_settings.get("latent_format")
|
| 164 |
+
|
| 165 |
+
if architecture in architectures_settings:
|
| 166 |
+
arch_config = architectures_settings[architecture]
|
| 167 |
+
unet_name = arch_config.get("unet_name", unet_name)
|
| 168 |
+
latent_format = arch_config.get("latent_format", latent_format)
|
| 169 |
+
else:
|
| 170 |
+
print(f"[PiD Injector] Warning: Model architecture '{architecture}' (file: '{active_model_file}') not explicitly mapped. Using default settings.")
|
| 171 |
+
|
| 172 |
+
pid_pos_id = assembler._get_unique_id()
|
| 173 |
+
pid_pos_node = assembler._get_node_template("PiDConditioning")
|
| 174 |
+
pid_pos_node['inputs']['latent_format'] = latent_format
|
| 175 |
+
pid_pos_node['inputs']['degrade_sigma'] = 0
|
| 176 |
+
pid_pos_node['inputs']['positive'] = [pos_text_encode_id, 0]
|
| 177 |
+
pid_pos_node['inputs']['latent'] = [original_ksampler_id, 0]
|
| 178 |
+
assembler.workflow[pid_pos_id] = pid_pos_node
|
| 179 |
+
|
| 180 |
+
pid_neg_id = assembler._get_unique_id()
|
| 181 |
+
pid_neg_node = assembler._get_node_template("PiDConditioning")
|
| 182 |
+
pid_neg_node['inputs']['latent_format'] = latent_format
|
| 183 |
+
pid_neg_node['inputs']['degrade_sigma'] = 0
|
| 184 |
+
pid_neg_node['inputs']['positive'] = [neg_text_encode_id, 0]
|
| 185 |
+
pid_neg_node['inputs']['latent'] = [original_ksampler_id, 0]
|
| 186 |
+
assembler.workflow[pid_neg_id] = pid_neg_node
|
| 187 |
+
|
| 188 |
+
pid_unet_loader_id = assembler._get_unique_id()
|
| 189 |
+
pid_unet_loader_node = assembler._get_node_template("UNETLoader")
|
| 190 |
+
pid_unet_loader_node['inputs']['unet_name'] = unet_name
|
| 191 |
+
pid_unet_loader_node['inputs']['weight_dtype'] = "default"
|
| 192 |
+
assembler.workflow[pid_unet_loader_id] = pid_unet_loader_node
|
| 193 |
+
|
| 194 |
+
orig_width = 1024
|
| 195 |
+
orig_height = 1024
|
| 196 |
+
original_latent_source_id = assembler.node_map.get('latent_source')
|
| 197 |
+
if original_latent_source_id in assembler.workflow:
|
| 198 |
+
node_inputs = assembler.workflow[original_latent_source_id].get('inputs', {})
|
| 199 |
+
if 'width' in node_inputs and 'height' in node_inputs:
|
| 200 |
+
orig_width = node_inputs['width']
|
| 201 |
+
orig_height = node_inputs['height']
|
| 202 |
+
else:
|
| 203 |
+
for node_data in assembler.workflow.values():
|
| 204 |
+
inputs = node_data.get('inputs', {})
|
| 205 |
+
if 'width' in inputs and 'height' in inputs and isinstance(inputs['width'], (int, float)) and isinstance(inputs['height'], (int, float)):
|
| 206 |
+
if 256 <= inputs['width'] <= 4096 and 256 <= inputs['height'] <= 4096:
|
| 207 |
+
orig_width = inputs['width']
|
| 208 |
+
orig_height = inputs['height']
|
| 209 |
+
break
|
| 210 |
+
else:
|
| 211 |
+
for node_data in assembler.workflow.values():
|
| 212 |
+
inputs = node_data.get('inputs', {})
|
| 213 |
+
if 'width' in inputs and 'height' in inputs and isinstance(inputs['width'], (int, float)) and isinstance(inputs['height'], (int, float)):
|
| 214 |
+
if 256 <= inputs['width'] <= 4096 and 256 <= inputs['height'] <= 4096:
|
| 215 |
+
orig_width = inputs['width']
|
| 216 |
+
orig_height = inputs['height']
|
| 217 |
+
break
|
| 218 |
+
|
| 219 |
+
empty_latent_id = assembler._get_unique_id()
|
| 220 |
+
empty_latent_node = assembler._get_node_template("EmptyChromaRadianceLatentImage")
|
| 221 |
+
empty_latent_node['inputs']['width'] = int(orig_width) * 4
|
| 222 |
+
empty_latent_node['inputs']['height'] = int(orig_height) * 4
|
| 223 |
+
empty_latent_node['inputs']['batch_size'] = 1
|
| 224 |
+
|
| 225 |
+
if original_latent_source_id in assembler.workflow:
|
| 226 |
+
orig_batch_size = assembler.workflow[original_latent_source_id]['inputs'].get('batch_size') or assembler.workflow[original_latent_source_id]['inputs'].get('amount')
|
| 227 |
+
if orig_batch_size:
|
| 228 |
+
empty_latent_node['inputs']['batch_size'] = orig_batch_size
|
| 229 |
+
|
| 230 |
+
assembler.workflow[empty_latent_id] = empty_latent_node
|
| 231 |
+
|
| 232 |
+
orig_seed = 0
|
| 233 |
+
if original_ksampler_id in assembler.workflow:
|
| 234 |
+
orig_seed = assembler.workflow[original_ksampler_id]['inputs'].get('seed', 0)
|
| 235 |
+
if orig_seed == -1:
|
| 236 |
+
orig_seed = random.randint(0, 2**32 - 1)
|
| 237 |
+
else:
|
| 238 |
+
orig_seed = (orig_seed + 1) % (2**32)
|
| 239 |
+
|
| 240 |
+
new_ksampler_id = assembler._get_unique_id()
|
| 241 |
+
new_ksampler_node = assembler._get_node_template("KSampler")
|
| 242 |
+
new_ksampler_node['inputs']['seed'] = orig_seed
|
| 243 |
+
new_ksampler_node['inputs']['steps'] = 4
|
| 244 |
+
new_ksampler_node['inputs']['cfg'] = 1
|
| 245 |
+
new_ksampler_node['inputs']['sampler_name'] = "lcm"
|
| 246 |
+
new_ksampler_node['inputs']['scheduler'] = "simple"
|
| 247 |
+
new_ksampler_node['inputs']['denoise'] = 1.0
|
| 248 |
+
new_ksampler_node['inputs']['model'] = [pid_unet_loader_id, 0]
|
| 249 |
+
new_ksampler_node['inputs']['positive'] = [pid_pos_id, 0]
|
| 250 |
+
new_ksampler_node['inputs']['negative'] = [pid_neg_id, 0]
|
| 251 |
+
new_ksampler_node['inputs']['latent_image'] = [empty_latent_id, 0]
|
| 252 |
+
assembler.workflow[new_ksampler_id] = new_ksampler_node
|
| 253 |
+
|
| 254 |
+
pid_vae_loader_id = assembler._get_unique_id()
|
| 255 |
+
pid_vae_loader_node = assembler._get_node_template("VAELoader")
|
| 256 |
+
pid_vae_loader_node['inputs']['vae_name'] = "pixel_space"
|
| 257 |
+
assembler.workflow[pid_vae_loader_id] = pid_vae_loader_node
|
| 258 |
+
|
| 259 |
+
pid_vae_decode_id = assembler._get_unique_id()
|
| 260 |
+
pid_vae_decode_node = assembler._get_node_template("VAEDecode")
|
| 261 |
+
pid_vae_decode_node['inputs']['samples'] = [new_ksampler_id, 0]
|
| 262 |
+
pid_vae_decode_node['inputs']['vae'] = [pid_vae_loader_id, 0]
|
| 263 |
+
assembler.workflow[pid_vae_decode_id] = pid_vae_decode_node
|
| 264 |
+
|
| 265 |
+
if original_vae_decode_id:
|
| 266 |
+
for node_id, node_data in assembler.workflow.items():
|
| 267 |
+
if 'inputs' in node_data:
|
| 268 |
+
for input_name, input_val in list(node_data['inputs'].items()):
|
| 269 |
+
if isinstance(input_val, list) and len(input_val) == 2:
|
| 270 |
+
if input_val[0] == original_vae_decode_id:
|
| 271 |
+
node_data['inputs'][input_name] = [pid_vae_decode_id, 0]
|
| 272 |
+
|
| 273 |
+
if original_vae_loader_id in assembler.workflow:
|
| 274 |
+
del assembler.workflow[original_vae_loader_id]
|
| 275 |
+
if original_vae_decode_id in assembler.workflow:
|
| 276 |
+
del assembler.workflow[original_vae_decode_id]
|
| 277 |
+
|
| 278 |
+
print("[PiD Injector] Successfully injected PiD pipeline and replaced VAE decode/loader.")
|
core/pipelines/pipeline_input_processor.py
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import random
|
| 3 |
+
import numpy as np
|
| 4 |
+
import gradio as gr
|
| 5 |
+
from PIL import Image, ImageChops
|
| 6 |
+
from typing import Dict, Any, List
|
| 7 |
+
|
| 8 |
+
from core.settings import INPUT_DIR
|
| 9 |
+
from utils.app_utils import (
|
| 10 |
+
sanitize_filename,
|
| 11 |
+
get_lora_path,
|
| 12 |
+
get_embedding_path,
|
| 13 |
+
ensure_controlnet_model_downloaded,
|
| 14 |
+
ensure_ipadapter_models_downloaded,
|
| 15 |
+
_ensure_model_downloaded,
|
| 16 |
+
ensure_sd3_ipadapter_models_downloaded,
|
| 17 |
+
get_vae_path,
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
def process_pipeline_inputs(ui_inputs: Dict[str, Any], progress: gr.Progress, workflow_model_type: str) -> Dict[str, Any]:
|
| 21 |
+
task_type = ui_inputs['task_type']
|
| 22 |
+
temp_files_to_clean = []
|
| 23 |
+
|
| 24 |
+
lora_data = ui_inputs.get('lora_data', [])
|
| 25 |
+
active_loras_for_gpu, active_loras_for_meta = [], []
|
| 26 |
+
if lora_data:
|
| 27 |
+
sources, ids, scales, files = lora_data[0::4], lora_data[1::4], lora_data[2::4], lora_data[3::4]
|
| 28 |
+
for i, (source, lora_id, scale, _) in enumerate(zip(sources, ids, scales, files)):
|
| 29 |
+
if scale > 0 and lora_id and lora_id.strip():
|
| 30 |
+
lora_filename = None
|
| 31 |
+
if source == "File":
|
| 32 |
+
lora_filename = sanitize_filename(lora_id)
|
| 33 |
+
elif source == "Civitai":
|
| 34 |
+
local_path, status = get_lora_path(source, lora_id, os.environ.get("CIVITAI_API_KEY", ""), progress)
|
| 35 |
+
if local_path: lora_filename = os.path.basename(local_path)
|
| 36 |
+
else: raise gr.Error(f"Failed to prepare LoRA {lora_id}: {status}")
|
| 37 |
+
|
| 38 |
+
if lora_filename:
|
| 39 |
+
active_loras_for_gpu.append({"lora_name": lora_filename, "strength_model": scale, "strength_clip": scale})
|
| 40 |
+
active_loras_for_meta.append(f"{source} {lora_id}:{scale}")
|
| 41 |
+
|
| 42 |
+
ui_inputs['denoise'] = 1.0
|
| 43 |
+
if task_type == 'img2img': ui_inputs['denoise'] = ui_inputs.get('img2img_denoise', 0.7)
|
| 44 |
+
elif task_type == 'hires_fix': ui_inputs['denoise'] = ui_inputs.get('hires_denoise', 0.55)
|
| 45 |
+
|
| 46 |
+
if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
|
| 47 |
+
|
| 48 |
+
if task_type == 'img2img':
|
| 49 |
+
input_image_pil = ui_inputs.get('img2img_image')
|
| 50 |
+
if not input_image_pil:
|
| 51 |
+
raise gr.Error("Please upload an image for Image-to-Image.")
|
| 52 |
+
temp_file_path = os.path.join(INPUT_DIR, f"temp_input_{random.randint(1000, 9999)}.png")
|
| 53 |
+
input_image_pil.save(temp_file_path, "PNG")
|
| 54 |
+
ui_inputs['input_image'] = os.path.basename(temp_file_path)
|
| 55 |
+
temp_files_to_clean.append(temp_file_path)
|
| 56 |
+
ui_inputs['width'] = input_image_pil.width
|
| 57 |
+
ui_inputs['height'] = input_image_pil.height
|
| 58 |
+
|
| 59 |
+
elif task_type == 'inpaint':
|
| 60 |
+
inpaint_dict = ui_inputs.get('inpaint_image_dict')
|
| 61 |
+
if not inpaint_dict or not inpaint_dict.get('background') or not inpaint_dict.get('layers'):
|
| 62 |
+
raise gr.Error("Inpainting requires an input image and a drawn mask.")
|
| 63 |
+
|
| 64 |
+
background_img = inpaint_dict['background'].convert("RGBA")
|
| 65 |
+
composite_mask_pil = Image.new('L', background_img.size, 0)
|
| 66 |
+
for layer in inpaint_dict['layers']:
|
| 67 |
+
if layer:
|
| 68 |
+
layer_alpha = layer.split()[-1]
|
| 69 |
+
composite_mask_pil = ImageChops.lighter(composite_mask_pil, layer_alpha)
|
| 70 |
+
|
| 71 |
+
inverted_mask_alpha = Image.fromarray(255 - np.array(composite_mask_pil), mode='L')
|
| 72 |
+
r, g, b, _ = background_img.split()
|
| 73 |
+
composite_image_with_mask = Image.merge('RGBA', [r, g, b, inverted_mask_alpha])
|
| 74 |
+
|
| 75 |
+
temp_file_path = os.path.join(INPUT_DIR, f"temp_inpaint_composite_{random.randint(1000, 9999)}.png")
|
| 76 |
+
composite_image_with_mask.save(temp_file_path, "PNG")
|
| 77 |
+
|
| 78 |
+
ui_inputs['input_image'] = os.path.basename(temp_file_path)
|
| 79 |
+
temp_files_to_clean.append(temp_file_path)
|
| 80 |
+
ui_inputs.pop('inpaint_mask', None)
|
| 81 |
+
|
| 82 |
+
elif task_type == 'outpaint':
|
| 83 |
+
input_image_pil = ui_inputs.get('outpaint_image')
|
| 84 |
+
if not input_image_pil:
|
| 85 |
+
raise gr.Error("Please upload an image for Outpainting.")
|
| 86 |
+
temp_file_path = os.path.join(INPUT_DIR, f"temp_input_{random.randint(1000, 9999)}.png")
|
| 87 |
+
input_image_pil.save(temp_file_path, "PNG")
|
| 88 |
+
ui_inputs['input_image'] = os.path.basename(temp_file_path)
|
| 89 |
+
temp_files_to_clean.append(temp_file_path)
|
| 90 |
+
|
| 91 |
+
ui_inputs['megapixels'] = 0.25
|
| 92 |
+
ui_inputs['grow_mask_by'] = ui_inputs.get('feathering', 10)
|
| 93 |
+
|
| 94 |
+
elif task_type == 'hires_fix':
|
| 95 |
+
input_image_pil = ui_inputs.get('hires_image')
|
| 96 |
+
if not input_image_pil:
|
| 97 |
+
raise gr.Error("Please upload an image for Hires Fix.")
|
| 98 |
+
temp_file_path = os.path.join(INPUT_DIR, f"temp_input_{random.randint(1000, 9999)}.png")
|
| 99 |
+
input_image_pil.save(temp_file_path, "PNG")
|
| 100 |
+
ui_inputs['input_image'] = os.path.basename(temp_file_path)
|
| 101 |
+
temp_files_to_clean.append(temp_file_path)
|
| 102 |
+
|
| 103 |
+
embedding_data = ui_inputs.get('embedding_data', [])
|
| 104 |
+
embedding_filenames = []
|
| 105 |
+
if embedding_data:
|
| 106 |
+
emb_sources, emb_ids, emb_files = embedding_data[0::3], embedding_data[1::3], embedding_data[2::3]
|
| 107 |
+
for i, (source, emb_id, _) in enumerate(zip(emb_sources, emb_ids, emb_files)):
|
| 108 |
+
if emb_id and emb_id.strip():
|
| 109 |
+
emb_filename = None
|
| 110 |
+
if source == "File":
|
| 111 |
+
emb_filename = sanitize_filename(emb_id)
|
| 112 |
+
elif source == "Civitai":
|
| 113 |
+
local_path, status = get_embedding_path(source, emb_id, os.environ.get("CIVITAI_API_KEY", ""), progress)
|
| 114 |
+
if local_path: emb_filename = os.path.basename(local_path)
|
| 115 |
+
else: raise gr.Error(f"Failed to prepare Embedding {emb_id}: {status}")
|
| 116 |
+
|
| 117 |
+
if emb_filename:
|
| 118 |
+
embedding_filenames.append(emb_filename)
|
| 119 |
+
|
| 120 |
+
if embedding_filenames:
|
| 121 |
+
embedding_prompt_text = " ".join([f"embedding:{f}" for f in embedding_filenames])
|
| 122 |
+
if ui_inputs['positive_prompt']:
|
| 123 |
+
ui_inputs['positive_prompt'] = f"{ui_inputs['positive_prompt']}, {embedding_prompt_text}"
|
| 124 |
+
else:
|
| 125 |
+
ui_inputs['positive_prompt'] = embedding_prompt_text
|
| 126 |
+
|
| 127 |
+
controlnet_data = ui_inputs.get('controlnet_data', [])
|
| 128 |
+
active_controlnets = []
|
| 129 |
+
if controlnet_data:
|
| 130 |
+
(cn_images, _, _, cn_strengths, cn_filepaths) = [controlnet_data[i::5] for i in range(5)]
|
| 131 |
+
for i in range(len(cn_images)):
|
| 132 |
+
if cn_images[i] and cn_strengths[i] > 0 and cn_filepaths[i] and cn_filepaths[i] != "None":
|
| 133 |
+
ensure_controlnet_model_downloaded(cn_filepaths[i], progress)
|
| 134 |
+
if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
|
| 135 |
+
cn_temp_path = os.path.join(INPUT_DIR, f"temp_cn_{i}_{random.randint(1000, 9999)}.png")
|
| 136 |
+
cn_images[i].save(cn_temp_path, "PNG")
|
| 137 |
+
temp_files_to_clean.append(cn_temp_path)
|
| 138 |
+
active_controlnets.append({
|
| 139 |
+
"image": os.path.basename(cn_temp_path), "strength": cn_strengths[i],
|
| 140 |
+
"start_percent": 0.0, "end_percent": 1.0, "control_net_name": cn_filepaths[i]
|
| 141 |
+
})
|
| 142 |
+
|
| 143 |
+
anima_controlnet_lllite_data = ui_inputs.get('anima_controlnet_lllite_data', [])
|
| 144 |
+
active_anima_controlnets = []
|
| 145 |
+
if anima_controlnet_lllite_data:
|
| 146 |
+
(cn_images, _, _, cn_strengths, cn_filepaths, cn_starts, cn_ends) = [anima_controlnet_lllite_data[i::7] for i in range(7)]
|
| 147 |
+
for i in range(len(cn_images)):
|
| 148 |
+
if cn_images[i] and cn_strengths[i] > 0 and cn_filepaths[i] and cn_filepaths[i] != "None":
|
| 149 |
+
_ensure_model_downloaded(cn_filepaths[i], progress)
|
| 150 |
+
if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
|
| 151 |
+
cn_temp_path = os.path.join(INPUT_DIR, f"temp_anima_cn_{i}_{random.randint(1000, 9999)}.png")
|
| 152 |
+
cn_images[i].save(cn_temp_path, "PNG")
|
| 153 |
+
temp_files_to_clean.append(cn_temp_path)
|
| 154 |
+
active_anima_controlnets.append({
|
| 155 |
+
"image": os.path.basename(cn_temp_path), "strength": cn_strengths[i],
|
| 156 |
+
"start_percent": cn_starts[i], "end_percent": cn_ends[i], "control_net_name": cn_filepaths[i]
|
| 157 |
+
})
|
| 158 |
+
|
| 159 |
+
diffsynth_controlnet_data = ui_inputs.get('diffsynth_controlnet_data', [])
|
| 160 |
+
active_diffsynth_controlnets = []
|
| 161 |
+
if diffsynth_controlnet_data:
|
| 162 |
+
(cn_images, _, _, cn_strengths, cn_filepaths) = [diffsynth_controlnet_data[i::5] for i in range(5)]
|
| 163 |
+
for i in range(len(cn_images)):
|
| 164 |
+
if cn_images[i] and cn_strengths[i] > 0 and cn_filepaths[i] and cn_filepaths[i] != "None":
|
| 165 |
+
ensure_controlnet_model_downloaded(cn_filepaths[i], progress)
|
| 166 |
+
if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
|
| 167 |
+
cn_temp_path = os.path.join(INPUT_DIR, f"temp_diffsynth_cn_{i}_{random.randint(1000, 9999)}.png")
|
| 168 |
+
cn_images[i].save(cn_temp_path, "PNG")
|
| 169 |
+
temp_files_to_clean.append(cn_temp_path)
|
| 170 |
+
active_diffsynth_controlnets.append({
|
| 171 |
+
"image": os.path.basename(cn_temp_path), "strength": cn_strengths[i],
|
| 172 |
+
"control_net_name": cn_filepaths[i]
|
| 173 |
+
})
|
| 174 |
+
|
| 175 |
+
ipadapter_data = ui_inputs.get('ipadapter_data', [])
|
| 176 |
+
active_ipadapters = []
|
| 177 |
+
if ipadapter_data:
|
| 178 |
+
num_ipa_units = (len(ipadapter_data) - 5) // 3
|
| 179 |
+
final_preset, final_weight, final_lora_strength, final_embeds_scaling, final_combine_method = ipadapter_data[-5:]
|
| 180 |
+
ipa_images, ipa_weights, ipa_lora_strengths = [ipadapter_data[i*num_ipa_units:(i+1)*num_ipa_units] for i in range(3)]
|
| 181 |
+
all_presets_to_download = set()
|
| 182 |
+
for i in range(num_ipa_units):
|
| 183 |
+
if ipa_images[i] and ipa_weights[i] > 0 and final_preset:
|
| 184 |
+
all_presets_to_download.add(final_preset)
|
| 185 |
+
if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
|
| 186 |
+
ipa_temp_path = os.path.join(INPUT_DIR, f"temp_ipa_{i}_{random.randint(1000, 9999)}.png")
|
| 187 |
+
ipa_images[i].save(ipa_temp_path, "PNG")
|
| 188 |
+
temp_files_to_clean.append(ipa_temp_path)
|
| 189 |
+
active_ipadapters.append({
|
| 190 |
+
"image": os.path.basename(ipa_temp_path), "preset": final_preset,
|
| 191 |
+
"weight": ipa_weights[i], "lora_strength": ipa_lora_strengths[i]
|
| 192 |
+
})
|
| 193 |
+
if active_ipadapters and final_preset:
|
| 194 |
+
all_presets_to_download.add(final_preset)
|
| 195 |
+
for preset in all_presets_to_download:
|
| 196 |
+
ensure_ipadapter_models_downloaded(preset, progress)
|
| 197 |
+
|
| 198 |
+
model_type_key = 'sd15' if workflow_model_type == 'sd15' else 'sdxl'
|
| 199 |
+
if active_ipadapters:
|
| 200 |
+
active_ipadapters.append({
|
| 201 |
+
'is_final_settings': True, 'model_type': model_type_key, 'final_preset': final_preset,
|
| 202 |
+
'final_weight': final_weight, 'final_lora_strength': final_lora_strength,
|
| 203 |
+
'final_embeds_scaling': final_embeds_scaling, 'final_combine_method': final_combine_method
|
| 204 |
+
})
|
| 205 |
+
|
| 206 |
+
flux1_ipadapter_data = ui_inputs.get('flux1_ipadapter_data', [])
|
| 207 |
+
active_flux1_ipadapters = []
|
| 208 |
+
if flux1_ipadapter_data:
|
| 209 |
+
num_units = len(flux1_ipadapter_data) // 4
|
| 210 |
+
f_images = flux1_ipadapter_data[0*num_units : 1*num_units]
|
| 211 |
+
f_weights = flux1_ipadapter_data[1*num_units : 2*num_units]
|
| 212 |
+
f_starts = flux1_ipadapter_data[2*num_units : 3*num_units]
|
| 213 |
+
f_ends = flux1_ipadapter_data[3*num_units : 4*num_units]
|
| 214 |
+
for i in range(len(f_images)):
|
| 215 |
+
if f_images[i] and f_weights[i] > 0:
|
| 216 |
+
for filename in ["ip-adapter.bin"]:
|
| 217 |
+
_ensure_model_downloaded(filename, progress)
|
| 218 |
+
|
| 219 |
+
from huggingface_hub import snapshot_download
|
| 220 |
+
progress(0.5, desc="Caching HF SigLIP model...")
|
| 221 |
+
snapshot_download(
|
| 222 |
+
repo_id="google/siglip-so400m-patch14-384",
|
| 223 |
+
allow_patterns=["*.json", "*.safetensors", "*.txt"],
|
| 224 |
+
ignore_patterns=["*.msgpack", "*.h5", "*.bin"]
|
| 225 |
+
)
|
| 226 |
+
|
| 227 |
+
temp_path = os.path.join(INPUT_DIR, f"temp_fipa_{i}_{random.randint(1000, 9999)}.png")
|
| 228 |
+
f_images[i].save(temp_path, "PNG")
|
| 229 |
+
temp_files_to_clean.append(temp_path)
|
| 230 |
+
active_flux1_ipadapters.append({
|
| 231 |
+
"image": os.path.basename(temp_path),
|
| 232 |
+
"weight": f_weights[i], "start_percent": f_starts[i], "end_percent": f_ends[i]
|
| 233 |
+
})
|
| 234 |
+
|
| 235 |
+
sd3_ipadapter_data = ui_inputs.get('sd3_ipadapter_chain', [])
|
| 236 |
+
active_sd3_ipadapters = []
|
| 237 |
+
if sd3_ipadapter_data:
|
| 238 |
+
num_units = len(sd3_ipadapter_data) // 4
|
| 239 |
+
s_images = sd3_ipadapter_data[0*num_units : 1*num_units]
|
| 240 |
+
s_weights = sd3_ipadapter_data[1*num_units : 2*num_units]
|
| 241 |
+
s_starts = sd3_ipadapter_data[2*num_units : 3*num_units]
|
| 242 |
+
s_ends = sd3_ipadapter_data[3*num_units : 4*num_units]
|
| 243 |
+
sd3_ipa_downloaded = False
|
| 244 |
+
for i in range(len(s_images)):
|
| 245 |
+
if s_images[i] and s_weights[i] > 0:
|
| 246 |
+
if not sd3_ipa_downloaded:
|
| 247 |
+
ensure_sd3_ipadapter_models_downloaded(progress)
|
| 248 |
+
sd3_ipa_downloaded = True
|
| 249 |
+
temp_path = os.path.join(INPUT_DIR, f"temp_s3ipa_{i}_{random.randint(1000, 9999)}.png")
|
| 250 |
+
s_images[i].save(temp_path, "PNG")
|
| 251 |
+
temp_files_to_clean.append(temp_path)
|
| 252 |
+
active_sd3_ipadapters.append({
|
| 253 |
+
"image": os.path.basename(temp_path),
|
| 254 |
+
"weight": s_weights[i], "start_percent": s_starts[i], "end_percent": s_ends[i]
|
| 255 |
+
})
|
| 256 |
+
|
| 257 |
+
style_data = ui_inputs.get('style_data', [])
|
| 258 |
+
active_styles = []
|
| 259 |
+
if style_data:
|
| 260 |
+
num_units = len(style_data) // 2
|
| 261 |
+
st_images = style_data[0*num_units : 1*num_units]
|
| 262 |
+
st_strengths = style_data[1*num_units : 2*num_units]
|
| 263 |
+
for i in range(len(st_images)):
|
| 264 |
+
if st_images[i] and st_strengths[i] > 0:
|
| 265 |
+
_ensure_model_downloaded("sigclip_vision_patch14_384.safetensors", progress)
|
| 266 |
+
temp_path = os.path.join(INPUT_DIR, f"temp_style_{i}_{random.randint(1000, 9999)}.png")
|
| 267 |
+
st_images[i].save(temp_path, "PNG")
|
| 268 |
+
temp_files_to_clean.append(temp_path)
|
| 269 |
+
active_styles.append({
|
| 270 |
+
"image": os.path.basename(temp_path), "strength": st_strengths[i]
|
| 271 |
+
})
|
| 272 |
+
|
| 273 |
+
reference_latent_data = ui_inputs.get('reference_latent_data', [])
|
| 274 |
+
active_reference_latents = []
|
| 275 |
+
if reference_latent_data:
|
| 276 |
+
for img in reference_latent_data:
|
| 277 |
+
if img:
|
| 278 |
+
if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
|
| 279 |
+
temp_path = os.path.join(INPUT_DIR, f"temp_ref_{random.randint(1000, 9999)}.png")
|
| 280 |
+
img.save(temp_path, "PNG")
|
| 281 |
+
temp_files_to_clean.append(temp_path)
|
| 282 |
+
active_reference_latents.append(os.path.basename(temp_path))
|
| 283 |
+
|
| 284 |
+
hidream_o1_reference_data = ui_inputs.get('hidream_o1_reference_data', [])
|
| 285 |
+
active_hidream_o1_reference = []
|
| 286 |
+
if hidream_o1_reference_data:
|
| 287 |
+
for img in hidream_o1_reference_data:
|
| 288 |
+
if img:
|
| 289 |
+
if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
|
| 290 |
+
temp_path = os.path.join(INPUT_DIR, f"temp_ho1_ref_{random.randint(1000, 9999)}.png")
|
| 291 |
+
img.save(temp_path, "PNG")
|
| 292 |
+
temp_files_to_clean.append(temp_path)
|
| 293 |
+
active_hidream_o1_reference.append(os.path.basename(temp_path))
|
| 294 |
+
|
| 295 |
+
vae_source = ui_inputs.get('vae_source')
|
| 296 |
+
vae_id = ui_inputs.get('vae_id')
|
| 297 |
+
vae_name_override = None
|
| 298 |
+
if vae_source and vae_source != "None":
|
| 299 |
+
if vae_source == "File":
|
| 300 |
+
vae_name_override = sanitize_filename(vae_id)
|
| 301 |
+
elif vae_source == "Civitai" and vae_id and vae_id.strip():
|
| 302 |
+
local_path, status = get_vae_path(vae_source, vae_id, os.environ.get("CIVITAI_API_KEY", ""), progress)
|
| 303 |
+
if local_path: vae_name_override = os.path.basename(local_path)
|
| 304 |
+
else: raise gr.Error(f"Failed to prepare VAE {vae_id}: {status}")
|
| 305 |
+
if vae_name_override:
|
| 306 |
+
ui_inputs['vae_name'] = vae_name_override
|
| 307 |
+
|
| 308 |
+
conditioning_data = ui_inputs.get('conditioning_data', [])
|
| 309 |
+
active_conditioning = []
|
| 310 |
+
if conditioning_data:
|
| 311 |
+
num_units = len(conditioning_data) // 6
|
| 312 |
+
prompts, widths, heights, xs, ys, strengths = [conditioning_data[i*num_units : (i+1)*num_units] for i in range(6)]
|
| 313 |
+
for i in range(num_units):
|
| 314 |
+
if prompts[i] and prompts[i].strip():
|
| 315 |
+
active_conditioning.append({
|
| 316 |
+
"prompt": prompts[i], "width": int(widths[i]), "height": int(heights[i]),
|
| 317 |
+
"x": int(xs[i]), "y": int(ys[i]), "strength": float(strengths[i])
|
| 318 |
+
})
|
| 319 |
+
|
| 320 |
+
return {
|
| 321 |
+
"active_loras_for_gpu": active_loras_for_gpu,
|
| 322 |
+
"active_loras_for_meta": active_loras_for_meta,
|
| 323 |
+
"active_controlnets": active_controlnets,
|
| 324 |
+
"active_anima_controlnets": active_anima_controlnets,
|
| 325 |
+
"active_diffsynth_controlnets": active_diffsynth_controlnets,
|
| 326 |
+
"active_ipadapters": active_ipadapters,
|
| 327 |
+
"active_flux1_ipadapters": active_flux1_ipadapters,
|
| 328 |
+
"active_sd3_ipadapters": active_sd3_ipadapters,
|
| 329 |
+
"active_styles": active_styles,
|
| 330 |
+
"active_reference_latents": active_reference_latents,
|
| 331 |
+
"active_hidream_o1_reference": active_hidream_o1_reference,
|
| 332 |
+
"active_conditioning": active_conditioning,
|
| 333 |
+
"temp_files_to_clean": temp_files_to_clean
|
| 334 |
+
}
|
core/pipelines/sd_image_pipeline.py
CHANGED
|
@@ -1,619 +1,254 @@
|
|
| 1 |
-
import os
|
| 2 |
-
import random
|
| 3 |
-
import shutil
|
| 4 |
-
import torch
|
| 5 |
-
import gradio as gr
|
| 6 |
-
from PIL import Image
|
| 7 |
-
from typing import List, Dict, Any
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
from .
|
| 12 |
-
from core.
|
| 13 |
-
from
|
| 14 |
-
from
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
path_or_components
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
return
|
| 57 |
-
|
| 58 |
-
def
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
input_image_pil = ui_inputs.get('hires_image')
|
| 255 |
-
if not input_image_pil:
|
| 256 |
-
raise gr.Error("Please upload an image for Hires Fix.")
|
| 257 |
-
temp_file_path = os.path.join(INPUT_DIR, f"temp_input_{random.randint(1000, 9999)}.png")
|
| 258 |
-
input_image_pil.save(temp_file_path, "PNG")
|
| 259 |
-
ui_inputs['input_image'] = os.path.basename(temp_file_path)
|
| 260 |
-
temp_files_to_clean.append(temp_file_path)
|
| 261 |
-
|
| 262 |
-
embedding_data = ui_inputs.get('embedding_data', [])
|
| 263 |
-
embedding_filenames = []
|
| 264 |
-
if embedding_data:
|
| 265 |
-
emb_sources, emb_ids, emb_files = embedding_data[0::3], embedding_data[1::3], embedding_data[2::3]
|
| 266 |
-
for i, (source, emb_id, _) in enumerate(zip(emb_sources, emb_ids, emb_files)):
|
| 267 |
-
if emb_id and emb_id.strip():
|
| 268 |
-
emb_filename = None
|
| 269 |
-
if source == "File":
|
| 270 |
-
emb_filename = sanitize_filename(emb_id)
|
| 271 |
-
elif source == "Civitai":
|
| 272 |
-
local_path, status = get_embedding_path(source, emb_id, os.environ.get("CIVITAI_API_KEY", ""), progress)
|
| 273 |
-
if local_path: emb_filename = os.path.basename(local_path)
|
| 274 |
-
else: raise gr.Error(f"Failed to prepare Embedding {emb_id}: {status}")
|
| 275 |
-
|
| 276 |
-
if emb_filename:
|
| 277 |
-
embedding_filenames.append(emb_filename)
|
| 278 |
-
|
| 279 |
-
if embedding_filenames:
|
| 280 |
-
embedding_prompt_text = " ".join([f"embedding:{f}" for f in embedding_filenames])
|
| 281 |
-
if ui_inputs['positive_prompt']:
|
| 282 |
-
ui_inputs['positive_prompt'] = f"{ui_inputs['positive_prompt']}, {embedding_prompt_text}"
|
| 283 |
-
else:
|
| 284 |
-
ui_inputs['positive_prompt'] = embedding_prompt_text
|
| 285 |
-
|
| 286 |
-
controlnet_data = ui_inputs.get('controlnet_data', [])
|
| 287 |
-
active_controlnets = []
|
| 288 |
-
if controlnet_data:
|
| 289 |
-
(cn_images, _, _, cn_strengths, cn_filepaths) = [controlnet_data[i::5] for i in range(5)]
|
| 290 |
-
for i in range(len(cn_images)):
|
| 291 |
-
if cn_images[i] and cn_strengths[i] > 0 and cn_filepaths[i] and cn_filepaths[i] != "None":
|
| 292 |
-
ensure_controlnet_model_downloaded(cn_filepaths[i], progress)
|
| 293 |
-
if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
|
| 294 |
-
cn_temp_path = os.path.join(INPUT_DIR, f"temp_cn_{i}_{random.randint(1000, 9999)}.png")
|
| 295 |
-
cn_images[i].save(cn_temp_path, "PNG")
|
| 296 |
-
temp_files_to_clean.append(cn_temp_path)
|
| 297 |
-
active_controlnets.append({
|
| 298 |
-
"image": os.path.basename(cn_temp_path), "strength": cn_strengths[i],
|
| 299 |
-
"start_percent": 0.0, "end_percent": 1.0, "control_net_name": cn_filepaths[i]
|
| 300 |
-
})
|
| 301 |
-
|
| 302 |
-
anima_controlnet_lllite_data = ui_inputs.get('anima_controlnet_lllite_data', [])
|
| 303 |
-
active_anima_controlnets = []
|
| 304 |
-
if anima_controlnet_lllite_data:
|
| 305 |
-
(cn_images, _, _, cn_strengths, cn_filepaths, cn_starts, cn_ends) = [anima_controlnet_lllite_data[i::7] for i in range(7)]
|
| 306 |
-
for i in range(len(cn_images)):
|
| 307 |
-
if cn_images[i] and cn_strengths[i] > 0 and cn_filepaths[i] and cn_filepaths[i] != "None":
|
| 308 |
-
from utils.app_utils import _ensure_model_downloaded
|
| 309 |
-
_ensure_model_downloaded(cn_filepaths[i], progress)
|
| 310 |
-
if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
|
| 311 |
-
cn_temp_path = os.path.join(INPUT_DIR, f"temp_anima_cn_{i}_{random.randint(1000, 9999)}.png")
|
| 312 |
-
cn_images[i].save(cn_temp_path, "PNG")
|
| 313 |
-
temp_files_to_clean.append(cn_temp_path)
|
| 314 |
-
active_anima_controlnets.append({
|
| 315 |
-
"image": os.path.basename(cn_temp_path), "strength": cn_strengths[i],
|
| 316 |
-
"start_percent": cn_starts[i], "end_percent": cn_ends[i], "control_net_name": cn_filepaths[i]
|
| 317 |
-
})
|
| 318 |
-
|
| 319 |
-
diffsynth_controlnet_data = ui_inputs.get('diffsynth_controlnet_data', [])
|
| 320 |
-
active_diffsynth_controlnets = []
|
| 321 |
-
if diffsynth_controlnet_data:
|
| 322 |
-
(cn_images, _, _, cn_strengths, cn_filepaths) = [diffsynth_controlnet_data[i::5] for i in range(5)]
|
| 323 |
-
for i in range(len(cn_images)):
|
| 324 |
-
if cn_images[i] and cn_strengths[i] > 0 and cn_filepaths[i] and cn_filepaths[i] != "None":
|
| 325 |
-
ensure_controlnet_model_downloaded(cn_filepaths[i], progress)
|
| 326 |
-
|
| 327 |
-
if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
|
| 328 |
-
cn_temp_path = os.path.join(INPUT_DIR, f"temp_diffsynth_cn_{i}_{random.randint(1000, 9999)}.png")
|
| 329 |
-
cn_images[i].save(cn_temp_path, "PNG")
|
| 330 |
-
temp_files_to_clean.append(cn_temp_path)
|
| 331 |
-
active_diffsynth_controlnets.append({
|
| 332 |
-
"image": os.path.basename(cn_temp_path), "strength": cn_strengths[i],
|
| 333 |
-
"control_net_name": cn_filepaths[i]
|
| 334 |
-
})
|
| 335 |
-
|
| 336 |
-
ipadapter_data = ui_inputs.get('ipadapter_data', [])
|
| 337 |
-
active_ipadapters = []
|
| 338 |
-
if ipadapter_data:
|
| 339 |
-
num_ipa_units = (len(ipadapter_data) - 5) // 3
|
| 340 |
-
final_preset, final_weight, final_lora_strength, final_embeds_scaling, final_combine_method = ipadapter_data[-5:]
|
| 341 |
-
ipa_images, ipa_weights, ipa_lora_strengths = [ipadapter_data[i*num_ipa_units:(i+1)*num_ipa_units] for i in range(3)]
|
| 342 |
-
all_presets_to_download = set()
|
| 343 |
-
for i in range(num_ipa_units):
|
| 344 |
-
if ipa_images[i] and ipa_weights[i] > 0 and final_preset:
|
| 345 |
-
all_presets_to_download.add(final_preset)
|
| 346 |
-
if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
|
| 347 |
-
ipa_temp_path = os.path.join(INPUT_DIR, f"temp_ipa_{i}_{random.randint(1000, 9999)}.png")
|
| 348 |
-
ipa_images[i].save(ipa_temp_path, "PNG")
|
| 349 |
-
temp_files_to_clean.append(ipa_temp_path)
|
| 350 |
-
active_ipadapters.append({
|
| 351 |
-
"image": os.path.basename(ipa_temp_path), "preset": final_preset,
|
| 352 |
-
"weight": ipa_weights[i], "lora_strength": ipa_lora_strengths[i]
|
| 353 |
-
})
|
| 354 |
-
if active_ipadapters and final_preset:
|
| 355 |
-
all_presets_to_download.add(final_preset)
|
| 356 |
-
for preset in all_presets_to_download:
|
| 357 |
-
ensure_ipadapter_models_downloaded(preset, progress)
|
| 358 |
-
|
| 359 |
-
model_type_key = 'sd15' if workflow_model_type == 'sd15' else 'sdxl'
|
| 360 |
-
if active_ipadapters:
|
| 361 |
-
active_ipadapters.append({
|
| 362 |
-
'is_final_settings': True, 'model_type': model_type_key, 'final_preset': final_preset,
|
| 363 |
-
'final_weight': final_weight, 'final_lora_strength': final_lora_strength,
|
| 364 |
-
'final_embeds_scaling': final_embeds_scaling, 'final_combine_method': final_combine_method
|
| 365 |
-
})
|
| 366 |
-
|
| 367 |
-
flux1_ipadapter_data = ui_inputs.get('flux1_ipadapter_data', [])
|
| 368 |
-
active_flux1_ipadapters = []
|
| 369 |
-
if flux1_ipadapter_data:
|
| 370 |
-
num_units = len(flux1_ipadapter_data) // 4
|
| 371 |
-
f_images = flux1_ipadapter_data[0*num_units : 1*num_units]
|
| 372 |
-
f_weights = flux1_ipadapter_data[1*num_units : 2*num_units]
|
| 373 |
-
f_starts = flux1_ipadapter_data[2*num_units : 3*num_units]
|
| 374 |
-
f_ends = flux1_ipadapter_data[3*num_units : 4*num_units]
|
| 375 |
-
for i in range(len(f_images)):
|
| 376 |
-
if f_images[i] and f_weights[i] > 0:
|
| 377 |
-
from utils.app_utils import _ensure_model_downloaded
|
| 378 |
-
for filename in ["ip-adapter.bin"]:
|
| 379 |
-
_ensure_model_downloaded(filename, progress)
|
| 380 |
-
|
| 381 |
-
from huggingface_hub import snapshot_download
|
| 382 |
-
progress(0.5, desc="Caching HF SigLIP model...")
|
| 383 |
-
snapshot_download(
|
| 384 |
-
repo_id="google/siglip-so400m-patch14-384",
|
| 385 |
-
allow_patterns=["*.json", "*.safetensors", "*.txt"],
|
| 386 |
-
ignore_patterns=["*.msgpack", "*.h5", "*.bin"]
|
| 387 |
-
)
|
| 388 |
-
|
| 389 |
-
temp_path = os.path.join(INPUT_DIR, f"temp_fipa_{i}_{random.randint(1000, 9999)}.png")
|
| 390 |
-
f_images[i].save(temp_path, "PNG")
|
| 391 |
-
temp_files_to_clean.append(temp_path)
|
| 392 |
-
active_flux1_ipadapters.append({
|
| 393 |
-
"image": os.path.basename(temp_path),
|
| 394 |
-
"weight": f_weights[i], "start_percent": f_starts[i], "end_percent": f_ends[i]
|
| 395 |
-
})
|
| 396 |
-
|
| 397 |
-
sd3_ipadapter_data = ui_inputs.get('sd3_ipadapter_chain', [])
|
| 398 |
-
active_sd3_ipadapters = []
|
| 399 |
-
if sd3_ipadapter_data:
|
| 400 |
-
num_units = len(sd3_ipadapter_data) // 4
|
| 401 |
-
s_images = sd3_ipadapter_data[0*num_units : 1*num_units]
|
| 402 |
-
s_weights = sd3_ipadapter_data[1*num_units : 2*num_units]
|
| 403 |
-
s_starts = sd3_ipadapter_data[2*num_units : 3*num_units]
|
| 404 |
-
s_ends = sd3_ipadapter_data[3*num_units : 4*num_units]
|
| 405 |
-
sd3_ipa_downloaded = False
|
| 406 |
-
for i in range(len(s_images)):
|
| 407 |
-
if s_images[i] and s_weights[i] > 0:
|
| 408 |
-
if not sd3_ipa_downloaded:
|
| 409 |
-
from utils.app_utils import ensure_sd3_ipadapter_models_downloaded
|
| 410 |
-
ensure_sd3_ipadapter_models_downloaded(progress)
|
| 411 |
-
sd3_ipa_downloaded = True
|
| 412 |
-
temp_path = os.path.join(INPUT_DIR, f"temp_s3ipa_{i}_{random.randint(1000, 9999)}.png")
|
| 413 |
-
s_images[i].save(temp_path, "PNG")
|
| 414 |
-
temp_files_to_clean.append(temp_path)
|
| 415 |
-
active_sd3_ipadapters.append({
|
| 416 |
-
"image": os.path.basename(temp_path),
|
| 417 |
-
"weight": s_weights[i], "start_percent": s_starts[i], "end_percent": s_ends[i]
|
| 418 |
-
})
|
| 419 |
-
|
| 420 |
-
style_data = ui_inputs.get('style_data', [])
|
| 421 |
-
active_styles = []
|
| 422 |
-
if style_data:
|
| 423 |
-
num_units = len(style_data) // 2
|
| 424 |
-
st_images = style_data[0*num_units : 1*num_units]
|
| 425 |
-
st_strengths = style_data[1*num_units : 2*num_units]
|
| 426 |
-
for i in range(len(st_images)):
|
| 427 |
-
if st_images[i] and st_strengths[i] > 0:
|
| 428 |
-
from utils.app_utils import _ensure_model_downloaded
|
| 429 |
-
_ensure_model_downloaded("sigclip_vision_patch14_384.safetensors", progress)
|
| 430 |
-
temp_path = os.path.join(INPUT_DIR, f"temp_style_{i}_{random.randint(1000, 9999)}.png")
|
| 431 |
-
st_images[i].save(temp_path, "PNG")
|
| 432 |
-
temp_files_to_clean.append(temp_path)
|
| 433 |
-
active_styles.append({
|
| 434 |
-
"image": os.path.basename(temp_path), "strength": st_strengths[i]
|
| 435 |
-
})
|
| 436 |
-
|
| 437 |
-
reference_latent_data = ui_inputs.get('reference_latent_data', [])
|
| 438 |
-
active_reference_latents = []
|
| 439 |
-
if reference_latent_data:
|
| 440 |
-
for img in reference_latent_data:
|
| 441 |
-
if img:
|
| 442 |
-
if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
|
| 443 |
-
temp_path = os.path.join(INPUT_DIR, f"temp_ref_{random.randint(1000, 9999)}.png")
|
| 444 |
-
img.save(temp_path, "PNG")
|
| 445 |
-
temp_files_to_clean.append(temp_path)
|
| 446 |
-
active_reference_latents.append(os.path.basename(temp_path))
|
| 447 |
-
|
| 448 |
-
hidream_o1_reference_data = ui_inputs.get('hidream_o1_reference_data', [])
|
| 449 |
-
active_hidream_o1_reference = []
|
| 450 |
-
if hidream_o1_reference_data:
|
| 451 |
-
for img in hidream_o1_reference_data:
|
| 452 |
-
if img:
|
| 453 |
-
if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
|
| 454 |
-
temp_path = os.path.join(INPUT_DIR, f"temp_ho1_ref_{random.randint(1000, 9999)}.png")
|
| 455 |
-
img.save(temp_path, "PNG")
|
| 456 |
-
temp_files_to_clean.append(temp_path)
|
| 457 |
-
active_hidream_o1_reference.append(os.path.basename(temp_path))
|
| 458 |
-
|
| 459 |
-
from utils.app_utils import get_vae_path
|
| 460 |
-
vae_source = ui_inputs.get('vae_source')
|
| 461 |
-
vae_id = ui_inputs.get('vae_id')
|
| 462 |
-
vae_name_override = None
|
| 463 |
-
if vae_source and vae_source != "None":
|
| 464 |
-
if vae_source == "File":
|
| 465 |
-
vae_name_override = sanitize_filename(vae_id)
|
| 466 |
-
elif vae_source == "Civitai" and vae_id and vae_id.strip():
|
| 467 |
-
local_path, status = get_vae_path(vae_source, vae_id, os.environ.get("CIVITAI_API_KEY", ""), progress)
|
| 468 |
-
if local_path: vae_name_override = os.path.basename(local_path)
|
| 469 |
-
else: raise gr.Error(f"Failed to prepare VAE {vae_id}: {status}")
|
| 470 |
-
if vae_name_override:
|
| 471 |
-
ui_inputs['vae_name'] = vae_name_override
|
| 472 |
-
|
| 473 |
-
conditioning_data = ui_inputs.get('conditioning_data', [])
|
| 474 |
-
active_conditioning = []
|
| 475 |
-
if conditioning_data:
|
| 476 |
-
num_units = len(conditioning_data) // 6
|
| 477 |
-
prompts, widths, heights, xs, ys, strengths = [conditioning_data[i*num_units : (i+1)*num_units] for i in range(6)]
|
| 478 |
-
for i in range(num_units):
|
| 479 |
-
if prompts[i] and prompts[i].strip():
|
| 480 |
-
active_conditioning.append({
|
| 481 |
-
"prompt": prompts[i], "width": int(widths[i]), "height": int(heights[i]),
|
| 482 |
-
"x": int(xs[i]), "y": int(ys[i]), "strength": float(strengths[i])
|
| 483 |
-
})
|
| 484 |
-
|
| 485 |
-
loras_string = f"LoRAs: [{', '.join(active_loras_for_meta)}]" if active_loras_for_meta else ""
|
| 486 |
-
|
| 487 |
-
progress(0.8, desc="Assembling workflow...")
|
| 488 |
-
|
| 489 |
-
if ui_inputs.get('seed') == -1:
|
| 490 |
-
ui_inputs['seed'] = random.randint(0, 2**32 - 1)
|
| 491 |
-
|
| 492 |
-
model_info = ALL_MODEL_MAP[model_display_name]
|
| 493 |
-
path_or_components = model_info[1]
|
| 494 |
-
latent_type = model_info[3] if len(model_info) > 3 and model_info[3] else 'latent'
|
| 495 |
-
latent_generator_template = "EmptyLatentImage"
|
| 496 |
-
if latent_type == 'sd3_latent':
|
| 497 |
-
latent_generator_template = "EmptySD3LatentImage"
|
| 498 |
-
elif latent_type == 'chroma_radiance_latent':
|
| 499 |
-
latent_generator_template = "EmptyChromaRadianceLatentImage"
|
| 500 |
-
elif latent_type == 'hunyuan_latent':
|
| 501 |
-
latent_generator_template = "EmptyHunyuanImageLatent"
|
| 502 |
-
|
| 503 |
-
dynamic_values = {
|
| 504 |
-
'task_type': ui_inputs['task_type'],
|
| 505 |
-
'model_type': workflow_model_type,
|
| 506 |
-
'latent_type': latent_type,
|
| 507 |
-
'latent_generator_template': latent_generator_template
|
| 508 |
-
}
|
| 509 |
-
|
| 510 |
-
recipe_path = os.path.join(os.path.dirname(__file__), "workflow_recipes", "sd_unified_recipe.yaml")
|
| 511 |
-
assembler = WorkflowAssembler(recipe_path, dynamic_values=dynamic_values)
|
| 512 |
-
|
| 513 |
-
hidream_o1_smoothing_data = []
|
| 514 |
-
if workflow_model_type == 'hidream-o1' and model_display_name == "HiDream-O1-Image":
|
| 515 |
-
hidream_o1_smoothing_data.append({})
|
| 516 |
-
|
| 517 |
-
workflow_inputs = {
|
| 518 |
-
**ui_inputs,
|
| 519 |
-
"positive_prompt": ui_inputs['positive_prompt'], "negative_prompt": ui_inputs['negative_prompt'],
|
| 520 |
-
"seed": ui_inputs['seed'], "steps": ui_inputs['num_inference_steps'], "cfg": ui_inputs['guidance_scale'],
|
| 521 |
-
"sampler_name": ui_inputs['sampler'], "scheduler": ui_inputs['scheduler'],
|
| 522 |
-
"batch_size": ui_inputs['batch_size'],
|
| 523 |
-
"clip_skip": ui_inputs['clip_skip'],
|
| 524 |
-
"denoise": ui_inputs['denoise'],
|
| 525 |
-
"vae_name": ui_inputs.get('vae_name'),
|
| 526 |
-
"guidance": ui_inputs.get('guidance', 3.5),
|
| 527 |
-
"lora_chain": active_loras_for_gpu,
|
| 528 |
-
"controlnet_chain": active_controlnets if not active_anima_controlnets else [],
|
| 529 |
-
"anima_controlnet_lllite_chain": active_anima_controlnets,
|
| 530 |
-
"diffsynth_controlnet_chain": active_diffsynth_controlnets,
|
| 531 |
-
"ipadapter_chain": active_ipadapters,
|
| 532 |
-
"flux1_ipadapter_chain": active_flux1_ipadapters,
|
| 533 |
-
"sd3_ipadapter_chain": active_sd3_ipadapters,
|
| 534 |
-
"style_chain": active_styles,
|
| 535 |
-
"conditioning_chain": active_conditioning,
|
| 536 |
-
"reference_latent_chain": active_reference_latents,
|
| 537 |
-
"hidream_o1_reference_chain": active_hidream_o1_reference,
|
| 538 |
-
"vae_chain": [ui_inputs.get('vae_name')] if ui_inputs.get('vae_name') else [],
|
| 539 |
-
"hidream_o1_smoothing_chain": hidream_o1_smoothing_data,
|
| 540 |
-
}
|
| 541 |
-
|
| 542 |
-
if isinstance(path_or_components, dict):
|
| 543 |
-
workflow_inputs.update({
|
| 544 |
-
'unet_name': path_or_components.get('unet'),
|
| 545 |
-
'vae_name': ui_inputs.get('vae_name') or path_or_components.get('vae'),
|
| 546 |
-
'clip_name': path_or_components.get('clip'),
|
| 547 |
-
'clip1_name': path_or_components.get('clip1'),
|
| 548 |
-
'clip2_name': path_or_components.get('clip2'),
|
| 549 |
-
'clip3_name': path_or_components.get('clip3'),
|
| 550 |
-
'clip4_name': path_or_components.get('clip4'),
|
| 551 |
-
'lora_name': path_or_components.get('lora'),
|
| 552 |
-
})
|
| 553 |
-
else:
|
| 554 |
-
workflow_inputs['model_name'] = path_or_components
|
| 555 |
-
|
| 556 |
-
if task_type == 'txt2img':
|
| 557 |
-
workflow_inputs['width'] = ui_inputs['width']
|
| 558 |
-
workflow_inputs['height'] = ui_inputs['height']
|
| 559 |
-
|
| 560 |
-
workflow = assembler.assemble(workflow_inputs)
|
| 561 |
-
|
| 562 |
-
progress(1.0, desc="All models ready. Requesting GPU for generation...")
|
| 563 |
-
|
| 564 |
-
try:
|
| 565 |
-
results = self._execute_gpu_logic(
|
| 566 |
-
self._gpu_logic,
|
| 567 |
-
duration=ui_inputs['zero_gpu_duration'],
|
| 568 |
-
default_duration=60,
|
| 569 |
-
task_name=f"ImageGen ({task_type})",
|
| 570 |
-
ui_inputs=ui_inputs,
|
| 571 |
-
loras_string=loras_string,
|
| 572 |
-
workflow=workflow,
|
| 573 |
-
assembler=assembler,
|
| 574 |
-
progress=progress
|
| 575 |
-
)
|
| 576 |
-
|
| 577 |
-
import json
|
| 578 |
-
import glob
|
| 579 |
-
from PIL import PngImagePlugin
|
| 580 |
-
|
| 581 |
-
prompt_json = json.dumps(workflow)
|
| 582 |
-
|
| 583 |
-
out_dir = os.path.abspath(OUTPUT_DIR)
|
| 584 |
-
os.makedirs(out_dir, exist_ok=True)
|
| 585 |
-
|
| 586 |
-
try:
|
| 587 |
-
existing_files = glob.glob(os.path.join(out_dir, "gen_*.png"))
|
| 588 |
-
existing_files.sort(key=os.path.getmtime)
|
| 589 |
-
while len(existing_files) > 50:
|
| 590 |
-
os.remove(existing_files.pop(0))
|
| 591 |
-
except Exception as e:
|
| 592 |
-
print(f"Warning: Failed to cleanup output dir: {e}")
|
| 593 |
-
|
| 594 |
-
final_results = []
|
| 595 |
-
for img in results:
|
| 596 |
-
if not isinstance(img, Image.Image):
|
| 597 |
-
final_results.append(img)
|
| 598 |
-
continue
|
| 599 |
-
|
| 600 |
-
metadata = PngImagePlugin.PngInfo()
|
| 601 |
-
params_string = img.info.get("parameters", "")
|
| 602 |
-
if params_string:
|
| 603 |
-
metadata.add_text("parameters", params_string)
|
| 604 |
-
metadata.add_text("prompt", prompt_json)
|
| 605 |
-
|
| 606 |
-
filename = f"gen_{random.randint(1000000, 9999999)}.png"
|
| 607 |
-
filepath = os.path.join(out_dir, filename)
|
| 608 |
-
img.save(filepath, "PNG", pnginfo=metadata)
|
| 609 |
-
final_results.append(filepath)
|
| 610 |
-
|
| 611 |
-
results = final_results
|
| 612 |
-
|
| 613 |
-
finally:
|
| 614 |
-
for temp_file in temp_files_to_clean:
|
| 615 |
-
if temp_file and os.path.exists(temp_file):
|
| 616 |
-
os.remove(temp_file)
|
| 617 |
-
print(f"✅ Cleaned up temp file: {temp_file}")
|
| 618 |
-
|
| 619 |
return results
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import random
|
| 3 |
+
import shutil
|
| 4 |
+
import torch
|
| 5 |
+
import gradio as gr
|
| 6 |
+
from PIL import Image
|
| 7 |
+
from typing import List, Dict, Any
|
| 8 |
+
|
| 9 |
+
from .base_pipeline import BasePipeline
|
| 10 |
+
from core.settings import *
|
| 11 |
+
from utils.app_utils import sanitize_prompt
|
| 12 |
+
from core.workflow_assembler import WorkflowAssembler
|
| 13 |
+
from .workflow_executor import WorkflowExecutor
|
| 14 |
+
from .pipeline_input_processor import process_pipeline_inputs
|
| 15 |
+
|
| 16 |
+
class SdImagePipeline(BasePipeline):
|
| 17 |
+
def get_required_models(self, model_display_name: str, **kwargs) -> List[str]:
|
| 18 |
+
model_info = ALL_MODEL_MAP.get(model_display_name)
|
| 19 |
+
if not model_info:
|
| 20 |
+
return [model_display_name]
|
| 21 |
+
|
| 22 |
+
path_or_components = model_info[1]
|
| 23 |
+
if isinstance(path_or_components, dict):
|
| 24 |
+
return [v for v in path_or_components.values() if v and v != "pixel_space"]
|
| 25 |
+
else:
|
| 26 |
+
return [model_display_name]
|
| 27 |
+
|
| 28 |
+
def _gpu_logic(self, ui_inputs: Dict, loras_string: str, workflow: Dict[str, Any], assembler: WorkflowAssembler, progress=gr.Progress(track_tqdm=True)):
|
| 29 |
+
model_display_name = ui_inputs['model_display_name']
|
| 30 |
+
|
| 31 |
+
progress(0.4, desc="Executing workflow...")
|
| 32 |
+
|
| 33 |
+
initial_objects = {}
|
| 34 |
+
|
| 35 |
+
decoded_images_tensor = WorkflowExecutor.execute_workflow(workflow, initial_objects=initial_objects)
|
| 36 |
+
|
| 37 |
+
output_images = []
|
| 38 |
+
start_seed = ui_inputs['seed'] if ui_inputs['seed'] != -1 else random.randint(0, 2**64 - 1)
|
| 39 |
+
for i in range(decoded_images_tensor.shape[0]):
|
| 40 |
+
img_tensor = decoded_images_tensor[i]
|
| 41 |
+
pil_image = Image.fromarray((img_tensor.cpu().numpy() * 255.0).astype("uint8"))
|
| 42 |
+
current_seed = start_seed + i
|
| 43 |
+
|
| 44 |
+
width_for_meta = ui_inputs.get('width', 'N/A')
|
| 45 |
+
height_for_meta = ui_inputs.get('height', 'N/A')
|
| 46 |
+
|
| 47 |
+
params_string = f"{ui_inputs['positive_prompt']}\nNegative prompt: {ui_inputs['negative_prompt']}\n"
|
| 48 |
+
params_string += f"Steps: {ui_inputs['num_inference_steps']}, Sampler: {ui_inputs['sampler']}, Scheduler: {ui_inputs['scheduler']}, CFG scale: {ui_inputs['guidance_scale']}, Seed: {current_seed}, Size: {width_for_meta}x{height_for_meta}, Base Model: {model_display_name}"
|
| 49 |
+
if ui_inputs['task_type'] != 'txt2img': params_string += f", Denoise: {ui_inputs['denoise']}"
|
| 50 |
+
if ui_inputs.get('clip_skip') and ui_inputs['clip_skip'] != 1: params_string += f", Clip skip: {abs(ui_inputs['clip_skip'])}"
|
| 51 |
+
if loras_string: params_string += f", {loras_string}"
|
| 52 |
+
|
| 53 |
+
pil_image.info = {'parameters': params_string.strip()}
|
| 54 |
+
output_images.append(pil_image)
|
| 55 |
+
|
| 56 |
+
return output_images
|
| 57 |
+
|
| 58 |
+
def run(self, ui_inputs: Dict, progress):
|
| 59 |
+
progress(0, desc="Preparing models...")
|
| 60 |
+
|
| 61 |
+
task_type = ui_inputs['task_type']
|
| 62 |
+
model_display_name = ui_inputs['model_display_name']
|
| 63 |
+
model_type = MODEL_TYPE_MAP.get(model_display_name, 'sdxl')
|
| 64 |
+
|
| 65 |
+
architectures_dict = ARCHITECTURES_CONFIG.get('architectures', {})
|
| 66 |
+
workflow_model_type = architectures_dict.get(model_type, {}).get("model_type", model_type.lower().replace(" ", "").replace(".", ""))
|
| 67 |
+
|
| 68 |
+
ui_inputs['positive_prompt'] = sanitize_prompt(ui_inputs.get('positive_prompt', ''))
|
| 69 |
+
ui_inputs['negative_prompt'] = sanitize_prompt(ui_inputs.get('negative_prompt', ''))
|
| 70 |
+
|
| 71 |
+
if 'clip_skip' in ui_inputs and ui_inputs['clip_skip'] is not None:
|
| 72 |
+
ui_inputs['clip_skip'] = -int(ui_inputs['clip_skip'])
|
| 73 |
+
else:
|
| 74 |
+
ui_inputs['clip_skip'] = -1
|
| 75 |
+
|
| 76 |
+
required_models = self.get_required_models(model_display_name=model_display_name)
|
| 77 |
+
|
| 78 |
+
is_pid_enabled = (ui_inputs.get('pid_settings', 'OFF') == 'ON' and task_type == 'txt2img')
|
| 79 |
+
if is_pid_enabled:
|
| 80 |
+
import yaml
|
| 81 |
+
pid_config_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), 'yaml', 'pid.yaml')
|
| 82 |
+
pid_unet_name = "pid_flux1_1024_to_4096_4step_mxfp8.safetensors"
|
| 83 |
+
try:
|
| 84 |
+
with open(pid_config_path, 'r', encoding='utf-8') as f:
|
| 85 |
+
pid_config = yaml.safe_load(f) or {}
|
| 86 |
+
pid_items = pid_config.get("PiD", [])
|
| 87 |
+
for item in pid_items:
|
| 88 |
+
archs = item.get("architectures", [])
|
| 89 |
+
if workflow_model_type in archs:
|
| 90 |
+
pid_unet_name = item.get("filepath")
|
| 91 |
+
break
|
| 92 |
+
except Exception as e:
|
| 93 |
+
print(f"Error loading PiD config for download: {e}")
|
| 94 |
+
|
| 95 |
+
if pid_unet_name not in required_models:
|
| 96 |
+
required_models.append(pid_unet_name)
|
| 97 |
+
if "gemma_2_2b_it_elm_fp8_scaled.safetensors" not in required_models:
|
| 98 |
+
required_models.append("gemma_2_2b_it_elm_fp8_scaled.safetensors")
|
| 99 |
+
|
| 100 |
+
self.model_manager.ensure_models_downloaded(required_models, progress=progress)
|
| 101 |
+
|
| 102 |
+
temp_files_to_clean = []
|
| 103 |
+
try:
|
| 104 |
+
processed = process_pipeline_inputs(ui_inputs, progress, workflow_model_type)
|
| 105 |
+
temp_files_to_clean.extend(processed["temp_files_to_clean"])
|
| 106 |
+
|
| 107 |
+
active_loras_for_gpu = processed["active_loras_for_gpu"]
|
| 108 |
+
active_loras_for_meta = processed["active_loras_for_meta"]
|
| 109 |
+
active_controlnets = processed["active_controlnets"]
|
| 110 |
+
active_anima_controlnets = processed["active_anima_controlnets"]
|
| 111 |
+
active_diffsynth_controlnets = processed["active_diffsynth_controlnets"]
|
| 112 |
+
active_ipadapters = processed["active_ipadapters"]
|
| 113 |
+
active_flux1_ipadapters = processed["active_flux1_ipadapters"]
|
| 114 |
+
active_sd3_ipadapters = processed["active_sd3_ipadapters"]
|
| 115 |
+
active_styles = processed["active_styles"]
|
| 116 |
+
active_reference_latents = processed["active_reference_latents"]
|
| 117 |
+
active_hidream_o1_reference = processed["active_hidream_o1_reference"]
|
| 118 |
+
active_conditioning = processed["active_conditioning"]
|
| 119 |
+
|
| 120 |
+
loras_string = f"LoRAs: [{', '.join(active_loras_for_meta)}]" if active_loras_for_meta else ""
|
| 121 |
+
|
| 122 |
+
progress(0.8, desc="Assembling workflow...")
|
| 123 |
+
|
| 124 |
+
if ui_inputs.get('seed') == -1:
|
| 125 |
+
ui_inputs['seed'] = random.randint(0, 2**32 - 1)
|
| 126 |
+
|
| 127 |
+
model_info = ALL_MODEL_MAP[model_display_name]
|
| 128 |
+
path_or_components = model_info[1]
|
| 129 |
+
latent_type = model_info[3] if len(model_info) > 3 and model_info[3] else 'latent'
|
| 130 |
+
latent_generator_template = "EmptyLatentImage"
|
| 131 |
+
if latent_type == 'sd3_latent':
|
| 132 |
+
latent_generator_template = "EmptySD3LatentImage"
|
| 133 |
+
elif latent_type == 'chroma_radiance_latent':
|
| 134 |
+
latent_generator_template = "EmptyChromaRadianceLatentImage"
|
| 135 |
+
elif latent_type == 'hunyuan_latent':
|
| 136 |
+
latent_generator_template = "EmptyHunyuanImageLatent"
|
| 137 |
+
|
| 138 |
+
dynamic_values = {
|
| 139 |
+
'task_type': ui_inputs['task_type'],
|
| 140 |
+
'model_type': workflow_model_type,
|
| 141 |
+
'latent_type': latent_type,
|
| 142 |
+
'latent_generator_template': latent_generator_template
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
recipe_path = os.path.join(os.path.dirname(__file__), "workflow_recipes", "sd_unified_recipe.yaml")
|
| 146 |
+
assembler = WorkflowAssembler(recipe_path, dynamic_values=dynamic_values)
|
| 147 |
+
|
| 148 |
+
hidream_o1_smoothing_data = []
|
| 149 |
+
if workflow_model_type == 'hidream-o1' and model_display_name == "HiDream-O1-Image":
|
| 150 |
+
hidream_o1_smoothing_data.append({})
|
| 151 |
+
|
| 152 |
+
workflow_inputs = {
|
| 153 |
+
**ui_inputs,
|
| 154 |
+
"positive_prompt": ui_inputs['positive_prompt'], "negative_prompt": ui_inputs['negative_prompt'],
|
| 155 |
+
"seed": ui_inputs['seed'], "steps": ui_inputs['num_inference_steps'], "cfg": ui_inputs['guidance_scale'],
|
| 156 |
+
"sampler_name": ui_inputs['sampler'], "scheduler": ui_inputs['scheduler'],
|
| 157 |
+
"batch_size": ui_inputs['batch_size'],
|
| 158 |
+
"clip_skip": ui_inputs['clip_skip'],
|
| 159 |
+
"denoise": ui_inputs['denoise'],
|
| 160 |
+
"vae_name": ui_inputs.get('vae_name'),
|
| 161 |
+
"guidance": ui_inputs.get('guidance', 3.5),
|
| 162 |
+
"lora_chain": active_loras_for_gpu,
|
| 163 |
+
"controlnet_chain": active_controlnets if not active_anima_controlnets else [],
|
| 164 |
+
"anima_controlnet_lllite_chain": active_anima_controlnets,
|
| 165 |
+
"diffsynth_controlnet_chain": active_diffsynth_controlnets,
|
| 166 |
+
"ipadapter_chain": active_ipadapters,
|
| 167 |
+
"flux1_ipadapter_chain": active_flux1_ipadapters,
|
| 168 |
+
"sd3_ipadapter_chain": active_sd3_ipadapters,
|
| 169 |
+
"style_chain": active_styles,
|
| 170 |
+
"conditioning_chain": active_conditioning,
|
| 171 |
+
"reference_latent_chain": active_reference_latents,
|
| 172 |
+
"hidream_o1_reference_chain": active_hidream_o1_reference,
|
| 173 |
+
"vae_chain": [ui_inputs.get('vae_name')] if ui_inputs.get('vae_name') else [],
|
| 174 |
+
"hidream_o1_smoothing_chain": hidream_o1_smoothing_data,
|
| 175 |
+
"pid_chain": [ui_inputs.get('pid_settings', 'OFF')] if is_pid_enabled else [],
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
if isinstance(path_or_components, dict):
|
| 179 |
+
workflow_inputs.update({
|
| 180 |
+
'unet_name': path_or_components.get('unet'),
|
| 181 |
+
'vae_name': ui_inputs.get('vae_name') or path_or_components.get('vae'),
|
| 182 |
+
'clip_name': path_or_components.get('clip'),
|
| 183 |
+
'clip1_name': path_or_components.get('clip1'),
|
| 184 |
+
'clip2_name': path_or_components.get('clip2'),
|
| 185 |
+
'clip3_name': path_or_components.get('clip3'),
|
| 186 |
+
'clip4_name': path_or_components.get('clip4'),
|
| 187 |
+
'lora_name': path_or_components.get('lora'),
|
| 188 |
+
})
|
| 189 |
+
else:
|
| 190 |
+
workflow_inputs['model_name'] = path_or_components
|
| 191 |
+
|
| 192 |
+
if task_type == 'txt2img':
|
| 193 |
+
workflow_inputs['width'] = ui_inputs['width']
|
| 194 |
+
workflow_inputs['height'] = ui_inputs['height']
|
| 195 |
+
|
| 196 |
+
workflow = assembler.assemble(workflow_inputs)
|
| 197 |
+
|
| 198 |
+
progress(1.0, desc="All models ready. Requesting GPU for generation...")
|
| 199 |
+
|
| 200 |
+
results = self._execute_gpu_logic(
|
| 201 |
+
self._gpu_logic,
|
| 202 |
+
duration=ui_inputs['zero_gpu_duration'],
|
| 203 |
+
default_duration=60,
|
| 204 |
+
task_name=f"ImageGen ({task_type})",
|
| 205 |
+
ui_inputs=ui_inputs,
|
| 206 |
+
loras_string=loras_string,
|
| 207 |
+
workflow=workflow,
|
| 208 |
+
assembler=assembler,
|
| 209 |
+
progress=progress
|
| 210 |
+
)
|
| 211 |
+
|
| 212 |
+
import json
|
| 213 |
+
import glob
|
| 214 |
+
from PIL import PngImagePlugin
|
| 215 |
+
|
| 216 |
+
prompt_json = json.dumps(workflow)
|
| 217 |
+
|
| 218 |
+
out_dir = os.path.abspath(OUTPUT_DIR)
|
| 219 |
+
os.makedirs(out_dir, exist_ok=True)
|
| 220 |
+
|
| 221 |
+
try:
|
| 222 |
+
existing_files = glob.glob(os.path.join(out_dir, "gen_*.png"))
|
| 223 |
+
existing_files.sort(key=os.path.getmtime)
|
| 224 |
+
while len(existing_files) > 50:
|
| 225 |
+
os.remove(existing_files.pop(0))
|
| 226 |
+
except Exception as e:
|
| 227 |
+
print(f"Warning: Failed to cleanup output dir: {e}")
|
| 228 |
+
|
| 229 |
+
final_results = []
|
| 230 |
+
for img in results:
|
| 231 |
+
if not isinstance(img, Image.Image):
|
| 232 |
+
final_results.append(img)
|
| 233 |
+
continue
|
| 234 |
+
|
| 235 |
+
metadata = PngImagePlugin.PngInfo()
|
| 236 |
+
params_string = img.info.get("parameters", "")
|
| 237 |
+
if params_string:
|
| 238 |
+
metadata.add_text("parameters", params_string)
|
| 239 |
+
metadata.add_text("prompt", prompt_json)
|
| 240 |
+
|
| 241 |
+
filename = f"gen_{random.randint(1000000, 9999999)}.png"
|
| 242 |
+
filepath = os.path.join(out_dir, filename)
|
| 243 |
+
img.save(filepath, "PNG", pnginfo=metadata)
|
| 244 |
+
final_results.append(filepath)
|
| 245 |
+
|
| 246 |
+
results = final_results
|
| 247 |
+
|
| 248 |
+
finally:
|
| 249 |
+
for temp_file in temp_files_to_clean:
|
| 250 |
+
if temp_file and os.path.exists(temp_file):
|
| 251 |
+
os.remove(temp_file)
|
| 252 |
+
print(f"✅ Cleaned up temp file: {temp_file}")
|
| 253 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 254 |
return results
|
core/pipelines/workflow_executor.py
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from collections import defaultdict, deque
|
| 3 |
+
from typing import Dict, Any, List
|
| 4 |
+
from comfy_integration.nodes import NODE_CLASS_MAPPINGS
|
| 5 |
+
from utils.app_utils import get_value_at_index
|
| 6 |
+
|
| 7 |
+
class WorkflowExecutor:
|
| 8 |
+
@staticmethod
|
| 9 |
+
def topological_sort(workflow: Dict[str, Any]) -> List[str]:
|
| 10 |
+
graph = defaultdict(list)
|
| 11 |
+
in_degree = {node_id: 0 for node_id in workflow}
|
| 12 |
+
|
| 13 |
+
for node_id, node_info in workflow.items():
|
| 14 |
+
for input_value in node_info.get('inputs', {}).values():
|
| 15 |
+
if isinstance(input_value, list) and len(input_value) == 2 and isinstance(input_value[0], str):
|
| 16 |
+
source_node_id = input_value[0]
|
| 17 |
+
if source_node_id in workflow:
|
| 18 |
+
graph[source_node_id].append(node_id)
|
| 19 |
+
in_degree[node_id] += 1
|
| 20 |
+
|
| 21 |
+
queue = deque([node_id for node_id, degree in in_degree.items() if degree == 0])
|
| 22 |
+
|
| 23 |
+
sorted_nodes = []
|
| 24 |
+
while queue:
|
| 25 |
+
current_node_id = queue.popleft()
|
| 26 |
+
sorted_nodes.append(current_node_id)
|
| 27 |
+
|
| 28 |
+
for neighbor_node_id in graph[current_node_id]:
|
| 29 |
+
in_degree[neighbor_node_id] -= 1
|
| 30 |
+
if in_degree[neighbor_node_id] == 0:
|
| 31 |
+
queue.append(neighbor_node_id)
|
| 32 |
+
|
| 33 |
+
if len(sorted_nodes) != len(workflow):
|
| 34 |
+
raise RuntimeError("Workflow contains a cycle and cannot be executed.")
|
| 35 |
+
|
| 36 |
+
return sorted_nodes
|
| 37 |
+
|
| 38 |
+
@staticmethod
|
| 39 |
+
def execute_workflow(workflow: Dict[str, Any], initial_objects: Dict[str, Any]):
|
| 40 |
+
with torch.no_grad():
|
| 41 |
+
computed_outputs = initial_objects
|
| 42 |
+
|
| 43 |
+
try:
|
| 44 |
+
sorted_node_ids = WorkflowExecutor.topological_sort(workflow)
|
| 45 |
+
print(f"--- [Workflow Executor] Execution order: {sorted_node_ids}")
|
| 46 |
+
except RuntimeError as e:
|
| 47 |
+
print("--- [Workflow Executor] ERROR: Failed to sort workflow. Dumping graph details. ---")
|
| 48 |
+
for node_id, node_info in workflow.items():
|
| 49 |
+
print(f" Node {node_id} ({node_info['class_type']}):")
|
| 50 |
+
for input_name, input_value in node_info['inputs'].items():
|
| 51 |
+
if isinstance(input_value, list) and len(input_value) == 2 and isinstance(input_value[0], str):
|
| 52 |
+
print(f" - {input_name} <- [{input_value[0]}, {input_value[1]}]")
|
| 53 |
+
raise e
|
| 54 |
+
|
| 55 |
+
for node_id in sorted_node_ids:
|
| 56 |
+
if node_id in computed_outputs:
|
| 57 |
+
continue
|
| 58 |
+
|
| 59 |
+
node_info = workflow[node_id]
|
| 60 |
+
class_type = node_info['class_type']
|
| 61 |
+
|
| 62 |
+
is_loader_with_filename = 'Loader' in class_type and any(key.endswith('_name') for key in node_info['inputs'])
|
| 63 |
+
if node_id in initial_objects and is_loader_with_filename:
|
| 64 |
+
continue
|
| 65 |
+
|
| 66 |
+
node_class = NODE_CLASS_MAPPINGS.get(class_type)
|
| 67 |
+
if node_class is None:
|
| 68 |
+
raise RuntimeError(f"Could not find node class '{class_type}'. Is it imported in comfy_integration/nodes.py?")
|
| 69 |
+
|
| 70 |
+
node_instance = node_class()
|
| 71 |
+
|
| 72 |
+
kwargs = {}
|
| 73 |
+
for param_name, param_value in node_info['inputs'].items():
|
| 74 |
+
if isinstance(param_value, list) and len(param_value) == 2 and isinstance(param_value[0], str):
|
| 75 |
+
source_node_id, output_index = param_value
|
| 76 |
+
if source_node_id not in computed_outputs:
|
| 77 |
+
raise RuntimeError(f"Workflow integrity error: Output of node {source_node_id} needed for {node_id} but not yet computed.")
|
| 78 |
+
|
| 79 |
+
source_output_tuple = computed_outputs[source_node_id]
|
| 80 |
+
actual_value = get_value_at_index(source_output_tuple, output_index)
|
| 81 |
+
else:
|
| 82 |
+
actual_value = param_value
|
| 83 |
+
|
| 84 |
+
if '.' in param_name:
|
| 85 |
+
parent_key, child_key = param_name.split('.', 1)
|
| 86 |
+
if parent_key not in kwargs or not isinstance(kwargs[parent_key], dict):
|
| 87 |
+
kwargs[parent_key] = {}
|
| 88 |
+
kwargs[parent_key][child_key] = actual_value
|
| 89 |
+
else:
|
| 90 |
+
kwargs[param_name] = actual_value
|
| 91 |
+
|
| 92 |
+
function_name = getattr(node_class, 'FUNCTION')
|
| 93 |
+
execution_method = getattr(node_instance, function_name)
|
| 94 |
+
|
| 95 |
+
result = execution_method(**kwargs)
|
| 96 |
+
computed_outputs[node_id] = result
|
| 97 |
+
|
| 98 |
+
final_node_id = None
|
| 99 |
+
for node_id in reversed(sorted_node_ids):
|
| 100 |
+
if workflow[node_id]['class_type'] == 'SaveImage':
|
| 101 |
+
final_node_id = node_id
|
| 102 |
+
break
|
| 103 |
+
|
| 104 |
+
if not final_node_id:
|
| 105 |
+
raise RuntimeError("Workflow does not contain a 'SaveImage' node as the output.")
|
| 106 |
+
|
| 107 |
+
save_image_inputs = workflow[final_node_id]['inputs']
|
| 108 |
+
image_source_node_id, image_source_index = save_image_inputs['images']
|
| 109 |
+
|
| 110 |
+
return get_value_at_index(computed_outputs[image_source_node_id], image_source_index)
|
core/pipelines/workflow_recipes/_partials/conditioning/anima.yaml
CHANGED
|
@@ -52,6 +52,10 @@ dynamic_conditioning_chains:
|
|
| 52 |
ksampler_node: "ksampler"
|
| 53 |
clip_source: "clip_loader:0"
|
| 54 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
ui_map:
|
| 56 |
unet_name: "unet_loader:unet_name"
|
| 57 |
vae_name: "vae_loader:vae_name"
|
|
|
|
| 52 |
ksampler_node: "ksampler"
|
| 53 |
clip_source: "clip_loader:0"
|
| 54 |
|
| 55 |
+
dynamic_pid_chains:
|
| 56 |
+
pid_chain:
|
| 57 |
+
ksampler_node: "ksampler"
|
| 58 |
+
|
| 59 |
ui_map:
|
| 60 |
unet_name: "unet_loader:unet_name"
|
| 61 |
vae_name: "vae_loader:vae_name"
|
core/pipelines/workflow_recipes/_partials/conditioning/chroma1.yaml
CHANGED
|
@@ -55,6 +55,10 @@ dynamic_conditioning_chains:
|
|
| 55 |
ksampler_node: "ksampler"
|
| 56 |
clip_source: "t5_tokenizer:0"
|
| 57 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
ui_map:
|
| 59 |
unet_name: "unet_loader:unet_name"
|
| 60 |
vae_name: "vae_loader:vae_name"
|
|
|
|
| 55 |
ksampler_node: "ksampler"
|
| 56 |
clip_source: "t5_tokenizer:0"
|
| 57 |
|
| 58 |
+
dynamic_pid_chains:
|
| 59 |
+
pid_chain:
|
| 60 |
+
ksampler_node: "ksampler"
|
| 61 |
+
|
| 62 |
ui_map:
|
| 63 |
unet_name: "unet_loader:unet_name"
|
| 64 |
vae_name: "vae_loader:vae_name"
|
core/pipelines/workflow_recipes/_partials/conditioning/ernie-image.yaml
CHANGED
|
@@ -48,6 +48,10 @@ dynamic_conditioning_chains:
|
|
| 48 |
ksampler_node: "ksampler"
|
| 49 |
clip_source: "clip_loader:0"
|
| 50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
ui_map:
|
| 52 |
unet_name: "unet_loader:unet_name"
|
| 53 |
clip_name: "clip_loader:clip_name"
|
|
|
|
| 48 |
ksampler_node: "ksampler"
|
| 49 |
clip_source: "clip_loader:0"
|
| 50 |
|
| 51 |
+
dynamic_pid_chains:
|
| 52 |
+
pid_chain:
|
| 53 |
+
ksampler_node: "ksampler"
|
| 54 |
+
|
| 55 |
ui_map:
|
| 56 |
unet_name: "unet_loader:unet_name"
|
| 57 |
clip_name: "clip_loader:clip_name"
|
core/pipelines/workflow_recipes/_partials/conditioning/flux1.yaml
CHANGED
|
@@ -56,6 +56,10 @@ dynamic_conditioning_chains:
|
|
| 56 |
ksampler_node: "ksampler"
|
| 57 |
clip_source: "clip_loader:0"
|
| 58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
ui_map:
|
| 60 |
unet_name: "unet_loader:unet_name"
|
| 61 |
vae_name: "vae_loader:vae_name"
|
|
|
|
| 56 |
ksampler_node: "ksampler"
|
| 57 |
clip_source: "clip_loader:0"
|
| 58 |
|
| 59 |
+
dynamic_pid_chains:
|
| 60 |
+
pid_chain:
|
| 61 |
+
ksampler_node: "ksampler"
|
| 62 |
+
|
| 63 |
ui_map:
|
| 64 |
unet_name: "unet_loader:unet_name"
|
| 65 |
vae_name: "vae_loader:vae_name"
|
core/pipelines/workflow_recipes/_partials/conditioning/flux2-kv.yaml
CHANGED
|
@@ -86,6 +86,10 @@ dynamic_reference_latent_chains:
|
|
| 86 |
ksampler_node: "ksampler"
|
| 87 |
vae_node: "vae_loader"
|
| 88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
ui_map:
|
| 90 |
unet_name: "unet_loader:unet_name"
|
| 91 |
clip_name: "clip_loader:clip_name"
|
|
|
|
| 86 |
ksampler_node: "ksampler"
|
| 87 |
vae_node: "vae_loader"
|
| 88 |
|
| 89 |
+
dynamic_pid_chains:
|
| 90 |
+
pid_chain:
|
| 91 |
+
ksampler_node: "ksampler"
|
| 92 |
+
|
| 93 |
ui_map:
|
| 94 |
unet_name: "unet_loader:unet_name"
|
| 95 |
clip_name: "clip_loader:clip_name"
|
core/pipelines/workflow_recipes/_partials/conditioning/flux2.yaml
CHANGED
|
@@ -78,6 +78,10 @@ dynamic_reference_latent_chains:
|
|
| 78 |
ksampler_node: "ksampler"
|
| 79 |
vae_node: "vae_loader"
|
| 80 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
ui_map:
|
| 82 |
unet_name: "unet_loader:unet_name"
|
| 83 |
clip_name: "clip_loader:clip_name"
|
|
|
|
| 78 |
ksampler_node: "ksampler"
|
| 79 |
vae_node: "vae_loader"
|
| 80 |
|
| 81 |
+
dynamic_pid_chains:
|
| 82 |
+
pid_chain:
|
| 83 |
+
ksampler_node: "ksampler"
|
| 84 |
+
|
| 85 |
ui_map:
|
| 86 |
unet_name: "unet_loader:unet_name"
|
| 87 |
clip_name: "clip_loader:clip_name"
|
core/pipelines/workflow_recipes/_partials/conditioning/hidream-i1.yaml
CHANGED
|
@@ -44,6 +44,10 @@ dynamic_conditioning_chains:
|
|
| 44 |
ksampler_node: "ksampler"
|
| 45 |
clip_source: "clip_loader:0"
|
| 46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
ui_map:
|
| 48 |
unet_name: "unet_loader:unet_name"
|
| 49 |
vae_name: "vae_loader:vae_name"
|
|
|
|
| 44 |
ksampler_node: "ksampler"
|
| 45 |
clip_source: "clip_loader:0"
|
| 46 |
|
| 47 |
+
dynamic_pid_chains:
|
| 48 |
+
pid_chain:
|
| 49 |
+
ksampler_node: "ksampler"
|
| 50 |
+
|
| 51 |
ui_map:
|
| 52 |
unet_name: "unet_loader:unet_name"
|
| 53 |
vae_name: "vae_loader:vae_name"
|
core/pipelines/workflow_recipes/_partials/conditioning/lens.yaml
CHANGED
|
@@ -48,6 +48,10 @@ dynamic_conditioning_chains:
|
|
| 48 |
ksampler_node: "ksampler"
|
| 49 |
clip_source: "clip_loader:0"
|
| 50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
ui_map:
|
| 52 |
unet_name: "unet_loader:unet_name"
|
| 53 |
clip_name: "clip_loader:clip_name"
|
|
|
|
| 48 |
ksampler_node: "ksampler"
|
| 49 |
clip_source: "clip_loader:0"
|
| 50 |
|
| 51 |
+
dynamic_pid_chains:
|
| 52 |
+
pid_chain:
|
| 53 |
+
ksampler_node: "ksampler"
|
| 54 |
+
|
| 55 |
ui_map:
|
| 56 |
unet_name: "unet_loader:unet_name"
|
| 57 |
clip_name: "clip_loader:clip_name"
|
core/pipelines/workflow_recipes/_partials/conditioning/longcat-image.yaml
CHANGED
|
@@ -77,6 +77,10 @@ dynamic_conditioning_chains:
|
|
| 77 |
ksampler_node: "ksampler"
|
| 78 |
clip_source: "clip_loader:0"
|
| 79 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
ui_map:
|
| 81 |
unet_name: "unet_loader:unet_name"
|
| 82 |
vae_name: "vae_loader:vae_name"
|
|
|
|
| 77 |
ksampler_node: "ksampler"
|
| 78 |
clip_source: "clip_loader:0"
|
| 79 |
|
| 80 |
+
dynamic_pid_chains:
|
| 81 |
+
pid_chain:
|
| 82 |
+
ksampler_node: "ksampler"
|
| 83 |
+
|
| 84 |
ui_map:
|
| 85 |
unet_name: "unet_loader:unet_name"
|
| 86 |
vae_name: "vae_loader:vae_name"
|
core/pipelines/workflow_recipes/_partials/conditioning/lumina.yaml
CHANGED
|
@@ -53,5 +53,9 @@ dynamic_conditioning_chains:
|
|
| 53 |
ksampler_node: "ksampler"
|
| 54 |
clip_source: "ckpt_loader:1"
|
| 55 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
ui_map:
|
| 57 |
model_name: "ckpt_loader:ckpt_name"
|
|
|
|
| 53 |
ksampler_node: "ksampler"
|
| 54 |
clip_source: "ckpt_loader:1"
|
| 55 |
|
| 56 |
+
dynamic_pid_chains:
|
| 57 |
+
pid_chain:
|
| 58 |
+
ksampler_node: "ksampler"
|
| 59 |
+
|
| 60 |
ui_map:
|
| 61 |
model_name: "ckpt_loader:ckpt_name"
|
core/pipelines/workflow_recipes/_partials/conditioning/newbie-image.yaml
CHANGED
|
@@ -58,6 +58,10 @@ dynamic_conditioning_chains:
|
|
| 58 |
ksampler_node: "ksampler"
|
| 59 |
clip_source: "clip_loader:0"
|
| 60 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
ui_map:
|
| 62 |
unet_name: "unet_loader:unet_name"
|
| 63 |
vae_name: "vae_loader:vae_name"
|
|
|
|
| 58 |
ksampler_node: "ksampler"
|
| 59 |
clip_source: "clip_loader:0"
|
| 60 |
|
| 61 |
+
dynamic_pid_chains:
|
| 62 |
+
pid_chain:
|
| 63 |
+
ksampler_node: "ksampler"
|
| 64 |
+
|
| 65 |
ui_map:
|
| 66 |
unet_name: "unet_loader:unet_name"
|
| 67 |
vae_name: "vae_loader:vae_name"
|
core/pipelines/workflow_recipes/_partials/conditioning/omnigen2.yaml
CHANGED
|
@@ -53,6 +53,10 @@ dynamic_reference_latent_chains:
|
|
| 53 |
ksampler_node: "ksampler"
|
| 54 |
vae_node: "vae_loader"
|
| 55 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
ui_map:
|
| 57 |
unet_name: "unet_loader:unet_name"
|
| 58 |
vae_name: "vae_loader:vae_name"
|
|
|
|
| 53 |
ksampler_node: "ksampler"
|
| 54 |
vae_node: "vae_loader"
|
| 55 |
|
| 56 |
+
dynamic_pid_chains:
|
| 57 |
+
pid_chain:
|
| 58 |
+
ksampler_node: "ksampler"
|
| 59 |
+
|
| 60 |
ui_map:
|
| 61 |
unet_name: "unet_loader:unet_name"
|
| 62 |
vae_name: "vae_loader:vae_name"
|
core/pipelines/workflow_recipes/_partials/conditioning/ovis-image.yaml
CHANGED
|
@@ -44,6 +44,10 @@ dynamic_conditioning_chains:
|
|
| 44 |
ksampler_node: "ksampler"
|
| 45 |
clip_source: "clip_loader:0"
|
| 46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
ui_map:
|
| 48 |
unet_name: "unet_loader:unet_name"
|
| 49 |
vae_name: "vae_loader:vae_name"
|
|
|
|
| 44 |
ksampler_node: "ksampler"
|
| 45 |
clip_source: "clip_loader:0"
|
| 46 |
|
| 47 |
+
dynamic_pid_chains:
|
| 48 |
+
pid_chain:
|
| 49 |
+
ksampler_node: "ksampler"
|
| 50 |
+
|
| 51 |
ui_map:
|
| 52 |
unet_name: "unet_loader:unet_name"
|
| 53 |
vae_name: "vae_loader:vae_name"
|
core/pipelines/workflow_recipes/_partials/conditioning/qwen-image.yaml
CHANGED
|
@@ -73,6 +73,10 @@ dynamic_conditioning_chains:
|
|
| 73 |
ksampler_node: "ksampler"
|
| 74 |
clip_source: "clip_loader:0"
|
| 75 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
ui_map:
|
| 77 |
unet_name: "unet_loader:unet_name"
|
| 78 |
vae_name: "vae_loader:vae_name"
|
|
|
|
| 73 |
ksampler_node: "ksampler"
|
| 74 |
clip_source: "clip_loader:0"
|
| 75 |
|
| 76 |
+
dynamic_pid_chains:
|
| 77 |
+
pid_chain:
|
| 78 |
+
ksampler_node: "ksampler"
|
| 79 |
+
|
| 80 |
ui_map:
|
| 81 |
unet_name: "unet_loader:unet_name"
|
| 82 |
vae_name: "vae_loader:vae_name"
|
core/pipelines/workflow_recipes/_partials/conditioning/sd35.yaml
CHANGED
|
@@ -54,5 +54,9 @@ dynamic_conditioning_chains:
|
|
| 54 |
ksampler_node: "ksampler"
|
| 55 |
clip_source: "ckpt_loader:1"
|
| 56 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
ui_map:
|
| 58 |
model_name: "ckpt_loader:ckpt_name"
|
|
|
|
| 54 |
ksampler_node: "ksampler"
|
| 55 |
clip_source: "ckpt_loader:1"
|
| 56 |
|
| 57 |
+
dynamic_pid_chains:
|
| 58 |
+
pid_chain:
|
| 59 |
+
ksampler_node: "ksampler"
|
| 60 |
+
|
| 61 |
ui_map:
|
| 62 |
model_name: "ckpt_loader:ckpt_name"
|
core/pipelines/workflow_recipes/_partials/conditioning/sdxl.yaml
CHANGED
|
@@ -59,5 +59,9 @@ dynamic_conditioning_chains:
|
|
| 59 |
ksampler_node: "ksampler"
|
| 60 |
clip_source: "ckpt_loader:1"
|
| 61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
ui_map:
|
| 63 |
model_name: "ckpt_loader:ckpt_name"
|
|
|
|
| 59 |
ksampler_node: "ksampler"
|
| 60 |
clip_source: "ckpt_loader:1"
|
| 61 |
|
| 62 |
+
dynamic_pid_chains:
|
| 63 |
+
pid_chain:
|
| 64 |
+
ksampler_node: "ksampler"
|
| 65 |
+
|
| 66 |
ui_map:
|
| 67 |
model_name: "ckpt_loader:ckpt_name"
|
core/pipelines/workflow_recipes/_partials/conditioning/z-image.yaml
CHANGED
|
@@ -59,6 +59,10 @@ dynamic_diffsynth_controlnet_chains:
|
|
| 59 |
ksampler_node: "ksampler"
|
| 60 |
vae_source: "vae_loader:0"
|
| 61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
ui_map:
|
| 63 |
unet_name: "unet_loader:unet_name"
|
| 64 |
vae_name: "vae_loader:vae_name"
|
|
|
|
| 59 |
ksampler_node: "ksampler"
|
| 60 |
vae_source: "vae_loader:0"
|
| 61 |
|
| 62 |
+
dynamic_pid_chains:
|
| 63 |
+
pid_chain:
|
| 64 |
+
ksampler_node: "ksampler"
|
| 65 |
+
|
| 66 |
ui_map:
|
| 67 |
unet_name: "unet_loader:unet_name"
|
| 68 |
vae_name: "vae_loader:vae_name"
|
requirements.txt
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
-
comfyui-frontend-package==1.
|
| 2 |
-
comfyui-workflow-templates==0.9.
|
| 3 |
comfyui-embedded-docs==0.5.2
|
| 4 |
torch
|
| 5 |
torchsde
|
|
|
|
| 1 |
+
comfyui-frontend-package==1.45.15
|
| 2 |
+
comfyui-workflow-templates==0.9.98
|
| 3 |
comfyui-embedded-docs==0.5.2
|
| 4 |
torch
|
| 5 |
torchsde
|
ui/events/change_handlers.py
CHANGED
|
@@ -16,7 +16,7 @@ from .config_loaders import (
|
|
| 16 |
load_ipadapter_config
|
| 17 |
)
|
| 18 |
|
| 19 |
-
def make_update_fn(m_comp, cat_comp, cs_comp, ar_comp, width_comp, height_comp, cn_types, cn_series, cn_filepaths, anima_cn_types, anima_cn_series, anima_cn_filepaths, diffsynth_cn_types, diffsynth_cn_series, diffsynth_cn_filepaths, ipa_preset, lora_acc, cn_acc, anima_cn_acc, diffsynth_cn_acc, ipa_acc, sd3_ipa_acc, flux1_ipa_acc, style_acc, embed_acc, cond_acc, ref_latent_acc, hidream_o1_ref_acc, guidance_comp, prompt_comp, neg_prompt_comp, steps_comp, cfg_comp, sampler_comp, scheduler_comp):
|
| 20 |
def update_fn(*args):
|
| 21 |
arch = args[0]
|
| 22 |
category = args[1]
|
|
@@ -66,6 +66,7 @@ def make_update_fn(m_comp, cat_comp, cs_comp, ar_comp, width_comp, height_comp,
|
|
| 66 |
if cond_acc: updates[cond_acc] = gr.update(visible=('conditioning' in enabled_chains))
|
| 67 |
if ref_latent_acc: updates[ref_latent_acc] = gr.update(visible=('reference_latent' in enabled_chains))
|
| 68 |
if hidream_o1_ref_acc: updates[hidream_o1_ref_acc] = gr.update(visible=('hidream_o1_reference' in enabled_chains))
|
|
|
|
| 69 |
|
| 70 |
if cs_comp:
|
| 71 |
updates[cs_comp] = gr.update(visible=(arch_model_type == "sd15"))
|
|
@@ -130,7 +131,7 @@ def make_update_fn(m_comp, cat_comp, cs_comp, ar_comp, width_comp, height_comp,
|
|
| 130 |
return update_fn
|
| 131 |
|
| 132 |
|
| 133 |
-
def make_model_change_fn(cat_comp_ref, cs_comp, ar_comp, width_comp, height_comp, cn_types, cn_series, cn_filepaths, anima_cn_types, anima_cn_series, anima_cn_filepaths, diffsynth_cn_types, diffsynth_cn_series, diffsynth_cn_filepaths, arch_comp_ref, ipa_preset, lora_acc, cn_acc, anima_cn_acc, diffsynth_cn_acc, ipa_acc, sd3_ipa_acc, flux1_ipa_acc, style_acc, embed_acc, cond_acc, ref_latent_acc, hidream_o1_ref_acc, guidance_comp, prompt_comp, neg_prompt_comp, steps_comp, cfg_comp, sampler_comp, scheduler_comp):
|
| 134 |
def change_fn(*args):
|
| 135 |
model_name = args[0]
|
| 136 |
idx = 1
|
|
@@ -185,6 +186,7 @@ def make_model_change_fn(cat_comp_ref, cs_comp, ar_comp, width_comp, height_comp
|
|
| 185 |
if cond_acc: updates[cond_acc] = gr.update(visible=('conditioning' in enabled_chains))
|
| 186 |
if ref_latent_acc: updates[ref_latent_acc] = gr.update(visible=('reference_latent' in enabled_chains))
|
| 187 |
if hidream_o1_ref_acc: updates[hidream_o1_ref_acc] = gr.update(visible=('hidream_o1_reference' in enabled_chains))
|
|
|
|
| 188 |
|
| 189 |
if cs_comp:
|
| 190 |
updates[cs_comp] = gr.update(visible=(arch_model_type == "sd15"))
|
|
@@ -330,4 +332,4 @@ def on_aspect_ratio_change(ratio_key, model_display_name):
|
|
| 330 |
|
| 331 |
res_map = RESOLUTION_MAP.get(arch_model_type, RESOLUTION_MAP.get("sdxl", {}))
|
| 332 |
w, h = res_map.get(ratio_key, (1024, 1024))
|
| 333 |
-
return w, h
|
|
|
|
| 16 |
load_ipadapter_config
|
| 17 |
)
|
| 18 |
|
| 19 |
+
def make_update_fn(m_comp, cat_comp, cs_comp, ar_comp, width_comp, height_comp, cn_types, cn_series, cn_filepaths, anima_cn_types, anima_cn_series, anima_cn_filepaths, diffsynth_cn_types, diffsynth_cn_series, diffsynth_cn_filepaths, ipa_preset, lora_acc, cn_acc, anima_cn_acc, diffsynth_cn_acc, ipa_acc, sd3_ipa_acc, flux1_ipa_acc, style_acc, embed_acc, cond_acc, ref_latent_acc, hidream_o1_ref_acc, guidance_comp, prompt_comp, neg_prompt_comp, steps_comp, cfg_comp, sampler_comp, scheduler_comp, pid_acc=None):
|
| 20 |
def update_fn(*args):
|
| 21 |
arch = args[0]
|
| 22 |
category = args[1]
|
|
|
|
| 66 |
if cond_acc: updates[cond_acc] = gr.update(visible=('conditioning' in enabled_chains))
|
| 67 |
if ref_latent_acc: updates[ref_latent_acc] = gr.update(visible=('reference_latent' in enabled_chains))
|
| 68 |
if hidream_o1_ref_acc: updates[hidream_o1_ref_acc] = gr.update(visible=('hidream_o1_reference' in enabled_chains))
|
| 69 |
+
if pid_acc: updates[pid_acc] = gr.update(visible=('pid' in enabled_chains))
|
| 70 |
|
| 71 |
if cs_comp:
|
| 72 |
updates[cs_comp] = gr.update(visible=(arch_model_type == "sd15"))
|
|
|
|
| 131 |
return update_fn
|
| 132 |
|
| 133 |
|
| 134 |
+
def make_model_change_fn(cat_comp_ref, cs_comp, ar_comp, width_comp, height_comp, cn_types, cn_series, cn_filepaths, anima_cn_types, anima_cn_series, anima_cn_filepaths, diffsynth_cn_types, diffsynth_cn_series, diffsynth_cn_filepaths, arch_comp_ref, ipa_preset, lora_acc, cn_acc, anima_cn_acc, diffsynth_cn_acc, ipa_acc, sd3_ipa_acc, flux1_ipa_acc, style_acc, embed_acc, cond_acc, ref_latent_acc, hidream_o1_ref_acc, guidance_comp, prompt_comp, neg_prompt_comp, steps_comp, cfg_comp, sampler_comp, scheduler_comp, pid_acc=None):
|
| 135 |
def change_fn(*args):
|
| 136 |
model_name = args[0]
|
| 137 |
idx = 1
|
|
|
|
| 186 |
if cond_acc: updates[cond_acc] = gr.update(visible=('conditioning' in enabled_chains))
|
| 187 |
if ref_latent_acc: updates[ref_latent_acc] = gr.update(visible=('reference_latent' in enabled_chains))
|
| 188 |
if hidream_o1_ref_acc: updates[hidream_o1_ref_acc] = gr.update(visible=('hidream_o1_reference' in enabled_chains))
|
| 189 |
+
if pid_acc: updates[pid_acc] = gr.update(visible=('pid' in enabled_chains))
|
| 190 |
|
| 191 |
if cs_comp:
|
| 192 |
updates[cs_comp] = gr.update(visible=(arch_model_type == "sd15"))
|
|
|
|
| 332 |
|
| 333 |
res_map = RESOLUTION_MAP.get(arch_model_type, RESOLUTION_MAP.get("sdxl", {}))
|
| 334 |
w, h = res_map.get(ratio_key, (1024, 1024))
|
| 335 |
+
return w, h
|
ui/events/main.py
CHANGED
|
@@ -60,6 +60,7 @@ def attach_event_handlers(ui_components, demo):
|
|
| 60 |
conditioning_accordion = ui_components.get(f'conditioning_accordion_{prefix}')
|
| 61 |
ref_latent_accordion = ui_components.get(f'reference_latent_accordion_{prefix}')
|
| 62 |
hidream_o1_ref_accordion = ui_components.get(f'hidream_o1_reference_accordion_{prefix}')
|
|
|
|
| 63 |
|
| 64 |
ipa_preset_list = ui_components.get(f'ipadapter_final_preset_{prefix}')
|
| 65 |
|
|
@@ -93,6 +94,7 @@ def attach_event_handlers(ui_components, demo):
|
|
| 93 |
if conditioning_accordion: outputs.append(conditioning_accordion)
|
| 94 |
if ref_latent_accordion: outputs.append(ref_latent_accordion)
|
| 95 |
if hidream_o1_ref_accordion: outputs.append(hidream_o1_ref_accordion)
|
|
|
|
| 96 |
if ipa_preset_list: outputs.append(ipa_preset_list)
|
| 97 |
|
| 98 |
outputs.extend(valid_extra_comps)
|
|
@@ -103,7 +105,8 @@ def attach_event_handlers(ui_components, demo):
|
|
| 103 |
anima_cn_types_list, anima_cn_series_list, anima_cn_filepaths_list,
|
| 104 |
diffsynth_cn_types_list, diffsynth_cn_series_list, diffsynth_cn_filepaths_list,
|
| 105 |
ipa_preset_list, lora_accordion, cn_accordion, anima_cn_accordion, diffsynth_cn_accordion, ipa_accordion, sd3_ipa_accordion, flux1_ipa_accordion, style_accordion, embedding_accordion, conditioning_accordion,
|
| 106 |
-
ref_latent_accordion, hidream_o1_ref_accordion, guidance_comp, prompt_comp, neg_prompt_comp, steps_comp, cfg_comp, sampler_comp, scheduler_comp
|
|
|
|
| 107 |
)
|
| 108 |
inputs = [arch_comp, cat_comp]
|
| 109 |
if aspect_ratio_comp:
|
|
@@ -133,6 +136,7 @@ def attach_event_handlers(ui_components, demo):
|
|
| 133 |
if conditioning_accordion: outputs2.append(conditioning_accordion)
|
| 134 |
if ref_latent_accordion: outputs2.append(ref_latent_accordion)
|
| 135 |
if hidream_o1_ref_accordion: outputs2.append(hidream_o1_ref_accordion)
|
|
|
|
| 136 |
if ipa_preset_list: outputs2.append(ipa_preset_list)
|
| 137 |
|
| 138 |
outputs2.extend(valid_extra_comps)
|
|
@@ -148,7 +152,8 @@ def attach_event_handlers(ui_components, demo):
|
|
| 148 |
anima_cn_types_list, anima_cn_series_list, anima_cn_filepaths_list,
|
| 149 |
diffsynth_cn_types_list, diffsynth_cn_series_list, diffsynth_cn_filepaths_list,
|
| 150 |
arch_comp, ipa_preset_list, lora_accordion, cn_accordion, anima_cn_accordion, diffsynth_cn_accordion, ipa_accordion, sd3_ipa_accordion, flux1_ipa_accordion, style_accordion, embedding_accordion, conditioning_accordion,
|
| 151 |
-
ref_latent_accordion, hidream_o1_ref_accordion, guidance_comp, prompt_comp, neg_prompt_comp, steps_comp, cfg_comp, sampler_comp, scheduler_comp
|
|
|
|
| 152 |
)
|
| 153 |
model_comp.change(fn=change_fn, inputs=inputs2, outputs=outputs2)
|
| 154 |
|
|
@@ -237,4 +242,4 @@ def attach_event_handlers(ui_components, demo):
|
|
| 237 |
height_component = ui_components.get(f'height_{prefix}') or ui_components.get(f'{prefix}_height')
|
| 238 |
model_dropdown = ui_components.get(f'base_model_{prefix}')
|
| 239 |
if aspect_ratio_dropdown and width_component and height_component and model_dropdown:
|
| 240 |
-
aspect_ratio_dropdown.change(fn=on_aspect_ratio_change, inputs=[aspect_ratio_dropdown, model_dropdown], outputs=[width_component, height_component], show_progress=False)
|
|
|
|
| 60 |
conditioning_accordion = ui_components.get(f'conditioning_accordion_{prefix}')
|
| 61 |
ref_latent_accordion = ui_components.get(f'reference_latent_accordion_{prefix}')
|
| 62 |
hidream_o1_ref_accordion = ui_components.get(f'hidream_o1_reference_accordion_{prefix}')
|
| 63 |
+
pid_accordion = ui_components.get(f'pid_accordion_{prefix}')
|
| 64 |
|
| 65 |
ipa_preset_list = ui_components.get(f'ipadapter_final_preset_{prefix}')
|
| 66 |
|
|
|
|
| 94 |
if conditioning_accordion: outputs.append(conditioning_accordion)
|
| 95 |
if ref_latent_accordion: outputs.append(ref_latent_accordion)
|
| 96 |
if hidream_o1_ref_accordion: outputs.append(hidream_o1_ref_accordion)
|
| 97 |
+
if pid_accordion: outputs.append(pid_accordion)
|
| 98 |
if ipa_preset_list: outputs.append(ipa_preset_list)
|
| 99 |
|
| 100 |
outputs.extend(valid_extra_comps)
|
|
|
|
| 105 |
anima_cn_types_list, anima_cn_series_list, anima_cn_filepaths_list,
|
| 106 |
diffsynth_cn_types_list, diffsynth_cn_series_list, diffsynth_cn_filepaths_list,
|
| 107 |
ipa_preset_list, lora_accordion, cn_accordion, anima_cn_accordion, diffsynth_cn_accordion, ipa_accordion, sd3_ipa_accordion, flux1_ipa_accordion, style_accordion, embedding_accordion, conditioning_accordion,
|
| 108 |
+
ref_latent_accordion, hidream_o1_ref_accordion, guidance_comp, prompt_comp, neg_prompt_comp, steps_comp, cfg_comp, sampler_comp, scheduler_comp,
|
| 109 |
+
pid_acc=pid_accordion
|
| 110 |
)
|
| 111 |
inputs = [arch_comp, cat_comp]
|
| 112 |
if aspect_ratio_comp:
|
|
|
|
| 136 |
if conditioning_accordion: outputs2.append(conditioning_accordion)
|
| 137 |
if ref_latent_accordion: outputs2.append(ref_latent_accordion)
|
| 138 |
if hidream_o1_ref_accordion: outputs2.append(hidream_o1_ref_accordion)
|
| 139 |
+
if pid_accordion: outputs2.append(pid_accordion)
|
| 140 |
if ipa_preset_list: outputs2.append(ipa_preset_list)
|
| 141 |
|
| 142 |
outputs2.extend(valid_extra_comps)
|
|
|
|
| 152 |
anima_cn_types_list, anima_cn_series_list, anima_cn_filepaths_list,
|
| 153 |
diffsynth_cn_types_list, diffsynth_cn_series_list, diffsynth_cn_filepaths_list,
|
| 154 |
arch_comp, ipa_preset_list, lora_accordion, cn_accordion, anima_cn_accordion, diffsynth_cn_accordion, ipa_accordion, sd3_ipa_accordion, flux1_ipa_accordion, style_accordion, embedding_accordion, conditioning_accordion,
|
| 155 |
+
ref_latent_accordion, hidream_o1_ref_accordion, guidance_comp, prompt_comp, neg_prompt_comp, steps_comp, cfg_comp, sampler_comp, scheduler_comp,
|
| 156 |
+
pid_acc=pid_accordion
|
| 157 |
)
|
| 158 |
model_comp.change(fn=change_fn, inputs=inputs2, outputs=outputs2)
|
| 159 |
|
|
|
|
| 242 |
height_component = ui_components.get(f'height_{prefix}') or ui_components.get(f'{prefix}_height')
|
| 243 |
model_dropdown = ui_components.get(f'base_model_{prefix}')
|
| 244 |
if aspect_ratio_dropdown and width_component and height_component and model_dropdown:
|
| 245 |
+
aspect_ratio_dropdown.change(fn=on_aspect_ratio_change, inputs=[aspect_ratio_dropdown, model_dropdown], outputs=[width_component, height_component], show_progress=False)
|
ui/events/run_handlers.py
CHANGED
|
@@ -19,6 +19,9 @@ def create_run_event(prefix: str, task_type: str, ui_components: dict):
|
|
| 19 |
'task_type': gr.State(task_type)
|
| 20 |
}
|
| 21 |
|
|
|
|
|
|
|
|
|
|
| 22 |
if task_type not in ['img2img', 'inpaint']:
|
| 23 |
run_inputs_map.update({
|
| 24 |
'width': ui_components.get(f'width_{prefix}') or ui_components.get(f'{prefix}_width'),
|
|
@@ -97,4 +100,4 @@ def create_run_event(prefix: str, task_type: str, ui_components: dict):
|
|
| 97 |
fn=lambda *args, progress=gr.Progress(track_tqdm=True): generate_image_wrapper(create_ui_inputs_dict(*args), progress),
|
| 98 |
inputs=input_list_flat,
|
| 99 |
outputs=[res_gal]
|
| 100 |
-
)
|
|
|
|
| 19 |
'task_type': gr.State(task_type)
|
| 20 |
}
|
| 21 |
|
| 22 |
+
if ui_components.get(f'pid_settings_{prefix}'):
|
| 23 |
+
run_inputs_map['pid_settings'] = ui_components[f'pid_settings_{prefix}']
|
| 24 |
+
|
| 25 |
if task_type not in ['img2img', 'inpaint']:
|
| 26 |
run_inputs_map.update({
|
| 27 |
'width': ui_components.get(f'width_{prefix}') or ui_components.get(f'{prefix}_width'),
|
|
|
|
| 100 |
fn=lambda *args, progress=gr.Progress(track_tqdm=True): generate_image_wrapper(create_ui_inputs_dict(*args), progress),
|
| 101 |
inputs=input_list_flat,
|
| 102 |
outputs=[res_gal]
|
| 103 |
+
)
|
ui/shared/txt2img_ui.py
CHANGED
|
@@ -6,7 +6,8 @@ from .ui_components import (
|
|
| 6 |
create_conditioning_ui, create_vae_override_ui,
|
| 7 |
create_model_architecture_filter_ui, create_category_filter_ui,
|
| 8 |
create_sd3_ipadapter_ui, create_flux1_ipadapter_ui, create_style_ui,
|
| 9 |
-
create_reference_latent_ui, create_hidream_o1_reference_ui
|
|
|
|
| 10 |
)
|
| 11 |
|
| 12 |
def create_ui():
|
|
@@ -53,5 +54,6 @@ def create_ui():
|
|
| 53 |
components.update(create_reference_latent_ui(prefix))
|
| 54 |
components.update(create_hidream_o1_reference_ui(prefix))
|
| 55 |
components.update(create_vae_override_ui(prefix))
|
|
|
|
| 56 |
|
| 57 |
return components
|
|
|
|
| 6 |
create_conditioning_ui, create_vae_override_ui,
|
| 7 |
create_model_architecture_filter_ui, create_category_filter_ui,
|
| 8 |
create_sd3_ipadapter_ui, create_flux1_ipadapter_ui, create_style_ui,
|
| 9 |
+
create_reference_latent_ui, create_hidream_o1_reference_ui,
|
| 10 |
+
create_pid_ui
|
| 11 |
)
|
| 12 |
|
| 13 |
def create_ui():
|
|
|
|
| 54 |
components.update(create_reference_latent_ui(prefix))
|
| 55 |
components.update(create_hidream_o1_reference_ui(prefix))
|
| 56 |
components.update(create_vae_override_ui(prefix))
|
| 57 |
+
components.update(create_pid_ui(prefix))
|
| 58 |
|
| 59 |
return components
|
ui/shared/ui_components.py
CHANGED
|
@@ -548,8 +548,8 @@ def create_vae_override_ui(prefix: str):
|
|
| 548 |
key = lambda name: f"{name}_{prefix}"
|
| 549 |
source_choices = ["None"] + LORA_SOURCE_CHOICES
|
| 550 |
|
| 551 |
-
with gr.Accordion("VAE Settings (Override)", open=False) as
|
| 552 |
-
components[key('vae_accordion')] =
|
| 553 |
gr.Markdown("💡 **Tip:** When downloading from Civitai, please use the **Version ID**, not the Model ID. You can find the Version ID in the URL (e.g., `civitai.com/models/123?modelVersionId=456`) or under the model's download button.")
|
| 554 |
with gr.Row():
|
| 555 |
components[key('vae_source')] = gr.Dropdown(
|
|
@@ -638,4 +638,21 @@ def create_hidream_o1_reference_ui(prefix: str, max_units=10):
|
|
| 638 |
|
| 639 |
components[key('all_hidream_o1_reference_components_flat')] = ref_image_inputs
|
| 640 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 641 |
return components
|
|
|
|
| 548 |
key = lambda name: f"{name}_{prefix}"
|
| 549 |
source_choices = ["None"] + LORA_SOURCE_CHOICES
|
| 550 |
|
| 551 |
+
with gr.Accordion("VAE Settings (Override)", open=False) as vae_accordion:
|
| 552 |
+
components[key('vae_accordion')] = vae_accordion
|
| 553 |
gr.Markdown("💡 **Tip:** When downloading from Civitai, please use the **Version ID**, not the Model ID. You can find the Version ID in the URL (e.g., `civitai.com/models/123?modelVersionId=456`) or under the model's download button.")
|
| 554 |
with gr.Row():
|
| 555 |
components[key('vae_source')] = gr.Dropdown(
|
|
|
|
| 638 |
|
| 639 |
components[key('all_hidream_o1_reference_components_flat')] = ref_image_inputs
|
| 640 |
|
| 641 |
+
return components
|
| 642 |
+
|
| 643 |
+
def create_pid_ui(prefix: str):
|
| 644 |
+
components = {}
|
| 645 |
+
key = lambda name: f"{name}_{prefix}"
|
| 646 |
+
|
| 647 |
+
with gr.Accordion("PiD Settings", open=False, visible=('pid' in default_enabled_chains)) as pid_accordion:
|
| 648 |
+
components[key('pid_accordion')] = pid_accordion
|
| 649 |
+
gr.Markdown("💡 **Tip:** Use PiD (Pixel Diffusion Decoder) instead of the VAE Decoder for 4x decoding.")
|
| 650 |
+
with gr.Row():
|
| 651 |
+
components[key('pid_settings')] = gr.Dropdown(
|
| 652 |
+
label="PiD Mode",
|
| 653 |
+
choices=["OFF", "ON"],
|
| 654 |
+
value="OFF",
|
| 655 |
+
interactive=True
|
| 656 |
+
)
|
| 657 |
+
|
| 658 |
return components
|
yaml/file_list.yaml
CHANGED
|
@@ -408,6 +408,27 @@ file:
|
|
| 408 |
source: "hf"
|
| 409 |
repo_id: "Comfy-Org/PixelDiT"
|
| 410 |
repository_file_path: "diffusion_models/pixeldit_1300m_1024px_mxfp8.safetensors"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 411 |
# Lens
|
| 412 |
- filename: "lens_mxfp8.safetensors"
|
| 413 |
source: "hf"
|
|
|
|
| 408 |
source: "hf"
|
| 409 |
repo_id: "Comfy-Org/PixelDiT"
|
| 410 |
repository_file_path: "diffusion_models/pixeldit_1300m_1024px_mxfp8.safetensors"
|
| 411 |
+
# PiD
|
| 412 |
+
- filename: "pid_sdxl_1024_to_4096_4step_bf16.safetensors"
|
| 413 |
+
source: "hf"
|
| 414 |
+
repo_id: "Comfy-Org/PixelDiT"
|
| 415 |
+
repository_file_path: "diffusion_models/pid_sdxl_1024_to_4096_4step_bf16.safetensors"
|
| 416 |
+
- filename: "pid_sd3_1024_to_4096_4step_bf16.safetensors"
|
| 417 |
+
source: "hf"
|
| 418 |
+
repo_id: "Comfy-Org/PixelDiT"
|
| 419 |
+
repository_file_path: "diffusion_models/pid_sd3_1024_to_4096_4step_bf16.safetensors"
|
| 420 |
+
- filename: "pid_flux1_1024_to_4096_4step_mxfp8.safetensors"
|
| 421 |
+
source: "hf"
|
| 422 |
+
repo_id: "Comfy-Org/PixelDiT"
|
| 423 |
+
repository_file_path: "diffusion_models/pid_flux1_1024_to_4096_4step_mxfp8.safetensors"
|
| 424 |
+
- filename: "pid_qwenimage_1024_to_4096_4step_bf16.safetensors"
|
| 425 |
+
source: "hf"
|
| 426 |
+
repo_id: "Comfy-Org/PixelDiT"
|
| 427 |
+
repository_file_path: "diffusion_models/pid_qwenimage_1024_to_4096_4step_bf16.safetensors"
|
| 428 |
+
- filename: "pid_flux2_1024_to_4096_4step_mxfp8.safetensors"
|
| 429 |
+
source: "hf"
|
| 430 |
+
repo_id: "Comfy-Org/PixelDiT"
|
| 431 |
+
repository_file_path: "diffusion_models/pid_flux2_1024_to_4096_4step_mxfp8.safetensors"
|
| 432 |
# Lens
|
| 433 |
- filename: "lens_mxfp8.safetensors"
|
| 434 |
source: "hf"
|
yaml/image_gen_features.yaml
CHANGED
|
@@ -1,11 +1,12 @@
|
|
| 1 |
default:
|
| 2 |
enabled_chains:
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
|
|
|
| 9 |
|
| 10 |
pixeldit:
|
| 11 |
enabled_chains:
|
|
@@ -14,119 +15,129 @@ pixeldit:
|
|
| 14 |
lens:
|
| 15 |
enabled_chains:
|
| 16 |
- conditioning
|
|
|
|
| 17 |
|
| 18 |
ernie-image:
|
| 19 |
enabled_chains:
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
flux2:
|
| 24 |
-
enabled_chains:
|
| 25 |
-
- lora
|
| 26 |
-
- conditioning
|
| 27 |
-
- reference_latent
|
| 28 |
-
|
| 29 |
-
flux2-kv:
|
| 30 |
-
enabled_chains:
|
| 31 |
-
- lora
|
| 32 |
-
- conditioning
|
| 33 |
-
- reference_latent
|
| 34 |
-
|
| 35 |
-
z-image:
|
| 36 |
-
enabled_chains:
|
| 37 |
-
- lora
|
| 38 |
-
- conditioning
|
| 39 |
-
- controlnet_model_patch
|
| 40 |
-
|
| 41 |
-
qwen-image:
|
| 42 |
enabled_chains:
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
|
|
|
| 47 |
longcat-image:
|
| 48 |
enabled_chains:
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
anima:
|
| 53 |
-
enabled_chains:
|
| 54 |
-
- lora
|
| 55 |
-
- anima_controlnet_lllite
|
| 56 |
-
- conditioning
|
| 57 |
-
|
| 58 |
newbie-image:
|
| 59 |
enabled_chains:
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
|
|
|
| 65 |
enabled_chains:
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
|
|
|
|
|
|
| 69 |
lumina:
|
| 70 |
enabled_chains:
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
enabled_chains:
|
| 77 |
-
- conditioning
|
| 78 |
-
|
| 79 |
sd35:
|
| 80 |
enabled_chains:
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
|
|
|
| 87 |
sdxl:
|
| 88 |
enabled_chains:
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
|
|
|
| 95 |
sd15:
|
| 96 |
enabled_chains:
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
flux1:
|
| 104 |
enabled_chains:
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
hidream-o1:
|
| 112 |
enabled_chains:
|
| 113 |
- lora
|
| 114 |
- conditioning
|
| 115 |
- hidream_o1_reference
|
| 116 |
-
|
| 117 |
hidream-i1:
|
| 118 |
enabled_chains:
|
| 119 |
- lora
|
| 120 |
- conditioning
|
| 121 |
-
|
| 122 |
-
|
| 123 |
enabled_chains:
|
| 124 |
-
|
|
|
|
| 125 |
|
| 126 |
-
|
| 127 |
enabled_chains:
|
| 128 |
-
|
|
|
|
|
|
|
| 129 |
|
| 130 |
-
|
| 131 |
enabled_chains:
|
| 132 |
-
|
|
|
|
|
|
|
|
|
| 1 |
default:
|
| 2 |
enabled_chains:
|
| 3 |
+
- lora
|
| 4 |
+
- controlnet
|
| 5 |
+
- ipadapter
|
| 6 |
+
- embedding
|
| 7 |
+
- style
|
| 8 |
+
- conditioning
|
| 9 |
+
- vae
|
| 10 |
|
| 11 |
pixeldit:
|
| 12 |
enabled_chains:
|
|
|
|
| 15 |
lens:
|
| 16 |
enabled_chains:
|
| 17 |
- conditioning
|
| 18 |
+
- pid
|
| 19 |
|
| 20 |
ernie-image:
|
| 21 |
enabled_chains:
|
| 22 |
+
- conditioning
|
| 23 |
+
- pid
|
| 24 |
+
anima:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
enabled_chains:
|
| 26 |
+
- lora
|
| 27 |
+
- anima_controlnet_lllite
|
| 28 |
+
- conditioning
|
| 29 |
+
- vae
|
| 30 |
+
- pid
|
| 31 |
longcat-image:
|
| 32 |
enabled_chains:
|
| 33 |
+
- lora
|
| 34 |
+
- conditioning
|
| 35 |
+
- pid
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
newbie-image:
|
| 37 |
enabled_chains:
|
| 38 |
+
- lora
|
| 39 |
+
- embedding
|
| 40 |
+
- conditioning
|
| 41 |
+
- vae
|
| 42 |
+
- pid
|
| 43 |
+
z-image:
|
| 44 |
enabled_chains:
|
| 45 |
+
- lora
|
| 46 |
+
- conditioning
|
| 47 |
+
- controlnet_model_patch
|
| 48 |
+
- vae
|
| 49 |
+
- pid
|
| 50 |
lumina:
|
| 51 |
enabled_chains:
|
| 52 |
+
- lora
|
| 53 |
+
- embedding
|
| 54 |
+
- conditioning
|
| 55 |
+
- vae
|
| 56 |
+
- pid
|
|
|
|
|
|
|
|
|
|
| 57 |
sd35:
|
| 58 |
enabled_chains:
|
| 59 |
+
- lora
|
| 60 |
+
- controlnet
|
| 61 |
+
- embedding
|
| 62 |
+
- conditioning
|
| 63 |
+
- sd3_ipadapter
|
| 64 |
+
- vae
|
| 65 |
+
- pid
|
| 66 |
sdxl:
|
| 67 |
enabled_chains:
|
| 68 |
+
- lora
|
| 69 |
+
- controlnet
|
| 70 |
+
- ipadapter
|
| 71 |
+
- embedding
|
| 72 |
+
- conditioning
|
| 73 |
+
- vae
|
| 74 |
+
- pid
|
| 75 |
sd15:
|
| 76 |
enabled_chains:
|
| 77 |
+
- lora
|
| 78 |
+
- controlnet
|
| 79 |
+
- ipadapter
|
| 80 |
+
- embedding
|
| 81 |
+
- conditioning
|
| 82 |
+
- vae
|
| 83 |
+
flux2:
|
| 84 |
+
enabled_chains:
|
| 85 |
+
- lora
|
| 86 |
+
- conditioning
|
| 87 |
+
- reference_latent
|
| 88 |
+
- vae
|
| 89 |
+
- pid
|
| 90 |
+
flux2-kv:
|
| 91 |
+
enabled_chains:
|
| 92 |
+
- lora
|
| 93 |
+
- conditioning
|
| 94 |
+
- reference_latent
|
| 95 |
+
- vae
|
| 96 |
+
- pid
|
| 97 |
flux1:
|
| 98 |
enabled_chains:
|
| 99 |
+
- lora
|
| 100 |
+
- controlnet
|
| 101 |
+
- style
|
| 102 |
+
- conditioning
|
| 103 |
+
- flux1_ipadapter
|
| 104 |
+
- vae
|
| 105 |
+
- pid
|
| 106 |
+
omnigen2:
|
| 107 |
+
enabled_chains:
|
| 108 |
+
- conditioning
|
| 109 |
+
- reference_latent
|
| 110 |
+
- pid
|
| 111 |
+
qwen-image:
|
| 112 |
+
enabled_chains:
|
| 113 |
+
- lora
|
| 114 |
+
- controlnet
|
| 115 |
+
- conditioning
|
| 116 |
+
- vae
|
| 117 |
+
- pid
|
| 118 |
hidream-o1:
|
| 119 |
enabled_chains:
|
| 120 |
- lora
|
| 121 |
- conditioning
|
| 122 |
- hidream_o1_reference
|
|
|
|
| 123 |
hidream-i1:
|
| 124 |
enabled_chains:
|
| 125 |
- lora
|
| 126 |
- conditioning
|
| 127 |
+
- pid
|
| 128 |
+
hunyuanimage:
|
| 129 |
enabled_chains:
|
| 130 |
+
- conditioning
|
| 131 |
+
- vae
|
| 132 |
|
| 133 |
+
ovis-image:
|
| 134 |
enabled_chains:
|
| 135 |
+
- conditioning
|
| 136 |
+
- vae
|
| 137 |
+
- pid
|
| 138 |
|
| 139 |
+
chroma1:
|
| 140 |
enabled_chains:
|
| 141 |
+
- conditioning
|
| 142 |
+
- vae
|
| 143 |
+
- pid
|
yaml/injectors.yaml
CHANGED
|
@@ -27,6 +27,8 @@ injector_definitions:
|
|
| 27 |
module: "chain_injectors.hidream_o1_smoothing_injector"
|
| 28 |
dynamic_hidream_o1_reference_chains:
|
| 29 |
module: "chain_injectors.hidream_o1_reference_injector"
|
|
|
|
|
|
|
| 30 |
|
| 31 |
injector_order:
|
| 32 |
- dynamic_vae_chains
|
|
@@ -42,4 +44,5 @@ injector_order:
|
|
| 42 |
- dynamic_controlnet_chains
|
| 43 |
- dynamic_anima_controlnet_lllite_chains
|
| 44 |
- dynamic_hidream_o1_smoothing_chains
|
| 45 |
-
- dynamic_hidream_o1_reference_chains
|
|
|
|
|
|
| 27 |
module: "chain_injectors.hidream_o1_smoothing_injector"
|
| 28 |
dynamic_hidream_o1_reference_chains:
|
| 29 |
module: "chain_injectors.hidream_o1_reference_injector"
|
| 30 |
+
dynamic_pid_chains:
|
| 31 |
+
module: "chain_injectors.pid_injector"
|
| 32 |
|
| 33 |
injector_order:
|
| 34 |
- dynamic_vae_chains
|
|
|
|
| 44 |
- dynamic_controlnet_chains
|
| 45 |
- dynamic_anima_controlnet_lllite_chains
|
| 46 |
- dynamic_hidream_o1_smoothing_chains
|
| 47 |
+
- dynamic_hidream_o1_reference_chains
|
| 48 |
+
- dynamic_pid_chains
|
yaml/pid.yaml
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
PiD:
|
| 2 |
+
- filepath: "pid_flux2_1024_to_4096_4step_mxfp8.safetensors"
|
| 3 |
+
latent_format: "flux"
|
| 4 |
+
architectures: ["flux2", "flux2-kv", "lens", "ernie-image"]
|
| 5 |
+
- filepath: "pid_qwenimage_1024_to_4096_4step_bf16.safetensors"
|
| 6 |
+
latent_format: "qwenimage"
|
| 7 |
+
architectures: ["anima", "qwen-image"]
|
| 8 |
+
- filepath: "pid_flux1_1024_to_4096_4step_mxfp8.safetensors"
|
| 9 |
+
latent_format: "flux"
|
| 10 |
+
architectures: ["longcat-image", "newbie-image", "z-image", "ovis-image", "omnigen2", "chroma1", "hidream-i1", "flux1"]
|
| 11 |
+
- filepath: "pid_sd3_1024_to_4096_4step_bf16.safetensors"
|
| 12 |
+
latent_format: "sd3"
|
| 13 |
+
architectures: ["sd35"]
|
| 14 |
+
- filepath: "pid_sdxl_1024_to_4096_4step_bf16.safetensors"
|
| 15 |
+
latent_format: "sdxl"
|
| 16 |
+
architectures: ["sdxl"]
|