RioShiina commited on
Commit
f5f1678
·
verified ·
1 Parent(s): 7ea42fe

Upload folder using huggingface_hub

Browse files
core/pipelines/pipeline_input_processor.py CHANGED
@@ -1,335 +1,335 @@
1
- import os
2
- import random
3
- import numpy as np
4
- import gradio as gr
5
- from PIL import Image, ImageChops
6
- from typing import Dict, Any, List
7
-
8
- from core.settings import INPUT_DIR
9
- from utils.app_utils import (
10
- sanitize_filename,
11
- get_lora_path,
12
- get_embedding_path,
13
- ensure_controlnet_model_downloaded,
14
- ensure_ipadapter_models_downloaded,
15
- _ensure_model_downloaded,
16
- ensure_sd3_ipadapter_models_downloaded,
17
- get_vae_path,
18
- )
19
-
20
- def process_pipeline_inputs(ui_inputs: Dict[str, Any], progress: gr.Progress, workflow_model_type: str) -> Dict[str, Any]:
21
- task_type = ui_inputs['task_type']
22
- temp_files_to_clean = []
23
-
24
- lora_data = ui_inputs.get('lora_data', [])
25
- active_loras_for_gpu, active_loras_for_meta = [], []
26
- if lora_data:
27
- sources, ids, scales, files = lora_data[0::4], lora_data[1::4], lora_data[2::4], lora_data[3::4]
28
- for i, (source, lora_id, scale, _) in enumerate(zip(sources, ids, scales, files)):
29
- if scale > 0 and lora_id and lora_id.strip():
30
- lora_filename = None
31
- if source == "File":
32
- lora_filename = sanitize_filename(lora_id)
33
- elif source == "Civitai":
34
- local_path, status = get_lora_path(source, lora_id, os.environ.get("CIVITAI_API_KEY", ""), progress)
35
- if local_path: lora_filename = os.path.basename(local_path)
36
- else: raise gr.Error(f"Failed to prepare LoRA {lora_id}: {status}")
37
-
38
- if lora_filename:
39
- active_loras_for_gpu.append({"lora_name": lora_filename, "strength_model": scale, "strength_clip": scale})
40
- active_loras_for_meta.append(f"{source} {lora_id}:{scale}")
41
-
42
- ui_inputs['denoise'] = 1.0
43
- if task_type == 'img2img': ui_inputs['denoise'] = ui_inputs.get('img2img_denoise', 0.7)
44
- elif task_type == 'hires_fix': ui_inputs['denoise'] = ui_inputs.get('hires_denoise', 0.55)
45
- elif task_type == 'inpaint': ui_inputs['denoise'] = ui_inputs.get('inpaint_denoise', 1.0)
46
-
47
- if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
48
-
49
- if task_type == 'img2img':
50
- input_image_pil = ui_inputs.get('img2img_image')
51
- if not input_image_pil:
52
- raise gr.Error("Please upload an image for Image-to-Image.")
53
- temp_file_path = os.path.join(INPUT_DIR, f"temp_input_{random.randint(1000, 9999)}.png")
54
- input_image_pil.save(temp_file_path, "PNG")
55
- ui_inputs['input_image'] = os.path.basename(temp_file_path)
56
- temp_files_to_clean.append(temp_file_path)
57
- ui_inputs['width'] = input_image_pil.width
58
- ui_inputs['height'] = input_image_pil.height
59
-
60
- elif task_type == 'inpaint':
61
- inpaint_dict = ui_inputs.get('inpaint_image_dict')
62
- if not inpaint_dict or not inpaint_dict.get('background') or not inpaint_dict.get('layers'):
63
- raise gr.Error("Inpainting requires an input image and a drawn mask.")
64
-
65
- background_img = inpaint_dict['background'].convert("RGBA")
66
- composite_mask_pil = Image.new('L', background_img.size, 0)
67
- for layer in inpaint_dict['layers']:
68
- if layer:
69
- layer_alpha = layer.split()[-1]
70
- composite_mask_pil = ImageChops.lighter(composite_mask_pil, layer_alpha)
71
-
72
- inverted_mask_alpha = Image.fromarray(255 - np.array(composite_mask_pil), mode='L')
73
- r, g, b, _ = background_img.split()
74
- composite_image_with_mask = Image.merge('RGBA', [r, g, b, inverted_mask_alpha])
75
-
76
- temp_file_path = os.path.join(INPUT_DIR, f"temp_inpaint_composite_{random.randint(1000, 9999)}.png")
77
- composite_image_with_mask.save(temp_file_path, "PNG")
78
-
79
- ui_inputs['input_image'] = os.path.basename(temp_file_path)
80
- temp_files_to_clean.append(temp_file_path)
81
- ui_inputs.pop('inpaint_mask', None)
82
-
83
- elif task_type == 'outpaint':
84
- input_image_pil = ui_inputs.get('outpaint_image')
85
- if not input_image_pil:
86
- raise gr.Error("Please upload an image for Outpainting.")
87
- temp_file_path = os.path.join(INPUT_DIR, f"temp_input_{random.randint(1000, 9999)}.png")
88
- input_image_pil.save(temp_file_path, "PNG")
89
- ui_inputs['input_image'] = os.path.basename(temp_file_path)
90
- temp_files_to_clean.append(temp_file_path)
91
-
92
- ui_inputs['megapixels'] = 0.25
93
- ui_inputs['grow_mask_by'] = ui_inputs.get('feathering', 10)
94
-
95
- elif task_type == 'hires_fix':
96
- input_image_pil = ui_inputs.get('hires_image')
97
- if not input_image_pil:
98
- raise gr.Error("Please upload an image for Hires Fix.")
99
- temp_file_path = os.path.join(INPUT_DIR, f"temp_input_{random.randint(1000, 9999)}.png")
100
- input_image_pil.save(temp_file_path, "PNG")
101
- ui_inputs['input_image'] = os.path.basename(temp_file_path)
102
- temp_files_to_clean.append(temp_file_path)
103
-
104
- embedding_data = ui_inputs.get('embedding_data', [])
105
- embedding_filenames = []
106
- if embedding_data:
107
- emb_sources, emb_ids, emb_files = embedding_data[0::3], embedding_data[1::3], embedding_data[2::3]
108
- for i, (source, emb_id, _) in enumerate(zip(emb_sources, emb_ids, emb_files)):
109
- if emb_id and emb_id.strip():
110
- emb_filename = None
111
- if source == "File":
112
- emb_filename = sanitize_filename(emb_id)
113
- elif source == "Civitai":
114
- local_path, status = get_embedding_path(source, emb_id, os.environ.get("CIVITAI_API_KEY", ""), progress)
115
- if local_path: emb_filename = os.path.basename(local_path)
116
- else: raise gr.Error(f"Failed to prepare Embedding {emb_id}: {status}")
117
-
118
- if emb_filename:
119
- embedding_filenames.append(emb_filename)
120
-
121
- if embedding_filenames:
122
- embedding_prompt_text = " ".join([f"embedding:{f}" for f in embedding_filenames])
123
- if ui_inputs['positive_prompt']:
124
- ui_inputs['positive_prompt'] = f"{ui_inputs['positive_prompt']}, {embedding_prompt_text}"
125
- else:
126
- ui_inputs['positive_prompt'] = embedding_prompt_text
127
-
128
- controlnet_data = ui_inputs.get('controlnet_data', [])
129
- active_controlnets = []
130
- if controlnet_data:
131
- (cn_images, _, _, cn_strengths, cn_filepaths) = [controlnet_data[i::5] for i in range(5)]
132
- for i in range(len(cn_images)):
133
- if cn_images[i] and cn_strengths[i] > 0 and cn_filepaths[i] and cn_filepaths[i] != "None":
134
- ensure_controlnet_model_downloaded(cn_filepaths[i], progress)
135
- if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
136
- cn_temp_path = os.path.join(INPUT_DIR, f"temp_cn_{i}_{random.randint(1000, 9999)}.png")
137
- cn_images[i].save(cn_temp_path, "PNG")
138
- temp_files_to_clean.append(cn_temp_path)
139
- active_controlnets.append({
140
- "image": os.path.basename(cn_temp_path), "strength": cn_strengths[i],
141
- "start_percent": 0.0, "end_percent": 1.0, "control_net_name": cn_filepaths[i]
142
- })
143
-
144
- anima_controlnet_lllite_data = ui_inputs.get('anima_controlnet_lllite_data', [])
145
- active_anima_controlnets = []
146
- if anima_controlnet_lllite_data:
147
- (cn_images, _, _, cn_strengths, cn_filepaths, cn_starts, cn_ends) = [anima_controlnet_lllite_data[i::7] for i in range(7)]
148
- for i in range(len(cn_images)):
149
- if cn_images[i] and cn_strengths[i] > 0 and cn_filepaths[i] and cn_filepaths[i] != "None":
150
- _ensure_model_downloaded(cn_filepaths[i], progress)
151
- if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
152
- cn_temp_path = os.path.join(INPUT_DIR, f"temp_anima_cn_{i}_{random.randint(1000, 9999)}.png")
153
- cn_images[i].save(cn_temp_path, "PNG")
154
- temp_files_to_clean.append(cn_temp_path)
155
- active_anima_controlnets.append({
156
- "image": os.path.basename(cn_temp_path), "strength": cn_strengths[i],
157
- "start_percent": cn_starts[i], "end_percent": cn_ends[i], "control_net_name": cn_filepaths[i]
158
- })
159
-
160
- diffsynth_controlnet_data = ui_inputs.get('diffsynth_controlnet_data', [])
161
- active_diffsynth_controlnets = []
162
- if diffsynth_controlnet_data:
163
- (cn_images, _, _, cn_strengths, cn_filepaths) = [diffsynth_controlnet_data[i::5] for i in range(5)]
164
- for i in range(len(cn_images)):
165
- if cn_images[i] and cn_strengths[i] > 0 and cn_filepaths[i] and cn_filepaths[i] != "None":
166
- ensure_controlnet_model_downloaded(cn_filepaths[i], progress)
167
- if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
168
- cn_temp_path = os.path.join(INPUT_DIR, f"temp_diffsynth_cn_{i}_{random.randint(1000, 9999)}.png")
169
- cn_images[i].save(cn_temp_path, "PNG")
170
- temp_files_to_clean.append(cn_temp_path)
171
- active_diffsynth_controlnets.append({
172
- "image": os.path.basename(cn_temp_path), "strength": cn_strengths[i],
173
- "control_net_name": cn_filepaths[i]
174
- })
175
-
176
- ipadapter_data = ui_inputs.get('ipadapter_data', [])
177
- active_ipadapters = []
178
- if ipadapter_data:
179
- num_ipa_units = (len(ipadapter_data) - 5) // 3
180
- final_preset, final_weight, final_lora_strength, final_embeds_scaling, final_combine_method = ipadapter_data[-5:]
181
- ipa_images, ipa_weights, ipa_lora_strengths = [ipadapter_data[i*num_ipa_units:(i+1)*num_ipa_units] for i in range(3)]
182
- all_presets_to_download = set()
183
- for i in range(num_ipa_units):
184
- if ipa_images[i] and ipa_weights[i] > 0 and final_preset:
185
- all_presets_to_download.add(final_preset)
186
- if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
187
- ipa_temp_path = os.path.join(INPUT_DIR, f"temp_ipa_{i}_{random.randint(1000, 9999)}.png")
188
- ipa_images[i].save(ipa_temp_path, "PNG")
189
- temp_files_to_clean.append(ipa_temp_path)
190
- active_ipadapters.append({
191
- "image": os.path.basename(ipa_temp_path), "preset": final_preset,
192
- "weight": ipa_weights[i], "lora_strength": ipa_lora_strengths[i]
193
- })
194
- if active_ipadapters and final_preset:
195
- all_presets_to_download.add(final_preset)
196
- for preset in all_presets_to_download:
197
- ensure_ipadapter_models_downloaded(preset, progress)
198
-
199
- model_type_key = 'sd15' if workflow_model_type == 'sd15' else 'sdxl'
200
- if active_ipadapters:
201
- active_ipadapters.append({
202
- 'is_final_settings': True, 'model_type': model_type_key, 'final_preset': final_preset,
203
- 'final_weight': final_weight, 'final_lora_strength': final_lora_strength,
204
- 'final_embeds_scaling': final_embeds_scaling, 'final_combine_method': final_combine_method
205
- })
206
-
207
- flux1_ipadapter_data = ui_inputs.get('flux1_ipadapter_data', [])
208
- active_flux1_ipadapters = []
209
- if flux1_ipadapter_data:
210
- num_units = len(flux1_ipadapter_data) // 4
211
- f_images = flux1_ipadapter_data[0*num_units : 1*num_units]
212
- f_weights = flux1_ipadapter_data[1*num_units : 2*num_units]
213
- f_starts = flux1_ipadapter_data[2*num_units : 3*num_units]
214
- f_ends = flux1_ipadapter_data[3*num_units : 4*num_units]
215
- for i in range(len(f_images)):
216
- if f_images[i] and f_weights[i] > 0:
217
- for filename in ["ip-adapter.bin"]:
218
- _ensure_model_downloaded(filename, progress)
219
-
220
- from huggingface_hub import snapshot_download
221
- progress(0.5, desc="Caching HF SigLIP model...")
222
- snapshot_download(
223
- repo_id="google/siglip-so400m-patch14-384",
224
- allow_patterns=["*.json", "*.safetensors", "*.txt"],
225
- ignore_patterns=["*.msgpack", "*.h5", "*.bin"]
226
- )
227
-
228
- temp_path = os.path.join(INPUT_DIR, f"temp_fipa_{i}_{random.randint(1000, 9999)}.png")
229
- f_images[i].save(temp_path, "PNG")
230
- temp_files_to_clean.append(temp_path)
231
- active_flux1_ipadapters.append({
232
- "image": os.path.basename(temp_path),
233
- "weight": f_weights[i], "start_percent": f_starts[i], "end_percent": f_ends[i]
234
- })
235
-
236
- sd3_ipadapter_data = ui_inputs.get('sd3_ipadapter_chain', [])
237
- active_sd3_ipadapters = []
238
- if sd3_ipadapter_data:
239
- num_units = len(sd3_ipadapter_data) // 4
240
- s_images = sd3_ipadapter_data[0*num_units : 1*num_units]
241
- s_weights = sd3_ipadapter_data[1*num_units : 2*num_units]
242
- s_starts = sd3_ipadapter_data[2*num_units : 3*num_units]
243
- s_ends = sd3_ipadapter_data[3*num_units : 4*num_units]
244
- sd3_ipa_downloaded = False
245
- for i in range(len(s_images)):
246
- if s_images[i] and s_weights[i] > 0:
247
- if not sd3_ipa_downloaded:
248
- ensure_sd3_ipadapter_models_downloaded(progress)
249
- sd3_ipa_downloaded = True
250
- temp_path = os.path.join(INPUT_DIR, f"temp_s3ipa_{i}_{random.randint(1000, 9999)}.png")
251
- s_images[i].save(temp_path, "PNG")
252
- temp_files_to_clean.append(temp_path)
253
- active_sd3_ipadapters.append({
254
- "image": os.path.basename(temp_path),
255
- "weight": s_weights[i], "start_percent": s_starts[i], "end_percent": s_ends[i]
256
- })
257
-
258
- style_data = ui_inputs.get('style_data', [])
259
- active_styles = []
260
- if style_data:
261
- num_units = len(style_data) // 2
262
- st_images = style_data[0*num_units : 1*num_units]
263
- st_strengths = style_data[1*num_units : 2*num_units]
264
- for i in range(len(st_images)):
265
- if st_images[i] and st_strengths[i] > 0:
266
- _ensure_model_downloaded("sigclip_vision_patch14_384.safetensors", progress)
267
- temp_path = os.path.join(INPUT_DIR, f"temp_style_{i}_{random.randint(1000, 9999)}.png")
268
- st_images[i].save(temp_path, "PNG")
269
- temp_files_to_clean.append(temp_path)
270
- active_styles.append({
271
- "image": os.path.basename(temp_path), "strength": st_strengths[i]
272
- })
273
-
274
- reference_latent_data = ui_inputs.get('reference_latent_data', [])
275
- active_reference_latents = []
276
- if reference_latent_data:
277
- for img in reference_latent_data:
278
- if img:
279
- if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
280
- temp_path = os.path.join(INPUT_DIR, f"temp_ref_{random.randint(1000, 9999)}.png")
281
- img.save(temp_path, "PNG")
282
- temp_files_to_clean.append(temp_path)
283
- active_reference_latents.append(os.path.basename(temp_path))
284
-
285
- hidream_o1_reference_data = ui_inputs.get('hidream_o1_reference_data', [])
286
- active_hidream_o1_reference = []
287
- if hidream_o1_reference_data:
288
- for img in hidream_o1_reference_data:
289
- if img:
290
- if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
291
- temp_path = os.path.join(INPUT_DIR, f"temp_ho1_ref_{random.randint(1000, 9999)}.png")
292
- img.save(temp_path, "PNG")
293
- temp_files_to_clean.append(temp_path)
294
- active_hidream_o1_reference.append(os.path.basename(temp_path))
295
-
296
- vae_source = ui_inputs.get('vae_source')
297
- vae_id = ui_inputs.get('vae_id')
298
- vae_name_override = None
299
- if vae_source and vae_source != "None":
300
- if vae_source == "File":
301
- vae_name_override = sanitize_filename(vae_id)
302
- elif vae_source == "Civitai" and vae_id and vae_id.strip():
303
- local_path, status = get_vae_path(vae_source, vae_id, os.environ.get("CIVITAI_API_KEY", ""), progress)
304
- if local_path: vae_name_override = os.path.basename(local_path)
305
- else: raise gr.Error(f"Failed to prepare VAE {vae_id}: {status}")
306
- if vae_name_override:
307
- ui_inputs['vae_name'] = vae_name_override
308
-
309
- conditioning_data = ui_inputs.get('conditioning_data', [])
310
- active_conditioning = []
311
- if conditioning_data:
312
- num_units = len(conditioning_data) // 6
313
- prompts, widths, heights, xs, ys, strengths = [conditioning_data[i*num_units : (i+1)*num_units] for i in range(6)]
314
- for i in range(num_units):
315
- if prompts[i] and prompts[i].strip():
316
- active_conditioning.append({
317
- "prompt": prompts[i], "width": int(widths[i]), "height": int(heights[i]),
318
- "x": int(xs[i]), "y": int(ys[i]), "strength": float(strengths[i])
319
- })
320
-
321
- return {
322
- "active_loras_for_gpu": active_loras_for_gpu,
323
- "active_loras_for_meta": active_loras_for_meta,
324
- "active_controlnets": active_controlnets,
325
- "active_anima_controlnets": active_anima_controlnets,
326
- "active_diffsynth_controlnets": active_diffsynth_controlnets,
327
- "active_ipadapters": active_ipadapters,
328
- "active_flux1_ipadapters": active_flux1_ipadapters,
329
- "active_sd3_ipadapters": active_sd3_ipadapters,
330
- "active_styles": active_styles,
331
- "active_reference_latents": active_reference_latents,
332
- "active_hidream_o1_reference": active_hidream_o1_reference,
333
- "active_conditioning": active_conditioning,
334
- "temp_files_to_clean": temp_files_to_clean
335
  }
 
1
+ import os
2
+ import random
3
+ import numpy as np
4
+ import gradio as gr
5
+ from PIL import Image, ImageChops
6
+ from typing import Dict, Any, List
7
+
8
+ from core.settings import INPUT_DIR
9
+ from utils.app_utils import (
10
+ sanitize_filename,
11
+ get_lora_path,
12
+ get_embedding_path,
13
+ ensure_controlnet_model_downloaded,
14
+ ensure_ipadapter_models_downloaded,
15
+ _ensure_model_downloaded,
16
+ ensure_sd3_ipadapter_models_downloaded,
17
+ get_vae_path,
18
+ )
19
+
20
+ def process_pipeline_inputs(ui_inputs: Dict[str, Any], progress: gr.Progress, workflow_model_type: str) -> Dict[str, Any]:
21
+ task_type = ui_inputs['task_type']
22
+ temp_files_to_clean = []
23
+
24
+ lora_data = ui_inputs.get('lora_data', [])
25
+ active_loras_for_gpu, active_loras_for_meta = [], []
26
+ if lora_data:
27
+ sources, ids, scales, files = lora_data[0::4], lora_data[1::4], lora_data[2::4], lora_data[3::4]
28
+ for i, (source, lora_id, scale, _) in enumerate(zip(sources, ids, scales, files)):
29
+ if scale > 0 and lora_id and lora_id.strip():
30
+ lora_filename = None
31
+ if source == "File":
32
+ lora_filename = sanitize_filename(lora_id)
33
+ elif source in ("Civitai", "Hugging Face"):
34
+ local_path, status = get_lora_path(source, lora_id, os.environ.get("CIVITAI_API_KEY", ""), progress)
35
+ if local_path: lora_filename = os.path.basename(local_path)
36
+ else: raise gr.Error(f"Failed to prepare LoRA {lora_id}: {status}")
37
+
38
+ if lora_filename:
39
+ active_loras_for_gpu.append({"lora_name": lora_filename, "strength_model": scale, "strength_clip": scale})
40
+ active_loras_for_meta.append(f"{source} {lora_id}:{scale}")
41
+
42
+ ui_inputs['denoise'] = 1.0
43
+ if task_type == 'img2img': ui_inputs['denoise'] = ui_inputs.get('img2img_denoise', 0.7)
44
+ elif task_type == 'hires_fix': ui_inputs['denoise'] = ui_inputs.get('hires_denoise', 0.55)
45
+ elif task_type == 'inpaint': ui_inputs['denoise'] = ui_inputs.get('inpaint_denoise', 1.0)
46
+
47
+ if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
48
+
49
+ if task_type == 'img2img':
50
+ input_image_pil = ui_inputs.get('img2img_image')
51
+ if not input_image_pil:
52
+ raise gr.Error("Please upload an image for Image-to-Image.")
53
+ temp_file_path = os.path.join(INPUT_DIR, f"temp_input_{random.randint(1000, 9999)}.png")
54
+ input_image_pil.save(temp_file_path, "PNG")
55
+ ui_inputs['input_image'] = os.path.basename(temp_file_path)
56
+ temp_files_to_clean.append(temp_file_path)
57
+ ui_inputs['width'] = input_image_pil.width
58
+ ui_inputs['height'] = input_image_pil.height
59
+
60
+ elif task_type == 'inpaint':
61
+ inpaint_dict = ui_inputs.get('inpaint_image_dict')
62
+ if not inpaint_dict or not inpaint_dict.get('background') or not inpaint_dict.get('layers'):
63
+ raise gr.Error("Inpainting requires an input image and a drawn mask.")
64
+
65
+ background_img = inpaint_dict['background'].convert("RGBA")
66
+ composite_mask_pil = Image.new('L', background_img.size, 0)
67
+ for layer in inpaint_dict['layers']:
68
+ if layer:
69
+ layer_alpha = layer.split()[-1]
70
+ composite_mask_pil = ImageChops.lighter(composite_mask_pil, layer_alpha)
71
+
72
+ inverted_mask_alpha = Image.fromarray(255 - np.array(composite_mask_pil), mode='L')
73
+ r, g, b, _ = background_img.split()
74
+ composite_image_with_mask = Image.merge('RGBA', [r, g, b, inverted_mask_alpha])
75
+
76
+ temp_file_path = os.path.join(INPUT_DIR, f"temp_inpaint_composite_{random.randint(1000, 9999)}.png")
77
+ composite_image_with_mask.save(temp_file_path, "PNG")
78
+
79
+ ui_inputs['input_image'] = os.path.basename(temp_file_path)
80
+ temp_files_to_clean.append(temp_file_path)
81
+ ui_inputs.pop('inpaint_mask', None)
82
+
83
+ elif task_type == 'outpaint':
84
+ input_image_pil = ui_inputs.get('outpaint_image')
85
+ if not input_image_pil:
86
+ raise gr.Error("Please upload an image for Outpainting.")
87
+ temp_file_path = os.path.join(INPUT_DIR, f"temp_input_{random.randint(1000, 9999)}.png")
88
+ input_image_pil.save(temp_file_path, "PNG")
89
+ ui_inputs['input_image'] = os.path.basename(temp_file_path)
90
+ temp_files_to_clean.append(temp_file_path)
91
+
92
+ ui_inputs['megapixels'] = 0.25
93
+ ui_inputs['grow_mask_by'] = ui_inputs.get('feathering', 10)
94
+
95
+ elif task_type == 'hires_fix':
96
+ input_image_pil = ui_inputs.get('hires_image')
97
+ if not input_image_pil:
98
+ raise gr.Error("Please upload an image for Hires Fix.")
99
+ temp_file_path = os.path.join(INPUT_DIR, f"temp_input_{random.randint(1000, 9999)}.png")
100
+ input_image_pil.save(temp_file_path, "PNG")
101
+ ui_inputs['input_image'] = os.path.basename(temp_file_path)
102
+ temp_files_to_clean.append(temp_file_path)
103
+
104
+ embedding_data = ui_inputs.get('embedding_data', [])
105
+ embedding_filenames = []
106
+ if embedding_data:
107
+ emb_sources, emb_ids, emb_files = embedding_data[0::3], embedding_data[1::3], embedding_data[2::3]
108
+ for i, (source, emb_id, _) in enumerate(zip(emb_sources, emb_ids, emb_files)):
109
+ if emb_id and emb_id.strip():
110
+ emb_filename = None
111
+ if source == "File":
112
+ emb_filename = sanitize_filename(emb_id)
113
+ elif source in ("Civitai", "Hugging Face"):
114
+ local_path, status = get_embedding_path(source, emb_id, os.environ.get("CIVITAI_API_KEY", ""), progress)
115
+ if local_path: emb_filename = os.path.basename(local_path)
116
+ else: raise gr.Error(f"Failed to prepare Embedding {emb_id}: {status}")
117
+
118
+ if emb_filename:
119
+ embedding_filenames.append(emb_filename)
120
+
121
+ if embedding_filenames:
122
+ embedding_prompt_text = " ".join([f"embedding:{f}" for f in embedding_filenames])
123
+ if ui_inputs['positive_prompt']:
124
+ ui_inputs['positive_prompt'] = f"{ui_inputs['positive_prompt']}, {embedding_prompt_text}"
125
+ else:
126
+ ui_inputs['positive_prompt'] = embedding_prompt_text
127
+
128
+ controlnet_data = ui_inputs.get('controlnet_data', [])
129
+ active_controlnets = []
130
+ if controlnet_data:
131
+ (cn_images, _, _, cn_strengths, cn_filepaths) = [controlnet_data[i::5] for i in range(5)]
132
+ for i in range(len(cn_images)):
133
+ if cn_images[i] and cn_strengths[i] > 0 and cn_filepaths[i] and cn_filepaths[i] != "None":
134
+ ensure_controlnet_model_downloaded(cn_filepaths[i], progress)
135
+ if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
136
+ cn_temp_path = os.path.join(INPUT_DIR, f"temp_cn_{i}_{random.randint(1000, 9999)}.png")
137
+ cn_images[i].save(cn_temp_path, "PNG")
138
+ temp_files_to_clean.append(cn_temp_path)
139
+ active_controlnets.append({
140
+ "image": os.path.basename(cn_temp_path), "strength": cn_strengths[i],
141
+ "start_percent": 0.0, "end_percent": 1.0, "control_net_name": cn_filepaths[i]
142
+ })
143
+
144
+ anima_controlnet_lllite_data = ui_inputs.get('anima_controlnet_lllite_data', [])
145
+ active_anima_controlnets = []
146
+ if anima_controlnet_lllite_data:
147
+ (cn_images, _, _, cn_strengths, cn_filepaths, cn_starts, cn_ends) = [anima_controlnet_lllite_data[i::7] for i in range(7)]
148
+ for i in range(len(cn_images)):
149
+ if cn_images[i] and cn_strengths[i] > 0 and cn_filepaths[i] and cn_filepaths[i] != "None":
150
+ _ensure_model_downloaded(cn_filepaths[i], progress)
151
+ if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
152
+ cn_temp_path = os.path.join(INPUT_DIR, f"temp_anima_cn_{i}_{random.randint(1000, 9999)}.png")
153
+ cn_images[i].save(cn_temp_path, "PNG")
154
+ temp_files_to_clean.append(cn_temp_path)
155
+ active_anima_controlnets.append({
156
+ "image": os.path.basename(cn_temp_path), "strength": cn_strengths[i],
157
+ "start_percent": cn_starts[i], "end_percent": cn_ends[i], "control_net_name": cn_filepaths[i]
158
+ })
159
+
160
+ diffsynth_controlnet_data = ui_inputs.get('diffsynth_controlnet_data', [])
161
+ active_diffsynth_controlnets = []
162
+ if diffsynth_controlnet_data:
163
+ (cn_images, _, _, cn_strengths, cn_filepaths) = [diffsynth_controlnet_data[i::5] for i in range(5)]
164
+ for i in range(len(cn_images)):
165
+ if cn_images[i] and cn_strengths[i] > 0 and cn_filepaths[i] and cn_filepaths[i] != "None":
166
+ ensure_controlnet_model_downloaded(cn_filepaths[i], progress)
167
+ if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
168
+ cn_temp_path = os.path.join(INPUT_DIR, f"temp_diffsynth_cn_{i}_{random.randint(1000, 9999)}.png")
169
+ cn_images[i].save(cn_temp_path, "PNG")
170
+ temp_files_to_clean.append(cn_temp_path)
171
+ active_diffsynth_controlnets.append({
172
+ "image": os.path.basename(cn_temp_path), "strength": cn_strengths[i],
173
+ "control_net_name": cn_filepaths[i]
174
+ })
175
+
176
+ ipadapter_data = ui_inputs.get('ipadapter_data', [])
177
+ active_ipadapters = []
178
+ if ipadapter_data:
179
+ num_ipa_units = (len(ipadapter_data) - 5) // 3
180
+ final_preset, final_weight, final_lora_strength, final_embeds_scaling, final_combine_method = ipadapter_data[-5:]
181
+ ipa_images, ipa_weights, ipa_lora_strengths = [ipadapter_data[i*num_ipa_units:(i+1)*num_ipa_units] for i in range(3)]
182
+ all_presets_to_download = set()
183
+ for i in range(num_ipa_units):
184
+ if ipa_images[i] and ipa_weights[i] > 0 and final_preset:
185
+ all_presets_to_download.add(final_preset)
186
+ if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
187
+ ipa_temp_path = os.path.join(INPUT_DIR, f"temp_ipa_{i}_{random.randint(1000, 9999)}.png")
188
+ ipa_images[i].save(ipa_temp_path, "PNG")
189
+ temp_files_to_clean.append(ipa_temp_path)
190
+ active_ipadapters.append({
191
+ "image": os.path.basename(ipa_temp_path), "preset": final_preset,
192
+ "weight": ipa_weights[i], "lora_strength": ipa_lora_strengths[i]
193
+ })
194
+ if active_ipadapters and final_preset:
195
+ all_presets_to_download.add(final_preset)
196
+ for preset in all_presets_to_download:
197
+ ensure_ipadapter_models_downloaded(preset, progress)
198
+
199
+ model_type_key = 'sd15' if workflow_model_type == 'sd15' else 'sdxl'
200
+ if active_ipadapters:
201
+ active_ipadapters.append({
202
+ 'is_final_settings': True, 'model_type': model_type_key, 'final_preset': final_preset,
203
+ 'final_weight': final_weight, 'final_lora_strength': final_lora_strength,
204
+ 'final_embeds_scaling': final_embeds_scaling, 'final_combine_method': final_combine_method
205
+ })
206
+
207
+ flux1_ipadapter_data = ui_inputs.get('flux1_ipadapter_data', [])
208
+ active_flux1_ipadapters = []
209
+ if flux1_ipadapter_data:
210
+ num_units = len(flux1_ipadapter_data) // 4
211
+ f_images = flux1_ipadapter_data[0*num_units : 1*num_units]
212
+ f_weights = flux1_ipadapter_data[1*num_units : 2*num_units]
213
+ f_starts = flux1_ipadapter_data[2*num_units : 3*num_units]
214
+ f_ends = flux1_ipadapter_data[3*num_units : 4*num_units]
215
+ for i in range(len(f_images)):
216
+ if f_images[i] and f_weights[i] > 0:
217
+ for filename in ["ip-adapter.bin"]:
218
+ _ensure_model_downloaded(filename, progress)
219
+
220
+ from huggingface_hub import snapshot_download
221
+ progress(0.5, desc="Caching HF SigLIP model...")
222
+ snapshot_download(
223
+ repo_id="google/siglip-so400m-patch14-384",
224
+ allow_patterns=["*.json", "*.safetensors", "*.txt"],
225
+ ignore_patterns=["*.msgpack", "*.h5", "*.bin"]
226
+ )
227
+
228
+ temp_path = os.path.join(INPUT_DIR, f"temp_fipa_{i}_{random.randint(1000, 9999)}.png")
229
+ f_images[i].save(temp_path, "PNG")
230
+ temp_files_to_clean.append(temp_path)
231
+ active_flux1_ipadapters.append({
232
+ "image": os.path.basename(temp_path),
233
+ "weight": f_weights[i], "start_percent": f_starts[i], "end_percent": f_ends[i]
234
+ })
235
+
236
+ sd3_ipadapter_data = ui_inputs.get('sd3_ipadapter_chain', [])
237
+ active_sd3_ipadapters = []
238
+ if sd3_ipadapter_data:
239
+ num_units = len(sd3_ipadapter_data) // 4
240
+ s_images = sd3_ipadapter_data[0*num_units : 1*num_units]
241
+ s_weights = sd3_ipadapter_data[1*num_units : 2*num_units]
242
+ s_starts = sd3_ipadapter_data[2*num_units : 3*num_units]
243
+ s_ends = sd3_ipadapter_data[3*num_units : 4*num_units]
244
+ sd3_ipa_downloaded = False
245
+ for i in range(len(s_images)):
246
+ if s_images[i] and s_weights[i] > 0:
247
+ if not sd3_ipa_downloaded:
248
+ ensure_sd3_ipadapter_models_downloaded(progress)
249
+ sd3_ipa_downloaded = True
250
+ temp_path = os.path.join(INPUT_DIR, f"temp_s3ipa_{i}_{random.randint(1000, 9999)}.png")
251
+ s_images[i].save(temp_path, "PNG")
252
+ temp_files_to_clean.append(temp_path)
253
+ active_sd3_ipadapters.append({
254
+ "image": os.path.basename(temp_path),
255
+ "weight": s_weights[i], "start_percent": s_starts[i], "end_percent": s_ends[i]
256
+ })
257
+
258
+ style_data = ui_inputs.get('style_data', [])
259
+ active_styles = []
260
+ if style_data:
261
+ num_units = len(style_data) // 2
262
+ st_images = style_data[0*num_units : 1*num_units]
263
+ st_strengths = style_data[1*num_units : 2*num_units]
264
+ for i in range(len(st_images)):
265
+ if st_images[i] and st_strengths[i] > 0:
266
+ _ensure_model_downloaded("sigclip_vision_patch14_384.safetensors", progress)
267
+ temp_path = os.path.join(INPUT_DIR, f"temp_style_{i}_{random.randint(1000, 9999)}.png")
268
+ st_images[i].save(temp_path, "PNG")
269
+ temp_files_to_clean.append(temp_path)
270
+ active_styles.append({
271
+ "image": os.path.basename(temp_path), "strength": st_strengths[i]
272
+ })
273
+
274
+ reference_latent_data = ui_inputs.get('reference_latent_data', [])
275
+ active_reference_latents = []
276
+ if reference_latent_data:
277
+ for img in reference_latent_data:
278
+ if img:
279
+ if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
280
+ temp_path = os.path.join(INPUT_DIR, f"temp_ref_{random.randint(1000, 9999)}.png")
281
+ img.save(temp_path, "PNG")
282
+ temp_files_to_clean.append(temp_path)
283
+ active_reference_latents.append(os.path.basename(temp_path))
284
+
285
+ hidream_o1_reference_data = ui_inputs.get('hidream_o1_reference_data', [])
286
+ active_hidream_o1_reference = []
287
+ if hidream_o1_reference_data:
288
+ for img in hidream_o1_reference_data:
289
+ if img:
290
+ if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
291
+ temp_path = os.path.join(INPUT_DIR, f"temp_ho1_ref_{random.randint(1000, 9999)}.png")
292
+ img.save(temp_path, "PNG")
293
+ temp_files_to_clean.append(temp_path)
294
+ active_hidream_o1_reference.append(os.path.basename(temp_path))
295
+
296
+ vae_source = ui_inputs.get('vae_source')
297
+ vae_id = ui_inputs.get('vae_id')
298
+ vae_name_override = None
299
+ if vae_source and vae_source != "None":
300
+ if vae_source == "File":
301
+ vae_name_override = sanitize_filename(vae_id)
302
+ elif vae_source in ("Civitai", "Hugging Face") and vae_id and vae_id.strip():
303
+ local_path, status = get_vae_path(vae_source, vae_id, os.environ.get("CIVITAI_API_KEY", ""), progress)
304
+ if local_path: vae_name_override = os.path.basename(local_path)
305
+ else: raise gr.Error(f"Failed to prepare VAE {vae_id}: {status}")
306
+ if vae_name_override:
307
+ ui_inputs['vae_name'] = vae_name_override
308
+
309
+ conditioning_data = ui_inputs.get('conditioning_data', [])
310
+ active_conditioning = []
311
+ if conditioning_data:
312
+ num_units = len(conditioning_data) // 6
313
+ prompts, widths, heights, xs, ys, strengths = [conditioning_data[i*num_units : (i+1)*num_units] for i in range(6)]
314
+ for i in range(num_units):
315
+ if prompts[i] and prompts[i].strip():
316
+ active_conditioning.append({
317
+ "prompt": prompts[i], "width": int(widths[i]), "height": int(heights[i]),
318
+ "x": int(xs[i]), "y": int(ys[i]), "strength": float(strengths[i])
319
+ })
320
+
321
+ return {
322
+ "active_loras_for_gpu": active_loras_for_gpu,
323
+ "active_loras_for_meta": active_loras_for_meta,
324
+ "active_controlnets": active_controlnets,
325
+ "active_anima_controlnets": active_anima_controlnets,
326
+ "active_diffsynth_controlnets": active_diffsynth_controlnets,
327
+ "active_ipadapters": active_ipadapters,
328
+ "active_flux1_ipadapters": active_flux1_ipadapters,
329
+ "active_sd3_ipadapters": active_sd3_ipadapters,
330
+ "active_styles": active_styles,
331
+ "active_reference_latents": active_reference_latents,
332
+ "active_hidream_o1_reference": active_hidream_o1_reference,
333
+ "active_conditioning": active_conditioning,
334
+ "temp_files_to_clean": temp_files_to_clean
335
  }
requirements.txt CHANGED
@@ -22,7 +22,7 @@ alembic
22
  SQLAlchemy>=2.0.0
23
  filelock
24
  av>=16.0.0
25
- comfy-kitchen==0.2.11
26
  comfy-aimdo==0.4.10
27
  requests
28
  simpleeval>=1.0.0
 
22
  SQLAlchemy>=2.0.0
23
  filelock
24
  av>=16.0.0
25
+ comfy-kitchen==0.2.12
26
  comfy-aimdo==0.4.10
27
  requests
28
  simpleeval>=1.0.0
ui/shared/ui_components.py CHANGED
@@ -128,14 +128,14 @@ def create_lora_settings_ui(prefix: str):
128
 
129
  with gr.Accordion("LoRA Settings", open=False, visible=('lora' in default_enabled_chains)) as lora_accordion:
130
  components[f'lora_accordion_{prefix}'] = lora_accordion
131
- gr.Markdown("💡 **Tip:** When downloading from Civitai, please use the **Version ID**, not the Model ID. You can find the Version ID in the URL (e.g., `civitai.com/models/123?modelVersionId=456`) or under the model's download button.")
132
  components[f'lora_count_state_{prefix}'] = gr.State(1)
133
 
134
  for i in range(MAX_LORAS):
135
  with gr.Row(visible=i==0) as row:
136
  source = gr.Dropdown(label=f"LoRA Source {i+1}", choices=LORA_SOURCE_CHOICES, value=LORA_SOURCE_CHOICES[0], scale=1)
137
- lora_id = gr.Textbox(label=f"Civitai Version ID / File", placeholder="Civitai Version ID or Filename", scale=2, type="text")
138
- scale = gr.Slider(label=f"Scale", minimum=0.0, maximum=2.0, step=0.05, value=0.8, scale=1)
139
  upload = gr.UploadButton(label="Upload", file_types=[".safetensors"], scale=1)
140
 
141
  lora_rows.append(row)
@@ -479,7 +479,7 @@ def create_embedding_ui(prefix: str):
479
 
480
  with gr.Accordion("Embedding Settings", open=False, visible=('embedding' in default_enabled_chains)) as accordion:
481
  components[key('embedding_accordion')] = accordion
482
- gr.Markdown("💡 **Tip:** When downloading from Civitai, please use the **Version ID**, not the Model ID. You can find the Version ID in the URL (e.g., `civitai.com/models/123?modelVersionId=456`) or under the model's download button. For example, entering the Version ID 456 from the example above will automatically save the file as \"civitai_456.safetensors\". You will need to manually enter embedding:civitai_456 in either your prompt or negative prompt to activate it.")
483
 
484
  embedding_rows, sources, ids, files, upload_buttons = [], [], [], [], []
485
  components.update({
@@ -493,7 +493,7 @@ def create_embedding_ui(prefix: str):
493
  for i in range(MAX_EMBEDDINGS):
494
  with gr.Row(visible=(i < 1)) as row:
495
  sources.append(gr.Dropdown(label=f"Embedding Source {i+1}", choices=LORA_SOURCE_CHOICES, value="Civitai", scale=1, interactive=True))
496
- ids.append(gr.Textbox(label="Civitai Version ID / File", placeholder="Civitai Version ID or Filename", scale=3, interactive=True, type="text"))
497
  upload_btn = gr.UploadButton("Upload", file_types=[".safetensors"], scale=1)
498
  files.append(gr.State(None))
499
  upload_buttons.append(upload_btn)
@@ -565,7 +565,7 @@ def create_vae_override_ui(prefix: str):
565
 
566
  with gr.Accordion("VAE Settings (Override)", open=False, visible=('vae' in default_enabled_chains)) as vae_accordion:
567
  components[key('vae_accordion')] = vae_accordion
568
- gr.Markdown("💡 **Tip:** When downloading from Civitai, please use the **Version ID**, not the Model ID. You can find the Version ID in the URL (e.g., `civitai.com/models/123?modelVersionId=456`) or under the model's download button.")
569
  with gr.Row():
570
  components[key('vae_source')] = gr.Dropdown(
571
  label="VAE Source",
@@ -575,8 +575,7 @@ def create_vae_override_ui(prefix: str):
575
  interactive=True
576
  )
577
  components[key('vae_id')] = gr.Textbox(
578
- label="Civitai Version ID / File",
579
- placeholder="Civitai Version ID or Filename",
580
  scale=3,
581
  interactive=True,
582
  type="text"
 
128
 
129
  with gr.Accordion("LoRA Settings", open=False, visible=('lora' in default_enabled_chains)) as lora_accordion:
130
  components[f'lora_accordion_{prefix}'] = lora_accordion
131
+ gr.Markdown("💡 **Tip:** When downloading from Civitai, please use the **Version ID**, not the Model ID. You can find the Version ID in the URL (e.g., `civitai.com/models/123?modelVersionId=456`) or under the model's download button. When downloading from Hugging Face, please use the format: `repo_id/filename.extension` or `repo_id/folder_path/filename.extension` (e.g., `lightx2v/Qwen-Image-Lightning/Qwen-Image-Lightning-4steps-V2.0-bf16.safetensors`).")
132
  components[f'lora_count_state_{prefix}'] = gr.State(1)
133
 
134
  for i in range(MAX_LORAS):
135
  with gr.Row(visible=i==0) as row:
136
  source = gr.Dropdown(label=f"LoRA Source {i+1}", choices=LORA_SOURCE_CHOICES, value=LORA_SOURCE_CHOICES[0], scale=1)
137
+ lora_id = gr.Textbox(label="Civitai Version ID / HF file / Upload File", scale=2, type="text")
138
+ scale = gr.Slider(label=f"Scale", minimum=0.0, maximum=2.0, step=0.05, value=1.0, scale=1)
139
  upload = gr.UploadButton(label="Upload", file_types=[".safetensors"], scale=1)
140
 
141
  lora_rows.append(row)
 
479
 
480
  with gr.Accordion("Embedding Settings", open=False, visible=('embedding' in default_enabled_chains)) as accordion:
481
  components[key('embedding_accordion')] = accordion
482
+ gr.Markdown("💡 **Tip:** When downloading from Civitai, please use the **Version ID**, not the Model ID. You can find the Version ID in the URL (e.g., `civitai.com/models/123?modelVersionId=456`) or under the model's download button. For example, entering the Version ID 456 will automatically save the file as \"civitai_456.safetensors\", and you will need to manually enter `embedding:civitai_456` in either your prompt or negative prompt to activate it.When downloading from Hugging Face, please use the format: repo_id/filename.extension or repo_id/folder_path/filename.extension (e.g., ilikebigturtles/lazypos/lazypos.safetensors or ilikebigturtles/lazyneg/lazyneg.safetensors). For Hugging Face files, you will need to enter embedding:filename (e.g., entering embedding:lazypos in your positive prompt, or embedding:lazyneg in your negative prompt) to activate it.")
483
 
484
  embedding_rows, sources, ids, files, upload_buttons = [], [], [], [], []
485
  components.update({
 
493
  for i in range(MAX_EMBEDDINGS):
494
  with gr.Row(visible=(i < 1)) as row:
495
  sources.append(gr.Dropdown(label=f"Embedding Source {i+1}", choices=LORA_SOURCE_CHOICES, value="Civitai", scale=1, interactive=True))
496
+ ids.append(gr.Textbox(label="Civitai Version ID / HF file / Upload File", scale=3, interactive=True, type="text"))
497
  upload_btn = gr.UploadButton("Upload", file_types=[".safetensors"], scale=1)
498
  files.append(gr.State(None))
499
  upload_buttons.append(upload_btn)
 
565
 
566
  with gr.Accordion("VAE Settings (Override)", open=False, visible=('vae' in default_enabled_chains)) as vae_accordion:
567
  components[key('vae_accordion')] = vae_accordion
568
+ gr.Markdown("💡 **Tip:** When downloading from Civitai, please use the **Version ID**, not the Model ID. You can find the Version ID in the URL (e.g., `civitai.com/models/123?modelVersionId=456`) or under the model's download button. When downloading from Hugging Face, please use the format: `repo_id/filename.extension` or `repo_id/folder_path/filename.extension` (e.g., `madebyollin/sdxl-vae-fp16-fix/sdxl_vae.safetensors`).")
569
  with gr.Row():
570
  components[key('vae_source')] = gr.Dropdown(
571
  label="VAE Source",
 
575
  interactive=True
576
  )
577
  components[key('vae_id')] = gr.Textbox(
578
+ label="Civitai Version ID / HF file / Upload File",
 
579
  scale=3,
580
  interactive=True,
581
  type="text"
utils/app_utils.py CHANGED
@@ -178,30 +178,51 @@ def get_lora_path(source: str, id_or_url: str, civitai_key: str, progress) -> tu
178
  file_info = get_civitai_file_info(version_id)
179
  api_key_to_use = civitai_key
180
  source_name = f"Civitai ID {version_id}"
 
 
 
 
 
 
 
 
 
181
  else:
182
  return None, "Invalid source."
183
 
184
  except ValueError as e:
185
  return None, f"Input validation failed: {e}"
186
 
187
- if os.path.exists(local_path):
188
- return local_path, "File already exists."
 
 
 
189
 
190
- if not file_info or not file_info.get('downloadUrl'):
191
- return None, f"Could not get download link for {source_name}."
 
192
 
193
- status = download_file(file_info['downloadUrl'], local_path, api_key_to_use, progress=progress, desc=f"Downloading {source_name}")
194
-
195
- return (local_path, status) if "Successfully" in status else (None, status)
 
 
 
 
 
 
 
 
 
196
 
197
  def get_embedding_path(source: str, id_or_url: str, civitai_key: str, progress) -> tuple[str | None, str]:
198
  if not id_or_url or not id_or_url.strip():
199
  return None, "No ID/URL provided."
200
 
201
  try:
202
- file_ext = ".safetensors"
203
-
204
  if source == "Civitai":
 
205
  version_id = sanitize_id(id_or_url)
206
  if not version_id:
207
  return None, "Invalid Civitai ID. Must be numeric."
@@ -214,30 +235,51 @@ def get_embedding_path(source: str, id_or_url: str, civitai_key: str, progress)
214
  local_path = os.path.join(EMBEDDING_DIR, filename)
215
  api_key_to_use = civitai_key
216
  source_name = f"Embedding Civitai ID {version_id}"
 
 
 
 
 
 
 
 
 
217
  else:
218
  return None, "Invalid source."
219
 
220
  except ValueError as e:
221
  return None, f"Input validation failed: {e}"
222
 
223
- if os.path.exists(local_path):
224
- return local_path, "File already exists."
 
 
 
225
 
226
- if not file_info or not file_info.get('downloadUrl'):
227
- return None, f"Could not get download link for {source_name}."
 
228
 
229
- status = download_file(file_info['downloadUrl'], local_path, api_key_to_use, progress=progress, desc=f"Downloading {source_name}")
230
-
231
- return (local_path, status) if "Successfully" in status else (None, status)
 
 
 
 
 
 
 
 
 
232
 
233
  def get_vae_path(source: str, id_or_url: str, civitai_key: str, progress) -> tuple[str | None, str]:
234
  if not id_or_url or not id_or_url.strip():
235
  return None, "No ID/URL provided."
236
 
237
  try:
238
- file_ext = ".safetensors"
239
-
240
  if source == "Civitai":
 
241
  version_id = sanitize_id(id_or_url)
242
  if not version_id:
243
  return None, "Invalid Civitai ID. Must be numeric."
@@ -250,21 +292,43 @@ def get_vae_path(source: str, id_or_url: str, civitai_key: str, progress) -> tup
250
  local_path = os.path.join(VAE_DIR, filename)
251
  api_key_to_use = civitai_key
252
  source_name = f"VAE Civitai ID {version_id}"
 
 
 
 
 
 
 
 
 
253
  else:
254
  return None, "Invalid source."
255
 
256
  except ValueError as e:
257
  return None, f"Input validation failed: {e}"
258
 
259
- if os.path.exists(local_path):
260
- return local_path, "File already exists."
 
 
 
261
 
262
- if not file_info or not file_info.get('downloadUrl'):
263
- return None, f"Could not get download link for {source_name}."
 
264
 
265
- status = download_file(file_info['downloadUrl'], local_path, api_key_to_use, progress=progress, desc=f"Downloading {source_name}")
266
-
267
- return (local_path, status) if "Successfully" in status else (None, status)
 
 
 
 
 
 
 
 
 
268
 
269
 
270
  def _ensure_model_downloaded(display_name: str, progress=gr.Progress()):
 
178
  file_info = get_civitai_file_info(version_id)
179
  api_key_to_use = civitai_key
180
  source_name = f"Civitai ID {version_id}"
181
+ elif source == "Hugging Face":
182
+ parts = id_or_url.strip().split('/')
183
+ if len(parts) < 3:
184
+ return None, "Invalid Hugging Face path. Format: repo_owner/repo_name/filename"
185
+ repo_id = f"{parts[0]}/{parts[1]}"
186
+ repo_file_path = "/".join(parts[2:])
187
+ filename = sanitize_filename(parts[-1])
188
+ local_path = os.path.join(LORA_DIR, filename)
189
+ source_name = f"HF {repo_file_path}"
190
  else:
191
  return None, "Invalid source."
192
 
193
  except ValueError as e:
194
  return None, f"Input validation failed: {e}"
195
 
196
+ if os.path.lexists(local_path):
197
+ if not os.path.exists(local_path):
198
+ os.remove(local_path)
199
+ else:
200
+ return local_path, "File already exists."
201
 
202
+ if source == "Civitai":
203
+ if not file_info or not file_info.get('downloadUrl'):
204
+ return None, f"Could not get download link for {source_name}."
205
 
206
+ status = download_file(file_info['downloadUrl'], local_path, api_key_to_use, progress=progress, desc=f"Downloading {source_name}")
207
+ return (local_path, status) if "Successfully" in status else (None, status)
208
+ elif source == "Hugging Face":
209
+ try:
210
+ if progress: progress(0, desc=f"Downloading {source_name}")
211
+ cached_path = hf_hub_download(repo_id=repo_id, filename=repo_file_path, token=os.environ.get("HF_TOKEN"))
212
+ os.makedirs(LORA_DIR, exist_ok=True)
213
+ os.symlink(cached_path, local_path)
214
+ if progress: progress(1.0, desc=f"Downloaded {source_name}")
215
+ return local_path, f"Successfully downloaded: {filename}"
216
+ except Exception as e:
217
+ return None, f"Hugging Face download failed: {e}"
218
 
219
  def get_embedding_path(source: str, id_or_url: str, civitai_key: str, progress) -> tuple[str | None, str]:
220
  if not id_or_url or not id_or_url.strip():
221
  return None, "No ID/URL provided."
222
 
223
  try:
 
 
224
  if source == "Civitai":
225
+ file_ext = ".safetensors"
226
  version_id = sanitize_id(id_or_url)
227
  if not version_id:
228
  return None, "Invalid Civitai ID. Must be numeric."
 
235
  local_path = os.path.join(EMBEDDING_DIR, filename)
236
  api_key_to_use = civitai_key
237
  source_name = f"Embedding Civitai ID {version_id}"
238
+ elif source == "Hugging Face":
239
+ parts = id_or_url.strip().split('/')
240
+ if len(parts) < 3:
241
+ return None, "Invalid Hugging Face path. Format: repo_owner/repo_name/filename"
242
+ repo_id = f"{parts[0]}/{parts[1]}"
243
+ repo_file_path = "/".join(parts[2:])
244
+ filename = sanitize_filename(parts[-1])
245
+ local_path = os.path.join(EMBEDDING_DIR, filename)
246
+ source_name = f"Embedding HF {repo_file_path}"
247
  else:
248
  return None, "Invalid source."
249
 
250
  except ValueError as e:
251
  return None, f"Input validation failed: {e}"
252
 
253
+ if os.path.lexists(local_path):
254
+ if not os.path.exists(local_path):
255
+ os.remove(local_path)
256
+ else:
257
+ return local_path, "File already exists."
258
 
259
+ if source == "Civitai":
260
+ if not file_info or not file_info.get('downloadUrl'):
261
+ return None, f"Could not get download link for {source_name}."
262
 
263
+ status = download_file(file_info['downloadUrl'], local_path, api_key_to_use, progress=progress, desc=f"Downloading {source_name}")
264
+ return (local_path, status) if "Successfully" in status else (None, status)
265
+ elif source == "Hugging Face":
266
+ try:
267
+ if progress: progress(0, desc=f"Downloading {source_name}")
268
+ cached_path = hf_hub_download(repo_id=repo_id, filename=repo_file_path, token=os.environ.get("HF_TOKEN"))
269
+ os.makedirs(EMBEDDING_DIR, exist_ok=True)
270
+ os.symlink(cached_path, local_path)
271
+ if progress: progress(1.0, desc=f"Downloaded {source_name}")
272
+ return local_path, f"Successfully downloaded: {filename}"
273
+ except Exception as e:
274
+ return None, f"Hugging Face download failed: {e}"
275
 
276
  def get_vae_path(source: str, id_or_url: str, civitai_key: str, progress) -> tuple[str | None, str]:
277
  if not id_or_url or not id_or_url.strip():
278
  return None, "No ID/URL provided."
279
 
280
  try:
 
 
281
  if source == "Civitai":
282
+ file_ext = ".safetensors"
283
  version_id = sanitize_id(id_or_url)
284
  if not version_id:
285
  return None, "Invalid Civitai ID. Must be numeric."
 
292
  local_path = os.path.join(VAE_DIR, filename)
293
  api_key_to_use = civitai_key
294
  source_name = f"VAE Civitai ID {version_id}"
295
+ elif source == "Hugging Face":
296
+ parts = id_or_url.strip().split('/')
297
+ if len(parts) < 3:
298
+ return None, "Invalid Hugging Face path. Format: repo_owner/repo_name/filename"
299
+ repo_id = f"{parts[0]}/{parts[1]}"
300
+ repo_file_path = "/".join(parts[2:])
301
+ filename = sanitize_filename(parts[-1])
302
+ local_path = os.path.join(VAE_DIR, filename)
303
+ source_name = f"VAE HF {repo_file_path}"
304
  else:
305
  return None, "Invalid source."
306
 
307
  except ValueError as e:
308
  return None, f"Input validation failed: {e}"
309
 
310
+ if os.path.lexists(local_path):
311
+ if not os.path.exists(local_path):
312
+ os.remove(local_path)
313
+ else:
314
+ return local_path, "File already exists."
315
 
316
+ if source == "Civitai":
317
+ if not file_info or not file_info.get('downloadUrl'):
318
+ return None, f"Could not get download link for {source_name}."
319
 
320
+ status = download_file(file_info['downloadUrl'], local_path, api_key_to_use, progress=progress, desc=f"Downloading {source_name}")
321
+ return (local_path, status) if "Successfully" in status else (None, status)
322
+ elif source == "Hugging Face":
323
+ try:
324
+ if progress: progress(0, desc=f"Downloading {source_name}")
325
+ cached_path = hf_hub_download(repo_id=repo_id, filename=repo_file_path, token=os.environ.get("HF_TOKEN"))
326
+ os.makedirs(VAE_DIR, exist_ok=True)
327
+ os.symlink(cached_path, local_path)
328
+ if progress: progress(1.0, desc=f"Downloaded {source_name}")
329
+ return local_path, f"Successfully downloaded: {filename}"
330
+ except Exception as e:
331
+ return None, f"Hugging Face download failed: {e}"
332
 
333
 
334
  def _ensure_model_downloaded(display_name: str, progress=gr.Progress()):
yaml/constants.yaml CHANGED
@@ -4,7 +4,7 @@ MAX_IPADAPTERS: 5
4
  MAX_EMBEDDINGS: 5
5
  MAX_CONDITIONINGS: 10
6
  MAX_REFERENCE_LATENTS: 10
7
- LORA_SOURCE_CHOICES: ["Civitai", "File"]
8
 
9
  RESOLUTION_MAP:
10
  krea-2:
 
4
  MAX_EMBEDDINGS: 5
5
  MAX_CONDITIONINGS: 10
6
  MAX_REFERENCE_LATENTS: 10
7
+ LORA_SOURCE_CHOICES: ["Civitai", "Hugging Face", "File"]
8
 
9
  RESOLUTION_MAP:
10
  krea-2: