RioShiina commited on
Commit
26d09bf
·
verified ·
1 Parent(s): 088ae2c

Add Qwen-Image Edit injector.

Browse files
README.md CHANGED
@@ -58,6 +58,7 @@ models:
58
  - Comfy-Org/Ovis-Image
59
  - Comfy-Org/PixelDiT
60
  - Comfy-Org/Qwen-Image_ComfyUI
 
61
  - Comfy-Org/sigclip_vision_384
62
  - Comfy-Org/stable-diffusion-3.5-fp8
63
  - Comfy-Org/vae-text-encorder-for-flux-klein-4b
@@ -95,6 +96,8 @@ models:
95
  - Laxhar/noobai-XL-1.1
96
  - Laxhar/noobai-XL-Vpred-1.0
97
  - licyk/sd_control_collection
 
 
98
  - LyliaEngine/Pony_Diffusion_V6_XL
99
  - MIC-Lab/illustriousXLv0.1_controlnet
100
  - MIC-Lab/illustriousXLv1.1_controlnet
@@ -157,6 +160,9 @@ models:
157
  - OmniGen2/OmniGen2
158
  - Qwen/Qwen-Image
159
  - Qwen/Qwen-Image-2512
 
 
 
160
  - stabilityai/stable-diffusion-3.5-large
161
  - stabilityai/stable-diffusion-3.5-medium
162
  - tencent/HunyuanImage-2.1
 
58
  - Comfy-Org/Ovis-Image
59
  - Comfy-Org/PixelDiT
60
  - Comfy-Org/Qwen-Image_ComfyUI
61
+ - Comfy-Org/Qwen-Image-Edit_ComfyUI
62
  - Comfy-Org/sigclip_vision_384
63
  - Comfy-Org/stable-diffusion-3.5-fp8
64
  - Comfy-Org/vae-text-encorder-for-flux-klein-4b
 
96
  - Laxhar/noobai-XL-1.1
97
  - Laxhar/noobai-XL-Vpred-1.0
98
  - licyk/sd_control_collection
99
+ - lightx2v/Qwen-Image-2512-Lightning
100
+ - lightx2v/Qwen-Image-Edit-2511-Lightning
101
  - LyliaEngine/Pony_Diffusion_V6_XL
102
  - MIC-Lab/illustriousXLv0.1_controlnet
103
  - MIC-Lab/illustriousXLv1.1_controlnet
 
160
  - OmniGen2/OmniGen2
161
  - Qwen/Qwen-Image
162
  - Qwen/Qwen-Image-2512
163
+ - Qwen/Qwen-Image-Edit
164
+ - Qwen/Qwen-Image-Edit-2509
165
+ - Qwen/Qwen-Image-Edit-2511
166
  - stabilityai/stable-diffusion-3.5-large
167
  - stabilityai/stable-diffusion-3.5-medium
168
  - tencent/HunyuanImage-2.1
chain_injectors/qwen_image_edit_injector.py ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ def create_node(assembler, class_type, title):
4
+ try:
5
+ node = assembler._get_node_template(class_type)
6
+ except Exception:
7
+ node = {
8
+ "inputs": {},
9
+ "class_type": class_type,
10
+ "_meta": {"title": title}
11
+ }
12
+ node['_meta']['title'] = title
13
+ return node
14
+
15
+ def inject(assembler, chain_definition, chain_items):
16
+ if not chain_items:
17
+ return
18
+
19
+ valid_images = []
20
+ for item in chain_items:
21
+ if not item:
22
+ continue
23
+ img_path = item
24
+ if isinstance(item, dict):
25
+ img_path = item.get('image') or item.get('filename') or item.get('path')
26
+ if img_path:
27
+ valid_images.append(img_path)
28
+
29
+ if not valid_images:
30
+ return
31
+
32
+ valid_images = valid_images[:3]
33
+
34
+ ksampler_name = chain_definition.get('ksampler_node', 'ksampler')
35
+ pos_prompt_name = chain_definition.get('pos_prompt_node', 'pos_prompt')
36
+ neg_prompt_name = chain_definition.get('neg_prompt_node', 'neg_prompt')
37
+ clip_loader_name = chain_definition.get('clip_loader_node', 'clip_loader')
38
+ vae_loader_name = chain_definition.get('vae_loader_node', 'vae_loader')
39
+ model_sampler_name = chain_definition.get('model_sampler_node', 'model_sampler')
40
+
41
+ if ksampler_name not in assembler.node_map:
42
+ print(f"Warning: Target node '{ksampler_name}' for Qwen-Image Edit chain not found. Skipping.")
43
+ return
44
+
45
+ ksampler_id = assembler.node_map[ksampler_name]
46
+
47
+ if 'model' not in assembler.workflow[ksampler_id]['inputs']:
48
+ print(f"Warning: KSampler node '{ksampler_name}' is missing 'model' input. Skipping.")
49
+ return
50
+
51
+ vae_connection = None
52
+ if vae_loader_name in assembler.node_map:
53
+ vae_connection = [assembler.node_map[vae_loader_name], 0]
54
+ else:
55
+ for node_id, node in assembler.workflow.items():
56
+ if isinstance(node, dict) and node.get('class_type') == 'VAELoader':
57
+ vae_connection = [node_id, 0]
58
+ break
59
+
60
+ clip_connection = None
61
+ if clip_loader_name in assembler.node_map:
62
+ clip_connection = [assembler.node_map[clip_loader_name], 0]
63
+ elif pos_prompt_name in assembler.node_map:
64
+ pos_id = assembler.node_map[pos_prompt_name]
65
+ clip_connection = assembler.workflow[pos_id]['inputs'].get('clip')
66
+
67
+ pos_prompt_id = assembler.node_map.get(pos_prompt_name)
68
+ neg_prompt_id = assembler.node_map.get(neg_prompt_name)
69
+
70
+ pos_text = ""
71
+ if pos_prompt_id and pos_prompt_id in assembler.workflow:
72
+ pos_text = assembler.workflow[pos_prompt_id]['inputs'].get('text', '')
73
+
74
+ neg_text = ""
75
+ if neg_prompt_id and neg_prompt_id in assembler.workflow:
76
+ neg_text = assembler.workflow[neg_prompt_id]['inputs'].get('text', '')
77
+
78
+ scaled_image_ids = []
79
+ for i, img_filename in enumerate(valid_images):
80
+ load_id = assembler._get_unique_id()
81
+ load_node = create_node(assembler, "LoadImage", f"Load Reference Image {i+1}")
82
+ load_node['inputs']['image'] = img_filename
83
+ assembler.workflow[load_id] = load_node
84
+
85
+ scale_id = assembler._get_unique_id()
86
+ scale_node = create_node(assembler, "ImageScaleToTotalPixels", f"Scale Reference {i+1}")
87
+ scale_node['inputs']['upscale_method'] = "lanczos"
88
+ scale_node['inputs']['megapixels'] = 1
89
+ scale_node['inputs']['resolution_steps'] = 1
90
+ scale_node['inputs']['image'] = [load_id, 0]
91
+ assembler.workflow[scale_id] = scale_node
92
+ scaled_image_ids.append(scale_id)
93
+
94
+ pos_encode_id = assembler._get_unique_id()
95
+ pos_encode_node = create_node(assembler, "TextEncodeQwenImageEditPlus", "TextEncodeQwenImageEditPlus (Positive)")
96
+ pos_encode_node['inputs']['prompt'] = pos_text
97
+ if clip_connection:
98
+ pos_encode_node['inputs']['clip'] = clip_connection
99
+ if vae_connection:
100
+ pos_encode_node['inputs']['vae'] = vae_connection
101
+ for idx, s_id in enumerate(scaled_image_ids):
102
+ pos_encode_node['inputs'][f"image{idx+1}"] = [s_id, 0]
103
+ assembler.workflow[pos_encode_id] = pos_encode_node
104
+
105
+ neg_encode_id = assembler._get_unique_id()
106
+ neg_encode_node = create_node(assembler, "TextEncodeQwenImageEditPlus", "TextEncodeQwenImageEditPlus")
107
+ neg_encode_node['inputs']['prompt'] = neg_text
108
+ if clip_connection:
109
+ neg_encode_node['inputs']['clip'] = clip_connection
110
+ if vae_connection:
111
+ neg_encode_node['inputs']['vae'] = vae_connection
112
+ for idx, s_id in enumerate(scaled_image_ids):
113
+ neg_encode_node['inputs'][f"image{idx+1}"] = [s_id, 0]
114
+ assembler.workflow[neg_encode_id] = neg_encode_node
115
+
116
+ pos_ref_id = assembler._get_unique_id()
117
+ pos_ref_node = create_node(assembler, "FluxKontextMultiReferenceLatentMethod", "Edit Model Reference Method")
118
+ pos_ref_node['inputs']['reference_latents_method'] = "index_timestep_zero"
119
+ pos_ref_node['inputs']['conditioning'] = [pos_encode_id, 0]
120
+ assembler.workflow[pos_ref_id] = pos_ref_node
121
+
122
+ neg_ref_id = assembler._get_unique_id()
123
+ neg_ref_node = create_node(assembler, "FluxKontextMultiReferenceLatentMethod", "Edit Model Reference Method")
124
+ neg_ref_node['inputs']['reference_latents_method'] = "index_timestep_zero"
125
+ neg_ref_node['inputs']['conditioning'] = [neg_encode_id, 0]
126
+ assembler.workflow[neg_ref_id] = neg_ref_node
127
+
128
+ assembler.workflow[ksampler_id]['inputs']['positive'] = [pos_ref_id, 0]
129
+ assembler.workflow[ksampler_id]['inputs']['negative'] = [neg_ref_id, 0]
130
+
131
+ model_sampler_id = assembler.node_map.get(model_sampler_name)
132
+ if not model_sampler_id:
133
+ for node_id, node in assembler.workflow.items():
134
+ if isinstance(node, dict) and node.get('class_type') == 'ModelSamplingAuraFlow':
135
+ model_sampler_id = node_id
136
+ break
137
+
138
+ if model_sampler_id and model_sampler_id in assembler.workflow:
139
+ assembler.workflow[model_sampler_id]['inputs']['shift'] = 3
140
+
141
+ current_model_connection = assembler.workflow[ksampler_id]['inputs']['model']
142
+ cfg_norm_id = assembler._get_unique_id()
143
+ cfg_norm_node = create_node(assembler, "CFGNorm", "CFGNorm")
144
+ cfg_norm_node['inputs']['strength'] = 1
145
+ cfg_norm_node['inputs']['pre_cfg'] = False
146
+ cfg_norm_node['inputs']['model'] = current_model_connection
147
+ assembler.workflow[cfg_norm_id] = cfg_norm_node
148
+ assembler.workflow[ksampler_id]['inputs']['model'] = [cfg_norm_id, 0]
149
+
150
+ if pos_prompt_id and pos_prompt_id in assembler.workflow:
151
+ del assembler.workflow[pos_prompt_id]
152
+
153
+ if neg_prompt_id and neg_prompt_id in assembler.workflow:
154
+ del assembler.workflow[neg_prompt_id]
155
+
156
+ print(f"Qwen-Image Edit injector applied with {len(valid_images)} reference image(s). Original CLIPTextEncode nodes replaced.")
core/pipelines/pipeline_input_processor.py CHANGED
@@ -368,6 +368,17 @@ def process_pipeline_inputs(ui_inputs: Dict[str, Any], progress: gr.Progress, wo
368
  temp_files_to_clean.append(temp_path)
369
  active_krea2_identity_edit.append(os.path.basename(temp_path))
370
 
 
 
 
 
 
 
 
 
 
 
 
371
  reference_image_data = ui_inputs.get('reference_image_data', [])
372
  active_reference_images = []
373
  if reference_image_data:
@@ -422,6 +433,7 @@ def process_pipeline_inputs(ui_inputs: Dict[str, Any], progress: gr.Progress, wo
422
  "active_hidream_o1_reference": active_hidream_o1_reference,
423
  "active_joyai_reference": active_joyai_reference,
424
  "active_krea2_identity_edit": active_krea2_identity_edit,
 
425
  "active_reference_images": active_reference_images,
426
  "active_conditioning": active_conditioning,
427
  "temp_files_to_clean": temp_files_to_clean
 
368
  temp_files_to_clean.append(temp_path)
369
  active_krea2_identity_edit.append(os.path.basename(temp_path))
370
 
371
+ qwen_image_edit_data = ui_inputs.get('qwen_image_edit_data', [])
372
+ active_qwen_image_edit = []
373
+ if qwen_image_edit_data:
374
+ for img in qwen_image_edit_data:
375
+ if img:
376
+ if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
377
+ temp_path = os.path.join(INPUT_DIR, f"temp_qwen_edit_ref_{random.randint(1000, 9999)}.png")
378
+ img.save(temp_path, "PNG")
379
+ temp_files_to_clean.append(temp_path)
380
+ active_qwen_image_edit.append(os.path.basename(temp_path))
381
+
382
  reference_image_data = ui_inputs.get('reference_image_data', [])
383
  active_reference_images = []
384
  if reference_image_data:
 
433
  "active_hidream_o1_reference": active_hidream_o1_reference,
434
  "active_joyai_reference": active_joyai_reference,
435
  "active_krea2_identity_edit": active_krea2_identity_edit,
436
+ "active_qwen_image_edit": active_qwen_image_edit,
437
  "active_reference_images": active_reference_images,
438
  "active_conditioning": active_conditioning,
439
  "temp_files_to_clean": temp_files_to_clean
core/pipelines/sd_image_pipeline.py CHANGED
@@ -118,6 +118,7 @@ class SdImagePipeline(BasePipeline):
118
  active_hidream_o1_reference = processed["active_hidream_o1_reference"]
119
  active_joyai_reference = processed.get("active_joyai_reference", [])
120
  active_krea2_identity_edit = processed.get("active_krea2_identity_edit", [])
 
121
  active_reference_images = processed.get("active_reference_images", [])
122
  active_conditioning = processed["active_conditioning"]
123
 
@@ -177,6 +178,7 @@ class SdImagePipeline(BasePipeline):
177
  "hidream_o1_reference_chain": active_hidream_o1_reference,
178
  "joyai_reference_chain": active_joyai_reference,
179
  "krea2_identity_edit_chain": active_krea2_identity_edit,
 
180
  "reference_image_chain": active_reference_images,
181
  "vae_chain": [ui_inputs.get('vae_name')] if ui_inputs.get('vae_name') else [],
182
  "hidream_o1_smoothing_chain": hidream_o1_smoothing_data,
 
118
  active_hidream_o1_reference = processed["active_hidream_o1_reference"]
119
  active_joyai_reference = processed.get("active_joyai_reference", [])
120
  active_krea2_identity_edit = processed.get("active_krea2_identity_edit", [])
121
+ active_qwen_image_edit = processed.get("active_qwen_image_edit", [])
122
  active_reference_images = processed.get("active_reference_images", [])
123
  active_conditioning = processed["active_conditioning"]
124
 
 
178
  "hidream_o1_reference_chain": active_hidream_o1_reference,
179
  "joyai_reference_chain": active_joyai_reference,
180
  "krea2_identity_edit_chain": active_krea2_identity_edit,
181
+ "qwen_image_edit_chain": active_qwen_image_edit,
182
  "reference_image_chain": active_reference_images,
183
  "vae_chain": [ui_inputs.get('vae_name')] if ui_inputs.get('vae_name') else [],
184
  "hidream_o1_smoothing_chain": hidream_o1_smoothing_data,
core/pipelines/workflow_recipes/_partials/conditioning/qwen-image.yaml CHANGED
@@ -71,6 +71,15 @@ dynamic_conditioning_chains:
71
  ksampler_node: "ksampler"
72
  clip_source: "clip_loader:0"
73
 
 
 
 
 
 
 
 
 
 
74
  dynamic_pid_chains:
75
  pid_chain:
76
  ksampler_node: "ksampler"
 
71
  ksampler_node: "ksampler"
72
  clip_source: "clip_loader:0"
73
 
74
+ dynamic_qwen_image_edit_chains:
75
+ qwen_image_edit_chain:
76
+ ksampler_node: "ksampler"
77
+ pos_prompt_node: "pos_prompt"
78
+ neg_prompt_node: "neg_prompt"
79
+ clip_loader_node: "clip_loader"
80
+ vae_loader_node: "vae_loader"
81
+ model_sampler_node: "model_sampler"
82
+
83
  dynamic_pid_chains:
84
  pid_chain:
85
  ksampler_node: "ksampler"
ui/events/chain_handlers.py CHANGED
@@ -1,892 +1,925 @@
1
- import gradio as gr
2
- from core.settings import VAE_DIR, LORA_DIR, EMBEDDING_DIR, ARCHITECTURES_CONFIG
3
- from utils.app_utils import save_uploaded_file_with_hash
4
- from ui.shared.ui_components import (
5
- MAX_CONTROLNETS,
6
- MAX_IPADAPTERS,
7
- MAX_EMBEDDINGS,
8
- MAX_CONDITIONINGS,
9
- MAX_LORAS
10
- )
11
- from .config_loaders import (
12
- load_controlnet_config,
13
- load_anima_controlnet_lllite_config,
14
- load_diffsynth_controlnet_config,
15
- load_krea2_controlnet_config,
16
- load_ipadapter_config
17
- )
18
-
19
- def on_vae_upload(file_obj):
20
- if not file_obj:
21
- return gr.update(), gr.update(), None
22
-
23
- hashed_filename = save_uploaded_file_with_hash(file_obj, VAE_DIR)
24
- return hashed_filename, "File", file_obj
25
-
26
-
27
- def on_lora_upload(file_obj):
28
- if not file_obj:
29
- return gr.update(), gr.update()
30
-
31
- hashed_filename = save_uploaded_file_with_hash(file_obj, LORA_DIR)
32
- return hashed_filename, "File"
33
-
34
-
35
- def on_embedding_upload(file_obj):
36
- if not file_obj:
37
- return gr.update(), gr.update(), None
38
-
39
- hashed_filename = save_uploaded_file_with_hash(file_obj, EMBEDDING_DIR)
40
- return hashed_filename, "File", file_obj
41
-
42
-
43
- def create_lora_event_handlers(prefix, ui_components):
44
- lora_rows = ui_components.get(f'lora_rows_{prefix}')
45
- if not lora_rows: return
46
- lora_ids = ui_components[f'lora_ids_{prefix}']
47
- lora_scales = ui_components[f'lora_scales_{prefix}']
48
- lora_uploads = ui_components[f'lora_uploads_{prefix}']
49
- lora_sources = ui_components[f'lora_sources_{prefix}']
50
- count_state = ui_components[f'lora_count_state_{prefix}']
51
- add_button = ui_components[f'add_lora_button_{prefix}']
52
- del_button = ui_components[f'delete_lora_button_{prefix}']
53
-
54
- for i in range(MAX_LORAS):
55
- lora_uploads[i].upload(
56
- fn=on_lora_upload,
57
- inputs=[lora_uploads[i]],
58
- outputs=[lora_ids[i], lora_sources[i]],
59
- show_progress=True
60
- )
61
-
62
- def add_lora_row(c):
63
- updates = {}
64
- if c < MAX_LORAS:
65
- c += 1
66
- updates[lora_rows[c - 1]] = gr.update(visible=True)
67
-
68
- updates[count_state] = c
69
- updates[add_button] = gr.update(visible=c < MAX_LORAS)
70
- updates[del_button] = gr.update(visible=c > 1)
71
- return updates
72
-
73
- def del_lora_row(c):
74
- updates = {}
75
- if c > 1:
76
- updates[lora_rows[c - 1]] = gr.update(visible=False)
77
- updates[lora_ids[c - 1]] = ""
78
- updates[lora_scales[c - 1]] = 0.0
79
- updates[lora_uploads[c - 1]] = None
80
- c -= 1
81
-
82
- updates[count_state] = c
83
- updates[add_button] = gr.update(visible=True)
84
- updates[del_button] = gr.update(visible=c > 1)
85
- return updates
86
-
87
- add_outputs = [count_state, add_button, del_button] + lora_rows
88
- del_outputs = [count_state, add_button, del_button] + lora_rows + lora_ids + lora_scales + lora_uploads
89
-
90
- add_button.click(add_lora_row, [count_state], add_outputs, show_progress=False)
91
- del_button.click(del_lora_row, [count_state], del_outputs, show_progress=False)
92
-
93
-
94
- def create_controlnet_event_handlers(prefix, ui_components):
95
- cn_rows = ui_components.get(f'controlnet_rows_{prefix}')
96
- if not cn_rows: return
97
- cn_types = ui_components[f'controlnet_types_{prefix}']
98
- cn_series = ui_components[f'controlnet_series_{prefix}']
99
- cn_filepaths = ui_components[f'controlnet_filepaths_{prefix}']
100
- cn_images = ui_components[f'controlnet_images_{prefix}']
101
- cn_strengths = ui_components[f'controlnet_strengths_{prefix}']
102
-
103
- count_state = ui_components[f'controlnet_count_state_{prefix}']
104
- add_button = ui_components[f'add_controlnet_button_{prefix}']
105
- del_button = ui_components[f'delete_controlnet_button_{prefix}']
106
- accordion = ui_components[f'controlnet_accordion_{prefix}']
107
-
108
- base_model_comp = ui_components.get(f'base_model_{prefix}')
109
- actual_arch_comp = base_model_comp if base_model_comp else gr.State("SDXL")
110
-
111
- def add_cn_row(c):
112
- c += 1
113
- updates = {
114
- count_state: c,
115
- cn_rows[c-1]: gr.update(visible=True),
116
- add_button: gr.update(visible=c < MAX_CONTROLNETS),
117
- del_button: gr.update(visible=True)
118
- }
119
- return updates
120
-
121
- def del_cn_row(c):
122
- c -= 1
123
- updates = {
124
- count_state: c,
125
- cn_rows[c]: gr.update(visible=False),
126
- cn_images[c]: None,
127
- cn_strengths[c]: 1.0,
128
- add_button: gr.update(visible=True),
129
- del_button: gr.update(visible=c > 0)
130
- }
131
- return updates
132
-
133
- add_outputs = [count_state, add_button, del_button] + cn_rows
134
- del_outputs = [count_state, add_button, del_button] + cn_rows + cn_images + cn_strengths
135
- add_button.click(fn=add_cn_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
136
- del_button.click(fn=del_cn_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
137
-
138
- def on_cn_type_change(selected_type, model_name):
139
- from core.settings import MODEL_TYPE_MAP
140
- m_type = MODEL_TYPE_MAP.get(model_name, "SDXL") if model_name else "SDXL"
141
- cn_full_config = load_controlnet_config()
142
-
143
- architectures_dict = ARCHITECTURES_CONFIG.get('architectures', {})
144
- controlnet_key = architectures_dict.get(m_type, {}).get("controlnet_key", m_type)
145
-
146
- cn_config = cn_full_config.get(controlnet_key, [])
147
- series_choices = []
148
- if selected_type:
149
- series_choices = sorted(list(set(
150
- model.get("Series", "Default") for model in cn_config
151
- if selected_type in model.get("Type", [])
152
- )))
153
- default_series = series_choices[0] if series_choices else None
154
- filepath = "None"
155
- if default_series:
156
- for model in cn_config:
157
- if model.get("Series") == default_series and selected_type in model.get("Type", []):
158
- filepath = model.get("Filepath")
159
- break
160
- return gr.update(choices=series_choices, value=default_series), filepath
161
-
162
- def on_cn_series_change(selected_series, selected_type, model_name):
163
- from core.settings import MODEL_TYPE_MAP
164
- m_type = MODEL_TYPE_MAP.get(model_name, "SDXL") if model_name else "SDXL"
165
- cn_full_config = load_controlnet_config()
166
-
167
- architectures_dict = ARCHITECTURES_CONFIG.get('architectures', {})
168
- controlnet_key = architectures_dict.get(m_type, {}).get("controlnet_key", m_type)
169
-
170
- cn_config = cn_full_config.get(controlnet_key, [])
171
- filepath = "None"
172
- if selected_series and selected_type:
173
- for model in cn_config:
174
- if model.get("Series") == selected_series and selected_type in model.get("Type", []):
175
- filepath = model.get("Filepath")
176
- break
177
- return filepath
178
-
179
- for i in range(MAX_CONTROLNETS):
180
- cn_types[i].change(
181
- fn=on_cn_type_change,
182
- inputs=[cn_types[i], actual_arch_comp],
183
- outputs=[cn_series[i], cn_filepaths[i]],
184
- show_progress=False
185
- )
186
- cn_series[i].change(
187
- fn=on_cn_series_change,
188
- inputs=[cn_series[i], cn_types[i], actual_arch_comp],
189
- outputs=[cn_filepaths[i]],
190
- show_progress=False
191
- )
192
-
193
- def on_accordion_expand(*images):
194
- return [gr.update() for _ in images]
195
-
196
- accordion.expand(
197
- fn=on_accordion_expand,
198
- inputs=cn_images,
199
- outputs=cn_images,
200
- show_progress=False
201
- )
202
-
203
-
204
- def create_krea2_controlnet_event_handlers(prefix, ui_components):
205
- cn_rows = ui_components.get(f'krea2_controlnet_rows_{prefix}')
206
- if not cn_rows: return
207
- cn_types = ui_components[f'krea2_controlnet_types_{prefix}']
208
- cn_series = ui_components[f'krea2_controlnet_series_{prefix}']
209
- cn_filepaths = ui_components[f'krea2_controlnet_filepaths_{prefix}']
210
- cn_images = ui_components[f'krea2_controlnet_images_{prefix}']
211
- cn_strengths = ui_components[f'krea2_controlnet_strengths_{prefix}']
212
-
213
- count_state = ui_components[f'krea2_controlnet_count_state_{prefix}']
214
- add_button = ui_components[f'add_krea2_controlnet_button_{prefix}']
215
- del_button = ui_components[f'delete_krea2_controlnet_button_{prefix}']
216
- accordion = ui_components[f'krea2_controlnet_accordion_{prefix}']
217
-
218
- def add_cn_row(c):
219
- c += 1
220
- updates = {
221
- count_state: c,
222
- cn_rows[c-1]: gr.update(visible=True),
223
- add_button: gr.update(visible=c < MAX_CONTROLNETS),
224
- del_button: gr.update(visible=True)
225
- }
226
- return updates
227
-
228
- def del_cn_row(c):
229
- c -= 1
230
- updates = {
231
- count_state: c,
232
- cn_rows[c]: gr.update(visible=False),
233
- cn_images[c]: None,
234
- cn_strengths[c]: 1.0,
235
- add_button: gr.update(visible=True),
236
- del_button: gr.update(visible=c > 0)
237
- }
238
- return updates
239
-
240
- add_outputs = [count_state, add_button, del_button] + cn_rows
241
- del_outputs = [count_state, add_button, del_button] + cn_rows + cn_images + cn_strengths
242
- add_button.click(fn=add_cn_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
243
- del_button.click(fn=del_cn_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
244
-
245
- def on_cn_type_change(selected_type):
246
- cn_config = load_krea2_controlnet_config()
247
- series_choices = []
248
- if selected_type:
249
- series_choices = sorted(list(set(
250
- model.get("Series", "Default") for model in cn_config
251
- if selected_type in model.get("Type", [])
252
- )))
253
- default_series = series_choices[0] if series_choices else None
254
- filepath = "None"
255
- if default_series:
256
- for model in cn_config:
257
- if model.get("Series") == default_series and selected_type in model.get("Type", []):
258
- filepath = model.get("Filepath")
259
- break
260
- return gr.update(choices=series_choices, value=default_series), filepath
261
-
262
- def on_cn_series_change(selected_series, selected_type):
263
- cn_config = load_krea2_controlnet_config()
264
- filepath = "None"
265
- if selected_series and selected_type:
266
- for model in cn_config:
267
- if model.get("Series") == selected_series and selected_type in model.get("Type", []):
268
- filepath = model.get("Filepath")
269
- break
270
- return filepath
271
-
272
- for i in range(MAX_CONTROLNETS):
273
- cn_types[i].change(
274
- fn=on_cn_type_change,
275
- inputs=[cn_types[i]],
276
- outputs=[cn_series[i], cn_filepaths[i]],
277
- show_progress=False
278
- )
279
- cn_series[i].change(
280
- fn=on_cn_series_change,
281
- inputs=[cn_series[i], cn_types[i]],
282
- outputs=[cn_filepaths[i]],
283
- show_progress=False
284
- )
285
-
286
- def on_accordion_expand(*images):
287
- return [gr.update() for _ in images]
288
-
289
- accordion.expand(
290
- fn=on_accordion_expand,
291
- inputs=cn_images,
292
- outputs=cn_images,
293
- show_progress=False
294
- )
295
-
296
-
297
- def create_anima_controlnet_lllite_event_handlers(prefix, ui_components):
298
- cn_rows = ui_components.get(f'anima_controlnet_lllite_rows_{prefix}')
299
- if not cn_rows: return
300
- cn_types = ui_components[f'anima_controlnet_lllite_types_{prefix}']
301
- cn_series = ui_components[f'anima_controlnet_lllite_series_{prefix}']
302
- cn_filepaths = ui_components[f'anima_controlnet_lllite_filepaths_{prefix}']
303
- cn_images = ui_components[f'anima_controlnet_lllite_images_{prefix}']
304
- cn_strengths = ui_components[f'anima_controlnet_lllite_strengths_{prefix}']
305
-
306
- count_state = ui_components[f'anima_controlnet_lllite_count_state_{prefix}']
307
- add_button = ui_components[f'add_anima_controlnet_lllite_button_{prefix}']
308
- del_button = ui_components[f'delete_anima_controlnet_lllite_button_{prefix}']
309
- accordion = ui_components[f'anima_controlnet_lllite_accordion_{prefix}']
310
-
311
- def add_cn_row(c):
312
- c += 1
313
- updates = {
314
- count_state: c,
315
- cn_rows[c-1]: gr.update(visible=True),
316
- add_button: gr.update(visible=c < MAX_CONTROLNETS),
317
- del_button: gr.update(visible=True)
318
- }
319
- return updates
320
-
321
- def del_cn_row(c):
322
- c -= 1
323
- updates = {
324
- count_state: c,
325
- cn_rows[c]: gr.update(visible=False),
326
- cn_images[c]: None,
327
- cn_strengths[c]: 1.0,
328
- add_button: gr.update(visible=True),
329
- del_button: gr.update(visible=c > 0)
330
- }
331
- return updates
332
-
333
- add_outputs = [count_state, add_button, del_button] + cn_rows
334
- del_outputs = [count_state, add_button, del_button] + cn_rows + cn_images + cn_strengths
335
- add_button.click(fn=add_cn_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
336
- del_button.click(fn=del_cn_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
337
-
338
- def on_cn_type_change(selected_type):
339
- cn_config = load_anima_controlnet_lllite_config()
340
- series_choices = []
341
- if selected_type:
342
- series_choices = sorted(list(set(
343
- model.get("Series", "Default") for model in cn_config
344
- if selected_type in model.get("Type", [])
345
- )))
346
- default_series = series_choices[0] if series_choices else None
347
- filepath = "None"
348
- if default_series:
349
- for model in cn_config:
350
- if model.get("Series") == default_series and selected_type in model.get("Type", []):
351
- filepath = model.get("Filepath")
352
- break
353
- return gr.update(choices=series_choices, value=default_series), filepath
354
-
355
- def on_cn_series_change(selected_series, selected_type):
356
- cn_config = load_anima_controlnet_lllite_config()
357
- filepath = "None"
358
- if selected_series and selected_type:
359
- for model in cn_config:
360
- if model.get("Series") == selected_series and selected_type in model.get("Type", []):
361
- filepath = model.get("Filepath")
362
- break
363
- return filepath
364
-
365
- for i in range(MAX_CONTROLNETS):
366
- cn_types[i].change(
367
- fn=on_cn_type_change,
368
- inputs=[cn_types[i]],
369
- outputs=[cn_series[i], cn_filepaths[i]],
370
- show_progress=False
371
- )
372
- cn_series[i].change(
373
- fn=on_cn_series_change,
374
- inputs=[cn_series[i], cn_types[i]],
375
- outputs=[cn_filepaths[i]],
376
- show_progress=False
377
- )
378
-
379
- def on_accordion_expand(*images):
380
- return [gr.update() for _ in images]
381
-
382
- accordion.expand(
383
- fn=on_accordion_expand,
384
- inputs=cn_images,
385
- outputs=cn_images,
386
- show_progress=False
387
- )
388
-
389
-
390
- def create_diffsynth_controlnet_event_handlers(prefix, ui_components):
391
- cn_rows = ui_components.get(f'diffsynth_controlnet_rows_{prefix}')
392
- if not cn_rows: return
393
- cn_types = ui_components[f'diffsynth_controlnet_types_{prefix}']
394
- cn_series = ui_components[f'diffsynth_controlnet_series_{prefix}']
395
- cn_filepaths = ui_components[f'diffsynth_controlnet_filepaths_{prefix}']
396
- cn_images = ui_components[f'diffsynth_controlnet_images_{prefix}']
397
- cn_strengths = ui_components[f'diffsynth_controlnet_strengths_{prefix}']
398
-
399
- count_state = ui_components[f'diffsynth_controlnet_count_state_{prefix}']
400
- add_button = ui_components[f'add_diffsynth_controlnet_button_{prefix}']
401
- del_button = ui_components[f'delete_diffsynth_controlnet_button_{prefix}']
402
- accordion = ui_components[f'diffsynth_controlnet_accordion_{prefix}']
403
-
404
- base_model_comp = ui_components.get(f'base_model_{prefix}')
405
- actual_arch_comp = base_model_comp if base_model_comp else gr.State("SDXL")
406
-
407
- def add_cn_row(c):
408
- c += 1
409
- updates = {
410
- count_state: c,
411
- cn_rows[c-1]: gr.update(visible=True),
412
- add_button: gr.update(visible=c < MAX_CONTROLNETS),
413
- del_button: gr.update(visible=True)
414
- }
415
- return updates
416
-
417
- def del_cn_row(c):
418
- c -= 1
419
- updates = {
420
- count_state: c,
421
- cn_rows[c]: gr.update(visible=False),
422
- cn_images[c]: None,
423
- cn_strengths[c]: 1.0,
424
- add_button: gr.update(visible=True),
425
- del_button: gr.update(visible=c > 0)
426
- }
427
- return updates
428
-
429
- add_outputs = [count_state, add_button, del_button] + cn_rows
430
- del_outputs = [count_state, add_button, del_button] + cn_rows + cn_images + cn_strengths
431
- add_button.click(fn=add_cn_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
432
- del_button.click(fn=del_cn_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
433
-
434
- def on_cn_type_change(selected_type, model_name):
435
- from core.settings import MODEL_TYPE_MAP
436
- m_type = MODEL_TYPE_MAP.get(model_name, "SDXL") if model_name else "SDXL"
437
- cn_full_config = load_diffsynth_controlnet_config()
438
-
439
- architectures_dict = ARCHITECTURES_CONFIG.get('architectures', {})
440
- controlnet_key = architectures_dict.get(m_type, {}).get("controlnet_key", m_type)
441
-
442
- cn_config = cn_full_config.get(controlnet_key, [])
443
- series_choices = []
444
- if selected_type:
445
- series_choices = sorted(list(set(
446
- model.get("Series", "Default") for model in cn_config
447
- if selected_type in model.get("Type", [])
448
- )))
449
- default_series = series_choices[0] if series_choices else None
450
- filepath = "None"
451
- if default_series:
452
- for model in cn_config:
453
- if model.get("Series") == default_series and selected_type in model.get("Type", []):
454
- filepath = model.get("Filepath")
455
- break
456
- return gr.update(choices=series_choices, value=default_series), filepath
457
-
458
- def on_cn_series_change(selected_series, selected_type, model_name):
459
- from core.settings import MODEL_TYPE_MAP
460
- m_type = MODEL_TYPE_MAP.get(model_name, "SDXL") if model_name else "SDXL"
461
- cn_full_config = load_diffsynth_controlnet_config()
462
-
463
- architectures_dict = ARCHITECTURES_CONFIG.get('architectures', {})
464
- controlnet_key = architectures_dict.get(m_type, {}).get("controlnet_key", m_type)
465
-
466
- cn_config = cn_full_config.get(controlnet_key, [])
467
- filepath = "None"
468
- if selected_series and selected_type:
469
- for model in cn_config:
470
- if model.get("Series") == selected_series and selected_type in model.get("Type", []):
471
- filepath = model.get("Filepath")
472
- break
473
- return filepath
474
-
475
- for i in range(MAX_CONTROLNETS):
476
- cn_types[i].change(
477
- fn=on_cn_type_change,
478
- inputs=[cn_types[i], actual_arch_comp],
479
- outputs=[cn_series[i], cn_filepaths[i]],
480
- show_progress=False
481
- )
482
- cn_series[i].change(
483
- fn=on_cn_series_change,
484
- inputs=[cn_series[i], cn_types[i], actual_arch_comp],
485
- outputs=[cn_filepaths[i]],
486
- show_progress=False
487
- )
488
-
489
- def on_accordion_expand(*images):
490
- return [gr.update() for _ in images]
491
-
492
- accordion.expand(
493
- fn=on_accordion_expand,
494
- inputs=cn_images,
495
- outputs=cn_images,
496
- show_progress=False
497
- )
498
-
499
-
500
- def create_flux1_ipadapter_event_handlers(prefix, ui_components):
501
- fipa_rows = ui_components.get(f'flux1_ipadapter_rows_{prefix}')
502
- if not fipa_rows: return
503
- count_state = ui_components[f'flux1_ipadapter_count_state_{prefix}']
504
- add_button = ui_components[f'add_flux1_ipadapter_button_{prefix}']
505
- del_button = ui_components[f'delete_flux1_ipadapter_button_{prefix}']
506
-
507
- def add_fipa_row(c):
508
- c += 1
509
- return {
510
- count_state: c,
511
- fipa_rows[c - 1]: gr.update(visible=True),
512
- add_button: gr.update(visible=c < MAX_IPADAPTERS),
513
- del_button: gr.update(visible=True),
514
- }
515
-
516
- def del_fipa_row(c):
517
- c -= 1
518
- return {
519
- count_state: c,
520
- fipa_rows[c]: gr.update(visible=False),
521
- add_button: gr.update(visible=True),
522
- del_button: gr.update(visible=c > 0),
523
- }
524
-
525
- add_outputs = [count_state, add_button, del_button] + fipa_rows
526
- del_outputs = [count_state, add_button, del_button] + fipa_rows
527
- add_button.click(fn=add_fipa_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
528
- del_button.click(fn=del_fipa_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
529
-
530
-
531
- def create_sd3_ipadapter_event_handlers(prefix, ui_components):
532
- ipa_rows = ui_components.get(f'sd3_ipadapter_rows_{prefix}')
533
- if not ipa_rows: return
534
- count_state = ui_components[f'sd3_ipadapter_count_state_{prefix}']
535
- add_button = ui_components[f'add_sd3_ipadapter_button_{prefix}']
536
- del_button = ui_components[f'delete_sd3_ipadapter_button_{prefix}']
537
- images = ui_components[f'sd3_ipadapter_images_{prefix}']
538
- weights = ui_components[f'sd3_ipadapter_weights_{prefix}']
539
- start_percents = ui_components[f'sd3_ipadapter_start_percents_{prefix}']
540
- end_percents = ui_components[f'sd3_ipadapter_end_percents_{prefix}']
541
-
542
- def add_ipa_row(c):
543
- c += 1
544
- return {
545
- count_state: c,
546
- ipa_rows[c - 1]: gr.update(visible=True),
547
- add_button: gr.update(visible=c < MAX_IPADAPTERS),
548
- del_button: gr.update(visible=True),
549
- }
550
-
551
- def del_ipa_row(c):
552
- c -= 1
553
- return {
554
- count_state: c,
555
- ipa_rows[c]: gr.update(visible=False),
556
- images[c]: None,
557
- weights[c]: 0.5,
558
- start_percents[c]: 0.0,
559
- end_percents[c]: 1.0,
560
- add_button: gr.update(visible=True),
561
- del_button: gr.update(visible=c > 0),
562
- }
563
-
564
- add_outputs = [count_state, add_button, del_button] + ipa_rows
565
- del_outputs = [count_state, add_button, del_button] + ipa_rows + images + weights + start_percents + end_percents
566
- add_button.click(fn=add_ipa_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
567
- del_button.click(fn=del_ipa_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
568
-
569
-
570
- def create_style_event_handlers(prefix, ui_components):
571
- style_rows = ui_components.get(f'style_rows_{prefix}')
572
- if not style_rows: return
573
- count_state = ui_components[f'style_count_state_{prefix}']
574
- add_button = ui_components[f'add_style_button_{prefix}']
575
- del_button = ui_components[f'delete_style_button_{prefix}']
576
-
577
- def add_style_row(c):
578
- c += 1
579
- return {
580
- count_state: c,
581
- style_rows[c - 1]: gr.update(visible=True),
582
- add_button: gr.update(visible=c < 5),
583
- del_button: gr.update(visible=True),
584
- }
585
-
586
- def del_style_row(c):
587
- c -= 1
588
- return {
589
- count_state: c,
590
- style_rows[c]: gr.update(visible=False),
591
- add_button: gr.update(visible=True),
592
- del_button: gr.update(visible=c > 0),
593
- }
594
-
595
- add_outputs = [count_state, add_button, del_button] + style_rows
596
- del_outputs = [count_state, add_button, del_button] + style_rows
597
- add_button.click(fn=add_style_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
598
- del_button.click(fn=del_style_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
599
-
600
-
601
- def create_ipadapter_event_handlers(prefix, ui_components):
602
- ipa_rows = ui_components.get(f'ipadapter_rows_{prefix}')
603
- if not ipa_rows: return
604
- ipa_lora_strengths = ui_components[f'ipadapter_lora_strengths_{prefix}']
605
- ipa_final_preset = ui_components[f'ipadapter_final_preset_{prefix}']
606
- ipa_final_lora_strength = ui_components[f'ipadapter_final_lora_strength_{prefix}']
607
- count_state = ui_components[f'ipadapter_count_state_{prefix}']
608
- add_button = ui_components[f'add_ipadapter_button_{prefix}']
609
- del_button = ui_components[f'delete_ipadapter_button_{prefix}']
610
- accordion = ui_components[f'ipadapter_accordion_{prefix}']
611
-
612
- def add_ipa_row(c):
613
- c += 1
614
- return {
615
- count_state: c,
616
- ipa_rows[c - 1]: gr.update(visible=True),
617
- add_button: gr.update(visible=c < MAX_IPADAPTERS),
618
- del_button: gr.update(visible=True),
619
- }
620
-
621
- def del_ipa_row(c):
622
- c -= 1
623
- return {
624
- count_state: c,
625
- ipa_rows[c]: gr.update(visible=False),
626
- add_button: gr.update(visible=True),
627
- del_button: gr.update(visible=c > 0),
628
- }
629
-
630
- add_outputs = [count_state, add_button, del_button] + ipa_rows
631
- del_outputs = [count_state, add_button, del_button] + ipa_rows
632
- add_button.click(fn=add_ipa_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
633
- del_button.click(fn=del_ipa_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
634
-
635
- def on_preset_change(preset_value):
636
- config = load_ipadapter_config()
637
- faceid_presets = []
638
- if config:
639
- faceid_presets.extend(config.get("IPAdapter_FaceID_presets", {}).get("SDXL", []))
640
- faceid_presets.extend(config.get("IPAdapter_FaceID_presets", {}).get("SD1.5", []))
641
-
642
- is_visible = preset_value in faceid_presets
643
- updates = [gr.update(visible=is_visible)] * (MAX_IPADAPTERS + 1)
644
- return updates
645
-
646
- all_lora_strength_sliders = [ipa_final_lora_strength] + ipa_lora_strengths
647
- ipa_final_preset.change(fn=on_preset_change, inputs=[ipa_final_preset], outputs=all_lora_strength_sliders, show_progress=False)
648
-
649
- accordion.expand(fn=lambda *imgs: [gr.update() for _ in imgs], inputs=ui_components[f'ipadapter_images_{prefix}'], outputs=ui_components[f'ipadapter_images_{prefix}'], show_progress=False)
650
-
651
-
652
- def create_reference_latent_event_handlers(prefix, ui_components):
653
- ref_rows = ui_components.get(f'reference_latent_rows_{prefix}')
654
- if not ref_rows: return
655
- count_state = ui_components[f'reference_latent_count_state_{prefix}']
656
- add_button = ui_components[f'add_reference_latent_button_{prefix}']
657
- del_button = ui_components[f'delete_reference_latent_button_{prefix}']
658
- images = ui_components[f'reference_latent_images_{prefix}']
659
-
660
- def add_ref_row(c):
661
- c += 1
662
- return {
663
- count_state: c,
664
- ref_rows[c - 1]: gr.update(visible=True),
665
- add_button: gr.update(visible=c < 10),
666
- del_button: gr.update(visible=True),
667
- }
668
-
669
- def del_ref_row(c):
670
- c -= 1
671
- return {
672
- count_state: c,
673
- ref_rows[c]: gr.update(visible=False),
674
- images[c]: None,
675
- add_button: gr.update(visible=True),
676
- del_button: gr.update(visible=c > 0),
677
- }
678
-
679
- add_outputs = [count_state, add_button, del_button] + ref_rows
680
- del_outputs = [count_state, add_button, del_button] + ref_rows + images
681
- add_button.click(fn=add_ref_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
682
- del_button.click(fn=del_ref_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
683
-
684
-
685
- def create_hidream_o1_reference_event_handlers(prefix, ui_components):
686
- ref_rows = ui_components.get(f'hidream_o1_reference_rows_{prefix}')
687
- if not ref_rows: return
688
- count_state = ui_components[f'hidream_o1_reference_count_state_{prefix}']
689
- add_button = ui_components[f'add_hidream_o1_reference_button_{prefix}']
690
- del_button = ui_components[f'delete_hidream_o1_reference_button_{prefix}']
691
- images = ui_components[f'hidream_o1_reference_images_{prefix}']
692
-
693
- def add_ref_row(c):
694
- c += 1
695
- return {
696
- count_state: c,
697
- ref_rows[c - 1]: gr.update(visible=True),
698
- add_button: gr.update(visible=c < 10),
699
- del_button: gr.update(visible=True),
700
- }
701
-
702
- def del_ref_row(c):
703
- c -= 1
704
- return {
705
- count_state: c,
706
- ref_rows[c]: gr.update(visible=False),
707
- images[c]: None,
708
- add_button: gr.update(visible=True),
709
- del_button: gr.update(visible=c > 0),
710
- }
711
-
712
- add_outputs = [count_state, add_button, del_button] + ref_rows
713
- del_outputs = [count_state, add_button, del_button] + ref_rows + images
714
- add_button.click(fn=add_ref_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
715
- del_button.click(fn=del_ref_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
716
-
717
-
718
- def create_joyai_reference_event_handlers(prefix, ui_components):
719
- ref_rows = ui_components.get(f'joyai_reference_rows_{prefix}')
720
- if not ref_rows: return
721
- count_state = ui_components[f'joyai_reference_count_state_{prefix}']
722
- add_button = ui_components[f'add_joyai_reference_button_{prefix}']
723
- del_button = ui_components[f'delete_joyai_reference_button_{prefix}']
724
- images = ui_components[f'joyai_reference_images_{prefix}']
725
-
726
- def add_ref_row(c):
727
- c += 1
728
- return {
729
- count_state: c,
730
- ref_rows[c - 1]: gr.update(visible=True),
731
- add_button: gr.update(visible=c < 2),
732
- del_button: gr.update(visible=True),
733
- }
734
-
735
- def del_ref_row(c):
736
- c -= 1
737
- return {
738
- count_state: c,
739
- ref_rows[c]: gr.update(visible=False),
740
- images[c]: None,
741
- add_button: gr.update(visible=True),
742
- del_button: gr.update(visible=c > 0),
743
- }
744
-
745
- add_outputs = [count_state, add_button, del_button] + ref_rows
746
- del_outputs = [count_state, add_button, del_button] + ref_rows + images
747
- add_button.click(fn=add_ref_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
748
- del_button.click(fn=del_ref_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
749
-
750
-
751
- def create_reference_image_event_handlers(prefix, ui_components):
752
- ref_rows = ui_components.get(f'reference_image_rows_{prefix}')
753
- if not ref_rows: return
754
- count_state = ui_components[f'reference_image_count_state_{prefix}']
755
- add_button = ui_components[f'add_reference_image_button_{prefix}']
756
- del_button = ui_components[f'delete_reference_image_button_{prefix}']
757
- images = ui_components[f'reference_image_images_{prefix}']
758
-
759
- def add_ref_row(c):
760
- c += 1
761
- return {
762
- count_state: c,
763
- ref_rows[c - 1]: gr.update(visible=True),
764
- add_button: gr.update(visible=c < 10),
765
- del_button: gr.update(visible=True),
766
- }
767
-
768
- def del_ref_row(c):
769
- c -= 1
770
- return {
771
- count_state: c,
772
- ref_rows[c]: gr.update(visible=False),
773
- images[c]: None,
774
- add_button: gr.update(visible=True),
775
- del_button: gr.update(visible=c > 0),
776
- }
777
-
778
- add_outputs = [count_state, add_button, del_button] + ref_rows
779
- del_outputs = [count_state, add_button, del_button] + ref_rows + images
780
- add_button.click(fn=add_ref_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
781
- del_button.click(fn=del_ref_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
782
-
783
-
784
- def create_embedding_event_handlers(prefix, ui_components):
785
- rows = ui_components.get(f'embedding_rows_{prefix}')
786
- if not rows: return
787
- ids = ui_components[f'embeddings_ids_{prefix}']
788
- files = ui_components[f'embeddings_files_{prefix}']
789
- sources = ui_components[f'embeddings_sources_{prefix}']
790
- upload_buttons = ui_components[f'embeddings_uploads_{prefix}']
791
- count_state = ui_components[f'embedding_count_state_{prefix}']
792
- add_button = ui_components[f'add_embedding_button_{prefix}']
793
- del_button = ui_components[f'delete_embedding_button_{prefix}']
794
-
795
- for i in range(MAX_EMBEDDINGS):
796
- upload_buttons[i].upload(
797
- fn=on_embedding_upload,
798
- inputs=[upload_buttons[i]],
799
- outputs=[ids[i], sources[i], files[i]],
800
- show_progress=True
801
- )
802
-
803
- def add_row(c):
804
- c += 1
805
- return {
806
- count_state: c,
807
- rows[c - 1]: gr.update(visible=True),
808
- add_button: gr.update(visible=c < MAX_EMBEDDINGS),
809
- del_button: gr.update(visible=True)
810
- }
811
-
812
- def del_row(c):
813
- c -= 1
814
- return {
815
- count_state: c,
816
- rows[c]: gr.update(visible=False),
817
- ids[c]: "",
818
- files[c]: None,
819
- add_button: gr.update(visible=True),
820
- del_button: gr.update(visible=c > 0)
821
- }
822
-
823
- add_outputs = [count_state, add_button, del_button] + rows
824
- del_outputs = [count_state, add_button, del_button] + rows + ids + files
825
- add_button.click(fn=add_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
826
- del_button.click(fn=del_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
827
-
828
-
829
- def create_conditioning_event_handlers(prefix, ui_components):
830
- rows = ui_components.get(f'conditioning_rows_{prefix}')
831
- if not rows: return
832
- prompts = ui_components[f'conditioning_prompts_{prefix}']
833
- count_state = ui_components[f'conditioning_count_state_{prefix}']
834
- add_button = ui_components[f'add_conditioning_button_{prefix}']
835
- del_button = ui_components[f'delete_conditioning_button_{prefix}']
836
-
837
- def add_row(c):
838
- c += 1
839
- return {
840
- count_state: c,
841
- rows[c - 1]: gr.update(visible=True),
842
- add_button: gr.update(visible=c < MAX_CONDITIONINGS),
843
- del_button: gr.update(visible=True),
844
- }
845
-
846
- def del_row(c):
847
- c -= 1
848
- return {
849
- count_state: c,
850
- rows[c]: gr.update(visible=False),
851
- prompts[c]: "",
852
- add_button: gr.update(visible=True),
853
- del_button: gr.update(visible=c > 0),
854
- }
855
-
856
- add_outputs = [count_state, add_button, del_button] + rows
857
- del_outputs = [count_state, add_button, del_button] + rows + prompts
858
- add_button.click(fn=add_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
859
- del_button.click(fn=del_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
860
-
861
-
862
- def create_krea2_identity_edit_event_handlers(prefix, ui_components):
863
- ref_rows = ui_components.get(f'krea2_identity_edit_rows_{prefix}')
864
- if not ref_rows: return
865
- count_state = ui_components[f'krea2_identity_edit_count_state_{prefix}']
866
- add_button = ui_components[f'add_krea2_identity_edit_button_{prefix}']
867
- del_button = ui_components[f'delete_krea2_identity_edit_button_{prefix}']
868
- images = ui_components[f'krea2_identity_edit_images_{prefix}']
869
-
870
- def add_ref_row(c):
871
- c += 1
872
- return {
873
- count_state: c,
874
- ref_rows[c - 1]: gr.update(visible=True),
875
- add_button: gr.update(visible=c < 2),
876
- del_button: gr.update(visible=True),
877
- }
878
-
879
- def del_ref_row(c):
880
- c -= 1
881
- return {
882
- count_state: c,
883
- ref_rows[c]: gr.update(visible=False),
884
- images[c]: None,
885
- add_button: gr.update(visible=True),
886
- del_button: gr.update(visible=c > 0),
887
- }
888
-
889
- add_outputs = [count_state, add_button, del_button] + ref_rows
890
- del_outputs = [count_state, add_button, del_button] + ref_rows + images
891
- add_button.click(fn=add_ref_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
892
  del_button.click(fn=del_ref_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
 
1
+ import gradio as gr
2
+ from core.settings import VAE_DIR, LORA_DIR, EMBEDDING_DIR, ARCHITECTURES_CONFIG
3
+ from utils.app_utils import save_uploaded_file_with_hash
4
+ from ui.shared.ui_components import (
5
+ MAX_CONTROLNETS,
6
+ MAX_IPADAPTERS,
7
+ MAX_EMBEDDINGS,
8
+ MAX_CONDITIONINGS,
9
+ MAX_LORAS
10
+ )
11
+ from .config_loaders import (
12
+ load_controlnet_config,
13
+ load_anima_controlnet_lllite_config,
14
+ load_diffsynth_controlnet_config,
15
+ load_krea2_controlnet_config,
16
+ load_ipadapter_config
17
+ )
18
+
19
+ def on_vae_upload(file_obj):
20
+ if not file_obj:
21
+ return gr.update(), gr.update(), None
22
+
23
+ hashed_filename = save_uploaded_file_with_hash(file_obj, VAE_DIR)
24
+ return hashed_filename, "File", file_obj
25
+
26
+
27
+ def on_lora_upload(file_obj):
28
+ if not file_obj:
29
+ return gr.update(), gr.update()
30
+
31
+ hashed_filename = save_uploaded_file_with_hash(file_obj, LORA_DIR)
32
+ return hashed_filename, "File"
33
+
34
+
35
+ def on_embedding_upload(file_obj):
36
+ if not file_obj:
37
+ return gr.update(), gr.update(), None
38
+
39
+ hashed_filename = save_uploaded_file_with_hash(file_obj, EMBEDDING_DIR)
40
+ return hashed_filename, "File", file_obj
41
+
42
+
43
+ def create_lora_event_handlers(prefix, ui_components):
44
+ lora_rows = ui_components.get(f'lora_rows_{prefix}')
45
+ if not lora_rows: return
46
+ lora_ids = ui_components[f'lora_ids_{prefix}']
47
+ lora_scales = ui_components[f'lora_scales_{prefix}']
48
+ lora_uploads = ui_components[f'lora_uploads_{prefix}']
49
+ lora_sources = ui_components[f'lora_sources_{prefix}']
50
+ count_state = ui_components[f'lora_count_state_{prefix}']
51
+ add_button = ui_components[f'add_lora_button_{prefix}']
52
+ del_button = ui_components[f'delete_lora_button_{prefix}']
53
+
54
+ for i in range(MAX_LORAS):
55
+ lora_uploads[i].upload(
56
+ fn=on_lora_upload,
57
+ inputs=[lora_uploads[i]],
58
+ outputs=[lora_ids[i], lora_sources[i]],
59
+ show_progress=True
60
+ )
61
+
62
+ def add_lora_row(c):
63
+ updates = {}
64
+ if c < MAX_LORAS:
65
+ c += 1
66
+ updates[lora_rows[c - 1]] = gr.update(visible=True)
67
+
68
+ updates[count_state] = c
69
+ updates[add_button] = gr.update(visible=c < MAX_LORAS)
70
+ updates[del_button] = gr.update(visible=c > 1)
71
+ return updates
72
+
73
+ def del_lora_row(c):
74
+ updates = {}
75
+ if c > 1:
76
+ updates[lora_rows[c - 1]] = gr.update(visible=False)
77
+ updates[lora_ids[c - 1]] = ""
78
+ updates[lora_scales[c - 1]] = 0.0
79
+ updates[lora_uploads[c - 1]] = None
80
+ c -= 1
81
+
82
+ updates[count_state] = c
83
+ updates[add_button] = gr.update(visible=True)
84
+ updates[del_button] = gr.update(visible=c > 1)
85
+ return updates
86
+
87
+ add_outputs = [count_state, add_button, del_button] + lora_rows
88
+ del_outputs = [count_state, add_button, del_button] + lora_rows + lora_ids + lora_scales + lora_uploads
89
+
90
+ add_button.click(add_lora_row, [count_state], add_outputs, show_progress=False)
91
+ del_button.click(del_lora_row, [count_state], del_outputs, show_progress=False)
92
+
93
+
94
+ def create_controlnet_event_handlers(prefix, ui_components):
95
+ cn_rows = ui_components.get(f'controlnet_rows_{prefix}')
96
+ if not cn_rows: return
97
+ cn_types = ui_components[f'controlnet_types_{prefix}']
98
+ cn_series = ui_components[f'controlnet_series_{prefix}']
99
+ cn_filepaths = ui_components[f'controlnet_filepaths_{prefix}']
100
+ cn_images = ui_components[f'controlnet_images_{prefix}']
101
+ cn_strengths = ui_components[f'controlnet_strengths_{prefix}']
102
+
103
+ count_state = ui_components[f'controlnet_count_state_{prefix}']
104
+ add_button = ui_components[f'add_controlnet_button_{prefix}']
105
+ del_button = ui_components[f'delete_controlnet_button_{prefix}']
106
+ accordion = ui_components[f'controlnet_accordion_{prefix}']
107
+
108
+ base_model_comp = ui_components.get(f'base_model_{prefix}')
109
+ actual_arch_comp = base_model_comp if base_model_comp else gr.State("SDXL")
110
+
111
+ def add_cn_row(c):
112
+ c += 1
113
+ updates = {
114
+ count_state: c,
115
+ cn_rows[c-1]: gr.update(visible=True),
116
+ add_button: gr.update(visible=c < MAX_CONTROLNETS),
117
+ del_button: gr.update(visible=True)
118
+ }
119
+ return updates
120
+
121
+ def del_cn_row(c):
122
+ c -= 1
123
+ updates = {
124
+ count_state: c,
125
+ cn_rows[c]: gr.update(visible=False),
126
+ cn_images[c]: None,
127
+ cn_strengths[c]: 1.0,
128
+ add_button: gr.update(visible=True),
129
+ del_button: gr.update(visible=c > 0)
130
+ }
131
+ return updates
132
+
133
+ add_outputs = [count_state, add_button, del_button] + cn_rows
134
+ del_outputs = [count_state, add_button, del_button] + cn_rows + cn_images + cn_strengths
135
+ add_button.click(fn=add_cn_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
136
+ del_button.click(fn=del_cn_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
137
+
138
+ def on_cn_type_change(selected_type, model_name):
139
+ from core.settings import MODEL_TYPE_MAP
140
+ m_type = MODEL_TYPE_MAP.get(model_name, "SDXL") if model_name else "SDXL"
141
+ cn_full_config = load_controlnet_config()
142
+
143
+ architectures_dict = ARCHITECTURES_CONFIG.get('architectures', {})
144
+ controlnet_key = architectures_dict.get(m_type, {}).get("controlnet_key", m_type)
145
+
146
+ cn_config = cn_full_config.get(controlnet_key, [])
147
+ series_choices = []
148
+ if selected_type:
149
+ series_choices = sorted(list(set(
150
+ model.get("Series", "Default") for model in cn_config
151
+ if selected_type in model.get("Type", [])
152
+ )))
153
+ default_series = series_choices[0] if series_choices else None
154
+ filepath = "None"
155
+ if default_series:
156
+ for model in cn_config:
157
+ if model.get("Series") == default_series and selected_type in model.get("Type", []):
158
+ filepath = model.get("Filepath")
159
+ break
160
+ return gr.update(choices=series_choices, value=default_series), filepath
161
+
162
+ def on_cn_series_change(selected_series, selected_type, model_name):
163
+ from core.settings import MODEL_TYPE_MAP
164
+ m_type = MODEL_TYPE_MAP.get(model_name, "SDXL") if model_name else "SDXL"
165
+ cn_full_config = load_controlnet_config()
166
+
167
+ architectures_dict = ARCHITECTURES_CONFIG.get('architectures', {})
168
+ controlnet_key = architectures_dict.get(m_type, {}).get("controlnet_key", m_type)
169
+
170
+ cn_config = cn_full_config.get(controlnet_key, [])
171
+ filepath = "None"
172
+ if selected_series and selected_type:
173
+ for model in cn_config:
174
+ if model.get("Series") == selected_series and selected_type in model.get("Type", []):
175
+ filepath = model.get("Filepath")
176
+ break
177
+ return filepath
178
+
179
+ for i in range(MAX_CONTROLNETS):
180
+ cn_types[i].change(
181
+ fn=on_cn_type_change,
182
+ inputs=[cn_types[i], actual_arch_comp],
183
+ outputs=[cn_series[i], cn_filepaths[i]],
184
+ show_progress=False
185
+ )
186
+ cn_series[i].change(
187
+ fn=on_cn_series_change,
188
+ inputs=[cn_series[i], cn_types[i], actual_arch_comp],
189
+ outputs=[cn_filepaths[i]],
190
+ show_progress=False
191
+ )
192
+
193
+ def on_accordion_expand(*images):
194
+ return [gr.update() for _ in images]
195
+
196
+ accordion.expand(
197
+ fn=on_accordion_expand,
198
+ inputs=cn_images,
199
+ outputs=cn_images,
200
+ show_progress=False
201
+ )
202
+
203
+
204
+ def create_krea2_controlnet_event_handlers(prefix, ui_components):
205
+ cn_rows = ui_components.get(f'krea2_controlnet_rows_{prefix}')
206
+ if not cn_rows: return
207
+ cn_types = ui_components[f'krea2_controlnet_types_{prefix}']
208
+ cn_series = ui_components[f'krea2_controlnet_series_{prefix}']
209
+ cn_filepaths = ui_components[f'krea2_controlnet_filepaths_{prefix}']
210
+ cn_images = ui_components[f'krea2_controlnet_images_{prefix}']
211
+ cn_strengths = ui_components[f'krea2_controlnet_strengths_{prefix}']
212
+
213
+ count_state = ui_components[f'krea2_controlnet_count_state_{prefix}']
214
+ add_button = ui_components[f'add_krea2_controlnet_button_{prefix}']
215
+ del_button = ui_components[f'delete_krea2_controlnet_button_{prefix}']
216
+ accordion = ui_components[f'krea2_controlnet_accordion_{prefix}']
217
+
218
+ def add_cn_row(c):
219
+ c += 1
220
+ updates = {
221
+ count_state: c,
222
+ cn_rows[c-1]: gr.update(visible=True),
223
+ add_button: gr.update(visible=c < MAX_CONTROLNETS),
224
+ del_button: gr.update(visible=True)
225
+ }
226
+ return updates
227
+
228
+ def del_cn_row(c):
229
+ c -= 1
230
+ updates = {
231
+ count_state: c,
232
+ cn_rows[c]: gr.update(visible=False),
233
+ cn_images[c]: None,
234
+ cn_strengths[c]: 1.0,
235
+ add_button: gr.update(visible=True),
236
+ del_button: gr.update(visible=c > 0)
237
+ }
238
+ return updates
239
+
240
+ add_outputs = [count_state, add_button, del_button] + cn_rows
241
+ del_outputs = [count_state, add_button, del_button] + cn_rows + cn_images + cn_strengths
242
+ add_button.click(fn=add_cn_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
243
+ del_button.click(fn=del_cn_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
244
+
245
+ def on_cn_type_change(selected_type):
246
+ cn_config = load_krea2_controlnet_config()
247
+ series_choices = []
248
+ if selected_type:
249
+ series_choices = sorted(list(set(
250
+ model.get("Series", "Default") for model in cn_config
251
+ if selected_type in model.get("Type", [])
252
+ )))
253
+ default_series = series_choices[0] if series_choices else None
254
+ filepath = "None"
255
+ if default_series:
256
+ for model in cn_config:
257
+ if model.get("Series") == default_series and selected_type in model.get("Type", []):
258
+ filepath = model.get("Filepath")
259
+ break
260
+ return gr.update(choices=series_choices, value=default_series), filepath
261
+
262
+ def on_cn_series_change(selected_series, selected_type):
263
+ cn_config = load_krea2_controlnet_config()
264
+ filepath = "None"
265
+ if selected_series and selected_type:
266
+ for model in cn_config:
267
+ if model.get("Series") == selected_series and selected_type in model.get("Type", []):
268
+ filepath = model.get("Filepath")
269
+ break
270
+ return filepath
271
+
272
+ for i in range(MAX_CONTROLNETS):
273
+ cn_types[i].change(
274
+ fn=on_cn_type_change,
275
+ inputs=[cn_types[i]],
276
+ outputs=[cn_series[i], cn_filepaths[i]],
277
+ show_progress=False
278
+ )
279
+ cn_series[i].change(
280
+ fn=on_cn_series_change,
281
+ inputs=[cn_series[i], cn_types[i]],
282
+ outputs=[cn_filepaths[i]],
283
+ show_progress=False
284
+ )
285
+
286
+ def on_accordion_expand(*images):
287
+ return [gr.update() for _ in images]
288
+
289
+ accordion.expand(
290
+ fn=on_accordion_expand,
291
+ inputs=cn_images,
292
+ outputs=cn_images,
293
+ show_progress=False
294
+ )
295
+
296
+
297
+ def create_anima_controlnet_lllite_event_handlers(prefix, ui_components):
298
+ cn_rows = ui_components.get(f'anima_controlnet_lllite_rows_{prefix}')
299
+ if not cn_rows: return
300
+ cn_types = ui_components[f'anima_controlnet_lllite_types_{prefix}']
301
+ cn_series = ui_components[f'anima_controlnet_lllite_series_{prefix}']
302
+ cn_filepaths = ui_components[f'anima_controlnet_lllite_filepaths_{prefix}']
303
+ cn_images = ui_components[f'anima_controlnet_lllite_images_{prefix}']
304
+ cn_strengths = ui_components[f'anima_controlnet_lllite_strengths_{prefix}']
305
+
306
+ count_state = ui_components[f'anima_controlnet_lllite_count_state_{prefix}']
307
+ add_button = ui_components[f'add_anima_controlnet_lllite_button_{prefix}']
308
+ del_button = ui_components[f'delete_anima_controlnet_lllite_button_{prefix}']
309
+ accordion = ui_components[f'anima_controlnet_lllite_accordion_{prefix}']
310
+
311
+ def add_cn_row(c):
312
+ c += 1
313
+ updates = {
314
+ count_state: c,
315
+ cn_rows[c-1]: gr.update(visible=True),
316
+ add_button: gr.update(visible=c < MAX_CONTROLNETS),
317
+ del_button: gr.update(visible=True)
318
+ }
319
+ return updates
320
+
321
+ def del_cn_row(c):
322
+ c -= 1
323
+ updates = {
324
+ count_state: c,
325
+ cn_rows[c]: gr.update(visible=False),
326
+ cn_images[c]: None,
327
+ cn_strengths[c]: 1.0,
328
+ add_button: gr.update(visible=True),
329
+ del_button: gr.update(visible=c > 0)
330
+ }
331
+ return updates
332
+
333
+ add_outputs = [count_state, add_button, del_button] + cn_rows
334
+ del_outputs = [count_state, add_button, del_button] + cn_rows + cn_images + cn_strengths
335
+ add_button.click(fn=add_cn_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
336
+ del_button.click(fn=del_cn_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
337
+
338
+ def on_cn_type_change(selected_type):
339
+ cn_config = load_anima_controlnet_lllite_config()
340
+ series_choices = []
341
+ if selected_type:
342
+ series_choices = sorted(list(set(
343
+ model.get("Series", "Default") for model in cn_config
344
+ if selected_type in model.get("Type", [])
345
+ )))
346
+ default_series = series_choices[0] if series_choices else None
347
+ filepath = "None"
348
+ if default_series:
349
+ for model in cn_config:
350
+ if model.get("Series") == default_series and selected_type in model.get("Type", []):
351
+ filepath = model.get("Filepath")
352
+ break
353
+ return gr.update(choices=series_choices, value=default_series), filepath
354
+
355
+ def on_cn_series_change(selected_series, selected_type):
356
+ cn_config = load_anima_controlnet_lllite_config()
357
+ filepath = "None"
358
+ if selected_series and selected_type:
359
+ for model in cn_config:
360
+ if model.get("Series") == selected_series and selected_type in model.get("Type", []):
361
+ filepath = model.get("Filepath")
362
+ break
363
+ return filepath
364
+
365
+ for i in range(MAX_CONTROLNETS):
366
+ cn_types[i].change(
367
+ fn=on_cn_type_change,
368
+ inputs=[cn_types[i]],
369
+ outputs=[cn_series[i], cn_filepaths[i]],
370
+ show_progress=False
371
+ )
372
+ cn_series[i].change(
373
+ fn=on_cn_series_change,
374
+ inputs=[cn_series[i], cn_types[i]],
375
+ outputs=[cn_filepaths[i]],
376
+ show_progress=False
377
+ )
378
+
379
+ def on_accordion_expand(*images):
380
+ return [gr.update() for _ in images]
381
+
382
+ accordion.expand(
383
+ fn=on_accordion_expand,
384
+ inputs=cn_images,
385
+ outputs=cn_images,
386
+ show_progress=False
387
+ )
388
+
389
+
390
+ def create_diffsynth_controlnet_event_handlers(prefix, ui_components):
391
+ cn_rows = ui_components.get(f'diffsynth_controlnet_rows_{prefix}')
392
+ if not cn_rows: return
393
+ cn_types = ui_components[f'diffsynth_controlnet_types_{prefix}']
394
+ cn_series = ui_components[f'diffsynth_controlnet_series_{prefix}']
395
+ cn_filepaths = ui_components[f'diffsynth_controlnet_filepaths_{prefix}']
396
+ cn_images = ui_components[f'diffsynth_controlnet_images_{prefix}']
397
+ cn_strengths = ui_components[f'diffsynth_controlnet_strengths_{prefix}']
398
+
399
+ count_state = ui_components[f'diffsynth_controlnet_count_state_{prefix}']
400
+ add_button = ui_components[f'add_diffsynth_controlnet_button_{prefix}']
401
+ del_button = ui_components[f'delete_diffsynth_controlnet_button_{prefix}']
402
+ accordion = ui_components[f'diffsynth_controlnet_accordion_{prefix}']
403
+
404
+ base_model_comp = ui_components.get(f'base_model_{prefix}')
405
+ actual_arch_comp = base_model_comp if base_model_comp else gr.State("SDXL")
406
+
407
+ def add_cn_row(c):
408
+ c += 1
409
+ updates = {
410
+ count_state: c,
411
+ cn_rows[c-1]: gr.update(visible=True),
412
+ add_button: gr.update(visible=c < MAX_CONTROLNETS),
413
+ del_button: gr.update(visible=True)
414
+ }
415
+ return updates
416
+
417
+ def del_cn_row(c):
418
+ c -= 1
419
+ updates = {
420
+ count_state: c,
421
+ cn_rows[c]: gr.update(visible=False),
422
+ cn_images[c]: None,
423
+ cn_strengths[c]: 1.0,
424
+ add_button: gr.update(visible=True),
425
+ del_button: gr.update(visible=c > 0)
426
+ }
427
+ return updates
428
+
429
+ add_outputs = [count_state, add_button, del_button] + cn_rows
430
+ del_outputs = [count_state, add_button, del_button] + cn_rows + cn_images + cn_strengths
431
+ add_button.click(fn=add_cn_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
432
+ del_button.click(fn=del_cn_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
433
+
434
+ def on_cn_type_change(selected_type, model_name):
435
+ from core.settings import MODEL_TYPE_MAP
436
+ m_type = MODEL_TYPE_MAP.get(model_name, "SDXL") if model_name else "SDXL"
437
+ cn_full_config = load_diffsynth_controlnet_config()
438
+
439
+ architectures_dict = ARCHITECTURES_CONFIG.get('architectures', {})
440
+ controlnet_key = architectures_dict.get(m_type, {}).get("controlnet_key", m_type)
441
+
442
+ cn_config = cn_full_config.get(controlnet_key, [])
443
+ series_choices = []
444
+ if selected_type:
445
+ series_choices = sorted(list(set(
446
+ model.get("Series", "Default") for model in cn_config
447
+ if selected_type in model.get("Type", [])
448
+ )))
449
+ default_series = series_choices[0] if series_choices else None
450
+ filepath = "None"
451
+ if default_series:
452
+ for model in cn_config:
453
+ if model.get("Series") == default_series and selected_type in model.get("Type", []):
454
+ filepath = model.get("Filepath")
455
+ break
456
+ return gr.update(choices=series_choices, value=default_series), filepath
457
+
458
+ def on_cn_series_change(selected_series, selected_type, model_name):
459
+ from core.settings import MODEL_TYPE_MAP
460
+ m_type = MODEL_TYPE_MAP.get(model_name, "SDXL") if model_name else "SDXL"
461
+ cn_full_config = load_diffsynth_controlnet_config()
462
+
463
+ architectures_dict = ARCHITECTURES_CONFIG.get('architectures', {})
464
+ controlnet_key = architectures_dict.get(m_type, {}).get("controlnet_key", m_type)
465
+
466
+ cn_config = cn_full_config.get(controlnet_key, [])
467
+ filepath = "None"
468
+ if selected_series and selected_type:
469
+ for model in cn_config:
470
+ if model.get("Series") == selected_series and selected_type in model.get("Type", []):
471
+ filepath = model.get("Filepath")
472
+ break
473
+ return filepath
474
+
475
+ for i in range(MAX_CONTROLNETS):
476
+ cn_types[i].change(
477
+ fn=on_cn_type_change,
478
+ inputs=[cn_types[i], actual_arch_comp],
479
+ outputs=[cn_series[i], cn_filepaths[i]],
480
+ show_progress=False
481
+ )
482
+ cn_series[i].change(
483
+ fn=on_cn_series_change,
484
+ inputs=[cn_series[i], cn_types[i], actual_arch_comp],
485
+ outputs=[cn_filepaths[i]],
486
+ show_progress=False
487
+ )
488
+
489
+ def on_accordion_expand(*images):
490
+ return [gr.update() for _ in images]
491
+
492
+ accordion.expand(
493
+ fn=on_accordion_expand,
494
+ inputs=cn_images,
495
+ outputs=cn_images,
496
+ show_progress=False
497
+ )
498
+
499
+
500
+ def create_flux1_ipadapter_event_handlers(prefix, ui_components):
501
+ fipa_rows = ui_components.get(f'flux1_ipadapter_rows_{prefix}')
502
+ if not fipa_rows: return
503
+ count_state = ui_components[f'flux1_ipadapter_count_state_{prefix}']
504
+ add_button = ui_components[f'add_flux1_ipadapter_button_{prefix}']
505
+ del_button = ui_components[f'delete_flux1_ipadapter_button_{prefix}']
506
+
507
+ def add_fipa_row(c):
508
+ c += 1
509
+ return {
510
+ count_state: c,
511
+ fipa_rows[c - 1]: gr.update(visible=True),
512
+ add_button: gr.update(visible=c < MAX_IPADAPTERS),
513
+ del_button: gr.update(visible=True),
514
+ }
515
+
516
+ def del_fipa_row(c):
517
+ c -= 1
518
+ return {
519
+ count_state: c,
520
+ fipa_rows[c]: gr.update(visible=False),
521
+ add_button: gr.update(visible=True),
522
+ del_button: gr.update(visible=c > 0),
523
+ }
524
+
525
+ add_outputs = [count_state, add_button, del_button] + fipa_rows
526
+ del_outputs = [count_state, add_button, del_button] + fipa_rows
527
+ add_button.click(fn=add_fipa_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
528
+ del_button.click(fn=del_fipa_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
529
+
530
+
531
+ def create_sd3_ipadapter_event_handlers(prefix, ui_components):
532
+ ipa_rows = ui_components.get(f'sd3_ipadapter_rows_{prefix}')
533
+ if not ipa_rows: return
534
+ count_state = ui_components[f'sd3_ipadapter_count_state_{prefix}']
535
+ add_button = ui_components[f'add_sd3_ipadapter_button_{prefix}']
536
+ del_button = ui_components[f'delete_sd3_ipadapter_button_{prefix}']
537
+ images = ui_components[f'sd3_ipadapter_images_{prefix}']
538
+ weights = ui_components[f'sd3_ipadapter_weights_{prefix}']
539
+ start_percents = ui_components[f'sd3_ipadapter_start_percents_{prefix}']
540
+ end_percents = ui_components[f'sd3_ipadapter_end_percents_{prefix}']
541
+
542
+ def add_ipa_row(c):
543
+ c += 1
544
+ return {
545
+ count_state: c,
546
+ ipa_rows[c - 1]: gr.update(visible=True),
547
+ add_button: gr.update(visible=c < MAX_IPADAPTERS),
548
+ del_button: gr.update(visible=True),
549
+ }
550
+
551
+ def del_ipa_row(c):
552
+ c -= 1
553
+ return {
554
+ count_state: c,
555
+ ipa_rows[c]: gr.update(visible=False),
556
+ images[c]: None,
557
+ weights[c]: 0.5,
558
+ start_percents[c]: 0.0,
559
+ end_percents[c]: 1.0,
560
+ add_button: gr.update(visible=True),
561
+ del_button: gr.update(visible=c > 0),
562
+ }
563
+
564
+ add_outputs = [count_state, add_button, del_button] + ipa_rows
565
+ del_outputs = [count_state, add_button, del_button] + ipa_rows + images + weights + start_percents + end_percents
566
+ add_button.click(fn=add_ipa_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
567
+ del_button.click(fn=del_ipa_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
568
+
569
+
570
+ def create_style_event_handlers(prefix, ui_components):
571
+ style_rows = ui_components.get(f'style_rows_{prefix}')
572
+ if not style_rows: return
573
+ count_state = ui_components[f'style_count_state_{prefix}']
574
+ add_button = ui_components[f'add_style_button_{prefix}']
575
+ del_button = ui_components[f'delete_style_button_{prefix}']
576
+
577
+ def add_style_row(c):
578
+ c += 1
579
+ return {
580
+ count_state: c,
581
+ style_rows[c - 1]: gr.update(visible=True),
582
+ add_button: gr.update(visible=c < 5),
583
+ del_button: gr.update(visible=True),
584
+ }
585
+
586
+ def del_style_row(c):
587
+ c -= 1
588
+ return {
589
+ count_state: c,
590
+ style_rows[c]: gr.update(visible=False),
591
+ add_button: gr.update(visible=True),
592
+ del_button: gr.update(visible=c > 0),
593
+ }
594
+
595
+ add_outputs = [count_state, add_button, del_button] + style_rows
596
+ del_outputs = [count_state, add_button, del_button] + style_rows
597
+ add_button.click(fn=add_style_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
598
+ del_button.click(fn=del_style_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
599
+
600
+
601
+ def create_ipadapter_event_handlers(prefix, ui_components):
602
+ ipa_rows = ui_components.get(f'ipadapter_rows_{prefix}')
603
+ if not ipa_rows: return
604
+ ipa_lora_strengths = ui_components[f'ipadapter_lora_strengths_{prefix}']
605
+ ipa_final_preset = ui_components[f'ipadapter_final_preset_{prefix}']
606
+ ipa_final_lora_strength = ui_components[f'ipadapter_final_lora_strength_{prefix}']
607
+ count_state = ui_components[f'ipadapter_count_state_{prefix}']
608
+ add_button = ui_components[f'add_ipadapter_button_{prefix}']
609
+ del_button = ui_components[f'delete_ipadapter_button_{prefix}']
610
+ accordion = ui_components[f'ipadapter_accordion_{prefix}']
611
+
612
+ def add_ipa_row(c):
613
+ c += 1
614
+ return {
615
+ count_state: c,
616
+ ipa_rows[c - 1]: gr.update(visible=True),
617
+ add_button: gr.update(visible=c < MAX_IPADAPTERS),
618
+ del_button: gr.update(visible=True),
619
+ }
620
+
621
+ def del_ipa_row(c):
622
+ c -= 1
623
+ return {
624
+ count_state: c,
625
+ ipa_rows[c]: gr.update(visible=False),
626
+ add_button: gr.update(visible=True),
627
+ del_button: gr.update(visible=c > 0),
628
+ }
629
+
630
+ add_outputs = [count_state, add_button, del_button] + ipa_rows
631
+ del_outputs = [count_state, add_button, del_button] + ipa_rows
632
+ add_button.click(fn=add_ipa_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
633
+ del_button.click(fn=del_ipa_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
634
+
635
+ def on_preset_change(preset_value):
636
+ config = load_ipadapter_config()
637
+ faceid_presets = []
638
+ if config:
639
+ faceid_presets.extend(config.get("IPAdapter_FaceID_presets", {}).get("SDXL", []))
640
+ faceid_presets.extend(config.get("IPAdapter_FaceID_presets", {}).get("SD1.5", []))
641
+
642
+ is_visible = preset_value in faceid_presets
643
+ updates = [gr.update(visible=is_visible)] * (MAX_IPADAPTERS + 1)
644
+ return updates
645
+
646
+ all_lora_strength_sliders = [ipa_final_lora_strength] + ipa_lora_strengths
647
+ ipa_final_preset.change(fn=on_preset_change, inputs=[ipa_final_preset], outputs=all_lora_strength_sliders, show_progress=False)
648
+
649
+ accordion.expand(fn=lambda *imgs: [gr.update() for _ in imgs], inputs=ui_components[f'ipadapter_images_{prefix}'], outputs=ui_components[f'ipadapter_images_{prefix}'], show_progress=False)
650
+
651
+
652
+ def create_reference_latent_event_handlers(prefix, ui_components):
653
+ ref_rows = ui_components.get(f'reference_latent_rows_{prefix}')
654
+ if not ref_rows: return
655
+ count_state = ui_components[f'reference_latent_count_state_{prefix}']
656
+ add_button = ui_components[f'add_reference_latent_button_{prefix}']
657
+ del_button = ui_components[f'delete_reference_latent_button_{prefix}']
658
+ images = ui_components[f'reference_latent_images_{prefix}']
659
+
660
+ def add_ref_row(c):
661
+ c += 1
662
+ return {
663
+ count_state: c,
664
+ ref_rows[c - 1]: gr.update(visible=True),
665
+ add_button: gr.update(visible=c < 10),
666
+ del_button: gr.update(visible=True),
667
+ }
668
+
669
+ def del_ref_row(c):
670
+ c -= 1
671
+ return {
672
+ count_state: c,
673
+ ref_rows[c]: gr.update(visible=False),
674
+ images[c]: None,
675
+ add_button: gr.update(visible=True),
676
+ del_button: gr.update(visible=c > 0),
677
+ }
678
+
679
+ add_outputs = [count_state, add_button, del_button] + ref_rows
680
+ del_outputs = [count_state, add_button, del_button] + ref_rows + images
681
+ add_button.click(fn=add_ref_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
682
+ del_button.click(fn=del_ref_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
683
+
684
+
685
+ def create_hidream_o1_reference_event_handlers(prefix, ui_components):
686
+ ref_rows = ui_components.get(f'hidream_o1_reference_rows_{prefix}')
687
+ if not ref_rows: return
688
+ count_state = ui_components[f'hidream_o1_reference_count_state_{prefix}']
689
+ add_button = ui_components[f'add_hidream_o1_reference_button_{prefix}']
690
+ del_button = ui_components[f'delete_hidream_o1_reference_button_{prefix}']
691
+ images = ui_components[f'hidream_o1_reference_images_{prefix}']
692
+
693
+ def add_ref_row(c):
694
+ c += 1
695
+ return {
696
+ count_state: c,
697
+ ref_rows[c - 1]: gr.update(visible=True),
698
+ add_button: gr.update(visible=c < 10),
699
+ del_button: gr.update(visible=True),
700
+ }
701
+
702
+ def del_ref_row(c):
703
+ c -= 1
704
+ return {
705
+ count_state: c,
706
+ ref_rows[c]: gr.update(visible=False),
707
+ images[c]: None,
708
+ add_button: gr.update(visible=True),
709
+ del_button: gr.update(visible=c > 0),
710
+ }
711
+
712
+ add_outputs = [count_state, add_button, del_button] + ref_rows
713
+ del_outputs = [count_state, add_button, del_button] + ref_rows + images
714
+ add_button.click(fn=add_ref_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
715
+ del_button.click(fn=del_ref_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
716
+
717
+
718
+ def create_joyai_reference_event_handlers(prefix, ui_components):
719
+ ref_rows = ui_components.get(f'joyai_reference_rows_{prefix}')
720
+ if not ref_rows: return
721
+ count_state = ui_components[f'joyai_reference_count_state_{prefix}']
722
+ add_button = ui_components[f'add_joyai_reference_button_{prefix}']
723
+ del_button = ui_components[f'delete_joyai_reference_button_{prefix}']
724
+ images = ui_components[f'joyai_reference_images_{prefix}']
725
+
726
+ def add_ref_row(c):
727
+ c += 1
728
+ return {
729
+ count_state: c,
730
+ ref_rows[c - 1]: gr.update(visible=True),
731
+ add_button: gr.update(visible=c < 2),
732
+ del_button: gr.update(visible=True),
733
+ }
734
+
735
+ def del_ref_row(c):
736
+ c -= 1
737
+ return {
738
+ count_state: c,
739
+ ref_rows[c]: gr.update(visible=False),
740
+ images[c]: None,
741
+ add_button: gr.update(visible=True),
742
+ del_button: gr.update(visible=c > 0),
743
+ }
744
+
745
+ add_outputs = [count_state, add_button, del_button] + ref_rows
746
+ del_outputs = [count_state, add_button, del_button] + ref_rows + images
747
+ add_button.click(fn=add_ref_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
748
+ del_button.click(fn=del_ref_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
749
+
750
+
751
+ def create_reference_image_event_handlers(prefix, ui_components):
752
+ ref_rows = ui_components.get(f'reference_image_rows_{prefix}')
753
+ if not ref_rows: return
754
+ count_state = ui_components[f'reference_image_count_state_{prefix}']
755
+ add_button = ui_components[f'add_reference_image_button_{prefix}']
756
+ del_button = ui_components[f'delete_reference_image_button_{prefix}']
757
+ images = ui_components[f'reference_image_images_{prefix}']
758
+
759
+ def add_ref_row(c):
760
+ c += 1
761
+ return {
762
+ count_state: c,
763
+ ref_rows[c - 1]: gr.update(visible=True),
764
+ add_button: gr.update(visible=c < 10),
765
+ del_button: gr.update(visible=True),
766
+ }
767
+
768
+ def del_ref_row(c):
769
+ c -= 1
770
+ return {
771
+ count_state: c,
772
+ ref_rows[c]: gr.update(visible=False),
773
+ images[c]: None,
774
+ add_button: gr.update(visible=True),
775
+ del_button: gr.update(visible=c > 0),
776
+ }
777
+
778
+ add_outputs = [count_state, add_button, del_button] + ref_rows
779
+ del_outputs = [count_state, add_button, del_button] + ref_rows + images
780
+ add_button.click(fn=add_ref_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
781
+ del_button.click(fn=del_ref_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
782
+
783
+
784
+ def create_embedding_event_handlers(prefix, ui_components):
785
+ rows = ui_components.get(f'embedding_rows_{prefix}')
786
+ if not rows: return
787
+ ids = ui_components[f'embeddings_ids_{prefix}']
788
+ files = ui_components[f'embeddings_files_{prefix}']
789
+ sources = ui_components[f'embeddings_sources_{prefix}']
790
+ upload_buttons = ui_components[f'embeddings_uploads_{prefix}']
791
+ count_state = ui_components[f'embedding_count_state_{prefix}']
792
+ add_button = ui_components[f'add_embedding_button_{prefix}']
793
+ del_button = ui_components[f'delete_embedding_button_{prefix}']
794
+
795
+ for i in range(MAX_EMBEDDINGS):
796
+ upload_buttons[i].upload(
797
+ fn=on_embedding_upload,
798
+ inputs=[upload_buttons[i]],
799
+ outputs=[ids[i], sources[i], files[i]],
800
+ show_progress=True
801
+ )
802
+
803
+ def add_row(c):
804
+ c += 1
805
+ return {
806
+ count_state: c,
807
+ rows[c - 1]: gr.update(visible=True),
808
+ add_button: gr.update(visible=c < MAX_EMBEDDINGS),
809
+ del_button: gr.update(visible=True)
810
+ }
811
+
812
+ def del_row(c):
813
+ c -= 1
814
+ return {
815
+ count_state: c,
816
+ rows[c]: gr.update(visible=False),
817
+ ids[c]: "",
818
+ files[c]: None,
819
+ add_button: gr.update(visible=True),
820
+ del_button: gr.update(visible=c > 0)
821
+ }
822
+
823
+ add_outputs = [count_state, add_button, del_button] + rows
824
+ del_outputs = [count_state, add_button, del_button] + rows + ids + files
825
+ add_button.click(fn=add_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
826
+ del_button.click(fn=del_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
827
+
828
+
829
+ def create_conditioning_event_handlers(prefix, ui_components):
830
+ rows = ui_components.get(f'conditioning_rows_{prefix}')
831
+ if not rows: return
832
+ prompts = ui_components[f'conditioning_prompts_{prefix}']
833
+ count_state = ui_components[f'conditioning_count_state_{prefix}']
834
+ add_button = ui_components[f'add_conditioning_button_{prefix}']
835
+ del_button = ui_components[f'delete_conditioning_button_{prefix}']
836
+
837
+ def add_row(c):
838
+ c += 1
839
+ return {
840
+ count_state: c,
841
+ rows[c - 1]: gr.update(visible=True),
842
+ add_button: gr.update(visible=c < MAX_CONDITIONINGS),
843
+ del_button: gr.update(visible=True),
844
+ }
845
+
846
+ def del_row(c):
847
+ c -= 1
848
+ return {
849
+ count_state: c,
850
+ rows[c]: gr.update(visible=False),
851
+ prompts[c]: "",
852
+ add_button: gr.update(visible=True),
853
+ del_button: gr.update(visible=c > 0),
854
+ }
855
+
856
+ add_outputs = [count_state, add_button, del_button] + rows
857
+ del_outputs = [count_state, add_button, del_button] + rows + prompts
858
+ add_button.click(fn=add_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
859
+ del_button.click(fn=del_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
860
+
861
+
862
+ def create_krea2_identity_edit_event_handlers(prefix, ui_components):
863
+ ref_rows = ui_components.get(f'krea2_identity_edit_rows_{prefix}')
864
+ if not ref_rows: return
865
+ count_state = ui_components[f'krea2_identity_edit_count_state_{prefix}']
866
+ add_button = ui_components[f'add_krea2_identity_edit_button_{prefix}']
867
+ del_button = ui_components[f'delete_krea2_identity_edit_button_{prefix}']
868
+ images = ui_components[f'krea2_identity_edit_images_{prefix}']
869
+
870
+ def add_ref_row(c):
871
+ c += 1
872
+ return {
873
+ count_state: c,
874
+ ref_rows[c - 1]: gr.update(visible=True),
875
+ add_button: gr.update(visible=c < 2),
876
+ del_button: gr.update(visible=True),
877
+ }
878
+
879
+ def del_ref_row(c):
880
+ c -= 1
881
+ return {
882
+ count_state: c,
883
+ ref_rows[c]: gr.update(visible=False),
884
+ images[c]: None,
885
+ add_button: gr.update(visible=True),
886
+ del_button: gr.update(visible=c > 0),
887
+ }
888
+
889
+ add_outputs = [count_state, add_button, del_button] + ref_rows
890
+ del_outputs = [count_state, add_button, del_button] + ref_rows + images
891
+ add_button.click(fn=add_ref_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
892
+ del_button.click(fn=del_ref_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
893
+
894
+
895
+ def create_qwen_image_edit_event_handlers(prefix, ui_components):
896
+ ref_rows = ui_components.get(f'qwen_image_edit_rows_{prefix}')
897
+ if not ref_rows: return
898
+ count_state = ui_components[f'qwen_image_edit_count_state_{prefix}']
899
+ add_button = ui_components[f'add_qwen_image_edit_button_{prefix}']
900
+ del_button = ui_components[f'delete_qwen_image_edit_button_{prefix}']
901
+ images = ui_components[f'qwen_image_edit_images_{prefix}']
902
+
903
+ def add_ref_row(c):
904
+ c += 1
905
+ return {
906
+ count_state: c,
907
+ ref_rows[c - 1]: gr.update(visible=True),
908
+ add_button: gr.update(visible=c < 3),
909
+ del_button: gr.update(visible=True),
910
+ }
911
+
912
+ def del_ref_row(c):
913
+ c -= 1
914
+ return {
915
+ count_state: c,
916
+ ref_rows[c]: gr.update(visible=False),
917
+ images[c]: None,
918
+ add_button: gr.update(visible=True),
919
+ del_button: gr.update(visible=c > 0),
920
+ }
921
+
922
+ add_outputs = [count_state, add_button, del_button] + ref_rows
923
+ del_outputs = [count_state, add_button, del_button] + ref_rows + images
924
+ add_button.click(fn=add_ref_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
925
  del_button.click(fn=del_ref_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
ui/events/change_handlers.py CHANGED
@@ -17,7 +17,7 @@ from .config_loaders import (
17
  load_ipadapter_config
18
  )
19
 
20
- 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, krea2_cn_types, krea2_cn_series, krea2_cn_filepaths, ipa_preset, lora_acc, cn_acc, anima_cn_acc, diffsynth_cn_acc, krea2_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, vae_acc=None, joyai_ref_acc=None, krea2_identity_edit_acc=None, ref_img_acc=None):
21
  def update_fn(*args):
22
  arch = args[0]
23
  category = args[1]
@@ -70,6 +70,7 @@ def make_update_fn(m_comp, cat_comp, cs_comp, ar_comp, width_comp, height_comp,
70
  if hidream_o1_ref_acc: updates[hidream_o1_ref_acc] = gr.update(visible=('hidream_o1_reference' in enabled_chains))
71
  if joyai_ref_acc: updates[joyai_ref_acc] = gr.update(visible=('joyai_reference' in enabled_chains))
72
  if krea2_identity_edit_acc: updates[krea2_identity_edit_acc] = gr.update(visible=('krea2_identity_edit' in enabled_chains))
 
73
  if ref_img_acc: updates[ref_img_acc] = gr.update(visible=('reference_image' in enabled_chains))
74
  if pid_acc: updates[pid_acc] = gr.update(visible=('pid' in enabled_chains))
75
  if vae_acc: updates[vae_acc] = gr.update(visible=('vae' in enabled_chains))
@@ -145,7 +146,7 @@ def make_update_fn(m_comp, cat_comp, cs_comp, ar_comp, width_comp, height_comp,
145
  return update_fn
146
 
147
 
148
- 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, krea2_cn_types, krea2_cn_series, krea2_cn_filepaths, arch_comp_ref, ipa_preset, lora_acc, cn_acc, anima_cn_acc, diffsynth_cn_acc, krea2_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, vae_acc=None, joyai_ref_acc=None, krea2_identity_edit_acc=None, ref_img_acc=None):
149
  def change_fn(*args):
150
  model_name = args[0]
151
  idx = 1
@@ -203,6 +204,7 @@ def make_model_change_fn(cat_comp_ref, cs_comp, ar_comp, width_comp, height_comp
203
  if hidream_o1_ref_acc: updates[hidream_o1_ref_acc] = gr.update(visible=('hidream_o1_reference' in enabled_chains))
204
  if joyai_ref_acc: updates[joyai_ref_acc] = gr.update(visible=('joyai_reference' in enabled_chains))
205
  if krea2_identity_edit_acc: updates[krea2_identity_edit_acc] = gr.update(visible=('krea2_identity_edit' in enabled_chains))
 
206
  if ref_img_acc: updates[ref_img_acc] = gr.update(visible=('reference_image' in enabled_chains))
207
  if pid_acc: updates[pid_acc] = gr.update(visible=('pid' in enabled_chains))
208
  if vae_acc: updates[vae_acc] = gr.update(visible=('vae' in enabled_chains))
 
17
  load_ipadapter_config
18
  )
19
 
20
+ 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, krea2_cn_types, krea2_cn_series, krea2_cn_filepaths, ipa_preset, lora_acc, cn_acc, anima_cn_acc, diffsynth_cn_acc, krea2_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, vae_acc=None, joyai_ref_acc=None, krea2_identity_edit_acc=None, qwen_image_edit_acc=None, ref_img_acc=None):
21
  def update_fn(*args):
22
  arch = args[0]
23
  category = args[1]
 
70
  if hidream_o1_ref_acc: updates[hidream_o1_ref_acc] = gr.update(visible=('hidream_o1_reference' in enabled_chains))
71
  if joyai_ref_acc: updates[joyai_ref_acc] = gr.update(visible=('joyai_reference' in enabled_chains))
72
  if krea2_identity_edit_acc: updates[krea2_identity_edit_acc] = gr.update(visible=('krea2_identity_edit' in enabled_chains))
73
+ if qwen_image_edit_acc: updates[qwen_image_edit_acc] = gr.update(visible=('qwen_image_edit' in enabled_chains))
74
  if ref_img_acc: updates[ref_img_acc] = gr.update(visible=('reference_image' in enabled_chains))
75
  if pid_acc: updates[pid_acc] = gr.update(visible=('pid' in enabled_chains))
76
  if vae_acc: updates[vae_acc] = gr.update(visible=('vae' in enabled_chains))
 
146
  return update_fn
147
 
148
 
149
+ 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, krea2_cn_types, krea2_cn_series, krea2_cn_filepaths, arch_comp_ref, ipa_preset, lora_acc, cn_acc, anima_cn_acc, diffsynth_cn_acc, krea2_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, vae_acc=None, joyai_ref_acc=None, krea2_identity_edit_acc=None, qwen_image_edit_acc=None, ref_img_acc=None):
150
  def change_fn(*args):
151
  model_name = args[0]
152
  idx = 1
 
204
  if hidream_o1_ref_acc: updates[hidream_o1_ref_acc] = gr.update(visible=('hidream_o1_reference' in enabled_chains))
205
  if joyai_ref_acc: updates[joyai_ref_acc] = gr.update(visible=('joyai_reference' in enabled_chains))
206
  if krea2_identity_edit_acc: updates[krea2_identity_edit_acc] = gr.update(visible=('krea2_identity_edit' in enabled_chains))
207
+ if qwen_image_edit_acc: updates[qwen_image_edit_acc] = gr.update(visible=('qwen_image_edit' in enabled_chains))
208
  if ref_img_acc: updates[ref_img_acc] = gr.update(visible=('reference_image' in enabled_chains))
209
  if pid_acc: updates[pid_acc] = gr.update(visible=('pid' in enabled_chains))
210
  if vae_acc: updates[vae_acc] = gr.update(visible=('vae' in enabled_chains))
ui/events/main.py CHANGED
@@ -1,280 +1,285 @@
1
- import gradio as gr
2
- from .chain_handlers import (
3
- create_lora_event_handlers,
4
- create_controlnet_event_handlers,
5
- create_anima_controlnet_lllite_event_handlers,
6
- create_diffsynth_controlnet_event_handlers,
7
- create_krea2_controlnet_event_handlers,
8
- create_ipadapter_event_handlers,
9
- create_embedding_event_handlers,
10
- create_conditioning_event_handlers,
11
- create_flux1_ipadapter_event_handlers,
12
- create_sd3_ipadapter_event_handlers,
13
- create_style_event_handlers,
14
- create_reference_latent_event_handlers,
15
- create_hidream_o1_reference_event_handlers,
16
- create_joyai_reference_event_handlers,
17
- create_krea2_identity_edit_event_handlers,
18
- create_reference_image_event_handlers
19
- )
20
- from .change_handlers import (
21
- make_update_fn,
22
- make_model_change_fn,
23
- run_on_load,
24
- on_aspect_ratio_change
25
- )
26
- from .run_handlers import create_run_event
27
-
28
- def attach_event_handlers(ui_components, demo):
29
- for prefix, task_type in [
30
- ("txt2img", "txt2img"), ("img2img", "img2img"), ("inpaint", "inpaint"),
31
- ("outpaint", "outpaint"), ("hires_fix", "hires_fix"),
32
- ]:
33
-
34
- arch_comp = ui_components.get(f'model_arch_{prefix}')
35
- cat_comp = ui_components.get(f'model_cat_{prefix}')
36
- model_comp = ui_components.get(f'base_model_{prefix}')
37
- clip_skip_comp = ui_components.get(f'clip_skip_{prefix}') or ui_components.get(f'{prefix}_clip_skip')
38
- guidance_comp = ui_components.get(f'guidance_{prefix}') or ui_components.get(f'{prefix}_guidance')
39
- aspect_ratio_comp = ui_components.get(f'aspect_ratio_{prefix}') or ui_components.get(f'{prefix}_aspect_ratio_dropdown')
40
- width_comp = ui_components.get(f'width_{prefix}') or ui_components.get(f'{prefix}_width')
41
- height_comp = ui_components.get(f'height_{prefix}') or ui_components.get(f'{prefix}_height')
42
-
43
- cn_types_list = ui_components.get(f'controlnet_types_{prefix}', [])
44
- cn_series_list = ui_components.get(f'controlnet_series_{prefix}', [])
45
- cn_filepaths_list = ui_components.get(f'controlnet_filepaths_{prefix}', [])
46
-
47
- anima_cn_types_list = ui_components.get(f'anima_controlnet_lllite_types_{prefix}', [])
48
- anima_cn_series_list = ui_components.get(f'anima_controlnet_lllite_series_{prefix}', [])
49
- anima_cn_filepaths_list = ui_components.get(f'anima_controlnet_lllite_filepaths_{prefix}', [])
50
-
51
- diffsynth_cn_types_list = ui_components.get(f'diffsynth_controlnet_types_{prefix}', [])
52
- diffsynth_cn_series_list = ui_components.get(f'diffsynth_controlnet_series_{prefix}', [])
53
- diffsynth_cn_filepaths_list = ui_components.get(f'diffsynth_controlnet_filepaths_{prefix}', [])
54
-
55
- krea2_cn_types_list = ui_components.get(f'krea2_controlnet_types_{prefix}', [])
56
- krea2_cn_series_list = ui_components.get(f'krea2_controlnet_series_{prefix}', [])
57
- krea2_cn_filepaths_list = ui_components.get(f'krea2_controlnet_filepaths_{prefix}', [])
58
-
59
- lora_accordion = ui_components.get(f'lora_accordion_{prefix}')
60
- cn_accordion = ui_components.get(f'controlnet_accordion_{prefix}')
61
- anima_cn_accordion = ui_components.get(f'anima_controlnet_lllite_accordion_{prefix}')
62
- diffsynth_cn_accordion = ui_components.get(f'diffsynth_controlnet_accordion_{prefix}')
63
- krea2_cn_accordion = ui_components.get(f'krea2_controlnet_accordion_{prefix}')
64
- ipa_accordion = ui_components.get(f'ipadapter_accordion_{prefix}')
65
- sd3_ipa_accordion = ui_components.get(f'sd3_ipadapter_accordion_{prefix}')
66
- flux1_ipa_accordion = ui_components.get(f'flux1_ipadapter_accordion_{prefix}')
67
- style_accordion = ui_components.get(f'style_accordion_{prefix}')
68
- embedding_accordion = ui_components.get(f'embedding_accordion_{prefix}')
69
- conditioning_accordion = ui_components.get(f'conditioning_accordion_{prefix}')
70
- ref_latent_accordion = ui_components.get(f'reference_latent_accordion_{prefix}')
71
- hidream_o1_ref_accordion = ui_components.get(f'hidream_o1_reference_accordion_{prefix}')
72
- joyai_ref_accordion = ui_components.get(f'joyai_reference_accordion_{prefix}')
73
- krea2_identity_edit_accordion = ui_components.get(f'krea2_identity_edit_accordion_{prefix}')
74
- ref_img_accordion = ui_components.get(f'reference_image_accordion_{prefix}')
75
- pid_accordion = ui_components.get(f'pid_accordion_{prefix}')
76
- vae_accordion = ui_components.get(f'vae_accordion_{prefix}')
77
-
78
- ipa_preset_list = ui_components.get(f'ipadapter_final_preset_{prefix}')
79
-
80
- prompt_comp = ui_components.get(f'prompt_{prefix}') or ui_components.get(f'{prefix}_positive_prompt')
81
- neg_prompt_comp = ui_components.get(f'neg_prompt_{prefix}') or ui_components.get(f'{prefix}_negative_prompt')
82
- steps_comp = ui_components.get(f'steps_{prefix}') or ui_components.get(f'{prefix}_steps')
83
- cfg_comp = ui_components.get(f'cfg_{prefix}') or ui_components.get(f'{prefix}_cfg')
84
- sampler_comp = ui_components.get(f'sampler_{prefix}') or ui_components.get(f'{prefix}_sampler_name')
85
- scheduler_comp = ui_components.get(f'scheduler_{prefix}') or ui_components.get(f'{prefix}_scheduler')
86
-
87
- extra_comps = [prompt_comp, neg_prompt_comp, steps_comp, cfg_comp, sampler_comp, scheduler_comp, width_comp, height_comp]
88
- valid_extra_comps = [c for c in extra_comps if c is not None]
89
-
90
- if arch_comp and cat_comp and model_comp:
91
- outputs = [model_comp, cat_comp]
92
- if clip_skip_comp: outputs.append(clip_skip_comp)
93
- if guidance_comp: outputs.append(guidance_comp)
94
- if aspect_ratio_comp: outputs.append(aspect_ratio_comp)
95
- outputs.extend(cn_types_list + cn_series_list + cn_filepaths_list)
96
- outputs.extend(anima_cn_types_list + anima_cn_series_list + anima_cn_filepaths_list)
97
- outputs.extend(diffsynth_cn_types_list + diffsynth_cn_series_list + diffsynth_cn_filepaths_list)
98
- outputs.extend(krea2_cn_types_list + krea2_cn_series_list + krea2_cn_filepaths_list)
99
- if lora_accordion: outputs.append(lora_accordion)
100
- if cn_accordion: outputs.append(cn_accordion)
101
- if anima_cn_accordion: outputs.append(anima_cn_accordion)
102
- if diffsynth_cn_accordion: outputs.append(diffsynth_cn_accordion)
103
- if krea2_cn_accordion: outputs.append(krea2_cn_accordion)
104
- if ipa_accordion: outputs.append(ipa_accordion)
105
- if sd3_ipa_accordion: outputs.append(sd3_ipa_accordion)
106
- if flux1_ipa_accordion: outputs.append(flux1_ipa_accordion)
107
- if style_accordion: outputs.append(style_accordion)
108
- if embedding_accordion: outputs.append(embedding_accordion)
109
- if conditioning_accordion: outputs.append(conditioning_accordion)
110
- if ref_latent_accordion: outputs.append(ref_latent_accordion)
111
- if hidream_o1_ref_accordion: outputs.append(hidream_o1_ref_accordion)
112
- if joyai_ref_accordion: outputs.append(joyai_ref_accordion)
113
- if krea2_identity_edit_accordion: outputs.append(krea2_identity_edit_accordion)
114
- if ref_img_accordion: outputs.append(ref_img_accordion)
115
- if pid_accordion: outputs.append(pid_accordion)
116
- if vae_accordion: outputs.append(vae_accordion)
117
- if ipa_preset_list: outputs.append(ipa_preset_list)
118
-
119
- outputs.extend(valid_extra_comps)
120
-
121
- update_fn = make_update_fn(
122
- model_comp, cat_comp, clip_skip_comp, aspect_ratio_comp, width_comp, height_comp,
123
- cn_types_list, cn_series_list, cn_filepaths_list,
124
- anima_cn_types_list, anima_cn_series_list, anima_cn_filepaths_list,
125
- diffsynth_cn_types_list, diffsynth_cn_series_list, diffsynth_cn_filepaths_list,
126
- krea2_cn_types_list, krea2_cn_series_list, krea2_cn_filepaths_list,
127
- ipa_preset_list, lora_accordion, cn_accordion, anima_cn_accordion, diffsynth_cn_accordion, krea2_cn_accordion, ipa_accordion, sd3_ipa_accordion, flux1_ipa_accordion, style_accordion, embedding_accordion, conditioning_accordion,
128
- ref_latent_accordion, hidream_o1_ref_accordion, guidance_comp, prompt_comp, neg_prompt_comp, steps_comp, cfg_comp, sampler_comp, scheduler_comp,
129
- pid_acc=pid_accordion, vae_acc=vae_accordion, joyai_ref_acc=joyai_ref_accordion, krea2_identity_edit_acc=krea2_identity_edit_accordion, ref_img_acc=ref_img_accordion
130
- )
131
- inputs = [arch_comp, cat_comp]
132
- if aspect_ratio_comp:
133
- inputs.append(aspect_ratio_comp)
134
- arch_comp.change(fn=update_fn, inputs=inputs, outputs=outputs)
135
- cat_comp.change(fn=update_fn, inputs=inputs, outputs=outputs)
136
-
137
- if model_comp:
138
- outputs2 = []
139
- if arch_comp: outputs2.append(arch_comp)
140
- if cat_comp: outputs2.append(cat_comp)
141
- if clip_skip_comp: outputs2.append(clip_skip_comp)
142
- if guidance_comp: outputs2.append(guidance_comp)
143
- if aspect_ratio_comp: outputs2.append(aspect_ratio_comp)
144
- outputs2.extend(cn_types_list + cn_series_list + cn_filepaths_list)
145
- outputs2.extend(anima_cn_types_list + anima_cn_series_list + anima_cn_filepaths_list)
146
- outputs2.extend(diffsynth_cn_types_list + diffsynth_cn_series_list + diffsynth_cn_filepaths_list)
147
- outputs2.extend(krea2_cn_types_list + krea2_cn_series_list + krea2_cn_filepaths_list)
148
- if lora_accordion: outputs2.append(lora_accordion)
149
- if cn_accordion: outputs2.append(cn_accordion)
150
- if anima_cn_accordion: outputs2.append(anima_cn_accordion)
151
- if diffsynth_cn_accordion: outputs2.append(diffsynth_cn_accordion)
152
- if krea2_cn_accordion: outputs2.append(krea2_cn_accordion)
153
- if ipa_accordion: outputs2.append(ipa_accordion)
154
- if sd3_ipa_accordion: outputs2.append(sd3_ipa_accordion)
155
- if flux1_ipa_accordion: outputs2.append(flux1_ipa_accordion)
156
- if style_accordion: outputs2.append(style_accordion)
157
- if embedding_accordion: outputs2.append(embedding_accordion)
158
- if conditioning_accordion: outputs2.append(conditioning_accordion)
159
- if ref_latent_accordion: outputs2.append(ref_latent_accordion)
160
- if hidream_o1_ref_accordion: outputs2.append(hidream_o1_ref_accordion)
161
- if joyai_ref_accordion: outputs2.append(joyai_ref_accordion)
162
- if krea2_identity_edit_accordion: outputs2.append(krea2_identity_edit_accordion)
163
- if ref_img_accordion: outputs2.append(ref_img_accordion)
164
- if pid_accordion: outputs2.append(pid_accordion)
165
- if vae_accordion: outputs2.append(vae_accordion)
166
- if ipa_preset_list: outputs2.append(ipa_preset_list)
167
-
168
- outputs2.extend(valid_extra_comps)
169
-
170
- if outputs2:
171
- inputs2 = [model_comp]
172
- if arch_comp: inputs2.append(arch_comp)
173
- if cat_comp: inputs2.append(cat_comp)
174
- if aspect_ratio_comp: inputs2.append(aspect_ratio_comp)
175
- change_fn = make_model_change_fn(
176
- cat_comp, clip_skip_comp, aspect_ratio_comp, width_comp, height_comp,
177
- cn_types_list, cn_series_list, cn_filepaths_list,
178
- anima_cn_types_list, anima_cn_series_list, anima_cn_filepaths_list,
179
- diffsynth_cn_types_list, diffsynth_cn_series_list, diffsynth_cn_filepaths_list,
180
- krea2_cn_types_list, krea2_cn_series_list, krea2_cn_filepaths_list,
181
- arch_comp, ipa_preset_list, lora_accordion, cn_accordion, anima_cn_accordion, diffsynth_cn_accordion, krea2_cn_accordion, ipa_accordion, sd3_ipa_accordion, flux1_ipa_accordion, style_accordion, embedding_accordion, conditioning_accordion,
182
- ref_latent_accordion, hidream_o1_ref_accordion, guidance_comp, prompt_comp, neg_prompt_comp, steps_comp, cfg_comp, sampler_comp, scheduler_comp,
183
- pid_acc=pid_accordion, vae_acc=vae_accordion, joyai_ref_acc=joyai_ref_accordion, krea2_identity_edit_acc=krea2_identity_edit_accordion, ref_img_acc=ref_img_accordion
184
- )
185
- model_comp.change(fn=change_fn, inputs=inputs2, outputs=outputs2)
186
-
187
- create_lora_event_handlers(prefix, ui_components)
188
- create_controlnet_event_handlers(prefix, ui_components)
189
- create_anima_controlnet_lllite_event_handlers(prefix, ui_components)
190
- create_diffsynth_controlnet_event_handlers(prefix, ui_components)
191
- create_krea2_controlnet_event_handlers(prefix, ui_components)
192
- create_ipadapter_event_handlers(prefix, ui_components)
193
- create_embedding_event_handlers(prefix, ui_components)
194
- create_conditioning_event_handlers(prefix, ui_components)
195
- create_flux1_ipadapter_event_handlers(prefix, ui_components)
196
- create_sd3_ipadapter_event_handlers(prefix, ui_components)
197
- create_style_event_handlers(prefix, ui_components)
198
- create_reference_latent_event_handlers(prefix, ui_components)
199
- create_hidream_o1_reference_event_handlers(prefix, ui_components)
200
- create_joyai_reference_event_handlers(prefix, ui_components)
201
- create_krea2_identity_edit_event_handlers(prefix, ui_components)
202
- create_reference_image_event_handlers(prefix, ui_components)
203
- create_run_event(prefix, task_type, ui_components)
204
-
205
- if 'view_mode_inpaint' in ui_components:
206
- def toggle_inpaint_fullscreen_view(view_mode):
207
- is_fullscreen = (view_mode == "Fullscreen View")
208
- other_elements_visible = not is_fullscreen
209
- editor_height = 800 if is_fullscreen else 272
210
-
211
- updates = {
212
- ui_components['prompts_column_inpaint']: gr.update(visible=other_elements_visible),
213
- ui_components['params_and_gallery_row_inpaint']: gr.update(visible=other_elements_visible),
214
- ui_components['accordion_wrapper_inpaint']: gr.update(visible=other_elements_visible),
215
- ui_components['input_image_dict_inpaint']: gr.update(height=editor_height),
216
- }
217
-
218
- model_and_run_rows = ui_components.get('model_and_run_row_inpaint', [])
219
- for row in model_and_run_rows:
220
- updates[row] = gr.update(visible=other_elements_visible)
221
-
222
- return updates
223
-
224
- output_components = []
225
- model_and_run_rows = ui_components.get('model_and_run_row_inpaint', [])
226
- if isinstance(model_and_run_rows, list):
227
- output_components.extend(model_and_run_rows)
228
- else:
229
- output_components.append(model_and_run_rows)
230
-
231
- output_components.extend([
232
- ui_components['prompts_column_inpaint'],
233
- ui_components['params_and_gallery_row_inpaint'],
234
- ui_components['accordion_wrapper_inpaint'],
235
- ui_components['input_image_dict_inpaint']
236
- ])
237
-
238
- ui_components['view_mode_inpaint'].change(
239
- fn=toggle_inpaint_fullscreen_view,
240
- inputs=[ui_components['view_mode_inpaint']],
241
- outputs=output_components,
242
- show_progress=False
243
- )
244
-
245
- all_load_outputs = []
246
- for prefix in ["txt2img", "img2img", "inpaint", "outpaint", "hires_fix"]:
247
- if f'controlnet_types_{prefix}' in ui_components:
248
- all_load_outputs.extend(ui_components[f'controlnet_types_{prefix}'])
249
- all_load_outputs.extend(ui_components[f'controlnet_series_{prefix}'])
250
- all_load_outputs.extend(ui_components[f'controlnet_filepaths_{prefix}'])
251
- if f'anima_controlnet_lllite_types_{prefix}' in ui_components:
252
- all_load_outputs.extend(ui_components[f'anima_controlnet_lllite_types_{prefix}'])
253
- all_load_outputs.extend(ui_components[f'anima_controlnet_lllite_series_{prefix}'])
254
- all_load_outputs.extend(ui_components[f'anima_controlnet_lllite_filepaths_{prefix}'])
255
- if f'diffsynth_controlnet_types_{prefix}' in ui_components:
256
- all_load_outputs.extend(ui_components[f'diffsynth_controlnet_types_{prefix}'])
257
- all_load_outputs.extend(ui_components[f'diffsynth_controlnet_series_{prefix}'])
258
- all_load_outputs.extend(ui_components[f'diffsynth_controlnet_filepaths_{prefix}'])
259
- if f'krea2_controlnet_types_{prefix}' in ui_components:
260
- all_load_outputs.extend(ui_components[f'krea2_controlnet_types_{prefix}'])
261
- all_load_outputs.extend(ui_components[f'krea2_controlnet_series_{prefix}'])
262
- all_load_outputs.extend(ui_components[f'krea2_controlnet_filepaths_{prefix}'])
263
- if f'ipadapter_final_preset_{prefix}' in ui_components:
264
- all_load_outputs.extend(ui_components[f'ipadapter_lora_strengths_{prefix}'])
265
- all_load_outputs.append(ui_components[f'ipadapter_final_preset_{prefix}'])
266
- all_load_outputs.append(ui_components[f'ipadapter_final_lora_strength_{prefix}'])
267
-
268
- if all_load_outputs:
269
- demo.load(
270
- fn=lambda: run_on_load(ui_components),
271
- outputs=all_load_outputs
272
- )
273
-
274
- for prefix in ["txt2img", "img2img", "inpaint", "outpaint", "hires_fix"]:
275
- aspect_ratio_dropdown = ui_components.get(f'aspect_ratio_{prefix}') or ui_components.get(f'{prefix}_aspect_ratio_dropdown')
276
- width_component = ui_components.get(f'width_{prefix}') or ui_components.get(f'{prefix}_width')
277
- height_component = ui_components.get(f'height_{prefix}') or ui_components.get(f'{prefix}_height')
278
- model_dropdown = ui_components.get(f'base_model_{prefix}')
279
- if aspect_ratio_dropdown and width_component and height_component and model_dropdown:
 
 
 
 
 
280
  aspect_ratio_dropdown.change(fn=on_aspect_ratio_change, inputs=[aspect_ratio_dropdown, model_dropdown], outputs=[width_component, height_component], show_progress=False)
 
1
+ import gradio as gr
2
+ from .chain_handlers import (
3
+ create_lora_event_handlers,
4
+ create_controlnet_event_handlers,
5
+ create_anima_controlnet_lllite_event_handlers,
6
+ create_diffsynth_controlnet_event_handlers,
7
+ create_krea2_controlnet_event_handlers,
8
+ create_ipadapter_event_handlers,
9
+ create_embedding_event_handlers,
10
+ create_conditioning_event_handlers,
11
+ create_flux1_ipadapter_event_handlers,
12
+ create_sd3_ipadapter_event_handlers,
13
+ create_style_event_handlers,
14
+ create_reference_latent_event_handlers,
15
+ create_hidream_o1_reference_event_handlers,
16
+ create_joyai_reference_event_handlers,
17
+ create_krea2_identity_edit_event_handlers,
18
+ create_qwen_image_edit_event_handlers,
19
+ create_reference_image_event_handlers
20
+ )
21
+ from .change_handlers import (
22
+ make_update_fn,
23
+ make_model_change_fn,
24
+ run_on_load,
25
+ on_aspect_ratio_change
26
+ )
27
+ from .run_handlers import create_run_event
28
+
29
+ def attach_event_handlers(ui_components, demo):
30
+ for prefix, task_type in [
31
+ ("txt2img", "txt2img"), ("img2img", "img2img"), ("inpaint", "inpaint"),
32
+ ("outpaint", "outpaint"), ("hires_fix", "hires_fix"),
33
+ ]:
34
+
35
+ arch_comp = ui_components.get(f'model_arch_{prefix}')
36
+ cat_comp = ui_components.get(f'model_cat_{prefix}')
37
+ model_comp = ui_components.get(f'base_model_{prefix}')
38
+ clip_skip_comp = ui_components.get(f'clip_skip_{prefix}') or ui_components.get(f'{prefix}_clip_skip')
39
+ guidance_comp = ui_components.get(f'guidance_{prefix}') or ui_components.get(f'{prefix}_guidance')
40
+ aspect_ratio_comp = ui_components.get(f'aspect_ratio_{prefix}') or ui_components.get(f'{prefix}_aspect_ratio_dropdown')
41
+ width_comp = ui_components.get(f'width_{prefix}') or ui_components.get(f'{prefix}_width')
42
+ height_comp = ui_components.get(f'height_{prefix}') or ui_components.get(f'{prefix}_height')
43
+
44
+ cn_types_list = ui_components.get(f'controlnet_types_{prefix}', [])
45
+ cn_series_list = ui_components.get(f'controlnet_series_{prefix}', [])
46
+ cn_filepaths_list = ui_components.get(f'controlnet_filepaths_{prefix}', [])
47
+
48
+ anima_cn_types_list = ui_components.get(f'anima_controlnet_lllite_types_{prefix}', [])
49
+ anima_cn_series_list = ui_components.get(f'anima_controlnet_lllite_series_{prefix}', [])
50
+ anima_cn_filepaths_list = ui_components.get(f'anima_controlnet_lllite_filepaths_{prefix}', [])
51
+
52
+ diffsynth_cn_types_list = ui_components.get(f'diffsynth_controlnet_types_{prefix}', [])
53
+ diffsynth_cn_series_list = ui_components.get(f'diffsynth_controlnet_series_{prefix}', [])
54
+ diffsynth_cn_filepaths_list = ui_components.get(f'diffsynth_controlnet_filepaths_{prefix}', [])
55
+
56
+ krea2_cn_types_list = ui_components.get(f'krea2_controlnet_types_{prefix}', [])
57
+ krea2_cn_series_list = ui_components.get(f'krea2_controlnet_series_{prefix}', [])
58
+ krea2_cn_filepaths_list = ui_components.get(f'krea2_controlnet_filepaths_{prefix}', [])
59
+
60
+ lora_accordion = ui_components.get(f'lora_accordion_{prefix}')
61
+ cn_accordion = ui_components.get(f'controlnet_accordion_{prefix}')
62
+ anima_cn_accordion = ui_components.get(f'anima_controlnet_lllite_accordion_{prefix}')
63
+ diffsynth_cn_accordion = ui_components.get(f'diffsynth_controlnet_accordion_{prefix}')
64
+ krea2_cn_accordion = ui_components.get(f'krea2_controlnet_accordion_{prefix}')
65
+ ipa_accordion = ui_components.get(f'ipadapter_accordion_{prefix}')
66
+ sd3_ipa_accordion = ui_components.get(f'sd3_ipadapter_accordion_{prefix}')
67
+ flux1_ipa_accordion = ui_components.get(f'flux1_ipadapter_accordion_{prefix}')
68
+ style_accordion = ui_components.get(f'style_accordion_{prefix}')
69
+ embedding_accordion = ui_components.get(f'embedding_accordion_{prefix}')
70
+ conditioning_accordion = ui_components.get(f'conditioning_accordion_{prefix}')
71
+ ref_latent_accordion = ui_components.get(f'reference_latent_accordion_{prefix}')
72
+ hidream_o1_ref_accordion = ui_components.get(f'hidream_o1_reference_accordion_{prefix}')
73
+ joyai_ref_accordion = ui_components.get(f'joyai_reference_accordion_{prefix}')
74
+ krea2_identity_edit_accordion = ui_components.get(f'krea2_identity_edit_accordion_{prefix}')
75
+ qwen_image_edit_accordion = ui_components.get(f'qwen_image_edit_accordion_{prefix}')
76
+ ref_img_accordion = ui_components.get(f'reference_image_accordion_{prefix}')
77
+ pid_accordion = ui_components.get(f'pid_accordion_{prefix}')
78
+ vae_accordion = ui_components.get(f'vae_accordion_{prefix}')
79
+
80
+ ipa_preset_list = ui_components.get(f'ipadapter_final_preset_{prefix}')
81
+
82
+ prompt_comp = ui_components.get(f'prompt_{prefix}') or ui_components.get(f'{prefix}_positive_prompt')
83
+ neg_prompt_comp = ui_components.get(f'neg_prompt_{prefix}') or ui_components.get(f'{prefix}_negative_prompt')
84
+ steps_comp = ui_components.get(f'steps_{prefix}') or ui_components.get(f'{prefix}_steps')
85
+ cfg_comp = ui_components.get(f'cfg_{prefix}') or ui_components.get(f'{prefix}_cfg')
86
+ sampler_comp = ui_components.get(f'sampler_{prefix}') or ui_components.get(f'{prefix}_sampler_name')
87
+ scheduler_comp = ui_components.get(f'scheduler_{prefix}') or ui_components.get(f'{prefix}_scheduler')
88
+
89
+ extra_comps = [prompt_comp, neg_prompt_comp, steps_comp, cfg_comp, sampler_comp, scheduler_comp, width_comp, height_comp]
90
+ valid_extra_comps = [c for c in extra_comps if c is not None]
91
+
92
+ if arch_comp and cat_comp and model_comp:
93
+ outputs = [model_comp, cat_comp]
94
+ if clip_skip_comp: outputs.append(clip_skip_comp)
95
+ if guidance_comp: outputs.append(guidance_comp)
96
+ if aspect_ratio_comp: outputs.append(aspect_ratio_comp)
97
+ outputs.extend(cn_types_list + cn_series_list + cn_filepaths_list)
98
+ outputs.extend(anima_cn_types_list + anima_cn_series_list + anima_cn_filepaths_list)
99
+ outputs.extend(diffsynth_cn_types_list + diffsynth_cn_series_list + diffsynth_cn_filepaths_list)
100
+ outputs.extend(krea2_cn_types_list + krea2_cn_series_list + krea2_cn_filepaths_list)
101
+ if lora_accordion: outputs.append(lora_accordion)
102
+ if cn_accordion: outputs.append(cn_accordion)
103
+ if anima_cn_accordion: outputs.append(anima_cn_accordion)
104
+ if diffsynth_cn_accordion: outputs.append(diffsynth_cn_accordion)
105
+ if krea2_cn_accordion: outputs.append(krea2_cn_accordion)
106
+ if ipa_accordion: outputs.append(ipa_accordion)
107
+ if sd3_ipa_accordion: outputs.append(sd3_ipa_accordion)
108
+ if flux1_ipa_accordion: outputs.append(flux1_ipa_accordion)
109
+ if style_accordion: outputs.append(style_accordion)
110
+ if embedding_accordion: outputs.append(embedding_accordion)
111
+ if conditioning_accordion: outputs.append(conditioning_accordion)
112
+ if ref_latent_accordion: outputs.append(ref_latent_accordion)
113
+ if hidream_o1_ref_accordion: outputs.append(hidream_o1_ref_accordion)
114
+ if joyai_ref_accordion: outputs.append(joyai_ref_accordion)
115
+ if krea2_identity_edit_accordion: outputs.append(krea2_identity_edit_accordion)
116
+ if qwen_image_edit_accordion: outputs.append(qwen_image_edit_accordion)
117
+ if ref_img_accordion: outputs.append(ref_img_accordion)
118
+ if pid_accordion: outputs.append(pid_accordion)
119
+ if vae_accordion: outputs.append(vae_accordion)
120
+ if ipa_preset_list: outputs.append(ipa_preset_list)
121
+
122
+ outputs.extend(valid_extra_comps)
123
+
124
+ update_fn = make_update_fn(
125
+ model_comp, cat_comp, clip_skip_comp, aspect_ratio_comp, width_comp, height_comp,
126
+ cn_types_list, cn_series_list, cn_filepaths_list,
127
+ anima_cn_types_list, anima_cn_series_list, anima_cn_filepaths_list,
128
+ diffsynth_cn_types_list, diffsynth_cn_series_list, diffsynth_cn_filepaths_list,
129
+ krea2_cn_types_list, krea2_cn_series_list, krea2_cn_filepaths_list,
130
+ ipa_preset_list, lora_accordion, cn_accordion, anima_cn_accordion, diffsynth_cn_accordion, krea2_cn_accordion, ipa_accordion, sd3_ipa_accordion, flux1_ipa_accordion, style_accordion, embedding_accordion, conditioning_accordion,
131
+ ref_latent_accordion, hidream_o1_ref_accordion, guidance_comp, prompt_comp, neg_prompt_comp, steps_comp, cfg_comp, sampler_comp, scheduler_comp,
132
+ pid_acc=pid_accordion, vae_acc=vae_accordion, joyai_ref_acc=joyai_ref_accordion, krea2_identity_edit_acc=krea2_identity_edit_accordion, qwen_image_edit_acc=qwen_image_edit_accordion, ref_img_acc=ref_img_accordion
133
+ )
134
+ inputs = [arch_comp, cat_comp]
135
+ if aspect_ratio_comp:
136
+ inputs.append(aspect_ratio_comp)
137
+ arch_comp.change(fn=update_fn, inputs=inputs, outputs=outputs)
138
+ cat_comp.change(fn=update_fn, inputs=inputs, outputs=outputs)
139
+
140
+ if model_comp:
141
+ outputs2 = []
142
+ if arch_comp: outputs2.append(arch_comp)
143
+ if cat_comp: outputs2.append(cat_comp)
144
+ if clip_skip_comp: outputs2.append(clip_skip_comp)
145
+ if guidance_comp: outputs2.append(guidance_comp)
146
+ if aspect_ratio_comp: outputs2.append(aspect_ratio_comp)
147
+ outputs2.extend(cn_types_list + cn_series_list + cn_filepaths_list)
148
+ outputs2.extend(anima_cn_types_list + anima_cn_series_list + anima_cn_filepaths_list)
149
+ outputs2.extend(diffsynth_cn_types_list + diffsynth_cn_series_list + diffsynth_cn_filepaths_list)
150
+ outputs2.extend(krea2_cn_types_list + krea2_cn_series_list + krea2_cn_filepaths_list)
151
+ if lora_accordion: outputs2.append(lora_accordion)
152
+ if cn_accordion: outputs2.append(cn_accordion)
153
+ if anima_cn_accordion: outputs2.append(anima_cn_accordion)
154
+ if diffsynth_cn_accordion: outputs2.append(diffsynth_cn_accordion)
155
+ if krea2_cn_accordion: outputs2.append(krea2_cn_accordion)
156
+ if ipa_accordion: outputs2.append(ipa_accordion)
157
+ if sd3_ipa_accordion: outputs2.append(sd3_ipa_accordion)
158
+ if flux1_ipa_accordion: outputs2.append(flux1_ipa_accordion)
159
+ if style_accordion: outputs2.append(style_accordion)
160
+ if embedding_accordion: outputs2.append(embedding_accordion)
161
+ if conditioning_accordion: outputs2.append(conditioning_accordion)
162
+ if ref_latent_accordion: outputs2.append(ref_latent_accordion)
163
+ if hidream_o1_ref_accordion: outputs2.append(hidream_o1_ref_accordion)
164
+ if joyai_ref_accordion: outputs2.append(joyai_ref_accordion)
165
+ if krea2_identity_edit_accordion: outputs2.append(krea2_identity_edit_accordion)
166
+ if qwen_image_edit_accordion: outputs2.append(qwen_image_edit_accordion)
167
+ if ref_img_accordion: outputs2.append(ref_img_accordion)
168
+ if pid_accordion: outputs2.append(pid_accordion)
169
+ if vae_accordion: outputs2.append(vae_accordion)
170
+ if ipa_preset_list: outputs2.append(ipa_preset_list)
171
+
172
+ outputs2.extend(valid_extra_comps)
173
+
174
+ if outputs2:
175
+ inputs2 = [model_comp]
176
+ if arch_comp: inputs2.append(arch_comp)
177
+ if cat_comp: inputs2.append(cat_comp)
178
+ if aspect_ratio_comp: inputs2.append(aspect_ratio_comp)
179
+ change_fn = make_model_change_fn(
180
+ cat_comp, clip_skip_comp, aspect_ratio_comp, width_comp, height_comp,
181
+ cn_types_list, cn_series_list, cn_filepaths_list,
182
+ anima_cn_types_list, anima_cn_series_list, anima_cn_filepaths_list,
183
+ diffsynth_cn_types_list, diffsynth_cn_series_list, diffsynth_cn_filepaths_list,
184
+ krea2_cn_types_list, krea2_cn_series_list, krea2_cn_filepaths_list,
185
+ arch_comp, ipa_preset_list, lora_accordion, cn_accordion, anima_cn_accordion, diffsynth_cn_accordion, krea2_cn_accordion, ipa_accordion, sd3_ipa_accordion, flux1_ipa_accordion, style_accordion, embedding_accordion, conditioning_accordion,
186
+ ref_latent_accordion, hidream_o1_ref_accordion, guidance_comp, prompt_comp, neg_prompt_comp, steps_comp, cfg_comp, sampler_comp, scheduler_comp,
187
+ pid_acc=pid_accordion, vae_acc=vae_accordion, joyai_ref_acc=joyai_ref_accordion, krea2_identity_edit_acc=krea2_identity_edit_accordion, qwen_image_edit_acc=qwen_image_edit_accordion, ref_img_acc=ref_img_accordion
188
+ )
189
+ model_comp.change(fn=change_fn, inputs=inputs2, outputs=outputs2)
190
+
191
+ create_lora_event_handlers(prefix, ui_components)
192
+ create_controlnet_event_handlers(prefix, ui_components)
193
+ create_anima_controlnet_lllite_event_handlers(prefix, ui_components)
194
+ create_diffsynth_controlnet_event_handlers(prefix, ui_components)
195
+ create_krea2_controlnet_event_handlers(prefix, ui_components)
196
+ create_ipadapter_event_handlers(prefix, ui_components)
197
+ create_embedding_event_handlers(prefix, ui_components)
198
+ create_conditioning_event_handlers(prefix, ui_components)
199
+ create_flux1_ipadapter_event_handlers(prefix, ui_components)
200
+ create_sd3_ipadapter_event_handlers(prefix, ui_components)
201
+ create_style_event_handlers(prefix, ui_components)
202
+ create_reference_latent_event_handlers(prefix, ui_components)
203
+ create_hidream_o1_reference_event_handlers(prefix, ui_components)
204
+ create_joyai_reference_event_handlers(prefix, ui_components)
205
+ create_krea2_identity_edit_event_handlers(prefix, ui_components)
206
+ create_qwen_image_edit_event_handlers(prefix, ui_components)
207
+ create_reference_image_event_handlers(prefix, ui_components)
208
+ create_run_event(prefix, task_type, ui_components)
209
+
210
+ if 'view_mode_inpaint' in ui_components:
211
+ def toggle_inpaint_fullscreen_view(view_mode):
212
+ is_fullscreen = (view_mode == "Fullscreen View")
213
+ other_elements_visible = not is_fullscreen
214
+ editor_height = 800 if is_fullscreen else 272
215
+
216
+ updates = {
217
+ ui_components['prompts_column_inpaint']: gr.update(visible=other_elements_visible),
218
+ ui_components['params_and_gallery_row_inpaint']: gr.update(visible=other_elements_visible),
219
+ ui_components['accordion_wrapper_inpaint']: gr.update(visible=other_elements_visible),
220
+ ui_components['input_image_dict_inpaint']: gr.update(height=editor_height),
221
+ }
222
+
223
+ model_and_run_rows = ui_components.get('model_and_run_row_inpaint', [])
224
+ for row in model_and_run_rows:
225
+ updates[row] = gr.update(visible=other_elements_visible)
226
+
227
+ return updates
228
+
229
+ output_components = []
230
+ model_and_run_rows = ui_components.get('model_and_run_row_inpaint', [])
231
+ if isinstance(model_and_run_rows, list):
232
+ output_components.extend(model_and_run_rows)
233
+ else:
234
+ output_components.append(model_and_run_rows)
235
+
236
+ output_components.extend([
237
+ ui_components['prompts_column_inpaint'],
238
+ ui_components['params_and_gallery_row_inpaint'],
239
+ ui_components['accordion_wrapper_inpaint'],
240
+ ui_components['input_image_dict_inpaint']
241
+ ])
242
+
243
+ ui_components['view_mode_inpaint'].change(
244
+ fn=toggle_inpaint_fullscreen_view,
245
+ inputs=[ui_components['view_mode_inpaint']],
246
+ outputs=output_components,
247
+ show_progress=False
248
+ )
249
+
250
+ all_load_outputs = []
251
+ for prefix in ["txt2img", "img2img", "inpaint", "outpaint", "hires_fix"]:
252
+ if f'controlnet_types_{prefix}' in ui_components:
253
+ all_load_outputs.extend(ui_components[f'controlnet_types_{prefix}'])
254
+ all_load_outputs.extend(ui_components[f'controlnet_series_{prefix}'])
255
+ all_load_outputs.extend(ui_components[f'controlnet_filepaths_{prefix}'])
256
+ if f'anima_controlnet_lllite_types_{prefix}' in ui_components:
257
+ all_load_outputs.extend(ui_components[f'anima_controlnet_lllite_types_{prefix}'])
258
+ all_load_outputs.extend(ui_components[f'anima_controlnet_lllite_series_{prefix}'])
259
+ all_load_outputs.extend(ui_components[f'anima_controlnet_lllite_filepaths_{prefix}'])
260
+ if f'diffsynth_controlnet_types_{prefix}' in ui_components:
261
+ all_load_outputs.extend(ui_components[f'diffsynth_controlnet_types_{prefix}'])
262
+ all_load_outputs.extend(ui_components[f'diffsynth_controlnet_series_{prefix}'])
263
+ all_load_outputs.extend(ui_components[f'diffsynth_controlnet_filepaths_{prefix}'])
264
+ if f'krea2_controlnet_types_{prefix}' in ui_components:
265
+ all_load_outputs.extend(ui_components[f'krea2_controlnet_types_{prefix}'])
266
+ all_load_outputs.extend(ui_components[f'krea2_controlnet_series_{prefix}'])
267
+ all_load_outputs.extend(ui_components[f'krea2_controlnet_filepaths_{prefix}'])
268
+ if f'ipadapter_final_preset_{prefix}' in ui_components:
269
+ all_load_outputs.extend(ui_components[f'ipadapter_lora_strengths_{prefix}'])
270
+ all_load_outputs.append(ui_components[f'ipadapter_final_preset_{prefix}'])
271
+ all_load_outputs.append(ui_components[f'ipadapter_final_lora_strength_{prefix}'])
272
+
273
+ if all_load_outputs:
274
+ demo.load(
275
+ fn=lambda: run_on_load(ui_components),
276
+ outputs=all_load_outputs
277
+ )
278
+
279
+ for prefix in ["txt2img", "img2img", "inpaint", "outpaint", "hires_fix"]:
280
+ aspect_ratio_dropdown = ui_components.get(f'aspect_ratio_{prefix}') or ui_components.get(f'{prefix}_aspect_ratio_dropdown')
281
+ width_component = ui_components.get(f'width_{prefix}') or ui_components.get(f'{prefix}_width')
282
+ height_component = ui_components.get(f'height_{prefix}') or ui_components.get(f'{prefix}_height')
283
+ model_dropdown = ui_components.get(f'base_model_{prefix}')
284
+ if aspect_ratio_dropdown and width_component and height_component and model_dropdown:
285
  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
@@ -54,6 +54,7 @@ def create_run_event(prefix: str, task_type: str, ui_components: dict):
54
  hidream_o1_reference_data_components = ui_components.get(f'all_hidream_o1_reference_components_flat_{prefix}', [])
55
  joyai_reference_data_components = ui_components.get(f'all_joyai_reference_components_flat_{prefix}', [])
56
  krea2_identity_edit_data_components = ui_components.get(f'all_krea2_identity_edit_components_flat_{prefix}', [])
 
57
  reference_image_data_components = ui_components.get(f'all_reference_image_components_flat_{prefix}', [])
58
 
59
  run_inputs_map['vae_source'] = ui_components.get(f'vae_source_{prefix}')
@@ -65,7 +66,7 @@ def create_run_event(prefix: str, task_type: str, ui_components: dict):
65
  all_chains = [
66
  lora_data_components, controlnet_data_components, anima_controlnet_lllite_data_components, diffsynth_controlnet_data_components, krea2_controlnet_data_components, ipadapter_data_components,
67
  sd3_ipadapter_data_components, flux1_ipadapter_data_components, style_data_components,
68
- embedding_data_components, conditioning_data_components, reference_latent_data_components, hidream_o1_reference_data_components, joyai_reference_data_components, krea2_identity_edit_data_components, reference_image_data_components
69
  ]
70
  for chain in all_chains:
71
  if chain:
@@ -97,6 +98,7 @@ def create_run_event(prefix: str, task_type: str, ui_components: dict):
97
  assign_chain_data('hidream_o1_reference_data', hidream_o1_reference_data_components)
98
  assign_chain_data('joyai_reference_data', joyai_reference_data_components)
99
  assign_chain_data('krea2_identity_edit_data', krea2_identity_edit_data_components)
 
100
  assign_chain_data('reference_image_data', reference_image_data_components)
101
 
102
  return ui_dict
 
54
  hidream_o1_reference_data_components = ui_components.get(f'all_hidream_o1_reference_components_flat_{prefix}', [])
55
  joyai_reference_data_components = ui_components.get(f'all_joyai_reference_components_flat_{prefix}', [])
56
  krea2_identity_edit_data_components = ui_components.get(f'all_krea2_identity_edit_components_flat_{prefix}', [])
57
+ qwen_image_edit_data_components = ui_components.get(f'all_qwen_image_edit_components_flat_{prefix}', [])
58
  reference_image_data_components = ui_components.get(f'all_reference_image_components_flat_{prefix}', [])
59
 
60
  run_inputs_map['vae_source'] = ui_components.get(f'vae_source_{prefix}')
 
66
  all_chains = [
67
  lora_data_components, controlnet_data_components, anima_controlnet_lllite_data_components, diffsynth_controlnet_data_components, krea2_controlnet_data_components, ipadapter_data_components,
68
  sd3_ipadapter_data_components, flux1_ipadapter_data_components, style_data_components,
69
+ embedding_data_components, conditioning_data_components, reference_latent_data_components, hidream_o1_reference_data_components, joyai_reference_data_components, krea2_identity_edit_data_components, qwen_image_edit_data_components, reference_image_data_components
70
  ]
71
  for chain in all_chains:
72
  if chain:
 
98
  assign_chain_data('hidream_o1_reference_data', hidream_o1_reference_data_components)
99
  assign_chain_data('joyai_reference_data', joyai_reference_data_components)
100
  assign_chain_data('krea2_identity_edit_data', krea2_identity_edit_data_components)
101
+ assign_chain_data('qwen_image_edit_data', qwen_image_edit_data_components)
102
  assign_chain_data('reference_image_data', reference_image_data_components)
103
 
104
  return ui_dict
ui/shared/hires_fix_ui.py CHANGED
@@ -7,7 +7,7 @@ from .ui_components import (
7
  create_conditioning_ui, create_vae_override_ui,
8
  create_model_architecture_filter_ui, create_category_filter_ui,
9
  create_sd3_ipadapter_ui, create_flux1_ipadapter_ui, create_style_ui,
10
- create_reference_latent_ui, create_hidream_o1_reference_ui, create_joyai_reference_ui, create_reference_image_ui, create_krea2_identity_edit_ui
11
  )
12
 
13
  default_vals = MODEL_DEFAULTS_CONFIG.get('Default', {})
@@ -103,6 +103,7 @@ def create_ui():
103
  components.update(create_hidream_o1_reference_ui(prefix))
104
  components.update(create_joyai_reference_ui(prefix))
105
  components.update(create_krea2_identity_edit_ui(prefix))
 
106
  components.update(create_reference_image_ui(prefix))
107
  components.update(create_vae_override_ui(prefix))
108
 
 
7
  create_conditioning_ui, create_vae_override_ui,
8
  create_model_architecture_filter_ui, create_category_filter_ui,
9
  create_sd3_ipadapter_ui, create_flux1_ipadapter_ui, create_style_ui,
10
+ create_reference_latent_ui, create_hidream_o1_reference_ui, create_joyai_reference_ui, create_reference_image_ui, create_krea2_identity_edit_ui, create_qwen_image_edit_ui
11
  )
12
 
13
  default_vals = MODEL_DEFAULTS_CONFIG.get('Default', {})
 
103
  components.update(create_hidream_o1_reference_ui(prefix))
104
  components.update(create_joyai_reference_ui(prefix))
105
  components.update(create_krea2_identity_edit_ui(prefix))
106
+ components.update(create_qwen_image_edit_ui(prefix))
107
  components.update(create_reference_image_ui(prefix))
108
  components.update(create_vae_override_ui(prefix))
109
 
ui/shared/img2img_ui.py CHANGED
@@ -7,7 +7,7 @@ from .ui_components import (
7
  create_conditioning_ui, create_vae_override_ui,
8
  create_model_architecture_filter_ui, create_category_filter_ui,
9
  create_sd3_ipadapter_ui, create_flux1_ipadapter_ui, create_style_ui,
10
- create_reference_latent_ui, create_hidream_o1_reference_ui, create_joyai_reference_ui, create_reference_image_ui, create_krea2_identity_edit_ui
11
  )
12
 
13
  default_vals = MODEL_DEFAULTS_CONFIG.get('Default', {})
@@ -84,6 +84,7 @@ def create_ui():
84
  components.update(create_hidream_o1_reference_ui(prefix))
85
  components.update(create_joyai_reference_ui(prefix))
86
  components.update(create_krea2_identity_edit_ui(prefix))
 
87
  components.update(create_reference_image_ui(prefix))
88
  components.update(create_vae_override_ui(prefix))
89
 
 
7
  create_conditioning_ui, create_vae_override_ui,
8
  create_model_architecture_filter_ui, create_category_filter_ui,
9
  create_sd3_ipadapter_ui, create_flux1_ipadapter_ui, create_style_ui,
10
+ create_reference_latent_ui, create_hidream_o1_reference_ui, create_joyai_reference_ui, create_reference_image_ui, create_krea2_identity_edit_ui, create_qwen_image_edit_ui
11
  )
12
 
13
  default_vals = MODEL_DEFAULTS_CONFIG.get('Default', {})
 
84
  components.update(create_hidream_o1_reference_ui(prefix))
85
  components.update(create_joyai_reference_ui(prefix))
86
  components.update(create_krea2_identity_edit_ui(prefix))
87
+ components.update(create_qwen_image_edit_ui(prefix))
88
  components.update(create_reference_image_ui(prefix))
89
  components.update(create_vae_override_ui(prefix))
90
 
ui/shared/inpaint_ui.py CHANGED
@@ -6,7 +6,7 @@ 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, create_joyai_reference_ui, create_reference_image_ui, create_krea2_identity_edit_ui
10
  )
11
 
12
  default_vals = MODEL_DEFAULTS_CONFIG.get('Default', {})
@@ -116,6 +116,7 @@ def create_ui():
116
  components.update(create_hidream_o1_reference_ui(prefix))
117
  components.update(create_joyai_reference_ui(prefix))
118
  components.update(create_krea2_identity_edit_ui(prefix))
 
119
  components.update(create_reference_image_ui(prefix))
120
  components.update(create_vae_override_ui(prefix))
121
  components[f'accordion_wrapper_{prefix}'] = accordion_wrapper
 
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, create_joyai_reference_ui, create_reference_image_ui, create_krea2_identity_edit_ui, create_qwen_image_edit_ui
10
  )
11
 
12
  default_vals = MODEL_DEFAULTS_CONFIG.get('Default', {})
 
116
  components.update(create_hidream_o1_reference_ui(prefix))
117
  components.update(create_joyai_reference_ui(prefix))
118
  components.update(create_krea2_identity_edit_ui(prefix))
119
+ components.update(create_qwen_image_edit_ui(prefix))
120
  components.update(create_reference_image_ui(prefix))
121
  components.update(create_vae_override_ui(prefix))
122
  components[f'accordion_wrapper_{prefix}'] = accordion_wrapper
ui/shared/outpaint_ui.py CHANGED
@@ -7,7 +7,7 @@ from .ui_components import (
7
  create_conditioning_ui, create_vae_override_ui,
8
  create_model_architecture_filter_ui, create_category_filter_ui,
9
  create_sd3_ipadapter_ui, create_flux1_ipadapter_ui, create_style_ui,
10
- create_reference_latent_ui, create_hidream_o1_reference_ui, create_joyai_reference_ui, create_reference_image_ui, create_krea2_identity_edit_ui
11
  )
12
 
13
  default_vals = MODEL_DEFAULTS_CONFIG.get('Default', {})
@@ -99,6 +99,7 @@ def create_ui():
99
  components.update(create_hidream_o1_reference_ui(prefix))
100
  components.update(create_joyai_reference_ui(prefix))
101
  components.update(create_krea2_identity_edit_ui(prefix))
 
102
  components.update(create_reference_image_ui(prefix))
103
  components.update(create_vae_override_ui(prefix))
104
 
 
7
  create_conditioning_ui, create_vae_override_ui,
8
  create_model_architecture_filter_ui, create_category_filter_ui,
9
  create_sd3_ipadapter_ui, create_flux1_ipadapter_ui, create_style_ui,
10
+ create_reference_latent_ui, create_hidream_o1_reference_ui, create_joyai_reference_ui, create_reference_image_ui, create_krea2_identity_edit_ui, create_qwen_image_edit_ui
11
  )
12
 
13
  default_vals = MODEL_DEFAULTS_CONFIG.get('Default', {})
 
99
  components.update(create_hidream_o1_reference_ui(prefix))
100
  components.update(create_joyai_reference_ui(prefix))
101
  components.update(create_krea2_identity_edit_ui(prefix))
102
+ components.update(create_qwen_image_edit_ui(prefix))
103
  components.update(create_reference_image_ui(prefix))
104
  components.update(create_vae_override_ui(prefix))
105
 
ui/shared/txt2img_ui.py CHANGED
@@ -6,7 +6,7 @@ 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, create_joyai_reference_ui, create_reference_image_ui, create_krea2_identity_edit_ui,
10
  create_pid_ui
11
  )
12
 
@@ -56,6 +56,7 @@ def create_ui():
56
  components.update(create_hidream_o1_reference_ui(prefix))
57
  components.update(create_joyai_reference_ui(prefix))
58
  components.update(create_krea2_identity_edit_ui(prefix))
 
59
  components.update(create_reference_image_ui(prefix))
60
  components.update(create_vae_override_ui(prefix))
61
  components.update(create_pid_ui(prefix))
 
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, create_joyai_reference_ui, create_reference_image_ui, create_krea2_identity_edit_ui, create_qwen_image_edit_ui,
10
  create_pid_ui
11
  )
12
 
 
56
  components.update(create_hidream_o1_reference_ui(prefix))
57
  components.update(create_joyai_reference_ui(prefix))
58
  components.update(create_krea2_identity_edit_ui(prefix))
59
+ components.update(create_qwen_image_edit_ui(prefix))
60
  components.update(create_reference_image_ui(prefix))
61
  components.update(create_vae_override_ui(prefix))
62
  components.update(create_pid_ui(prefix))
ui/shared/ui_components.py CHANGED
@@ -798,4 +798,33 @@ def create_krea2_identity_edit_ui(prefix: str, max_units=2):
798
 
799
  components[key('all_krea2_identity_edit_components_flat')] = ref_image_inputs
800
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
801
  return components
 
798
 
799
  components[key('all_krea2_identity_edit_components_flat')] = ref_image_inputs
800
 
801
+ return components
802
+
803
+ def create_qwen_image_edit_ui(prefix: str, max_units=3):
804
+ components = {}
805
+ key = lambda name: f"{name}_{prefix}"
806
+
807
+ with gr.Accordion("Qwen-Image Edit Settings", open=False, visible=('qwen_image_edit' in default_enabled_chains)) as ref_accordion:
808
+ components[key('qwen_image_edit_accordion')] = ref_accordion
809
+ gr.Markdown("💡 **Tip:** (lightx2v/Qwen-Image-Edit-2511-Lightning recommended) In txt2img mode, adding a single reference image performs an **Image Edit**, while adding multiple images performs an **Image Combine**.")
810
+
811
+ ref_image_groups = []
812
+ ref_image_inputs = []
813
+ with gr.Row():
814
+ for i in range(max_units):
815
+ with gr.Column(visible=(i < 1), min_width=160) as img_col:
816
+ img_comp = gr.Image(type="pil", label=f"Ref. {i+1}", sources=["upload"], height=150)
817
+ ref_image_groups.append(img_col)
818
+ ref_image_inputs.append(img_comp)
819
+
820
+ components[key('qwen_image_edit_rows')] = ref_image_groups
821
+ components[key('qwen_image_edit_images')] = ref_image_inputs
822
+
823
+ with gr.Row():
824
+ components[key('add_qwen_image_edit_button')] = gr.Button("✚ Add Reference Image")
825
+ components[key('delete_qwen_image_edit_button')] = gr.Button("➖ Delete Reference Image", visible=False)
826
+ components[key('qwen_image_edit_count_state')] = gr.State(1)
827
+
828
+ components[key('all_qwen_image_edit_components_flat')] = ref_image_inputs
829
+
830
  return components
yaml/file_list.yaml CHANGED
@@ -590,6 +590,10 @@ file:
590
  repo_id: "Comfy-Org/z_image"
591
  repository_file_path: "split_files/diffusion_models/z_image_bf16.safetensors"
592
  # Qwen-Image
 
 
 
 
593
  - filename: "qwen_image_2512_fp8_e4m3fn.safetensors"
594
  source: "hf"
595
  repo_id: "Comfy-Org/Qwen-Image_ComfyUI"
@@ -598,6 +602,23 @@ file:
598
  source: "hf"
599
  repo_id: "Comfy-Org/Qwen-Image_ComfyUI"
600
  repository_file_path: "split_files/diffusion_models/qwen_image_nvfp4.safetensors"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
601
  # Kandinsky-5
602
  - filename: "kandinsky5lite_t2i.safetensors"
603
  source: "hf"
 
590
  repo_id: "Comfy-Org/z_image"
591
  repository_file_path: "split_files/diffusion_models/z_image_bf16.safetensors"
592
  # Qwen-Image
593
+ - filename: "qwen_image_2512_fp8_e4m3fn_scaled_comfyui_4steps_v1.0.safetensors"
594
+ source: "hf"
595
+ repo_id: "lightx2v/Qwen-Image-2512-Lightning"
596
+ repository_file_path: "qwen_image_2512_fp8_e4m3fn_scaled_comfyui_4steps_v1.0.safetensors"
597
  - filename: "qwen_image_2512_fp8_e4m3fn.safetensors"
598
  source: "hf"
599
  repo_id: "Comfy-Org/Qwen-Image_ComfyUI"
 
602
  source: "hf"
603
  repo_id: "Comfy-Org/Qwen-Image_ComfyUI"
604
  repository_file_path: "split_files/diffusion_models/qwen_image_nvfp4.safetensors"
605
+ # Qwen-Image-Edit
606
+ - filename: "qwen_image_edit_2511_fp8_e4m3fn_scaled_lightning_comfyui_4steps_v1.0.safetensors"
607
+ source: "hf"
608
+ repo_id: "lightx2v/Qwen-Image-Edit-2511-Lightning"
609
+ repository_file_path: "qwen_image_edit_2511_fp8_e4m3fn_scaled_lightning_comfyui_4steps_v1.0.safetensors"
610
+ - filename: "qwen_image_edit_2511_int8_convrot.safetensors"
611
+ source: "hf"
612
+ repo_id: "Comfy-Org/Qwen-Image-Edit_ComfyUI"
613
+ repository_file_path: "split_files/diffusion_models/qwen_image_edit_2511_int8_convrot.safetensors"
614
+ - filename: "qwen_image_edit_2509_fp8mixed.safetensors"
615
+ source: "hf"
616
+ repo_id: "Comfy-Org/Qwen-Image-Edit_ComfyUI"
617
+ repository_file_path: "split_files/diffusion_models/qwen_image_edit_2509_fp8mixed.safetensors"
618
+ - filename: "qwen_image_edit_fp8_e4m3fn.safetensors"
619
+ source: "hf"
620
+ repo_id: "Comfy-Org/Qwen-Image-Edit_ComfyUI"
621
+ repository_file_path: "split_files/diffusion_models/qwen_image_edit_fp8_e4m3fn.safetensors"
622
  # Kandinsky-5
623
  - filename: "kandinsky5lite_t2i.safetensors"
624
  source: "hf"
yaml/image_gen_features.yaml CHANGED
@@ -77,6 +77,7 @@ qwen-image:
77
  - lora
78
  - controlnet
79
  - conditioning
 
80
  - vae
81
  - pid
82
 
 
77
  - lora
78
  - controlnet
79
  - conditioning
80
+ - qwen_image_edit
81
  - vae
82
  - pid
83
 
yaml/injectors.yaml CHANGED
@@ -33,6 +33,8 @@ injector_definitions:
33
  module: "chain_injectors.joyai_reference_injector"
34
  dynamic_krea2_identity_edit_chains:
35
  module: "chain_injectors.krea2_identity_edit_injector"
 
 
36
  dynamic_reference_image_chains:
37
  module: "chain_injectors.reference_image_injector"
38
  dynamic_pid_chains:
@@ -52,6 +54,7 @@ injector_order:
52
  - dynamic_controlnet_chains
53
  - dynamic_krea2_controlnet_chains
54
  - dynamic_krea2_identity_edit_chains
 
55
  - dynamic_anima_controlnet_lllite_chains
56
  - dynamic_hidream_o1_smoothing_chains
57
  - dynamic_hidream_o1_reference_chains
 
33
  module: "chain_injectors.joyai_reference_injector"
34
  dynamic_krea2_identity_edit_chains:
35
  module: "chain_injectors.krea2_identity_edit_injector"
36
+ dynamic_qwen_image_edit_chains:
37
+ module: "chain_injectors.qwen_image_edit_injector"
38
  dynamic_reference_image_chains:
39
  module: "chain_injectors.reference_image_injector"
40
  dynamic_pid_chains:
 
54
  - dynamic_controlnet_chains
55
  - dynamic_krea2_controlnet_chains
56
  - dynamic_krea2_identity_edit_chains
57
+ - dynamic_qwen_image_edit_chains
58
  - dynamic_anima_controlnet_lllite_chains
59
  - dynamic_hidream_o1_smoothing_chains
60
  - dynamic_hidream_o1_reference_chains
yaml/model_defaults.yaml CHANGED
@@ -125,6 +125,12 @@ Qwen-Image:
125
  cfg: 4.0
126
  sampler_name: "euler"
127
  scheduler: "simple"
 
 
 
 
 
 
128
 
129
  LongCat-Image:
130
  _defaults:
 
125
  cfg: 4.0
126
  sampler_name: "euler"
127
  scheduler: "simple"
128
+ "lightx2v/Qwen-Image-2512-Lightning":
129
+ steps: 4
130
+ cfg: 1.0
131
+ "lightx2v/Qwen-Image-Edit-2511-Lightning":
132
+ steps: 4
133
+ cfg: 1.0
134
 
135
  LongCat-Image:
136
  _defaults:
yaml/model_list.yaml CHANGED
@@ -156,6 +156,11 @@ Checkpoint:
156
  Qwen-Image:
157
  latent_type: sd3_latent
158
  models:
 
 
 
 
 
159
  - display_name: "Qwen-Image-2512"
160
  components:
161
  unet: "qwen_image_2512_fp8_e4m3fn.safetensors"
@@ -166,6 +171,26 @@ Checkpoint:
166
  unet: "qwen_image_nvfp4.safetensors"
167
  vae: "qwen_image_vae.safetensors"
168
  clip: "qwen_2.5_vl_7b_nvfp4.safetensors"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  LongCat-Image:
170
  latent_type: sd3_latent
171
  models:
 
156
  Qwen-Image:
157
  latent_type: sd3_latent
158
  models:
159
+ - display_name: "lightx2v/Qwen-Image-2512-Lightning"
160
+ components:
161
+ unet: "qwen_image_2512_fp8_e4m3fn_scaled_comfyui_4steps_v1.0.safetensors"
162
+ vae: "qwen_image_vae.safetensors"
163
+ clip: "qwen_2.5_vl_7b_nvfp4.safetensors"
164
  - display_name: "Qwen-Image-2512"
165
  components:
166
  unet: "qwen_image_2512_fp8_e4m3fn.safetensors"
 
171
  unet: "qwen_image_nvfp4.safetensors"
172
  vae: "qwen_image_vae.safetensors"
173
  clip: "qwen_2.5_vl_7b_nvfp4.safetensors"
174
+ - display_name: "lightx2v/Qwen-Image-Edit-2511-Lightning"
175
+ components:
176
+ unet: "qwen_image_edit_2511_fp8_e4m3fn_scaled_lightning_comfyui_4steps_v1.0.safetensors"
177
+ vae: "qwen_image_vae.safetensors"
178
+ clip: "qwen_2.5_vl_7b_nvfp4.safetensors"
179
+ - display_name: "Qwen-Image-Edit-2511"
180
+ components:
181
+ unet: "qwen_image_edit_2511_int8_convrot.safetensors"
182
+ vae: "qwen_image_vae.safetensors"
183
+ clip: "qwen_2.5_vl_7b_nvfp4.safetensors"
184
+ - display_name: "Qwen-Image-Edit-2509"
185
+ components:
186
+ unet: "qwen_image_edit_2509_fp8mixed.safetensors"
187
+ vae: "qwen_image_vae.safetensors"
188
+ clip: "qwen_2.5_vl_7b_nvfp4.safetensors"
189
+ - display_name: "Qwen-Image-Edit"
190
+ components:
191
+ unet: "qwen_image_edit_fp8_e4m3fn.safetensors"
192
+ vae: "qwen_image_vae.safetensors"
193
+ clip: "qwen_2.5_vl_7b_nvfp4.safetensors"
194
  LongCat-Image:
195
  latent_type: sd3_latent
196
  models: