RioShiina commited on
Commit
44eb2bf
·
verified ·
1 Parent(s): a2bae93

Upload 105 files

Browse files
core/pipelines/sd_image_pipeline.py CHANGED
@@ -1,259 +1,259 @@
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_krea2_controlnets = processed.get("active_krea2_controlnets", [])
113
- active_ipadapters = processed["active_ipadapters"]
114
- active_flux1_ipadapters = processed["active_flux1_ipadapters"]
115
- active_sd3_ipadapters = processed["active_sd3_ipadapters"]
116
- active_styles = processed["active_styles"]
117
- active_reference_latents = processed["active_reference_latents"]
118
- active_hidream_o1_reference = processed["active_hidream_o1_reference"]
119
- active_conditioning = processed["active_conditioning"]
120
-
121
- loras_string = f"LoRAs: [{', '.join(active_loras_for_meta)}]" if active_loras_for_meta else ""
122
-
123
- progress(0.8, desc="Assembling workflow...")
124
-
125
- if ui_inputs.get('seed') == -1:
126
- ui_inputs['seed'] = random.randint(0, 2**32 - 1)
127
-
128
- model_info = ALL_MODEL_MAP[model_display_name]
129
- path_or_components = model_info[1]
130
- latent_type = model_info[3] if len(model_info) > 3 and model_info[3] else 'latent'
131
- latent_generator_template = "EmptyLatentImage"
132
- if latent_type == 'sd3_latent':
133
- latent_generator_template = "EmptySD3LatentImage"
134
- elif latent_type == 'chroma_radiance_latent':
135
- latent_generator_template = "EmptyChromaRadianceLatentImage"
136
- elif latent_type == 'hunyuan_latent':
137
- latent_generator_template = "EmptyHunyuanImageLatent"
138
-
139
- dynamic_values = {
140
- 'task_type': ui_inputs['task_type'],
141
- 'model_type': workflow_model_type,
142
- 'latent_type': latent_type,
143
- 'latent_generator_template': latent_generator_template
144
- }
145
-
146
- recipe_path = os.path.join(os.path.dirname(__file__), "workflow_recipes", "sd_unified_recipe.yaml")
147
- assembler = WorkflowAssembler(recipe_path, dynamic_values=dynamic_values)
148
-
149
- hidream_o1_smoothing_data = []
150
- if workflow_model_type == 'hidream-o1' and model_display_name == "HiDream-O1-Image":
151
- hidream_o1_smoothing_data.append({})
152
-
153
- workflow_inputs = {
154
- **ui_inputs,
155
- "positive_prompt": ui_inputs['positive_prompt'], "negative_prompt": ui_inputs['negative_prompt'],
156
- "seed": ui_inputs['seed'], "steps": ui_inputs['num_inference_steps'], "cfg": ui_inputs['guidance_scale'],
157
- "sampler_name": ui_inputs['sampler'], "scheduler": ui_inputs['scheduler'],
158
- "batch_size": ui_inputs['batch_size'],
159
- "clip_skip": ui_inputs['clip_skip'],
160
- "denoise": ui_inputs['denoise'],
161
- "vae_name": ui_inputs.get('vae_name'),
162
- "guidance": ui_inputs.get('guidance', 3.5),
163
- "lora_chain": active_loras_for_gpu,
164
- "controlnet_chain": active_controlnets if not active_anima_controlnets else [],
165
- "anima_controlnet_lllite_chain": active_anima_controlnets,
166
- "diffsynth_controlnet_chain": active_diffsynth_controlnets,
167
- "krea2_controlnet_chain": active_krea2_controlnets,
168
- "ipadapter_chain": active_ipadapters,
169
- "flux1_ipadapter_chain": active_flux1_ipadapters,
170
- "sd3_ipadapter_chain": active_sd3_ipadapters,
171
- "style_chain": active_styles,
172
- "conditioning_chain": active_conditioning,
173
- "reference_latent_chain": active_reference_latents,
174
- "hidream_o1_reference_chain": active_hidream_o1_reference,
175
- "vae_chain": [ui_inputs.get('vae_name')] if ui_inputs.get('vae_name') else [],
176
- "hidream_o1_smoothing_chain": hidream_o1_smoothing_data,
177
- "pid_chain": [ui_inputs.get('pid_settings', 'OFF')] if is_pid_enabled else [],
178
- "scheduler_width": ui_inputs.get('width', 1024),
179
- "scheduler_height": ui_inputs.get('height', 1024),
180
- }
181
-
182
- if isinstance(path_or_components, dict):
183
- workflow_inputs.update({
184
- 'unet_name': path_or_components.get('unet'),
185
- 'unet_uncond_name': path_or_components.get('unet_uncond'),
186
- 'vae_name': ui_inputs.get('vae_name') or path_or_components.get('vae'),
187
- 'clip_name': path_or_components.get('clip'),
188
- 'clip1_name': path_or_components.get('clip1'),
189
- 'clip2_name': path_or_components.get('clip2'),
190
- 'clip3_name': path_or_components.get('clip3'),
191
- 'clip4_name': path_or_components.get('clip4'),
192
- 'lora_name': path_or_components.get('lora'),
193
- })
194
- else:
195
- workflow_inputs['model_name'] = path_or_components
196
-
197
- if task_type == 'txt2img':
198
- workflow_inputs['width'] = ui_inputs['width']
199
- workflow_inputs['height'] = ui_inputs['height']
200
-
201
- workflow = assembler.assemble(workflow_inputs)
202
-
203
- progress(1.0, desc="All models ready. Requesting GPU for generation...")
204
-
205
- results = self._execute_gpu_logic(
206
- self._gpu_logic,
207
- duration=ui_inputs['zero_gpu_duration'],
208
- default_duration=60,
209
- task_name=f"ImageGen ({task_type})",
210
- ui_inputs=ui_inputs,
211
- loras_string=loras_string,
212
- workflow=workflow,
213
- assembler=assembler,
214
- progress=progress
215
- )
216
-
217
- import json
218
- import glob
219
- from PIL import PngImagePlugin
220
-
221
- prompt_json = json.dumps(workflow)
222
-
223
- out_dir = os.path.abspath(OUTPUT_DIR)
224
- os.makedirs(out_dir, exist_ok=True)
225
-
226
- try:
227
- existing_files = glob.glob(os.path.join(out_dir, "gen_*.png"))
228
- existing_files.sort(key=os.path.getmtime)
229
- while len(existing_files) > 50:
230
- os.remove(existing_files.pop(0))
231
- except Exception as e:
232
- print(f"Warning: Failed to cleanup output dir: {e}")
233
-
234
- final_results = []
235
- for img in results:
236
- if not isinstance(img, Image.Image):
237
- final_results.append(img)
238
- continue
239
-
240
- metadata = PngImagePlugin.PngInfo()
241
- params_string = img.info.get("parameters", "")
242
- if params_string:
243
- metadata.add_text("parameters", params_string)
244
- metadata.add_text("prompt", prompt_json)
245
-
246
- filename = f"gen_{random.randint(1000000, 9999999)}.png"
247
- filepath = os.path.join(out_dir, filename)
248
- img.save(filepath, "PNG", pnginfo=metadata)
249
- final_results.append(filepath)
250
-
251
- results = final_results
252
-
253
- finally:
254
- for temp_file in temp_files_to_clean:
255
- if temp_file and os.path.exists(temp_file):
256
- os.remove(temp_file)
257
- print(f"✅ Cleaned up temp file: {temp_file}")
258
-
259
  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_krea2_controlnets = processed.get("active_krea2_controlnets", [])
113
+ active_ipadapters = processed["active_ipadapters"]
114
+ active_flux1_ipadapters = processed["active_flux1_ipadapters"]
115
+ active_sd3_ipadapters = processed["active_sd3_ipadapters"]
116
+ active_styles = processed["active_styles"]
117
+ active_reference_latents = processed["active_reference_latents"]
118
+ active_hidream_o1_reference = processed["active_hidream_o1_reference"]
119
+ active_conditioning = processed["active_conditioning"]
120
+
121
+ loras_string = f"LoRAs: [{', '.join(active_loras_for_meta)}]" if active_loras_for_meta else ""
122
+
123
+ progress(0.8, desc="Assembling workflow...")
124
+
125
+ if ui_inputs.get('seed') == -1:
126
+ ui_inputs['seed'] = random.randint(0, 2**32 - 1)
127
+
128
+ model_info = ALL_MODEL_MAP[model_display_name]
129
+ path_or_components = model_info[1]
130
+ latent_type = model_info[3] if len(model_info) > 3 and model_info[3] else 'latent'
131
+ latent_generator_template = "EmptyLatentImage"
132
+ if latent_type == 'sd3_latent':
133
+ latent_generator_template = "EmptySD3LatentImage"
134
+ elif latent_type == 'chroma_radiance_latent':
135
+ latent_generator_template = "EmptyChromaRadianceLatentImage"
136
+ elif latent_type == 'hunyuan_latent':
137
+ latent_generator_template = "EmptyHunyuanImageLatent"
138
+
139
+ dynamic_values = {
140
+ 'task_type': ui_inputs['task_type'],
141
+ 'model_type': workflow_model_type,
142
+ 'latent_type': latent_type,
143
+ 'latent_generator_template': latent_generator_template
144
+ }
145
+
146
+ recipe_path = os.path.join(os.path.dirname(__file__), "workflow_recipes", "sd_unified_recipe.yaml")
147
+ assembler = WorkflowAssembler(recipe_path, dynamic_values=dynamic_values)
148
+
149
+ hidream_o1_smoothing_data = []
150
+ if workflow_model_type == 'hidream-o1' and model_display_name == "HiDream-O1-Image":
151
+ hidream_o1_smoothing_data.append({})
152
+
153
+ workflow_inputs = {
154
+ **ui_inputs,
155
+ "positive_prompt": ui_inputs['positive_prompt'], "negative_prompt": ui_inputs['negative_prompt'],
156
+ "seed": ui_inputs['seed'], "steps": ui_inputs['num_inference_steps'], "cfg": ui_inputs['guidance_scale'],
157
+ "sampler_name": ui_inputs['sampler'], "scheduler": ui_inputs['scheduler'],
158
+ "batch_size": ui_inputs['batch_size'],
159
+ "clip_skip": ui_inputs['clip_skip'],
160
+ "denoise": ui_inputs['denoise'],
161
+ "vae_name": ui_inputs.get('vae_name'),
162
+ "guidance": ui_inputs.get('guidance', 3.5),
163
+ "lora_chain": active_loras_for_gpu,
164
+ "controlnet_chain": active_controlnets if not active_anima_controlnets else [],
165
+ "anima_controlnet_lllite_chain": active_anima_controlnets,
166
+ "diffsynth_controlnet_chain": active_diffsynth_controlnets,
167
+ "krea2_controlnet_chain": active_krea2_controlnets,
168
+ "ipadapter_chain": active_ipadapters,
169
+ "flux1_ipadapter_chain": active_flux1_ipadapters,
170
+ "sd3_ipadapter_chain": active_sd3_ipadapters,
171
+ "style_chain": active_styles,
172
+ "conditioning_chain": active_conditioning,
173
+ "reference_latent_chain": active_reference_latents,
174
+ "hidream_o1_reference_chain": active_hidream_o1_reference,
175
+ "vae_chain": [ui_inputs.get('vae_name')] if ui_inputs.get('vae_name') else [],
176
+ "hidream_o1_smoothing_chain": hidream_o1_smoothing_data,
177
+ "pid_chain": [ui_inputs.get('pid_settings', 'OFF')] if is_pid_enabled else [],
178
+ "scheduler_width": ui_inputs.get('width', 1024),
179
+ "scheduler_height": ui_inputs.get('height', 1024),
180
+ }
181
+
182
+ if isinstance(path_or_components, dict):
183
+ workflow_inputs.update({
184
+ 'unet_name': path_or_components.get('unet'),
185
+ 'unet_uncond_name': path_or_components.get('unet_uncond'),
186
+ 'vae_name': ui_inputs.get('vae_name') or path_or_components.get('vae'),
187
+ 'clip_name': path_or_components.get('clip'),
188
+ 'clip1_name': path_or_components.get('clip1'),
189
+ 'clip2_name': path_or_components.get('clip2'),
190
+ 'clip3_name': path_or_components.get('clip3'),
191
+ 'clip4_name': path_or_components.get('clip4'),
192
+ 'lora_name': path_or_components.get('lora'),
193
+ })
194
+ else:
195
+ workflow_inputs['model_name'] = path_or_components
196
+
197
+ if task_type == 'txt2img':
198
+ workflow_inputs['width'] = ui_inputs['width']
199
+ workflow_inputs['height'] = ui_inputs['height']
200
+
201
+ workflow = assembler.assemble(workflow_inputs)
202
+
203
+ progress(1.0, desc="All models ready. Requesting GPU for generation...")
204
+
205
+ results = self._execute_gpu_logic(
206
+ self._gpu_logic,
207
+ duration=ui_inputs['zero_gpu_duration'],
208
+ default_duration=60,
209
+ task_name=f"ImageGen ({task_type})",
210
+ ui_inputs=ui_inputs,
211
+ loras_string=loras_string,
212
+ workflow=workflow,
213
+ assembler=assembler,
214
+ progress=progress
215
+ )
216
+
217
+ import json
218
+ import glob
219
+ from PIL import PngImagePlugin
220
+
221
+ prompt_json = json.dumps(workflow)
222
+
223
+ out_dir = os.path.abspath(OUTPUT_DIR)
224
+ os.makedirs(out_dir, exist_ok=True)
225
+
226
+ try:
227
+ existing_files = glob.glob(os.path.join(out_dir, "gen_*.png"))
228
+ existing_files.sort(key=os.path.getmtime)
229
+ while len(existing_files) > 50:
230
+ os.remove(existing_files.pop(0))
231
+ except Exception as e:
232
+ print(f"Warning: Failed to cleanup output dir: {e}")
233
+
234
+ final_results = []
235
+ for img in results:
236
+ if not isinstance(img, Image.Image):
237
+ final_results.append(img)
238
+ continue
239
+
240
+ metadata = PngImagePlugin.PngInfo()
241
+ params_string = img.info.get("parameters", "")
242
+ if params_string:
243
+ metadata.add_text("parameters", params_string)
244
+ metadata.add_text("prompt", prompt_json)
245
+
246
+ filename = f"gen_{random.randint(1000000, 9999999)}.png"
247
+ filepath = os.path.join(out_dir, filename)
248
+ img.save(filepath, "PNG", pnginfo=metadata)
249
+ final_results.append(filepath)
250
+
251
+ results = final_results
252
+
253
+ finally:
254
+ for temp_file in temp_files_to_clean:
255
+ if temp_file and os.path.exists(temp_file):
256
+ os.remove(temp_file)
257
+ print(f"✅ Cleaned up temp file: {temp_file}")
258
+
259
  return results
ui/events/run_handlers.py CHANGED
@@ -1,105 +1,105 @@
1
- import gradio as gr
2
- from core.generation_logic import generate_image_wrapper
3
-
4
- def create_run_event(prefix: str, task_type: str, ui_components: dict):
5
- run_inputs_map = {
6
- 'model_display_name': ui_components[f'base_model_{prefix}'],
7
- 'positive_prompt': ui_components.get(f'prompt_{prefix}') or ui_components.get(f'{prefix}_positive_prompt'),
8
- 'negative_prompt': ui_components.get(f'neg_prompt_{prefix}') or ui_components.get(f'{prefix}_negative_prompt'),
9
- 'seed': ui_components.get(f'seed_{prefix}') or ui_components.get(f'{prefix}_seed'),
10
- 'batch_size': ui_components.get(f'batch_size_{prefix}') or ui_components.get(f'{prefix}_batch_size'),
11
- 'guidance_scale': ui_components.get(f'cfg_{prefix}') or ui_components.get(f'{prefix}_cfg'),
12
- 'num_inference_steps': ui_components.get(f'steps_{prefix}') or ui_components.get(f'{prefix}_steps'),
13
- 'sampler': ui_components.get(f'sampler_{prefix}') or ui_components.get(f'{prefix}_sampler_name'),
14
- 'scheduler': ui_components.get(f'scheduler_{prefix}') or ui_components.get(f'{prefix}_scheduler'),
15
- 'zero_gpu_duration': ui_components.get(f'zero_gpu_{prefix}'),
16
-
17
- 'clip_skip': ui_components.get(f'clip_skip_{prefix}'),
18
- 'guidance': ui_components.get(f'guidance_{prefix}'),
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'),
28
- 'height': ui_components.get(f'height_{prefix}') or ui_components.get(f'{prefix}_height')
29
- })
30
-
31
- task_specific_map = {
32
- 'img2img': {'img2img_image': f'input_image_{prefix}', 'img2img_denoise': f'denoise_{prefix}'},
33
- 'inpaint': {'inpaint_image_dict': f'input_image_dict_{prefix}', 'grow_mask_by': f'grow_mask_by_{prefix}', 'inpaint_denoise': f'denoise_{prefix}'},
34
- 'outpaint': {'outpaint_image': f'input_image_{prefix}', 'left': f'left_{prefix}', 'top': f'top_{prefix}', 'right': f'right_{prefix}', 'bottom': f'bottom_{prefix}', 'feathering': f'feathering_{prefix}'},
35
- 'hires_fix': {'hires_image': f'input_image_{prefix}', 'hires_upscaler': f'hires_upscaler_{prefix}', 'hires_scale_by': f'hires_scale_by_{prefix}', 'hires_denoise': f'denoise_{prefix}'}
36
- }
37
- if task_type in task_specific_map:
38
- for key, comp_name in task_specific_map[task_type].items():
39
- if comp_name in ui_components:
40
- run_inputs_map[key] = ui_components[comp_name]
41
-
42
- lora_data_components = ui_components.get(f'all_lora_components_flat_{prefix}', [])
43
- controlnet_data_components = ui_components.get(f'all_controlnet_components_flat_{prefix}', [])
44
- anima_controlnet_lllite_data_components = ui_components.get(f'all_anima_controlnet_lllite_components_flat_{prefix}', [])
45
- diffsynth_controlnet_data_components = ui_components.get(f'all_diffsynth_controlnet_components_flat_{prefix}', [])
46
- krea2_controlnet_data_components = ui_components.get(f'all_krea2_controlnet_components_flat_{prefix}', [])
47
- ipadapter_data_components = ui_components.get(f'all_ipadapter_components_flat_{prefix}', [])
48
- sd3_ipadapter_data_components = ui_components.get(f'all_sd3_ipadapter_components_flat_{prefix}', [])
49
- flux1_ipadapter_data_components = ui_components.get(f'all_flux1_ipadapter_components_flat_{prefix}', [])
50
- style_data_components = ui_components.get(f'all_style_components_flat_{prefix}', [])
51
- embedding_data_components = ui_components.get(f'all_embedding_components_flat_{prefix}', [])
52
- conditioning_data_components = ui_components.get(f'all_conditioning_components_flat_{prefix}', [])
53
- reference_latent_data_components = ui_components.get(f'all_reference_latent_components_flat_{prefix}', [])
54
- hidream_o1_reference_data_components = ui_components.get(f'all_hidream_o1_reference_components_flat_{prefix}', [])
55
-
56
- run_inputs_map['vae_source'] = ui_components.get(f'vae_source_{prefix}')
57
- run_inputs_map['vae_id'] = ui_components.get(f'vae_id_{prefix}')
58
- run_inputs_map['vae_file'] = ui_components.get(f'vae_file_{prefix}')
59
-
60
- input_keys = list(run_inputs_map.keys())
61
- input_list_flat = [v for v in run_inputs_map.values() if v is not None]
62
- all_chains = [
63
- lora_data_components, controlnet_data_components, anima_controlnet_lllite_data_components, diffsynth_controlnet_data_components, krea2_controlnet_data_components, ipadapter_data_components,
64
- sd3_ipadapter_data_components, flux1_ipadapter_data_components, style_data_components,
65
- embedding_data_components, conditioning_data_components, reference_latent_data_components, hidream_o1_reference_data_components
66
- ]
67
- for chain in all_chains:
68
- if chain:
69
- input_list_flat.extend(chain)
70
-
71
- def create_ui_inputs_dict(*args):
72
- valid_keys = [k for k in input_keys if run_inputs_map[k] is not None]
73
- ui_dict = dict(zip(valid_keys, args[:len(valid_keys)]))
74
- arg_idx = len(valid_keys)
75
-
76
- def assign_chain_data(chain_key, components_list):
77
- nonlocal arg_idx
78
- if components_list:
79
- ui_dict[chain_key] = list(args[arg_idx : arg_idx + len(components_list)])
80
- arg_idx += len(components_list)
81
-
82
- assign_chain_data('lora_data', lora_data_components)
83
- assign_chain_data('controlnet_data', controlnet_data_components)
84
- assign_chain_data('anima_controlnet_lllite_data', anima_controlnet_lllite_data_components)
85
- assign_chain_data('diffsynth_controlnet_data', diffsynth_controlnet_data_components)
86
- assign_chain_data('krea2_controlnet_data', krea2_controlnet_data_components)
87
- assign_chain_data('ipadapter_data', ipadapter_data_components)
88
- assign_chain_data('sd3_ipadapter_chain', sd3_ipadapter_data_components)
89
- assign_chain_data('flux1_ipadapter_data', flux1_ipadapter_data_components)
90
- assign_chain_data('style_data', style_data_components)
91
- assign_chain_data('embedding_data', embedding_data_components)
92
- assign_chain_data('conditioning_data', conditioning_data_components)
93
- assign_chain_data('reference_latent_data', reference_latent_data_components)
94
- assign_chain_data('hidream_o1_reference_data', hidream_o1_reference_data_components)
95
-
96
- return ui_dict
97
-
98
- run_btn = ui_components.get(f'run_{prefix}') or ui_components.get(f'{prefix}_run_button')
99
- res_gal = ui_components.get(f'result_{prefix}') or ui_components.get(f'{prefix}_output_gallery')
100
- if run_btn and res_gal:
101
- run_btn.click(
102
- fn=lambda *args, progress=gr.Progress(track_tqdm=True): generate_image_wrapper(create_ui_inputs_dict(*args), progress),
103
- inputs=input_list_flat,
104
- outputs=[res_gal]
105
  )
 
1
+ import gradio as gr
2
+ from core.generation_logic import generate_image_wrapper
3
+
4
+ def create_run_event(prefix: str, task_type: str, ui_components: dict):
5
+ run_inputs_map = {
6
+ 'model_display_name': ui_components[f'base_model_{prefix}'],
7
+ 'positive_prompt': ui_components.get(f'prompt_{prefix}') or ui_components.get(f'{prefix}_positive_prompt'),
8
+ 'negative_prompt': ui_components.get(f'neg_prompt_{prefix}') or ui_components.get(f'{prefix}_negative_prompt'),
9
+ 'seed': ui_components.get(f'seed_{prefix}') or ui_components.get(f'{prefix}_seed'),
10
+ 'batch_size': ui_components.get(f'batch_size_{prefix}') or ui_components.get(f'{prefix}_batch_size'),
11
+ 'guidance_scale': ui_components.get(f'cfg_{prefix}') or ui_components.get(f'{prefix}_cfg'),
12
+ 'num_inference_steps': ui_components.get(f'steps_{prefix}') or ui_components.get(f'{prefix}_steps'),
13
+ 'sampler': ui_components.get(f'sampler_{prefix}') or ui_components.get(f'{prefix}_sampler_name'),
14
+ 'scheduler': ui_components.get(f'scheduler_{prefix}') or ui_components.get(f'{prefix}_scheduler'),
15
+ 'zero_gpu_duration': ui_components.get(f'zero_gpu_{prefix}'),
16
+
17
+ 'clip_skip': ui_components.get(f'clip_skip_{prefix}'),
18
+ 'guidance': ui_components.get(f'guidance_{prefix}'),
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'),
28
+ 'height': ui_components.get(f'height_{prefix}') or ui_components.get(f'{prefix}_height')
29
+ })
30
+
31
+ task_specific_map = {
32
+ 'img2img': {'img2img_image': f'input_image_{prefix}', 'img2img_denoise': f'denoise_{prefix}'},
33
+ 'inpaint': {'inpaint_image_dict': f'input_image_dict_{prefix}', 'grow_mask_by': f'grow_mask_by_{prefix}', 'inpaint_denoise': f'denoise_{prefix}'},
34
+ 'outpaint': {'outpaint_image': f'input_image_{prefix}', 'left': f'left_{prefix}', 'top': f'top_{prefix}', 'right': f'right_{prefix}', 'bottom': f'bottom_{prefix}', 'feathering': f'feathering_{prefix}'},
35
+ 'hires_fix': {'hires_image': f'input_image_{prefix}', 'hires_upscaler': f'hires_upscaler_{prefix}', 'hires_scale_by': f'hires_scale_by_{prefix}', 'hires_denoise': f'denoise_{prefix}'}
36
+ }
37
+ if task_type in task_specific_map:
38
+ for key, comp_name in task_specific_map[task_type].items():
39
+ if comp_name in ui_components:
40
+ run_inputs_map[key] = ui_components[comp_name]
41
+
42
+ lora_data_components = ui_components.get(f'all_lora_components_flat_{prefix}', [])
43
+ controlnet_data_components = ui_components.get(f'all_controlnet_components_flat_{prefix}', [])
44
+ anima_controlnet_lllite_data_components = ui_components.get(f'all_anima_controlnet_lllite_components_flat_{prefix}', [])
45
+ diffsynth_controlnet_data_components = ui_components.get(f'all_diffsynth_controlnet_components_flat_{prefix}', [])
46
+ krea2_controlnet_data_components = ui_components.get(f'all_krea2_controlnet_components_flat_{prefix}', [])
47
+ ipadapter_data_components = ui_components.get(f'all_ipadapter_components_flat_{prefix}', [])
48
+ sd3_ipadapter_data_components = ui_components.get(f'all_sd3_ipadapter_components_flat_{prefix}', [])
49
+ flux1_ipadapter_data_components = ui_components.get(f'all_flux1_ipadapter_components_flat_{prefix}', [])
50
+ style_data_components = ui_components.get(f'all_style_components_flat_{prefix}', [])
51
+ embedding_data_components = ui_components.get(f'all_embedding_components_flat_{prefix}', [])
52
+ conditioning_data_components = ui_components.get(f'all_conditioning_components_flat_{prefix}', [])
53
+ reference_latent_data_components = ui_components.get(f'all_reference_latent_components_flat_{prefix}', [])
54
+ hidream_o1_reference_data_components = ui_components.get(f'all_hidream_o1_reference_components_flat_{prefix}', [])
55
+
56
+ run_inputs_map['vae_source'] = ui_components.get(f'vae_source_{prefix}')
57
+ run_inputs_map['vae_id'] = ui_components.get(f'vae_id_{prefix}')
58
+ run_inputs_map['vae_file'] = ui_components.get(f'vae_file_{prefix}')
59
+
60
+ input_keys = list(run_inputs_map.keys())
61
+ input_list_flat = [v for v in run_inputs_map.values() if v is not None]
62
+ all_chains = [
63
+ lora_data_components, controlnet_data_components, anima_controlnet_lllite_data_components, diffsynth_controlnet_data_components, krea2_controlnet_data_components, ipadapter_data_components,
64
+ sd3_ipadapter_data_components, flux1_ipadapter_data_components, style_data_components,
65
+ embedding_data_components, conditioning_data_components, reference_latent_data_components, hidream_o1_reference_data_components
66
+ ]
67
+ for chain in all_chains:
68
+ if chain:
69
+ input_list_flat.extend(chain)
70
+
71
+ def create_ui_inputs_dict(*args):
72
+ valid_keys = [k for k in input_keys if run_inputs_map[k] is not None]
73
+ ui_dict = dict(zip(valid_keys, args[:len(valid_keys)]))
74
+ arg_idx = len(valid_keys)
75
+
76
+ def assign_chain_data(chain_key, components_list):
77
+ nonlocal arg_idx
78
+ if components_list:
79
+ ui_dict[chain_key] = list(args[arg_idx : arg_idx + len(components_list)])
80
+ arg_idx += len(components_list)
81
+
82
+ assign_chain_data('lora_data', lora_data_components)
83
+ assign_chain_data('controlnet_data', controlnet_data_components)
84
+ assign_chain_data('anima_controlnet_lllite_data', anima_controlnet_lllite_data_components)
85
+ assign_chain_data('diffsynth_controlnet_data', diffsynth_controlnet_data_components)
86
+ assign_chain_data('krea2_controlnet_data', krea2_controlnet_data_components)
87
+ assign_chain_data('ipadapter_data', ipadapter_data_components)
88
+ assign_chain_data('sd3_ipadapter_chain', sd3_ipadapter_data_components)
89
+ assign_chain_data('flux1_ipadapter_data', flux1_ipadapter_data_components)
90
+ assign_chain_data('style_data', style_data_components)
91
+ assign_chain_data('embedding_data', embedding_data_components)
92
+ assign_chain_data('conditioning_data', conditioning_data_components)
93
+ assign_chain_data('reference_latent_data', reference_latent_data_components)
94
+ assign_chain_data('hidream_o1_reference_data', hidream_o1_reference_data_components)
95
+
96
+ return ui_dict
97
+
98
+ run_btn = ui_components.get(f'run_{prefix}') or ui_components.get(f'{prefix}_run_button')
99
+ res_gal = ui_components.get(f'result_{prefix}') or ui_components.get(f'{prefix}_output_gallery')
100
+ if run_btn and res_gal:
101
+ run_btn.click(
102
+ fn=lambda *args, progress=gr.Progress(track_tqdm=True): generate_image_wrapper(create_ui_inputs_dict(*args), progress),
103
+ inputs=input_list_flat,
104
+ outputs=[res_gal]
105
  )
yaml/file_list.yaml CHANGED
@@ -444,18 +444,18 @@ file:
444
  source: "hf"
445
  repo_id: "Comfy-Org/PixelDiT"
446
  repository_file_path: "diffusion_models/pid_sd3_1024_to_4096_4step_bf16.safetensors"
447
- - filename: "pid_flux1_1024_to_4096_4step_mxfp8.safetensors"
448
  source: "hf"
449
  repo_id: "Comfy-Org/PixelDiT"
450
- repository_file_path: "diffusion_models/pid_flux1_1024_to_4096_4step_mxfp8.safetensors"
451
- - filename: "pid_qwenimage_1024_to_4096_4step_bf16.safetensors"
452
  source: "hf"
453
  repo_id: "Comfy-Org/PixelDiT"
454
- repository_file_path: "diffusion_models/pid_qwenimage_1024_to_4096_4step_bf16.safetensors"
455
- - filename: "pid_flux2_1024_to_4096_4step_mxfp8.safetensors"
456
  source: "hf"
457
  repo_id: "Comfy-Org/PixelDiT"
458
- repository_file_path: "diffusion_models/pid_flux2_1024_to_4096_4step_mxfp8.safetensors"
459
  # Lens
460
  - filename: "lens_mxfp8.safetensors"
461
  source: "hf"
 
444
  source: "hf"
445
  repo_id: "Comfy-Org/PixelDiT"
446
  repository_file_path: "diffusion_models/pid_sd3_1024_to_4096_4step_bf16.safetensors"
447
+ - filename: "pid_1.5_flux1_1024_to_4096_4step_int8_convrot.safetensors"
448
  source: "hf"
449
  repo_id: "Comfy-Org/PixelDiT"
450
+ repository_file_path: "diffusion_models/1.5/pid_1.5_flux1_1024_to_4096_4step_int8_convrot.safetensors"
451
+ - filename: "pid_1.5_qwenimage_1024_to_4096_4step_int8_convrot.safetensors"
452
  source: "hf"
453
  repo_id: "Comfy-Org/PixelDiT"
454
+ repository_file_path: "diffusion_models/1.5/pid_1.5_qwenimage_1024_to_4096_4step_int8_convrot.safetensors"
455
+ - filename: "pid_1.5_flux2_1024_to_4096_4step_int8_convrot.safetensors"
456
  source: "hf"
457
  repo_id: "Comfy-Org/PixelDiT"
458
+ repository_file_path: "diffusion_models/1.5/pid_1.5_flux2_1024_to_4096_4step_int8_convrot.safetensors"
459
  # Lens
460
  - filename: "lens_mxfp8.safetensors"
461
  source: "hf"
yaml/pid.yaml CHANGED
@@ -1,16 +1,16 @@
1
- PiD:
2
- - filepath: "pid_flux2_1024_to_4096_4step_mxfp8.safetensors"
3
- latent_format: "flux"
4
- architectures: ["flux2", "flux2-kv", "ideogram-4", "lens", "ernie-image"]
5
- - filepath: "pid_qwenimage_1024_to_4096_4step_bf16.safetensors"
6
- latent_format: "qwenimage"
7
- architectures: ["anima", "qwen-image", "krea-2"]
8
- - filepath: "pid_flux1_1024_to_4096_4step_mxfp8.safetensors"
9
- latent_format: "flux"
10
- architectures: ["longcat-image", "newbie-image", "z-image", "kandinsky-5", "ovis-image", "omnigen2", "chroma1", "hidream-i1", "flux1", "boogu-image"]
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"]
 
1
+ PiD:
2
+ - filepath: "pid_1.5_flux2_1024_to_4096_4step_int8_convrot.safetensors"
3
+ latent_format: "flux"
4
+ architectures: ["flux2", "flux2-kv", "ideogram-4", "lens", "ernie-image"]
5
+ - filepath: "pid_1.5_qwenimage_1024_to_4096_4step_int8_convrot.safetensors"
6
+ latent_format: "qwenimage"
7
+ architectures: ["anima", "qwen-image", "krea-2"]
8
+ - filepath: "pid_1.5_flux1_1024_to_4096_4step_int8_convrot.safetensors"
9
+ latent_format: "flux"
10
+ architectures: ["longcat-image", "newbie-image", "z-image", "kandinsky-5", "ovis-image", "omnigen2", "chroma1", "hidream-i1", "flux1", "boogu-image"]
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"]