RioShiina commited on
Commit
3a02128
·
verified ·
1 Parent(s): e410621

Upload folder using huggingface_hub

Browse files
README.md CHANGED
@@ -1,5 +1,5 @@
1
  ---
2
- title: ImageGen - SD1.5
3
  emoji: 🖼
4
  colorFrom: purple
5
  colorTo: red
@@ -7,4 +7,4 @@ sdk: gradio
7
  sdk_version: "5.50.0"
8
  app_file: app.py
9
  short_description: Multi-task image generator with dynamic, chainable workflows
10
- ---
 
1
  ---
2
+ title: ImageGen - Anima
3
  emoji: 🖼
4
  colorFrom: purple
5
  colorTo: red
 
7
  sdk_version: "5.50.0"
8
  app_file: app.py
9
  short_description: Multi-task image generator with dynamic, chainable workflows
10
+ ---
app.py CHANGED
@@ -58,7 +58,6 @@ def main():
58
  except Exception as e:
59
  print(f"--- [Setup] ❌ SageAttention installation failed: {e}. Continuing with default attention. ---")
60
 
61
-
62
  print("--- [Setup] Reloading site-packages to detect newly installed packages... ---")
63
  try:
64
  site.main()
@@ -69,8 +68,7 @@ def main():
69
  from comfy_integration import setup as setup_comfyui
70
  from utils.app_utils import (
71
  build_preprocessor_model_map,
72
- build_preprocessor_parameter_map,
73
- load_ipadapter_presets
74
  )
75
  from core import shared_state
76
  from core.settings import ALL_MODEL_MAP, ALL_FILE_DOWNLOAD_MAP
@@ -78,27 +76,39 @@ def main():
78
  def check_all_model_urls_on_startup():
79
  print("--- [Setup] Checking all model URL validity (one-time check) ---")
80
  for display_name, model_info in ALL_MODEL_MAP.items():
81
- repo_id, filename, _, _ = model_info
82
- if not repo_id: continue
83
-
84
- download_info = ALL_FILE_DOWNLOAD_MAP.get(filename, {})
85
- repo_file_path = download_info.get('repository_file_path', filename)
86
- url = f"https://huggingface.co/{repo_id}/resolve/main/{repo_file_path}"
87
 
88
- try:
89
- response = requests.head(url, timeout=5, allow_redirects=True)
90
- if response.status_code >= 400:
91
- print(f"❌ Invalid URL for '{display_name}': {url} (Status: {response.status_code})")
 
 
 
 
 
 
 
 
 
 
 
 
92
  shared_state.INVALID_MODEL_URLS[display_name] = True
93
- except requests.RequestException as e:
94
- print(f"❌ URL check failed for '{display_name}': {e}")
95
- shared_state.INVALID_MODEL_URLS[display_name] = True
96
  print("--- [Setup] ✅ Finished checking model URLs. ---")
97
 
98
  print("--- Starting Application Setup ---")
99
 
100
  setup_comfyui.initialize_comfyui()
101
 
 
 
 
 
 
 
102
  check_all_model_urls_on_startup()
103
 
104
  print("--- Building ControlNet preprocessor maps ---")
@@ -108,11 +118,6 @@ def main():
108
  build_preprocessor_parameter_map()
109
  print("--- ✅ ControlNet preprocessor setup complete. ---")
110
 
111
- print("--- Loading IPAdapter presets ---")
112
- load_ipadapter_presets()
113
- print("--- ✅ IPAdapter setup complete. ---")
114
-
115
-
116
  print("--- Environment configured. Proceeding with module imports. ---")
117
  from ui.layout import build_ui
118
  from ui.events import attach_event_handlers
 
58
  except Exception as e:
59
  print(f"--- [Setup] ❌ SageAttention installation failed: {e}. Continuing with default attention. ---")
60
 
 
61
  print("--- [Setup] Reloading site-packages to detect newly installed packages... ---")
62
  try:
63
  site.main()
 
68
  from comfy_integration import setup as setup_comfyui
69
  from utils.app_utils import (
70
  build_preprocessor_model_map,
71
+ build_preprocessor_parameter_map
 
72
  )
73
  from core import shared_state
74
  from core.settings import ALL_MODEL_MAP, ALL_FILE_DOWNLOAD_MAP
 
76
  def check_all_model_urls_on_startup():
77
  print("--- [Setup] Checking all model URL validity (one-time check) ---")
78
  for display_name, model_info in ALL_MODEL_MAP.items():
79
+ _, components, _, _ = model_info
80
+ if not components: continue
 
 
 
 
81
 
82
+ for filename in components.values():
83
+ download_info = ALL_FILE_DOWNLOAD_MAP.get(filename, {})
84
+ repo_id = download_info.get('repo_id')
85
+ if not repo_id: continue
86
+
87
+ repo_file_path = download_info.get('repository_file_path', filename)
88
+ url = f"https://huggingface.co/{repo_id}/resolve/main/{repo_file_path}"
89
+
90
+ try:
91
+ response = requests.head(url, timeout=5, allow_redirects=True)
92
+ if response.status_code >= 400:
93
+ print(f"❌ Invalid URL for '{display_name}' component '{filename}': {url} (Status: {response.status_code})")
94
+ shared_state.INVALID_MODEL_URLS[display_name] = True
95
+ break
96
+ except requests.RequestException as e:
97
+ print(f"❌ URL check failed for '{display_name}' component '{filename}': {e}")
98
  shared_state.INVALID_MODEL_URLS[display_name] = True
99
+ break
 
 
100
  print("--- [Setup] ✅ Finished checking model URLs. ---")
101
 
102
  print("--- Starting Application Setup ---")
103
 
104
  setup_comfyui.initialize_comfyui()
105
 
106
+ print("--- Initiating GPU Startup Check & SageAttention Patch ---")
107
+ try:
108
+ dummy_gpu_for_startup()
109
+ except Exception as e:
110
+ print(f"--- [GPU Startup] ⚠️ Warning: Startup check failed: {e} ---")
111
+
112
  check_all_model_urls_on_startup()
113
 
114
  print("--- Building ControlNet preprocessor maps ---")
 
118
  build_preprocessor_parameter_map()
119
  print("--- ✅ ControlNet preprocessor setup complete. ---")
120
 
 
 
 
 
 
121
  print("--- Environment configured. Proceeding with module imports. ---")
122
  from ui.layout import build_ui
123
  from ui.events import attach_event_handlers
chain_injectors/conditioning_injector.py CHANGED
@@ -48,8 +48,8 @@ def inject(assembler, chain_definition, chain_items):
48
 
49
  set_area_id = assembler._get_unique_id()
50
  set_area_node = assembler._get_node_template("ConditioningSetArea")
51
- set_area_node['inputs']['width'] = item_data.get('width', 512)
52
- set_area_node['inputs']['height'] = item_data.get('height', 512)
53
  set_area_node['inputs']['x'] = item_data.get('x', 0)
54
  set_area_node['inputs']['y'] = item_data.get('y', 0)
55
  set_area_node['inputs']['strength'] = item_data.get('strength', 1.0)
 
48
 
49
  set_area_id = assembler._get_unique_id()
50
  set_area_node = assembler._get_node_template("ConditioningSetArea")
51
+ set_area_node['inputs']['width'] = item_data.get('width', 1024)
52
+ set_area_node['inputs']['height'] = item_data.get('height', 1024)
53
  set_area_node['inputs']['x'] = item_data.get('x', 0)
54
  set_area_node['inputs']['y'] = item_data.get('y', 0)
55
  set_area_node['inputs']['strength'] = item_data.get('strength', 1.0)
chain_injectors/controlnet_injector.py CHANGED
@@ -13,17 +13,13 @@ def inject(assembler, chain_definition, chain_items):
13
  'negative' not in assembler.workflow[ksampler_id]['inputs']:
14
  print(f"Warning: KSampler node '{ksampler_name}' is missing 'positive' or 'negative' inputs. Skipping ControlNet chain.")
15
  return
16
-
17
- vae_source_str = chain_definition.get('vae_source')
18
- if not vae_source_str:
19
- print("Warning: 'vae_source' definition missing in the recipe for the ControlNet chain. Skipping.")
20
- return
21
- vae_node_name, vae_idx_str = vae_source_str.split(':')
22
- if vae_node_name not in assembler.node_map:
23
- print(f"Warning: VAE source node '{vae_node_name}' for ControlNet chain not found. Skipping.")
24
- return
25
- vae_connection = [assembler.node_map[vae_node_name], int(vae_idx_str)]
26
 
 
 
 
 
 
 
27
  current_positive_connection = assembler.workflow[ksampler_id]['inputs']['positive']
28
  current_negative_connection = assembler.workflow[ksampler_id]['inputs']['negative']
29
 
@@ -47,6 +43,7 @@ def inject(assembler, chain_definition, chain_items):
47
  apply_cn_node['inputs']['negative'] = current_negative_connection
48
  apply_cn_node['inputs']['control_net'] = [cn_loader_id, 0]
49
  apply_cn_node['inputs']['image'] = [image_loader_id, 0]
 
50
  apply_cn_node['inputs']['vae'] = vae_connection
51
 
52
  assembler.workflow[apply_cn_id] = apply_cn_node
 
13
  'negative' not in assembler.workflow[ksampler_id]['inputs']:
14
  print(f"Warning: KSampler node '{ksampler_name}' is missing 'positive' or 'negative' inputs. Skipping ControlNet chain.")
15
  return
 
 
 
 
 
 
 
 
 
 
16
 
17
+ vae_source_name = chain_definition.get('vae_source_node')
18
+ if not vae_source_name or vae_source_name not in assembler.node_map:
19
+ print(f"Warning: VAE source node '{vae_source_name}' for ControlNet chain not found in recipe. Skipping chain injection.")
20
+ return
21
+ vae_connection = [assembler.node_map[vae_source_name], 0]
22
+
23
  current_positive_connection = assembler.workflow[ksampler_id]['inputs']['positive']
24
  current_negative_connection = assembler.workflow[ksampler_id]['inputs']['negative']
25
 
 
43
  apply_cn_node['inputs']['negative'] = current_negative_connection
44
  apply_cn_node['inputs']['control_net'] = [cn_loader_id, 0]
45
  apply_cn_node['inputs']['image'] = [image_loader_id, 0]
46
+
47
  apply_cn_node['inputs']['vae'] = vae_connection
48
 
49
  assembler.workflow[apply_cn_id] = apply_cn_node
chain_injectors/ipadapter_injector.py DELETED
@@ -1,106 +0,0 @@
1
- def inject(assembler, chain_definition, chain_items):
2
- if not chain_items:
3
- return
4
-
5
- final_settings = {}
6
- if chain_items and isinstance(chain_items[-1], dict) and chain_items[-1].get('is_final_settings'):
7
- final_settings = chain_items.pop()
8
-
9
- if not chain_items:
10
- return
11
-
12
- end_node_name = chain_definition.get('end')
13
- if not end_node_name or end_node_name not in assembler.node_map:
14
- print(f"Warning: Target node '{end_node_name}' for IPAdapter chain not found. Skipping chain injection.")
15
- return
16
-
17
- end_node_id = assembler.node_map[end_node_name]
18
-
19
- if 'model' not in assembler.workflow[end_node_id]['inputs']:
20
- print(f"Warning: Target node '{end_node_name}' is missing 'model' input. Skipping IPAdapter chain.")
21
- return
22
-
23
- current_model_connection = assembler.workflow[end_node_id]['inputs']['model']
24
-
25
- model_type = final_settings.get('model_type', 'sd15')
26
- megapixels = 1.05 if model_type == 'sdxl' else 0.39
27
-
28
- pos_embed_outputs = []
29
- neg_embed_outputs = []
30
-
31
- for i, item_data in enumerate(chain_items):
32
- loader_type = 'FaceID' if 'FACEID' in item_data.get('preset', '') else 'Unified'
33
-
34
- loader_template_name = "IPAdapterUnifiedLoader"
35
- if loader_type == 'FaceID':
36
- loader_template_name = "IPAdapterUnifiedLoaderFaceID"
37
-
38
- image_loader_id = assembler._get_unique_id()
39
- image_loader_node = assembler._get_node_template("LoadImage")
40
- image_loader_node['inputs']['image'] = item_data['image']
41
- assembler.workflow[image_loader_id] = image_loader_node
42
-
43
- image_scaler_id = assembler._get_unique_id()
44
- image_scaler_node = assembler._get_node_template("ImageScaleToTotalPixels")
45
- image_scaler_node['inputs']['image'] = [image_loader_id, 0]
46
- image_scaler_node['inputs']['megapixels'] = megapixels
47
- image_scaler_node['inputs']['upscale_method'] = "lanczos"
48
- assembler.workflow[image_scaler_id] = image_scaler_node
49
-
50
- ipadapter_loader_id = assembler._get_unique_id()
51
- ipadapter_loader_node = assembler._get_node_template(loader_template_name)
52
- ipadapter_loader_node['inputs']['model'] = current_model_connection
53
- ipadapter_loader_node['inputs']['preset'] = item_data['preset']
54
- if loader_type == 'FaceID':
55
- ipadapter_loader_node['inputs']['lora_strength'] = item_data.get('lora_strength', 0.6)
56
- assembler.workflow[ipadapter_loader_id] = ipadapter_loader_node
57
-
58
- encoder_id = assembler._get_unique_id()
59
- encoder_node = assembler._get_node_template("IPAdapterEncoder")
60
- encoder_node['inputs']['weight'] = item_data['weight']
61
- encoder_node['inputs']['ipadapter'] = [ipadapter_loader_id, 1]
62
- encoder_node['inputs']['image'] = [image_scaler_id, 0]
63
- assembler.workflow[encoder_id] = encoder_node
64
-
65
- pos_embed_outputs.append([encoder_id, 0])
66
- neg_embed_outputs.append([encoder_id, 1])
67
-
68
- pos_combiner_id = assembler._get_unique_id()
69
- pos_combiner_node = assembler._get_node_template("IPAdapterCombineEmbeds")
70
- pos_combiner_node['inputs']['method'] = final_settings.get('final_combine_method', 'concat')
71
- for i, conn in enumerate(pos_embed_outputs):
72
- pos_combiner_node['inputs'][f'embed{i+1}'] = conn
73
- assembler.workflow[pos_combiner_id] = pos_combiner_node
74
-
75
- neg_combiner_id = assembler._get_unique_id()
76
- neg_combiner_node = assembler._get_node_template("IPAdapterCombineEmbeds")
77
- neg_combiner_node['inputs']['method'] = final_settings.get('final_combine_method', 'concat')
78
- for i, conn in enumerate(neg_embed_outputs):
79
- neg_combiner_node['inputs'][f'embed{i+1}'] = conn
80
- assembler.workflow[neg_combiner_id] = neg_combiner_node
81
-
82
- final_loader_type = 'FaceID' if 'FACEID' in final_settings.get('final_preset', '') else 'Unified'
83
- final_loader_template_name = "IPAdapterUnifiedLoader"
84
- if final_loader_type == 'FaceID':
85
- final_loader_template_name = "IPAdapterUnifiedLoaderFaceID"
86
-
87
- final_loader_id = assembler._get_unique_id()
88
- final_loader_node = assembler._get_node_template(final_loader_template_name)
89
- final_loader_node['inputs']['model'] = current_model_connection
90
- final_loader_node['inputs']['preset'] = final_settings.get('final_preset', 'STANDARD (medium strength)')
91
- if final_loader_type == 'FaceID':
92
- final_loader_node['inputs']['lora_strength'] = final_settings.get('final_lora_strength', 0.6)
93
- assembler.workflow[final_loader_id] = final_loader_node
94
-
95
- apply_embeds_id = assembler._get_unique_id()
96
- apply_embeds_node = assembler._get_node_template("IPAdapterEmbeds")
97
- apply_embeds_node['inputs']['weight'] = final_settings.get('final_weight', 1.0)
98
- apply_embeds_node['inputs']['embeds_scaling'] = final_settings.get('final_embeds_scaling', 'V only')
99
- apply_embeds_node['inputs']['model'] = [final_loader_id, 0]
100
- apply_embeds_node['inputs']['ipadapter'] = [final_loader_id, 1]
101
- apply_embeds_node['inputs']['pos_embed'] = [pos_combiner_id, 0]
102
- apply_embeds_node['inputs']['neg_embed'] = [neg_combiner_id, 0]
103
- assembler.workflow[apply_embeds_id] = apply_embeds_node
104
-
105
- assembler.workflow[end_node_id]['inputs']['model'] = [apply_embeds_id, 0]
106
- print(f"IPAdapter injector applied. Redirected '{end_node_name}' model input through {len(chain_items)} reference images.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
chain_injectors/lora_injector.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from copy import deepcopy
2
+
3
+ def inject(assembler, chain_definition, chain_items):
4
+ if not chain_items:
5
+ return
6
+
7
+ start_node_name = chain_definition.get('start')
8
+ start_node_id = None
9
+ if start_node_name:
10
+ if start_node_name not in assembler.node_map:
11
+ print(f"Warning: Start node '{start_node_name}' for dynamic LoRA chain not found. Skipping chain.")
12
+ return
13
+ start_node_id = assembler.node_map[start_node_name]
14
+
15
+ output_map = chain_definition.get('output_map', {})
16
+ current_connections = {}
17
+ for key, type_name in output_map.items():
18
+ if ':' in str(key):
19
+ node_name, idx_str = key.split(':')
20
+ if node_name not in assembler.node_map:
21
+ print(f"Warning: Node '{node_name}' in chain's output_map not found. Skipping.")
22
+ continue
23
+ node_id = assembler.node_map[node_name]
24
+ start_output_idx = int(idx_str)
25
+ current_connections[type_name] = [node_id, start_output_idx]
26
+ elif start_node_id:
27
+ start_output_idx = int(key)
28
+ current_connections[type_name] = [start_node_id, start_output_idx]
29
+ else:
30
+ print(f"Warning: LoRA chain has no 'start' node defined, and an output_map key '{key}' is not in 'node:index' format. Skipping this connection.")
31
+
32
+
33
+ input_map = chain_definition.get('input_map', {})
34
+ chain_output_map = chain_definition.get('template_output_map', { "0": "model", "1": "clip" })
35
+
36
+ for item_data in chain_items:
37
+ template_name = chain_definition['template']
38
+ template = assembler._get_node_template(template_name)
39
+ node_data = deepcopy(template)
40
+
41
+ for param_name, value in item_data.items():
42
+ if param_name in node_data['inputs']:
43
+ node_data['inputs'][param_name] = value
44
+
45
+ for type_name, input_name in input_map.items():
46
+ if type_name in current_connections:
47
+ node_data['inputs'][input_name] = current_connections[type_name]
48
+
49
+ new_node_id = assembler._get_unique_id()
50
+ assembler.workflow[new_node_id] = node_data
51
+
52
+ for idx_str, type_name in chain_output_map.items():
53
+ current_connections[type_name] = [new_node_id, int(idx_str)]
54
+
55
+ end_input_map = chain_definition.get('end_input_map', {})
56
+ for type_name, targets in end_input_map.items():
57
+ if type_name in current_connections:
58
+ if not isinstance(targets, list):
59
+ targets = [targets]
60
+
61
+ for target_str in targets:
62
+ end_node_name, end_input_name = target_str.split(':')
63
+ if end_node_name in assembler.node_map:
64
+ end_node_id = assembler.node_map[end_node_name]
65
+ assembler.workflow[end_node_id]['inputs'][end_input_name] = current_connections[type_name]
66
+ else:
67
+ print(f"Warning: End node '{end_node_name}' for dynamic chain not found. Skipping connection.")
comfy_integration/setup.py CHANGED
@@ -48,13 +48,6 @@ def initialize_comfyui():
48
  else:
49
  print("✅ comfyui_controlnet_aux extension already exists.")
50
 
51
- ipadapter_plus_path = os.path.join(APP_DIR, "custom_nodes", "ComfyUI_IPAdapter_plus")
52
- if not os.path.exists(ipadapter_plus_path):
53
- os.system(f"git clone https://github.com/cubiq/ComfyUI_IPAdapter_plus.git {ipadapter_plus_path}")
54
- print("✅ ComfyUI_IPAdapter_plus extension cloned.")
55
- else:
56
- print("✅ ComfyUI_IPAdapter_plus extension already exists.")
57
-
58
  print(f"✅ Current working directory is: {os.getcwd()}")
59
 
60
  import comfy.model_management
 
48
  else:
49
  print("✅ comfyui_controlnet_aux extension already exists.")
50
 
 
 
 
 
 
 
 
51
  print(f"✅ Current working directory is: {os.getcwd()}")
52
 
53
  import comfy.model_management
core/model_manager.py CHANGED
@@ -1,14 +1,10 @@
1
  import gc
2
- from typing import Dict, List, Any, Set
3
 
4
- import torch
5
  import gradio as gr
6
- from comfy import model_management
7
 
8
- from core.settings import ALL_MODEL_MAP, CHECKPOINT_DIR, LORA_DIR, DIFFUSION_MODELS_DIR, VAE_DIR, TEXT_ENCODERS_DIR
9
- from comfy_integration.nodes import checkpointloadersimple, LoraLoader
10
- from nodes import NODE_CLASS_MAPPINGS
11
- from utils.app_utils import get_value_at_index, _ensure_model_downloaded
12
 
13
 
14
  class ModelManager:
@@ -22,124 +18,31 @@ class ModelManager:
22
  def __init__(self):
23
  if hasattr(self, 'initialized'):
24
  return
25
- self.loaded_models: Dict[str, Any] = {}
26
- self.last_active_loras: List[Dict[str, Any]] = []
27
  self.initialized = True
28
  print("✅ ModelManager initialized.")
29
 
30
- def get_loaded_model_names(self) -> Set[str]:
31
- return set(self.loaded_models.keys())
32
-
33
- def _load_single_model(self, display_name: str, progress) -> Any:
34
- print(f"--- [ModelManager] Loading model: '{display_name}' ---")
35
-
36
- filename = _ensure_model_downloaded(display_name, progress)
37
 
38
- _, _, model_type, _ = ALL_MODEL_MAP[display_name]
 
 
 
 
 
 
39
 
40
- loader_map = {
41
- "SDXL": (checkpointloadersimple, "load_checkpoint", {"ckpt_name": filename}),
42
- "SD1.5": (checkpointloadersimple, "load_checkpoint", {"ckpt_name": filename}),
43
- "UNET": (NODE_CLASS_MAPPINGS["UNETLoader"](), "load_unet", {"unet_name": filename, "weight_dtype": "default"}),
44
- "VAE": (NODE_CLASS_MAPPINGS["VAELoader"](), "load_vae", {"vae_name": filename}),
45
- "TEXT_ENCODER": (NODE_CLASS_MAPPINGS["CLIPLoader"](), "load_clip", {"clip_name": filename, "type": "wan", "device": "default"}),
46
- }
47
-
48
- if model_type not in loader_map:
49
- if model_type == "LORA":
50
- print(f"--- [ModelManager] ✅ '{display_name}' is a LoRA. It will be loaded dynamically. ---")
51
- return (filename,)
52
- raise ValueError(f"[ModelManager] No loader configured for model type '{model_type}'")
53
-
54
- loader_instance, method_name, kwargs = loader_map[model_type]
55
 
56
- load_method = getattr(loader_instance, method_name)
57
- loaded_tuple = load_method(**kwargs)
58
-
59
- print(f"--- [ModelManager] ✅ Successfully loaded '{display_name}' to CPU/RAM ---")
60
- return loaded_tuple
61
-
62
- def move_models_to_gpu(self, required_models: List[str]):
63
- print(f"--- [ModelManager] Moving models to GPU: {required_models} ---")
64
- models_to_load_gpu = []
65
- for name in required_models:
66
- if name in self.loaded_models:
67
- model_tuple = self.loaded_models[name]
68
- _, _, model_type, _ = ALL_MODEL_MAP[name]
69
- if model_type in ["SDXL", "SD1.5"]:
70
- models_to_load_gpu.append(get_value_at_index(model_tuple, 0))
71
-
72
- if models_to_load_gpu:
73
- model_management.load_models_gpu(models_to_load_gpu)
74
- print("--- [ModelManager] ✅ Models successfully moved to GPU. ---")
75
- else:
76
- print("--- [ModelManager] ⚠️ No checkpoint models found to move to GPU. ---")
77
-
78
- def ensure_models_downloaded(self, required_models: List[str], progress):
79
- print(f"--- [ModelManager] Ensuring models are downloaded: {required_models} ---")
80
- for i, display_name in enumerate(required_models):
81
  if progress and hasattr(progress, '__call__'):
82
- progress(i / len(required_models), desc=f"Checking file: {display_name}")
83
  try:
84
- _ensure_model_downloaded(display_name, progress)
85
  except Exception as e:
86
- raise gr.Error(f"Failed to download model '{display_name}'. Reason: {e}")
 
87
  print(f"--- [ModelManager] ✅ All required models are present on disk. ---")
88
 
89
- def load_managed_models(self, required_models: List[str], active_loras: List[Dict[str, Any]], progress) -> Dict[str, Any]:
90
- required_set = set(required_models)
91
- current_set = set(self.loaded_models.keys())
92
-
93
- loras_changed = self.last_active_loras != active_loras
94
- models_to_unload = current_set - required_set
95
-
96
- must_reload = bool(models_to_unload) or loras_changed
97
-
98
- if must_reload:
99
- if models_to_unload:
100
- print(f"--- [ModelManager] Models to unload: {models_to_unload} ---")
101
- if loras_changed and not models_to_unload:
102
- print(f"--- [ModelManager] LoRA configuration changed. Reloading base model(s): {current_set.intersection(required_set)} ---")
103
-
104
- model_management.unload_all_models()
105
- self.loaded_models.clear()
106
- gc.collect()
107
- torch.cuda.empty_cache()
108
- print("--- [ModelManager] All models unloaded to free RAM. ---")
109
-
110
- models_to_load = required_set if must_reload else (required_set - current_set)
111
-
112
- if models_to_load:
113
- print(f"--- [ModelManager] Models to load: {models_to_load} ---")
114
- for i, display_name in enumerate(models_to_load):
115
- progress(i / len(models_to_load), desc=f"Loading model: {display_name}")
116
- try:
117
- loaded_model_data = self._load_single_model(display_name, progress)
118
-
119
- if active_loras and ALL_MODEL_MAP[display_name][2] in ["SDXL", "SD1.5"]:
120
- print(f"--- [ModelManager] Applying {len(active_loras)} LoRAs on CPU... ---")
121
- lora_loader = LoraLoader()
122
- patched_model, patched_clip = loaded_model_data[0], loaded_model_data[1]
123
-
124
- for lora_info in active_loras:
125
- patched_model, patched_clip = lora_loader.load_lora(
126
- model=patched_model,
127
- clip=patched_clip,
128
- lora_name=lora_info["lora_name"],
129
- strength_model=lora_info["strength_model"],
130
- strength_clip=lora_info["strength_clip"]
131
- )
132
-
133
- loaded_model_data = (patched_model, patched_clip, loaded_model_data[2])
134
- print(f"--- [ModelManager] ✅ All LoRAs merged into the model on CPU. ---")
135
-
136
- self.loaded_models[display_name] = loaded_model_data
137
- except Exception as e:
138
- raise gr.Error(f"Failed to load model or apply LoRA '{display_name}'. Reason: {e}")
139
- else:
140
- print(f"--- [ModelManager] All required models are already loaded. ---")
141
-
142
- self.last_active_loras = active_loras
143
- return {name: self.loaded_models[name] for name in required_models}
144
-
145
  model_manager = ModelManager()
 
1
  import gc
2
+ from typing import List
3
 
 
4
  import gradio as gr
 
5
 
6
+ from core.settings import ALL_MODEL_MAP
7
+ from utils.app_utils import _ensure_model_downloaded
 
 
8
 
9
 
10
  class ModelManager:
 
18
  def __init__(self):
19
  if hasattr(self, 'initialized'):
20
  return
 
 
21
  self.initialized = True
22
  print("✅ ModelManager initialized.")
23
 
24
+ def ensure_models_downloaded(self, required_models: List[str], progress):
25
+ print(f"--- [ModelManager] Ensuring models are downloaded: {required_models} ---")
 
 
 
 
 
26
 
27
+ files_to_download = set()
28
+ for display_name in required_models:
29
+ if display_name in ALL_MODEL_MAP:
30
+ _, components, _, _ = ALL_MODEL_MAP[display_name]
31
+ for component_key, component_file in components.items():
32
+ if component_key in ['unet', 'clip', 'vae', 'lora']:
33
+ files_to_download.add(component_file)
34
 
35
+ files_to_download = list(files_to_download)
36
+ total_files = len(files_to_download)
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
+ for i, filename in enumerate(files_to_download):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  if progress and hasattr(progress, '__call__'):
40
+ progress(i / total_files, desc=f"Checking file: {filename}")
41
  try:
42
+ _ensure_model_downloaded(filename, progress)
43
  except Exception as e:
44
+ raise gr.Error(f"Failed to download model component '{filename}'. Reason: {e}")
45
+
46
  print(f"--- [ModelManager] ✅ All required models are present on disk. ---")
47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  model_manager = ModelManager()
core/pipelines/sd_image_pipeline.py CHANGED
@@ -11,7 +11,7 @@ import numpy as np
11
  from .base_pipeline import BasePipeline
12
  from core.settings import *
13
  from comfy_integration.nodes import *
14
- from utils.app_utils import get_value_at_index, sanitize_prompt, get_lora_path, get_embedding_path, ensure_controlnet_model_downloaded, ensure_ipadapter_models_downloaded, sanitize_filename
15
  from core.workflow_assembler import WorkflowAssembler
16
 
17
  class SdImagePipeline(BasePipeline):
@@ -71,6 +71,10 @@ class SdImagePipeline(BasePipeline):
71
  node_info = workflow[node_id]
72
  class_type = node_info['class_type']
73
 
 
 
 
 
74
  node_class = NODE_CLASS_MAPPINGS.get(class_type)
75
  if node_class is None:
76
  raise RuntimeError(f"Could not find node class '{class_type}'. Is it imported in comfy_integration/nodes.py?")
@@ -109,24 +113,13 @@ class SdImagePipeline(BasePipeline):
109
 
110
  return get_value_at_index(computed_outputs[image_source_node_id], image_source_index)
111
 
112
- def _gpu_logic(self, ui_inputs: Dict, loras_string: str, required_models_for_gpu: List[str], workflow: Dict[str, Any], assembler: WorkflowAssembler, progress=gr.Progress(track_tqdm=True)):
113
  model_display_name = ui_inputs['model_display_name']
114
 
115
- progress(0.1, desc="Moving models to GPU...")
116
- self.model_manager.move_models_to_gpu(required_models_for_gpu)
117
-
118
  progress(0.4, desc="Executing workflow...")
119
 
120
- loaded_model_tuple = self.model_manager.loaded_models[model_display_name]
121
-
122
- ckpt_loader_node_id = assembler.node_map.get("ckpt_loader")
123
- if not ckpt_loader_node_id:
124
- raise RuntimeError("Workflow is missing the 'ckpt_loader' node required for model injection.")
125
-
126
- initial_objects = {
127
- ckpt_loader_node_id: loaded_model_tuple
128
- }
129
-
130
  decoded_images_tensor = self._execute_workflow(workflow, initial_objects=initial_objects)
131
 
132
  output_images = []
@@ -163,25 +156,23 @@ class SdImagePipeline(BasePipeline):
163
 
164
  lora_data = ui_inputs.get('lora_data', [])
165
  active_loras_for_gpu, active_loras_for_meta = [], []
166
- sources, ids, scales, files = lora_data[0::4], lora_data[1::4], lora_data[2::4], lora_data[3::4]
167
-
168
- for i, (source, lora_id, scale, _) in enumerate(zip(sources, ids, scales, files)):
169
- if scale > 0 and lora_id and lora_id.strip():
170
- lora_filename = None
171
- if source == "File":
172
- lora_filename = sanitize_filename(lora_id)
173
- elif source == "Civitai":
174
- local_path, status = get_lora_path(source, lora_id, ui_inputs['civitai_api_key'], progress)
175
- if local_path: lora_filename = os.path.basename(local_path)
176
- else: raise gr.Error(f"Failed to prepare LoRA {lora_id}: {status}")
177
-
178
- if lora_filename:
179
- active_loras_for_gpu.append({"lora_name": lora_filename, "strength_model": scale, "strength_clip": scale})
180
- active_loras_for_meta.append(f"{source} {lora_id}:{scale}")
 
181
 
182
- progress(0.1, desc="Loading models into RAM...")
183
- self.model_manager.load_managed_models(required_models, active_loras=active_loras_for_gpu, progress=progress)
184
-
185
  ui_inputs['denoise'] = 1.0
186
  if task_type == 'img2img': ui_inputs['denoise'] = ui_inputs.get('img2img_denoise', 0.7)
187
  elif task_type == 'hires_fix': ui_inputs['denoise'] = ui_inputs.get('hires_denoise', 0.55)
@@ -266,54 +257,20 @@ class SdImagePipeline(BasePipeline):
266
 
267
  controlnet_data = ui_inputs.get('controlnet_data', [])
268
  active_controlnets = []
269
- (cn_images, _, _, cn_strengths, cn_filepaths) = [controlnet_data[i::5] for i in range(5)]
270
- for i in range(len(cn_images)):
271
- if cn_images[i] and cn_strengths[i] > 0 and cn_filepaths[i] and cn_filepaths[i] != "None":
272
- ensure_controlnet_model_downloaded(cn_filepaths[i], progress)
273
-
274
- if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
275
- cn_temp_path = os.path.join(INPUT_DIR, f"temp_cn_{i}_{random.randint(1000, 9999)}.png")
276
- cn_images[i].save(cn_temp_path, "PNG")
277
- temp_files_to_clean.append(cn_temp_path)
278
- active_controlnets.append({
279
- "image": os.path.basename(cn_temp_path), "strength": cn_strengths[i],
280
- "start_percent": 0.0, "end_percent": 1.0, "control_net_name": cn_filepaths[i]
281
- })
282
-
283
- ipadapter_data = ui_inputs.get('ipadapter_data', [])
284
- active_ipadapters = []
285
- if ipadapter_data:
286
- num_ipa_units = (len(ipadapter_data) - 5) // 3
287
- final_preset, final_weight, final_lora_strength, final_embeds_scaling, final_combine_method = ipadapter_data[-5:]
288
- ipa_images, ipa_weights, ipa_lora_strengths = [ipadapter_data[i*num_ipa_units:(i+1)*num_ipa_units] for i in range(3)]
289
-
290
- all_presets_to_download = set()
291
-
292
- for i in range(num_ipa_units):
293
- if ipa_images[i] and ipa_weights[i] > 0 and final_preset:
294
- all_presets_to_download.add(final_preset)
295
-
296
  if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
297
- ipa_temp_path = os.path.join(INPUT_DIR, f"temp_ipa_{i}_{random.randint(1000, 9999)}.png")
298
- ipa_images[i].save(ipa_temp_path, "PNG")
299
- temp_files_to_clean.append(ipa_temp_path)
300
- active_ipadapters.append({
301
- "image": os.path.basename(ipa_temp_path), "preset": final_preset,
302
- "weight": ipa_weights[i], "lora_strength": ipa_lora_strengths[i]
303
  })
304
-
305
- if active_ipadapters and final_preset:
306
- all_presets_to_download.add(final_preset)
307
-
308
- for preset in all_presets_to_download:
309
- ensure_ipadapter_models_downloaded(preset, progress)
310
-
311
- if active_ipadapters:
312
- active_ipadapters.append({
313
- 'is_final_settings': True, 'model_type': 'sd15', 'final_preset': final_preset,
314
- 'final_weight': final_weight, 'final_lora_strength': final_lora_strength,
315
- 'final_embeds_scaling': final_embeds_scaling, 'final_combine_method': final_combine_method
316
- })
317
 
318
  from utils.app_utils import get_vae_path
319
  vae_source = ui_inputs.get('vae_source')
@@ -361,17 +318,22 @@ class SdImagePipeline(BasePipeline):
361
  if ui_inputs.get('seed') == -1:
362
  ui_inputs['seed'] = random.randint(0, 2**32 - 1)
363
 
364
- dynamic_values = {'task_type': ui_inputs['task_type'], 'model_type': "sd15"}
365
 
366
  recipe_path = os.path.join(os.path.dirname(__file__), "workflow_recipes", "sd_unified_recipe.yaml")
367
  assembler = WorkflowAssembler(recipe_path, dynamic_values=dynamic_values)
368
 
 
 
 
 
 
 
369
  workflow_inputs = {
370
  "positive_prompt": ui_inputs['positive_prompt'], "negative_prompt": ui_inputs['negative_prompt'],
371
  "seed": ui_inputs['seed'], "steps": ui_inputs['num_inference_steps'], "cfg": ui_inputs['guidance_scale'],
372
  "sampler_name": ui_inputs['sampler'], "scheduler": ui_inputs['scheduler'],
373
  "batch_size": ui_inputs['batch_size'],
374
- "clip_skip": -int(ui_inputs['clip_skip']),
375
  "denoise": ui_inputs['denoise'],
376
  "input_image": ui_inputs.get('input_image'),
377
  "inpaint_image": ui_inputs.get('inpaint_image'),
@@ -379,10 +341,11 @@ class SdImagePipeline(BasePipeline):
379
  "left": ui_inputs.get('outpaint_left'), "top": ui_inputs.get('outpaint_top'),
380
  "right": ui_inputs.get('outpaint_right'), "bottom": ui_inputs.get('outpaint_bottom'),
381
  "hires_upscaler": ui_inputs.get('hires_upscaler'), "hires_scale_by": ui_inputs.get('hires_scale_by'),
382
- "model_name": ALL_MODEL_MAP[ui_inputs['model_display_name']][1],
383
- "vae_name": ui_inputs.get('vae_name'),
 
 
384
  "controlnet_chain": active_controlnets,
385
- "ipadapter_chain": active_ipadapters,
386
  "conditioning_chain": active_conditioning,
387
  }
388
 
@@ -391,25 +354,6 @@ class SdImagePipeline(BasePipeline):
391
  workflow_inputs['height'] = ui_inputs['height']
392
 
393
  workflow = assembler.assemble(workflow_inputs)
394
-
395
- if workflow_inputs.get("vae_name"):
396
- print("--- [Workflow Patch] VAE override provided. Adding VAELoader and rewiring connections. ---")
397
- vae_loader_id = assembler._get_unique_id()
398
- vae_loader_node = assembler._get_node_template("VAELoader")
399
- vae_loader_node['inputs']['vae_name'] = workflow_inputs["vae_name"]
400
- workflow[vae_loader_id] = vae_loader_node
401
-
402
- vae_decode_id = assembler.node_map.get("vae_decode")
403
- if vae_decode_id and vae_decode_id in workflow:
404
- workflow[vae_decode_id]['inputs']['vae'] = [vae_loader_id, 0]
405
- print(f" - Rewired 'vae_decode' (ID: {vae_decode_id}) to use new VAELoader.")
406
-
407
- vae_encode_id = assembler.node_map.get("vae_encode")
408
- if vae_encode_id and vae_encode_id in workflow:
409
- workflow[vae_encode_id]['inputs']['vae'] = [vae_loader_id, 0]
410
- print(f" - Rewired 'vae_encode' (ID: {vae_encode_id}) to use new VAELoader.")
411
- else:
412
- print("--- [Workflow Info] No VAE override. Using VAE from checkpoint. ---")
413
 
414
  progress(1.0, desc="All models ready. Requesting GPU for generation...")
415
 
@@ -421,11 +365,47 @@ class SdImagePipeline(BasePipeline):
421
  task_name=f"ImageGen ({task_type})",
422
  ui_inputs=ui_inputs,
423
  loras_string=loras_string,
424
- required_models_for_gpu=required_models,
425
  workflow=workflow,
426
  assembler=assembler,
427
  progress=progress
428
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
429
  finally:
430
  for temp_file in temp_files_to_clean:
431
  if temp_file and os.path.exists(temp_file):
 
11
  from .base_pipeline import BasePipeline
12
  from core.settings import *
13
  from comfy_integration.nodes import *
14
+ from utils.app_utils import get_value_at_index, sanitize_prompt, get_lora_path, get_embedding_path, ensure_controlnet_model_downloaded, sanitize_filename
15
  from core.workflow_assembler import WorkflowAssembler
16
 
17
  class SdImagePipeline(BasePipeline):
 
71
  node_info = workflow[node_id]
72
  class_type = node_info['class_type']
73
 
74
+ is_loader_with_filename = 'Loader' in class_type and any(key.endswith('_name') for key in node_info['inputs'])
75
+ if node_id in initial_objects and is_loader_with_filename:
76
+ continue
77
+
78
  node_class = NODE_CLASS_MAPPINGS.get(class_type)
79
  if node_class is None:
80
  raise RuntimeError(f"Could not find node class '{class_type}'. Is it imported in comfy_integration/nodes.py?")
 
113
 
114
  return get_value_at_index(computed_outputs[image_source_node_id], image_source_index)
115
 
116
+ def _gpu_logic(self, ui_inputs: Dict, loras_string: str, workflow: Dict[str, Any], assembler: WorkflowAssembler, progress=gr.Progress(track_tqdm=True)):
117
  model_display_name = ui_inputs['model_display_name']
118
 
 
 
 
119
  progress(0.4, desc="Executing workflow...")
120
 
121
+ initial_objects = {}
122
+
 
 
 
 
 
 
 
 
123
  decoded_images_tensor = self._execute_workflow(workflow, initial_objects=initial_objects)
124
 
125
  output_images = []
 
156
 
157
  lora_data = ui_inputs.get('lora_data', [])
158
  active_loras_for_gpu, active_loras_for_meta = [], []
159
+ if lora_data:
160
+ sources, ids, scales, files = lora_data[0::4], lora_data[1::4], lora_data[2::4], lora_data[3::4]
161
+
162
+ for i, (source, lora_id, scale, _) in enumerate(zip(sources, ids, scales, files)):
163
+ if scale > 0 and lora_id and lora_id.strip():
164
+ lora_filename = None
165
+ if source == "File":
166
+ lora_filename = sanitize_filename(lora_id)
167
+ elif source == "Civitai":
168
+ local_path, status = get_lora_path(source, lora_id, ui_inputs['civitai_api_key'], progress)
169
+ if local_path: lora_filename = os.path.basename(local_path)
170
+ else: raise gr.Error(f"Failed to prepare LoRA {lora_id}: {status}")
171
+
172
+ if lora_filename:
173
+ active_loras_for_gpu.append({"lora_name": lora_filename, "strength_model": scale, "strength_clip": scale})
174
+ active_loras_for_meta.append(f"{source} {lora_id}:{scale}")
175
 
 
 
 
176
  ui_inputs['denoise'] = 1.0
177
  if task_type == 'img2img': ui_inputs['denoise'] = ui_inputs.get('img2img_denoise', 0.7)
178
  elif task_type == 'hires_fix': ui_inputs['denoise'] = ui_inputs.get('hires_denoise', 0.55)
 
257
 
258
  controlnet_data = ui_inputs.get('controlnet_data', [])
259
  active_controlnets = []
260
+ if controlnet_data:
261
+ (cn_images, _, _, cn_strengths, cn_filepaths) = [controlnet_data[i::5] for i in range(5)]
262
+ for i in range(len(cn_images)):
263
+ if cn_images[i] and cn_strengths[i] > 0 and cn_filepaths[i] and cn_filepaths[i] != "None":
264
+ ensure_controlnet_model_downloaded(cn_filepaths[i], progress)
265
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
  if not os.path.exists(INPUT_DIR): os.makedirs(INPUT_DIR)
267
+ cn_temp_path = os.path.join(INPUT_DIR, f"temp_cn_{i}_{random.randint(1000, 9999)}.png")
268
+ cn_images[i].save(cn_temp_path, "PNG")
269
+ temp_files_to_clean.append(cn_temp_path)
270
+ active_controlnets.append({
271
+ "image": os.path.basename(cn_temp_path), "strength": cn_strengths[i],
272
+ "start_percent": 0.0, "end_percent": 1.0, "control_net_name": cn_filepaths[i]
273
  })
 
 
 
 
 
 
 
 
 
 
 
 
 
274
 
275
  from utils.app_utils import get_vae_path
276
  vae_source = ui_inputs.get('vae_source')
 
318
  if ui_inputs.get('seed') == -1:
319
  ui_inputs['seed'] = random.randint(0, 2**32 - 1)
320
 
321
+ dynamic_values = {'task_type': ui_inputs['task_type']}
322
 
323
  recipe_path = os.path.join(os.path.dirname(__file__), "workflow_recipes", "sd_unified_recipe.yaml")
324
  assembler = WorkflowAssembler(recipe_path, dynamic_values=dynamic_values)
325
 
326
+ model_display_name = ui_inputs['model_display_name']
327
+ if model_display_name not in ALL_MODEL_MAP:
328
+ raise gr.Error(f"Model '{model_display_name}' is not configured in model_list.yaml.")
329
+
330
+ _, components, _, _ = ALL_MODEL_MAP[model_display_name]
331
+
332
  workflow_inputs = {
333
  "positive_prompt": ui_inputs['positive_prompt'], "negative_prompt": ui_inputs['negative_prompt'],
334
  "seed": ui_inputs['seed'], "steps": ui_inputs['num_inference_steps'], "cfg": ui_inputs['guidance_scale'],
335
  "sampler_name": ui_inputs['sampler'], "scheduler": ui_inputs['scheduler'],
336
  "batch_size": ui_inputs['batch_size'],
 
337
  "denoise": ui_inputs['denoise'],
338
  "input_image": ui_inputs.get('input_image'),
339
  "inpaint_image": ui_inputs.get('inpaint_image'),
 
341
  "left": ui_inputs.get('outpaint_left'), "top": ui_inputs.get('outpaint_top'),
342
  "right": ui_inputs.get('outpaint_right'), "bottom": ui_inputs.get('outpaint_bottom'),
343
  "hires_upscaler": ui_inputs.get('hires_upscaler'), "hires_scale_by": ui_inputs.get('hires_scale_by'),
344
+ "unet_name": components['unet'],
345
+ "clip_name": components['clip'],
346
+ "vae_name": ui_inputs.get('vae_name', components['vae']),
347
+ "lora_chain": active_loras_for_gpu,
348
  "controlnet_chain": active_controlnets,
 
349
  "conditioning_chain": active_conditioning,
350
  }
351
 
 
354
  workflow_inputs['height'] = ui_inputs['height']
355
 
356
  workflow = assembler.assemble(workflow_inputs)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
 
358
  progress(1.0, desc="All models ready. Requesting GPU for generation...")
359
 
 
365
  task_name=f"ImageGen ({task_type})",
366
  ui_inputs=ui_inputs,
367
  loras_string=loras_string,
 
368
  workflow=workflow,
369
  assembler=assembler,
370
  progress=progress
371
  )
372
+
373
+ import json
374
+ import glob
375
+ from PIL import PngImagePlugin
376
+
377
+ prompt_json = json.dumps(workflow)
378
+
379
+ out_dir = os.path.abspath(OUTPUT_DIR)
380
+ os.makedirs(out_dir, exist_ok=True)
381
+
382
+ try:
383
+ existing_files = glob.glob(os.path.join(out_dir, "gen_*.png"))
384
+ existing_files.sort(key=os.path.getmtime)
385
+ while len(existing_files) > 50:
386
+ os.remove(existing_files.pop(0))
387
+ except Exception as e:
388
+ print(f"Warning: Failed to cleanup output dir: {e}")
389
+
390
+ final_results = []
391
+ for img in results:
392
+ if not isinstance(img, Image.Image):
393
+ final_results.append(img)
394
+ continue
395
+
396
+ metadata = PngImagePlugin.PngInfo()
397
+ params_string = img.info.get("parameters", "")
398
+ if params_string:
399
+ metadata.add_text("parameters", params_string)
400
+ metadata.add_text("prompt", prompt_json)
401
+
402
+ filename = f"gen_{random.randint(1000000, 9999999)}.png"
403
+ filepath = os.path.join(out_dir, filename)
404
+ img.save(filepath, "PNG", pnginfo=metadata)
405
+ final_results.append(filepath)
406
+
407
+ results = final_results
408
+
409
  finally:
410
  for temp_file in temp_files_to_clean:
411
  if temp_file and os.path.exists(temp_file):
core/pipelines/workflow_recipes/_partials/conditioning/{sd15.yaml → anima.yaml} RENAMED
@@ -1,59 +1,72 @@
1
  nodes:
2
- ckpt_loader:
3
- class_type: CheckpointLoaderSimple
4
- title: "Load SD1.5 Checkpoint"
5
-
6
- clip_set_last_layer:
7
- class_type: CLIPSetLastLayer
8
- title: "CLIP Set Last Layer"
 
 
 
 
 
 
 
9
 
10
  pos_prompt:
11
  class_type: CLIPTextEncode
12
  title: "Positive Prompt Encoder"
13
-
14
  neg_prompt:
15
  class_type: CLIPTextEncode
16
  title: "Negative Prompt Encoder"
17
 
18
  connections:
19
- - from: "ckpt_loader:0"
20
  to: "ksampler:model"
21
-
22
- - from: "ckpt_loader:1"
23
- to: "clip_set_last_layer:clip"
24
- - from: "clip_set_last_layer:0"
25
  to: "pos_prompt:clip"
26
- - from: "clip_set_last_layer:0"
27
  to: "neg_prompt:clip"
28
-
29
- - from: "ckpt_loader:2"
30
  to: "vae_decode:vae"
31
-
 
 
32
  - from: "pos_prompt:0"
33
  to: "ksampler:positive"
34
  - from: "neg_prompt:0"
35
  to: "ksampler:negative"
36
-
37
- ui_map:
38
- model_name: "ckpt_loader:ckpt_name"
39
- clip_skip: "clip_set_last_layer:stop_at_clip_layer"
40
- positive_prompt: "pos_prompt:text"
41
- negative_prompt: "neg_prompt:text"
42
-
 
 
 
 
 
 
 
43
  dynamic_controlnet_chains:
44
  controlnet_chain:
45
  template: "ControlNetApplyAdvanced"
46
  ksampler_node: "ksampler"
47
- vae_source: "ckpt_loader:2"
48
-
49
- dynamic_ipadapter_chains:
50
- ipadapter_chain:
51
- end: "ksampler"
52
- final_preset: "{{ ipadapter_final_preset }}"
53
- final_weight: "{{ ipadapter_final_weight }}"
54
- final_embeds_scaling: "{{ ipadapter_embeds_scaling }}"
55
 
56
  dynamic_conditioning_chains:
57
  conditioning_chain:
58
  ksampler_node: "ksampler"
59
- clip_source: "clip_set_last_layer:0"
 
 
 
 
 
 
 
 
1
  nodes:
2
+ unet_loader:
3
+ class_type: UNETLoader
4
+ title: "Load Anima UNET"
5
+ params:
6
+ weight_dtype: "default"
7
+ vae_loader:
8
+ class_type: VAELoader
9
+ title: "Load Anima VAE"
10
+ clip_loader:
11
+ class_type: CLIPLoader
12
+ title: "Load Anima CLIP"
13
+ params:
14
+ type: "stable_diffusion"
15
+ device: "default"
16
 
17
  pos_prompt:
18
  class_type: CLIPTextEncode
19
  title: "Positive Prompt Encoder"
 
20
  neg_prompt:
21
  class_type: CLIPTextEncode
22
  title: "Negative Prompt Encoder"
23
 
24
  connections:
25
+ - from: "unet_loader:0"
26
  to: "ksampler:model"
27
+
28
+ - from: "clip_loader:0"
 
 
29
  to: "pos_prompt:clip"
30
+ - from: "clip_loader:0"
31
  to: "neg_prompt:clip"
32
+
33
+ - from: "vae_loader:0"
34
  to: "vae_decode:vae"
35
+ - from: "vae_loader:0"
36
+ to: "vae_encode:vae"
37
+
38
  - from: "pos_prompt:0"
39
  to: "ksampler:positive"
40
  - from: "neg_prompt:0"
41
  to: "ksampler:negative"
42
+
43
+ dynamic_lora_chains:
44
+ lora_chain:
45
+ template: "LoraLoader"
46
+ output_map:
47
+ "unet_loader:0": "model"
48
+ "clip_loader:0": "clip"
49
+ input_map:
50
+ "model": "model"
51
+ "clip": "clip"
52
+ end_input_map:
53
+ "model": ["ksampler:model"]
54
+ "clip": ["pos_prompt:clip", "neg_prompt:clip"]
55
+
56
  dynamic_controlnet_chains:
57
  controlnet_chain:
58
  template: "ControlNetApplyAdvanced"
59
  ksampler_node: "ksampler"
60
+ vae_source_node: "vae_loader"
 
 
 
 
 
 
 
61
 
62
  dynamic_conditioning_chains:
63
  conditioning_chain:
64
  ksampler_node: "ksampler"
65
+ clip_source: "clip_loader:0"
66
+
67
+ ui_map:
68
+ unet_name: "unet_loader:unet_name"
69
+ vae_name: "vae_loader:vae_name"
70
+ clip_name: "clip_loader:clip_name"
71
+ positive_prompt: "pos_prompt:text"
72
+ negative_prompt: "neg_prompt:text"
core/pipelines/workflow_recipes/sd_unified_recipe.yaml CHANGED
@@ -1,10 +1,8 @@
1
  imports:
2
  - "_partials/_base_sampler.yaml"
3
  - "_partials/input/{{ task_type }}.yaml"
4
- - "_partials/conditioning/sd15.yaml"
5
 
6
  connections:
7
  - from: "latent_source:0"
8
- to: "ksampler:latent_image"
9
- - from: "ckpt_loader:2"
10
- to: "vae_encode:vae"
 
1
  imports:
2
  - "_partials/_base_sampler.yaml"
3
  - "_partials/input/{{ task_type }}.yaml"
4
+ - "_partials/conditioning/anima.yaml"
5
 
6
  connections:
7
  - from: "latent_source:0"
8
+ to: "ksampler:latent_image"
 
 
core/settings.py CHANGED
@@ -15,7 +15,6 @@ OUTPUT_DIR = "output"
15
  _PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
16
  _MODEL_LIST_PATH = os.path.join(_PROJECT_ROOT, 'yaml', 'model_list.yaml')
17
  _FILE_LIST_PATH = os.path.join(_PROJECT_ROOT, 'yaml', 'file_list.yaml')
18
- _IPADAPTER_LIST_PATH = os.path.join(_PROJECT_ROOT, 'yaml', 'ipadapter.yaml')
19
  _CONSTANTS_PATH = os.path.join(_PROJECT_ROOT, 'yaml', 'constants.yaml')
20
 
21
 
@@ -66,15 +65,12 @@ def load_models_from_yaml(model_list_filepath=_MODEL_LIST_PATH, download_map=Non
66
  if not isinstance(models, list): continue
67
  for model in models:
68
  display_name = model['display_name']
69
- filename = model['path']
70
-
71
- download_info = download_map.get(filename, {})
72
- repo_id = download_info.get('repo_id', '')
73
 
74
  model_tuple = (
75
- repo_id,
76
- filename,
77
- "SD1.5",
78
  None
79
  )
80
  model_maps[map_name][display_name] = model_tuple
@@ -103,15 +99,13 @@ try:
103
  MAX_EMBEDDINGS = _constants.get('MAX_EMBEDDINGS', 5)
104
  MAX_CONDITIONINGS = _constants.get('MAX_CONDITIONINGS', 10)
105
  MAX_CONTROLNETS = _constants.get('MAX_CONTROLNETS', 5)
106
- MAX_IPADAPTERS = _constants.get('MAX_IPADAPTERS', 5)
107
  LORA_SOURCE_CHOICES = _constants.get('LORA_SOURCE_CHOICES', ["Civitai", "Custom URL", "File"])
108
  RESOLUTION_MAP = _constants.get('RESOLUTION_MAP', {})
109
- SAMPLER_MAP = _constants.get('SAMPLER_MAP', {})
110
  except Exception as e:
111
  print(f"FATAL: Could not load constants from YAML. Error: {e}")
112
- MAX_LORAS, MAX_EMBEDDINGS, MAX_CONDITIONINGS, MAX_CONTROLNETS, MAX_IPADAPTERS = 5, 5, 10, 5, 5
113
  LORA_SOURCE_CHOICES = ["Civitai", "Custom URL", "File"]
114
- RESOLUTION_MAP, SAMPLER_MAP = {}, {}
115
 
116
 
117
- DEFAULT_NEGATIVE_PROMPT = "monochrome, (low quality, worst quality:1.2), 3d, watermark, signature, ugly, poorly drawn,"
 
15
  _PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
16
  _MODEL_LIST_PATH = os.path.join(_PROJECT_ROOT, 'yaml', 'model_list.yaml')
17
  _FILE_LIST_PATH = os.path.join(_PROJECT_ROOT, 'yaml', 'file_list.yaml')
 
18
  _CONSTANTS_PATH = os.path.join(_PROJECT_ROOT, 'yaml', 'constants.yaml')
19
 
20
 
 
65
  if not isinstance(models, list): continue
66
  for model in models:
67
  display_name = model['display_name']
68
+ components = model.get('components', {})
 
 
 
69
 
70
  model_tuple = (
71
+ None,
72
+ components,
73
+ "SDXL",
74
  None
75
  )
76
  model_maps[map_name][display_name] = model_tuple
 
99
  MAX_EMBEDDINGS = _constants.get('MAX_EMBEDDINGS', 5)
100
  MAX_CONDITIONINGS = _constants.get('MAX_CONDITIONINGS', 10)
101
  MAX_CONTROLNETS = _constants.get('MAX_CONTROLNETS', 5)
 
102
  LORA_SOURCE_CHOICES = _constants.get('LORA_SOURCE_CHOICES', ["Civitai", "Custom URL", "File"])
103
  RESOLUTION_MAP = _constants.get('RESOLUTION_MAP', {})
 
104
  except Exception as e:
105
  print(f"FATAL: Could not load constants from YAML. Error: {e}")
106
+ MAX_LORAS, MAX_EMBEDDINGS, MAX_CONDITIONINGS, MAX_CONTROLNETS = 5, 5, 10, 5
107
  LORA_SOURCE_CHOICES = ["Civitai", "Custom URL", "File"]
108
+ RESOLUTION_MAP = {}
109
 
110
 
111
+ DEFAULT_NEGATIVE_PROMPT = ""
requirements.txt CHANGED
@@ -1,5 +1,5 @@
1
- comfyui-frontend-package==1.41.20
2
- comfyui-workflow-templates==0.9.21
3
  comfyui-embedded-docs==0.4.3
4
  torch
5
  torchsde
 
1
+ comfyui-frontend-package==1.42.10
2
+ comfyui-workflow-templates==0.9.47
3
  comfyui-embedded-docs==0.4.3
4
  torch
5
  torchsde
ui/events.py CHANGED
@@ -10,7 +10,7 @@ from comfy_integration.nodes import SAMPLER_CHOICES, SCHEDULER_CHOICES
10
 
11
  from core.pipelines.controlnet_preprocessor import CPU_ONLY_PREPROCESSORS
12
  from utils.app_utils import PREPROCESSOR_MODEL_MAP, PREPROCESSOR_PARAMETER_MAP, save_uploaded_file_with_hash
13
- from ui.shared.ui_components import RESOLUTION_MAP, MAX_CONTROLNETS, MAX_IPADAPTERS, MAX_EMBEDDINGS, MAX_CONDITIONINGS, MAX_LORAS
14
 
15
 
16
  @lru_cache(maxsize=1)
@@ -22,104 +22,11 @@ def load_controlnet_config():
22
  with open(_CN_MODEL_LIST_PATH, 'r', encoding='utf-8') as f:
23
  config = yaml.safe_load(f)
24
  print("--- ✅ controlnet_models.yaml loaded successfully ---")
25
- return config.get("ControlNet", {}).get("SD1.5", [])
26
  except Exception as e:
27
  print(f"Error loading controlnet_models.yaml: {e}")
28
  return []
29
 
30
- @lru_cache(maxsize=1)
31
- def load_ipadapter_config():
32
- _PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
33
- _IPA_MODEL_LIST_PATH = os.path.join(_PROJECT_ROOT, 'yaml', 'ipadapter.yaml')
34
- try:
35
- print("--- Loading ipadapter.yaml ---")
36
- with open(_IPA_MODEL_LIST_PATH, 'r', encoding='utf-8') as f:
37
- config = yaml.safe_load(f)
38
- print("--- ✅ ipadapter.yaml loaded successfully ---")
39
- return config
40
- except Exception as e:
41
- print(f"Error loading ipadapter.yaml: {e}")
42
- return {}
43
-
44
-
45
- def apply_data_to_ui(data, prefix, ui_components):
46
- final_sampler = data.get('sampler') if data.get('sampler') in SAMPLER_CHOICES else SAMPLER_CHOICES[0]
47
- default_scheduler = 'normal' if 'normal' in SCHEDULER_CHOICES else SCHEDULER_CHOICES[0]
48
- final_scheduler = data.get('scheduler') if data.get('scheduler') in SCHEDULER_CHOICES else default_scheduler
49
-
50
- updates = {}
51
- base_model_name = data.get('base_model')
52
-
53
- model_map = MODEL_MAP_CHECKPOINT
54
-
55
- if f'base_model_{prefix}' in ui_components:
56
- model_dropdown_component = ui_components[f'base_model_{prefix}']
57
- if base_model_name and base_model_name in model_map:
58
- updates[model_dropdown_component] = base_model_name
59
- else:
60
- updates[model_dropdown_component] = gr.update()
61
-
62
- common_params = {
63
- f'prompt_{prefix}': data.get('prompt', ''),
64
- f'neg_prompt_{prefix}': data.get('negative_prompt', ''),
65
- f'seed_{prefix}': data.get('seed', -1),
66
- f'cfg_{prefix}': data.get('cfg_scale', 7.5),
67
- f'steps_{prefix}': data.get('steps', 28),
68
- f'sampler_{prefix}': final_sampler,
69
- f'scheduler_{prefix}': final_scheduler,
70
- }
71
-
72
- for comp_name, value in common_params.items():
73
- if comp_name in ui_components:
74
- updates[ui_components[comp_name]] = value
75
-
76
- if prefix == 'txt2img':
77
- if f'width_{prefix}' in ui_components:
78
- updates[ui_components[f'width_{prefix}']] = data.get('width', 1024)
79
- if f'height_{prefix}' in ui_components:
80
- updates[ui_components[f'height_{prefix}']] = data.get('height', 1024)
81
-
82
- tab_indices = {"txt2img": 0, "img2img": 1, "inpaint": 2, "outpaint": 3, "hires_fix": 4}
83
- tab_index = tab_indices.get(prefix, 0)
84
-
85
- updates[ui_components['tabs']] = gr.Tabs(selected=0)
86
- updates[ui_components['image_gen_tabs']] = gr.Tabs(selected=tab_index)
87
-
88
- return updates
89
-
90
-
91
- def send_info_to_tab(image, prefix, ui_components):
92
- if not image or not image.info.get('parameters', ''):
93
- all_comps = [comp for comp_or_list in ui_components.values() for comp in (comp_or_list if isinstance(comp_or_list, list) else [comp_or_list])]
94
- return {comp: gr.update() for comp in all_comps}
95
-
96
- data = parse_parameters(image.info['parameters'])
97
-
98
- image_input_map = {
99
- "img2img": 'input_image_img2img',
100
- "inpaint": 'input_image_dict_inpaint',
101
- "outpaint": 'input_image_outpaint',
102
- "hires_fix": 'input_image_hires_fix'
103
- }
104
-
105
- updates = apply_data_to_ui(data, prefix, ui_components)
106
-
107
- if prefix in image_input_map and image_input_map[prefix] in ui_components:
108
- component_key = image_input_map[prefix]
109
- updates[ui_components[component_key]] = gr.update(value=image)
110
-
111
- return updates
112
-
113
-
114
- def send_info_by_hash(image, ui_components):
115
- if not image or not image.info.get('parameters', ''):
116
- all_comps = [comp for comp_or_list in ui_components.values() for comp in (comp_or_list if isinstance(comp_or_list, list) else [comp_or_list])]
117
- return {comp: gr.update() for comp in all_comps}
118
-
119
- data = parse_parameters(image.info['parameters'])
120
-
121
- return apply_data_to_ui(data, "txt2img", ui_components)
122
-
123
 
124
  def attach_event_handlers(ui_components, demo):
125
  def update_cn_input_visibility(choice):
@@ -230,7 +137,7 @@ def attach_event_handlers(ui_components, demo):
230
  ] + all_dynamic_inputs,
231
  outputs=[ui_components["output_gallery_cn"]]
232
  )
233
-
234
  def create_lora_event_handlers(prefix):
235
  lora_rows = ui_components[f'lora_rows_{prefix}']
236
  lora_ids = ui_components[f'lora_ids_{prefix}']
@@ -362,57 +269,6 @@ def attach_event_handlers(ui_components, demo):
362
  show_progress=False
363
  )
364
 
365
- def create_ipadapter_event_handlers(prefix):
366
- ipa_rows = ui_components[f'ipadapter_rows_{prefix}']
367
- ipa_lora_strengths = ui_components[f'ipadapter_lora_strengths_{prefix}']
368
- ipa_final_preset = ui_components[f'ipadapter_final_preset_{prefix}']
369
- ipa_final_lora_strength = ui_components[f'ipadapter_final_lora_strength_{prefix}']
370
- count_state = ui_components[f'ipadapter_count_state_{prefix}']
371
- add_button = ui_components[f'add_ipadapter_button_{prefix}']
372
- del_button = ui_components[f'delete_ipadapter_button_{prefix}']
373
- accordion = ui_components[f'ipadapter_accordion_{prefix}']
374
-
375
- def add_ipa_row(c):
376
- c += 1
377
- return {
378
- count_state: c,
379
- ipa_rows[c - 1]: gr.update(visible=True),
380
- add_button: gr.update(visible=c < MAX_IPADAPTERS),
381
- del_button: gr.update(visible=True),
382
- }
383
-
384
- def del_ipa_row(c):
385
- c -= 1
386
- return {
387
- count_state: c,
388
- ipa_rows[c]: gr.update(visible=False),
389
- add_button: gr.update(visible=True),
390
- del_button: gr.update(visible=c > 0),
391
- }
392
-
393
- add_outputs = [count_state, add_button, del_button] + ipa_rows
394
- del_outputs = [count_state, add_button, del_button] + ipa_rows
395
- add_button.click(fn=add_ipa_row, inputs=[count_state], outputs=add_outputs, show_progress=False)
396
- del_button.click(fn=del_ipa_row, inputs=[count_state], outputs=del_outputs, show_progress=False)
397
-
398
- def on_preset_change(preset_value):
399
- config = load_ipadapter_config()
400
- faceid_presets = []
401
- if isinstance(config, list):
402
- faceid_presets = [
403
- p.get('preset_name', '') for p in config
404
- if 'FACE' in p.get('preset_name', '') or 'FACEID' in p.get('preset_name', '')
405
- ]
406
- is_visible = preset_value in faceid_presets
407
- updates = [gr.update(visible=is_visible)] * (MAX_IPADAPTERS + 1)
408
- return updates
409
-
410
- all_lora_strength_sliders = [ipa_final_lora_strength] + ipa_lora_strengths
411
- ipa_final_preset.change(fn=on_preset_change, inputs=[ipa_final_preset], outputs=all_lora_strength_sliders, show_progress=False)
412
-
413
- 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)
414
-
415
-
416
  def create_embedding_event_handlers(prefix):
417
  rows = ui_components[f'embedding_rows_{prefix}']
418
  ids = ui_components[f'embeddings_ids_{prefix}']
@@ -531,7 +387,6 @@ def attach_event_handlers(ui_components, demo):
531
 
532
  lora_data_components = ui_components.get(f'all_lora_components_flat_{prefix}', [])
533
  controlnet_data_components = ui_components.get(f'all_controlnet_components_flat_{prefix}', [])
534
- ipadapter_data_components = ui_components.get(f'all_ipadapter_components_flat_{prefix}', [])
535
  embedding_data_components = ui_components.get(f'all_embedding_components_flat_{prefix}', [])
536
  conditioning_data_components = ui_components.get(f'all_conditioning_components_flat_{prefix}', [])
537
 
@@ -541,7 +396,7 @@ def attach_event_handlers(ui_components, demo):
541
 
542
  input_keys = list(run_inputs_map.keys())
543
  input_list_flat = [v for v in run_inputs_map.values() if v is not None]
544
- input_list_flat += lora_data_components + controlnet_data_components + ipadapter_data_components + embedding_data_components + conditioning_data_components
545
 
546
  def create_ui_inputs_dict(*args):
547
  valid_keys = [k for k in input_keys if run_inputs_map[k] is not None]
@@ -552,8 +407,6 @@ def attach_event_handlers(ui_components, demo):
552
  arg_idx += len(lora_data_components)
553
  ui_dict['controlnet_data'] = list(args[arg_idx : arg_idx + len(controlnet_data_components)])
554
  arg_idx += len(controlnet_data_components)
555
- ui_dict['ipadapter_data'] = list(args[arg_idx : arg_idx + len(ipadapter_data_components)])
556
- arg_idx += len(ipadapter_data_components)
557
  ui_dict['embedding_data'] = list(args[arg_idx : arg_idx + len(embedding_data_components)])
558
  arg_idx += len(embedding_data_components)
559
  ui_dict['conditioning_data'] = list(args[arg_idx : arg_idx + len(conditioning_data_components)])
@@ -584,7 +437,6 @@ def attach_event_handlers(ui_components, demo):
584
  show_progress=False
585
  )
586
  if f'add_controlnet_button_{prefix}' in ui_components: create_controlnet_event_handlers(prefix)
587
- if f'add_ipadapter_button_{prefix}' in ui_components: create_ipadapter_event_handlers(prefix)
588
  if f'add_embedding_button_{prefix}' in ui_components:
589
  create_embedding_event_handlers(prefix)
590
  if f'embeddings_uploads_{prefix}' in ui_components:
@@ -615,29 +467,13 @@ def attach_event_handlers(ui_components, demo):
615
 
616
  create_run_event(prefix, task_type)
617
 
618
-
619
- ui_components["info_get_button"].click(
620
- get_png_info,
621
- [ui_components["info_image_input"]],
622
- [ui_components["info_prompt_output"], ui_components["info_neg_prompt_output"], ui_components["info_params_output"]]
623
- )
624
-
625
- flat_ui_list = [comp for comp_or_list in ui_components.values() for comp in (comp_or_list if isinstance(comp_or_list, list) else [comp_or_list])]
626
-
627
- ui_components["send_to_txt2img_button"].click(lambda img: send_info_by_hash(img, ui_components), [ui_components["info_image_input"]], flat_ui_list)
628
- ui_components["send_to_img2img_button"].click(lambda img: send_info_to_tab(img, "img2img", ui_components), [ui_components["info_image_input"]], flat_ui_list)
629
- ui_components["send_to_inpaint_button"].click(lambda img: send_info_to_tab(img, "inpaint", ui_components), [ui_components["info_image_input"]], flat_ui_list)
630
- ui_components["send_to_outpaint_button"].click(lambda img: send_info_to_tab(img, "outpaint", ui_components), [ui_components["info_image_input"]], flat_ui_list)
631
- ui_components["send_to_hires_fix_button"].click(lambda img: send_info_to_tab(img, "hires_fix", ui_components), [ui_components["info_image_input"]], flat_ui_list)
632
-
633
  def on_aspect_ratio_change(ratio_key, model_display_name):
634
- model_type = MODEL_TYPE_MAP.get(model_display_name, 'sd1.5').lower()
635
- if model_type == 'sd1.5': model_type = 'sd15'
636
- res_map = RESOLUTION_MAP.get(model_type, RESOLUTION_MAP.get("sd15", {}))
637
- w, h = res_map.get(ratio_key, (512, 512))
638
  return w, h
639
 
640
- for prefix in ["txt2img", "img2img", "inpaint", "outpaint", "hires_fix"]:
641
  if f'aspect_ratio_{prefix}' in ui_components:
642
  aspect_ratio_dropdown = ui_components[f'aspect_ratio_{prefix}']
643
  width_component = ui_components[f'width_{prefix}']
@@ -695,41 +531,10 @@ def attach_event_handlers(ui_components, demo):
695
  updates[filepath_state] = filepath
696
  return updates
697
 
698
- def initialize_all_ipa_dropdowns():
699
- config = load_ipadapter_config()
700
- if not config or not isinstance(config, list): return {}
701
-
702
- unified_presets = []
703
- faceid_presets = []
704
- for preset_info in config:
705
- name = preset_info.get("preset_name")
706
- if not name:
707
- continue
708
- if "FACEID" in name or "FACE" in name:
709
- faceid_presets.append(name)
710
- else:
711
- unified_presets.append(name)
712
-
713
- all_presets = unified_presets + faceid_presets
714
- default_preset = all_presets[0] if all_presets else None
715
- is_faceid_default = default_preset in faceid_presets
716
-
717
- lora_strength_update = gr.update(visible=is_faceid_default)
718
-
719
- updates = {}
720
- for prefix in ["txt2img", "img2img", "inpaint", "outpaint", "hires_fix"]:
721
- if f'ipadapter_final_preset_{prefix}' in ui_components:
722
- for lora_strength_slider in ui_components[f'ipadapter_lora_strengths_{prefix}']:
723
- updates[lora_strength_slider] = lora_strength_update
724
- updates[ui_components[f'ipadapter_final_preset_{prefix}']] = gr.update(choices=all_presets, value=default_preset)
725
- updates[ui_components[f'ipadapter_final_lora_strength_{prefix}']] = lora_strength_update
726
- return updates
727
-
728
  def run_on_load():
 
729
  cn_updates = initialize_all_cn_dropdowns()
730
- ipa_updates = initialize_all_ipa_dropdowns()
731
-
732
- all_updates = {**cn_updates, **ipa_updates}
733
 
734
  default_preprocessor = "Canny Edge"
735
  model_update = update_preprocessor_models_dropdown(default_preprocessor)
@@ -752,11 +557,7 @@ def attach_event_handlers(ui_components, demo):
752
  all_load_outputs.extend(ui_components[f'controlnet_types_{prefix}'])
753
  all_load_outputs.extend(ui_components[f'controlnet_series_{prefix}'])
754
  all_load_outputs.extend(ui_components[f'controlnet_filepaths_{prefix}'])
755
- if f'ipadapter_final_preset_{prefix}' in ui_components:
756
- all_load_outputs.extend(ui_components[f'ipadapter_lora_strengths_{prefix}'])
757
- all_load_outputs.append(ui_components[f'ipadapter_final_preset_{prefix}'])
758
- all_load_outputs.append(ui_components[f'ipadapter_final_lora_strength_{prefix}'])
759
-
760
  all_load_outputs.extend([
761
  ui_components["preprocessor_model_cn"],
762
  *ui_components["cn_sliders"],
@@ -765,8 +566,9 @@ def attach_event_handlers(ui_components, demo):
765
  ui_components["run_cn"],
766
  ui_components["zero_gpu_cn"]
767
  ])
768
-
769
- demo.load(
770
- fn=run_on_load,
771
- outputs=all_load_outputs
772
- )
 
 
10
 
11
  from core.pipelines.controlnet_preprocessor import CPU_ONLY_PREPROCESSORS
12
  from utils.app_utils import PREPROCESSOR_MODEL_MAP, PREPROCESSOR_PARAMETER_MAP, save_uploaded_file_with_hash
13
+ from ui.shared.ui_components import RESOLUTION_MAP, MAX_CONTROLNETS, MAX_EMBEDDINGS, MAX_CONDITIONINGS, MAX_LORAS
14
 
15
 
16
  @lru_cache(maxsize=1)
 
22
  with open(_CN_MODEL_LIST_PATH, 'r', encoding='utf-8') as f:
23
  config = yaml.safe_load(f)
24
  print("--- ✅ controlnet_models.yaml loaded successfully ---")
25
+ return config.get("ControlNet", {}).get("Anima", [])
26
  except Exception as e:
27
  print(f"Error loading controlnet_models.yaml: {e}")
28
  return []
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
  def attach_event_handlers(ui_components, demo):
32
  def update_cn_input_visibility(choice):
 
137
  ] + all_dynamic_inputs,
138
  outputs=[ui_components["output_gallery_cn"]]
139
  )
140
+
141
  def create_lora_event_handlers(prefix):
142
  lora_rows = ui_components[f'lora_rows_{prefix}']
143
  lora_ids = ui_components[f'lora_ids_{prefix}']
 
269
  show_progress=False
270
  )
271
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  def create_embedding_event_handlers(prefix):
273
  rows = ui_components[f'embedding_rows_{prefix}']
274
  ids = ui_components[f'embeddings_ids_{prefix}']
 
387
 
388
  lora_data_components = ui_components.get(f'all_lora_components_flat_{prefix}', [])
389
  controlnet_data_components = ui_components.get(f'all_controlnet_components_flat_{prefix}', [])
 
390
  embedding_data_components = ui_components.get(f'all_embedding_components_flat_{prefix}', [])
391
  conditioning_data_components = ui_components.get(f'all_conditioning_components_flat_{prefix}', [])
392
 
 
396
 
397
  input_keys = list(run_inputs_map.keys())
398
  input_list_flat = [v for v in run_inputs_map.values() if v is not None]
399
+ input_list_flat += lora_data_components + controlnet_data_components + embedding_data_components + conditioning_data_components
400
 
401
  def create_ui_inputs_dict(*args):
402
  valid_keys = [k for k in input_keys if run_inputs_map[k] is not None]
 
407
  arg_idx += len(lora_data_components)
408
  ui_dict['controlnet_data'] = list(args[arg_idx : arg_idx + len(controlnet_data_components)])
409
  arg_idx += len(controlnet_data_components)
 
 
410
  ui_dict['embedding_data'] = list(args[arg_idx : arg_idx + len(embedding_data_components)])
411
  arg_idx += len(embedding_data_components)
412
  ui_dict['conditioning_data'] = list(args[arg_idx : arg_idx + len(conditioning_data_components)])
 
437
  show_progress=False
438
  )
439
  if f'add_controlnet_button_{prefix}' in ui_components: create_controlnet_event_handlers(prefix)
 
440
  if f'add_embedding_button_{prefix}' in ui_components:
441
  create_embedding_event_handlers(prefix)
442
  if f'embeddings_uploads_{prefix}' in ui_components:
 
467
 
468
  create_run_event(prefix, task_type)
469
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
470
  def on_aspect_ratio_change(ratio_key, model_display_name):
471
+ model_type = MODEL_TYPE_MAP.get(model_display_name, 'sdxl').lower()
472
+ res_map = RESOLUTION_MAP.get(model_type, RESOLUTION_MAP.get("sdxl", {}))
473
+ w, h = res_map.get(ratio_key, (1024, 1024))
 
474
  return w, h
475
 
476
+ for prefix in ["txt2img", "img2img", "outpaint", "hires_fix"]:
477
  if f'aspect_ratio_{prefix}' in ui_components:
478
  aspect_ratio_dropdown = ui_components[f'aspect_ratio_{prefix}']
479
  width_component = ui_components[f'width_{prefix}']
 
531
  updates[filepath_state] = filepath
532
  return updates
533
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
534
  def run_on_load():
535
+ all_updates = {}
536
  cn_updates = initialize_all_cn_dropdowns()
537
+ all_updates.update(cn_updates)
 
 
538
 
539
  default_preprocessor = "Canny Edge"
540
  model_update = update_preprocessor_models_dropdown(default_preprocessor)
 
557
  all_load_outputs.extend(ui_components[f'controlnet_types_{prefix}'])
558
  all_load_outputs.extend(ui_components[f'controlnet_series_{prefix}'])
559
  all_load_outputs.extend(ui_components[f'controlnet_filepaths_{prefix}'])
560
+
 
 
 
 
561
  all_load_outputs.extend([
562
  ui_components["preprocessor_model_cn"],
563
  *ui_components["cn_sliders"],
 
566
  ui_components["run_cn"],
567
  ui_components["zero_gpu_cn"]
568
  ])
569
+
570
+ if all_load_outputs:
571
+ demo.load(
572
+ fn=run_on_load,
573
+ outputs=all_load_outputs
574
+ )
ui/layout.py CHANGED
@@ -21,20 +21,19 @@ def build_ui(event_handler_function):
21
  ui_components = {}
22
 
23
  with gr.Blocks() as demo:
24
- gr.Markdown("# ImageGen - SD1.5")
25
  gr.Markdown(
26
  "This demo is a streamlined version of the [Comfy web UI](https://github.com/RioShiina47/comfy-webui)'s ImgGen functionality. "
27
  "Other versions are also available: "
28
  "[FLUX.2](https://huggingface.co/spaces/RioShiina/ImageGen-FLUX.2), "
29
  "[Z-Image](https://huggingface.co/spaces/RioShiina/ImageGen-Z-Image), "
30
- "[Qwen-Image](https://huggingface.co/spaces/RioShiina/ImageGen-Qwen-Image), "
31
  "[Illstrious](https://huggingface.co/spaces/RioShiina/ImageGen-Illstrious), "
32
  "[NoobAI](https://huggingface.co/spaces/RioShiina/ImageGen-NoobAI), "
33
  "[Pony](https://huggingface.co/spaces/RioShiina/ImageGen-Pony), "
34
  "[SDXL](https://huggingface.co/spaces/RioShiina/ImageGen-SDXL)"
35
  )
36
  with gr.Tabs(elem_id="tabs_container") as tabs:
37
- with gr.TabItem("SD1.5", id=0):
38
  with gr.Tabs(elem_id="image_gen_tabs") as image_gen_tabs:
39
  with gr.TabItem("Txt2Img", id=0):
40
  ui_components.update(txt2img_ui.create_ui())
@@ -81,34 +80,9 @@ def build_ui(event_handler_function):
81
  "preprocessor_settings_ui": preprocessor_settings_ui, "cn_sliders": cn_sliders,
82
  "cn_dropdowns": cn_dropdowns, "cn_checkboxes": cn_checkboxes
83
  })
84
-
85
- with gr.TabItem("PNG Info", id=2):
86
- with gr.Column():
87
- info_image_input = gr.Image(type="pil", label="Upload Image", height=512)
88
- with gr.Row():
89
- info_get_button = gr.Button("Get Info")
90
- send_to_txt2img_button = gr.Button("Send to Txt2Img", variant="primary")
91
- with gr.Row():
92
- send_to_img2img_button = gr.Button("Send to Img2Img")
93
- send_to_inpaint_button = gr.Button("Send to Inpaint")
94
- send_to_outpaint_button = gr.Button("Send to Outpaint")
95
- send_to_hires_fix_button = gr.Button("Send to Hires. Fix")
96
- gr.Markdown("### Positive Prompt"); info_prompt_output = gr.Textbox(lines=3, interactive=False, show_label=False)
97
- gr.Markdown("### Negative Prompt"); info_neg_prompt_output = gr.Textbox(lines=3, interactive=False, show_label=False)
98
- gr.Markdown("### Other Parameters"); info_params_output = gr.Textbox(lines=5, interactive=False, show_label=False)
99
- ui_components.update({
100
- "info_image_input": info_image_input, "info_get_button": info_get_button,
101
- "send_to_txt2img_button": send_to_txt2img_button,
102
- "send_to_img2img_button": send_to_img2img_button,
103
- "send_to_inpaint_button": send_to_inpaint_button,
104
- "send_to_outpaint_button": send_to_outpaint_button,
105
- "send_to_hires_fix_button": send_to_hires_fix_button,
106
- "info_prompt_output": info_prompt_output, "info_neg_prompt_output": info_neg_prompt_output,
107
- "info_params_output": info_params_output
108
- })
109
-
110
- ui_components["tabs"] = tabs
111
 
 
 
112
  gr.Markdown("<div style='text-align: center; margin-top: 20px;'>Made by RioShiina with ❤️<br><a href='https://github.com/RioShiina47' target='_blank'>GitHub</a> | <a href='https://huggingface.co/RioShiina' target='_blank'>Hugging Face</a> | <a href='https://civitai.com/user/RioShiina' target='_blank'>Civitai</a></div>")
113
 
114
  event_handler_function(ui_components, demo)
 
21
  ui_components = {}
22
 
23
  with gr.Blocks() as demo:
24
+ gr.Markdown("# ImageGen - Anima")
25
  gr.Markdown(
26
  "This demo is a streamlined version of the [Comfy web UI](https://github.com/RioShiina47/comfy-webui)'s ImgGen functionality. "
27
  "Other versions are also available: "
28
  "[FLUX.2](https://huggingface.co/spaces/RioShiina/ImageGen-FLUX.2), "
29
  "[Z-Image](https://huggingface.co/spaces/RioShiina/ImageGen-Z-Image), "
 
30
  "[Illstrious](https://huggingface.co/spaces/RioShiina/ImageGen-Illstrious), "
31
  "[NoobAI](https://huggingface.co/spaces/RioShiina/ImageGen-NoobAI), "
32
  "[Pony](https://huggingface.co/spaces/RioShiina/ImageGen-Pony), "
33
  "[SDXL](https://huggingface.co/spaces/RioShiina/ImageGen-SDXL)"
34
  )
35
  with gr.Tabs(elem_id="tabs_container") as tabs:
36
+ with gr.TabItem("ImageGen", id=0):
37
  with gr.Tabs(elem_id="image_gen_tabs") as image_gen_tabs:
38
  with gr.TabItem("Txt2Img", id=0):
39
  ui_components.update(txt2img_ui.create_ui())
 
80
  "preprocessor_settings_ui": preprocessor_settings_ui, "cn_sliders": cn_sliders,
81
  "cn_dropdowns": cn_dropdowns, "cn_checkboxes": cn_checkboxes
82
  })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
 
84
+ ui_components['tabs'] = tabs
85
+
86
  gr.Markdown("<div style='text-align: center; margin-top: 20px;'>Made by RioShiina with ❤️<br><a href='https://github.com/RioShiina47' target='_blank'>GitHub</a> | <a href='https://huggingface.co/RioShiina' target='_blank'>Hugging Face</a> | <a href='https://civitai.com/user/RioShiina' target='_blank'>Civitai</a></div>")
87
 
88
  event_handler_function(ui_components, demo)
ui/shared/hires_fix_ui.py CHANGED
@@ -3,7 +3,7 @@ from core.settings import MODEL_MAP_CHECKPOINT
3
  from comfy_integration.nodes import SAMPLER_CHOICES, SCHEDULER_CHOICES
4
  from .ui_components import (
5
  create_lora_settings_ui,
6
- create_controlnet_ui, create_ipadapter_ui, create_embedding_ui,
7
  create_conditioning_ui, create_vae_override_ui, create_api_key_ui
8
  )
9
 
@@ -27,7 +27,7 @@ def create_ui():
27
  components[f'input_image_{prefix}'] = gr.Image(type="pil", label="Input Image", height=255)
28
  with gr.Column(scale=2):
29
  components[f'prompt_{prefix}'] = gr.Text(label="Prompt", lines=3, placeholder="Describe the final image...")
30
- components[f'neg_prompt_{prefix}'] = gr.Text(label="Negative prompt", lines=3, value="monochrome, (low quality, worst quality:1.2), 3d, watermark, signature, ugly, poorly drawn,")
31
 
32
  with gr.Row():
33
  with gr.Column(scale=1):
@@ -45,18 +45,18 @@ def create_ui():
45
  components[f'denoise_{prefix}'] = gr.Slider(label="Denoise Strength", minimum=0.0, maximum=1.0, step=0.01, value=0.55)
46
 
47
  with gr.Row():
48
- components[f'sampler_{prefix}'] = gr.Dropdown(label="Sampler", choices=SAMPLER_CHOICES, value=SAMPLER_CHOICES[0])
49
- components[f'scheduler_{prefix}'] = gr.Dropdown(label="Scheduler", choices=SCHEDULER_CHOICES, value='normal' if 'normal' in SCHEDULER_CHOICES else SCHEDULER_CHOICES[0])
50
  with gr.Row():
51
- components[f'steps_{prefix}'] = gr.Slider(label="Steps", minimum=1, maximum=100, step=1, value=28)
52
- components[f'cfg_{prefix}'] = gr.Slider(label="CFG Scale", minimum=1.0, maximum=20.0, step=0.1, value=7.5)
53
  with gr.Row():
54
  components[f'seed_{prefix}'] = gr.Number(label="Seed (-1 for random)", value=-1, precision=0)
55
  components[f'batch_size_{prefix}'] = gr.Slider(label="Batch Size", minimum=1, maximum=16, step=1, value=1)
56
  with gr.Row():
57
- components[f'clip_skip_{prefix}'] = gr.Slider(label="Clip Skip", minimum=1, maximum=2, step=1, value=1)
58
  components[f'zero_gpu_{prefix}'] = gr.Number(label="ZeroGPU Duration (s)", value=None, placeholder="Default: 60s, Max: 120s", info="Optional: Set how long to reserve the GPU.")
59
 
 
60
  components[f'width_{prefix}'] = gr.State(value=512)
61
  components[f'height_{prefix}'] = gr.State(value=512)
62
 
@@ -66,9 +66,8 @@ def create_ui():
66
  components.update(create_api_key_ui(prefix))
67
  components.update(create_lora_settings_ui(prefix))
68
  components.update(create_controlnet_ui(prefix))
69
- components.update(create_ipadapter_ui(prefix))
70
- components.update(create_embedding_ui(prefix))
71
  components.update(create_conditioning_ui(prefix))
72
- components.update(create_vae_override_ui(prefix))
73
 
74
  return components
 
3
  from comfy_integration.nodes import SAMPLER_CHOICES, SCHEDULER_CHOICES
4
  from .ui_components import (
5
  create_lora_settings_ui,
6
+ create_controlnet_ui, create_embedding_ui,
7
  create_conditioning_ui, create_vae_override_ui, create_api_key_ui
8
  )
9
 
 
27
  components[f'input_image_{prefix}'] = gr.Image(type="pil", label="Input Image", height=255)
28
  with gr.Column(scale=2):
29
  components[f'prompt_{prefix}'] = gr.Text(label="Prompt", lines=3, placeholder="Describe the final image...")
30
+ components[f'neg_prompt_{prefix}'] = gr.Text(label="Negative prompt", lines=3, value="")
31
 
32
  with gr.Row():
33
  with gr.Column(scale=1):
 
45
  components[f'denoise_{prefix}'] = gr.Slider(label="Denoise Strength", minimum=0.0, maximum=1.0, step=0.01, value=0.55)
46
 
47
  with gr.Row():
48
+ components[f'sampler_{prefix}'] = gr.Dropdown(label="Sampler", choices=SAMPLER_CHOICES, value="er_sde")
49
+ components[f'scheduler_{prefix}'] = gr.Dropdown(label="Scheduler", choices=SCHEDULER_CHOICES, value="simple")
50
  with gr.Row():
51
+ components[f'steps_{prefix}'] = gr.Slider(label="Steps", minimum=1, maximum=100, step=1, value=30)
52
+ components[f'cfg_{prefix}'] = gr.Slider(label="CFG Scale", minimum=1.0, maximum=20.0, step=0.1, value=4.0)
53
  with gr.Row():
54
  components[f'seed_{prefix}'] = gr.Number(label="Seed (-1 for random)", value=-1, precision=0)
55
  components[f'batch_size_{prefix}'] = gr.Slider(label="Batch Size", minimum=1, maximum=16, step=1, value=1)
56
  with gr.Row():
 
57
  components[f'zero_gpu_{prefix}'] = gr.Number(label="ZeroGPU Duration (s)", value=None, placeholder="Default: 60s, Max: 120s", info="Optional: Set how long to reserve the GPU.")
58
 
59
+ components[f'clip_skip_{prefix}'] = gr.State(value=1)
60
  components[f'width_{prefix}'] = gr.State(value=512)
61
  components[f'height_{prefix}'] = gr.State(value=512)
62
 
 
66
  components.update(create_api_key_ui(prefix))
67
  components.update(create_lora_settings_ui(prefix))
68
  components.update(create_controlnet_ui(prefix))
69
+ # components.update(create_embedding_ui(prefix))
 
70
  components.update(create_conditioning_ui(prefix))
71
+ # components.update(create_vae_override_ui(prefix))
72
 
73
  return components
ui/shared/img2img_ui.py CHANGED
@@ -3,7 +3,7 @@ from core.settings import MODEL_MAP_CHECKPOINT
3
  from comfy_integration.nodes import SAMPLER_CHOICES, SCHEDULER_CHOICES
4
  from .ui_components import (
5
  create_lora_settings_ui,
6
- create_controlnet_ui, create_ipadapter_ui, create_embedding_ui,
7
  create_conditioning_ui, create_vae_override_ui, create_api_key_ui
8
  )
9
 
@@ -23,34 +23,34 @@ def create_ui():
23
 
24
  with gr.Column(scale=2):
25
  components[f'prompt_{prefix}'] = gr.Text(label="Prompt", lines=3, placeholder="Enter your prompt")
26
- components[f'neg_prompt_{prefix}'] = gr.Text(label="Negative prompt", lines=3, value="monochrome, (low quality, worst quality:1.2), 3d, watermark, signature, ugly, poorly drawn,")
27
 
28
  with gr.Row():
29
  with gr.Column(scale=1):
30
  components[f'denoise_{prefix}'] = gr.Slider(label="Denoise Strength", minimum=0.0, maximum=1.0, step=0.01, value=0.7)
31
 
32
  with gr.Row():
33
- components[f'sampler_{prefix}'] = gr.Dropdown(label="Sampler", choices=SAMPLER_CHOICES, value=SAMPLER_CHOICES[0])
34
- components[f'scheduler_{prefix}'] = gr.Dropdown(label="Scheduler", choices=SCHEDULER_CHOICES, value='normal' if 'normal' in SCHEDULER_CHOICES else SCHEDULER_CHOICES[0])
35
  with gr.Row():
36
- components[f'steps_{prefix}'] = gr.Slider(label="Steps", minimum=1, maximum=100, step=1, value=28)
37
- components[f'cfg_{prefix}'] = gr.Slider(label="CFG Scale", minimum=1.0, maximum=20.0, step=0.1, value=7.5)
38
  with gr.Row():
39
  components[f'seed_{prefix}'] = gr.Number(label="Seed (-1 for random)", value=-1, precision=0)
40
  components[f'batch_size_{prefix}'] = gr.Slider(label="Batch Size", minimum=1, maximum=16, step=1, value=1)
41
  with gr.Row():
42
- components[f'clip_skip_{prefix}'] = gr.Slider(label="Clip Skip", minimum=1, maximum=2, step=1, value=1)
43
  components[f'zero_gpu_{prefix}'] = gr.Number(label="ZeroGPU Duration (s)", value=None, placeholder="Default: 60s, Max: 120s", info="Optional: Set how long to reserve the GPU. Longer jobs may need more time.")
44
 
 
 
45
  with gr.Column(scale=1):
46
  components[f'result_{prefix}'] = gr.Gallery(label="Result", show_label=False, columns=1, object_fit="contain", height=505)
47
 
48
  components.update(create_api_key_ui(prefix))
49
  components.update(create_lora_settings_ui(prefix))
50
  components.update(create_controlnet_ui(prefix))
51
- components.update(create_ipadapter_ui(prefix))
52
- components.update(create_embedding_ui(prefix))
53
  components.update(create_conditioning_ui(prefix))
54
- components.update(create_vae_override_ui(prefix))
55
 
56
  return components
 
3
  from comfy_integration.nodes import SAMPLER_CHOICES, SCHEDULER_CHOICES
4
  from .ui_components import (
5
  create_lora_settings_ui,
6
+ create_controlnet_ui, create_embedding_ui,
7
  create_conditioning_ui, create_vae_override_ui, create_api_key_ui
8
  )
9
 
 
23
 
24
  with gr.Column(scale=2):
25
  components[f'prompt_{prefix}'] = gr.Text(label="Prompt", lines=3, placeholder="Enter your prompt")
26
+ components[f'neg_prompt_{prefix}'] = gr.Text(label="Negative prompt", lines=3, value="")
27
 
28
  with gr.Row():
29
  with gr.Column(scale=1):
30
  components[f'denoise_{prefix}'] = gr.Slider(label="Denoise Strength", minimum=0.0, maximum=1.0, step=0.01, value=0.7)
31
 
32
  with gr.Row():
33
+ components[f'sampler_{prefix}'] = gr.Dropdown(label="Sampler", choices=SAMPLER_CHOICES, value="er_sde")
34
+ components[f'scheduler_{prefix}'] = gr.Dropdown(label="Scheduler", choices=SCHEDULER_CHOICES, value="simple")
35
  with gr.Row():
36
+ components[f'steps_{prefix}'] = gr.Slider(label="Steps", minimum=1, maximum=100, step=1, value=30)
37
+ components[f'cfg_{prefix}'] = gr.Slider(label="CFG Scale", minimum=1.0, maximum=20.0, step=0.1, value=4.0)
38
  with gr.Row():
39
  components[f'seed_{prefix}'] = gr.Number(label="Seed (-1 for random)", value=-1, precision=0)
40
  components[f'batch_size_{prefix}'] = gr.Slider(label="Batch Size", minimum=1, maximum=16, step=1, value=1)
41
  with gr.Row():
 
42
  components[f'zero_gpu_{prefix}'] = gr.Number(label="ZeroGPU Duration (s)", value=None, placeholder="Default: 60s, Max: 120s", info="Optional: Set how long to reserve the GPU. Longer jobs may need more time.")
43
 
44
+ components[f'clip_skip_{prefix}'] = gr.State(value=1)
45
+
46
  with gr.Column(scale=1):
47
  components[f'result_{prefix}'] = gr.Gallery(label="Result", show_label=False, columns=1, object_fit="contain", height=505)
48
 
49
  components.update(create_api_key_ui(prefix))
50
  components.update(create_lora_settings_ui(prefix))
51
  components.update(create_controlnet_ui(prefix))
52
+ # components.update(create_embedding_ui(prefix))
 
53
  components.update(create_conditioning_ui(prefix))
54
+ # components.update(create_vae_override_ui(prefix))
55
 
56
  return components
ui/shared/inpaint_ui.py CHANGED
@@ -2,7 +2,7 @@ import gradio as gr
2
  from core.settings import MODEL_MAP_CHECKPOINT
3
  from .ui_components import (
4
  create_base_parameter_ui, create_lora_settings_ui,
5
- create_controlnet_ui, create_ipadapter_ui, create_embedding_ui,
6
  create_conditioning_ui, create_vae_override_ui, create_api_key_ui
7
  )
8
 
@@ -40,7 +40,7 @@ def create_ui():
40
 
41
  with gr.Column(scale=2) as prompts_column:
42
  components[f'prompt_{prefix}'] = gr.Text(label="Prompt", lines=6, placeholder="Describe what to fill in the mask...")
43
- components[f'neg_prompt_{prefix}'] = gr.Text(label="Negative prompt", lines=6, value="monochrome, (low quality, worst quality:1.2), 3d, watermark, signature, ugly, poorly drawn,")
44
  components[f'prompts_column_{prefix}'] = prompts_column
45
 
46
  with gr.Row() as params_and_gallery_row:
@@ -48,18 +48,18 @@ def create_ui():
48
  param_defaults = {'w': 1024, 'h': 1024, 'cs_vis': False, 'cs_val': 1}
49
  from comfy_integration.nodes import SAMPLER_CHOICES, SCHEDULER_CHOICES
50
  with gr.Row():
51
- components[f'sampler_{prefix}'] = gr.Dropdown(label="Sampler", choices=SAMPLER_CHOICES, value=SAMPLER_CHOICES[0])
52
- components[f'scheduler_{prefix}'] = gr.Dropdown(label="Scheduler", choices=SCHEDULER_CHOICES, value='normal' if 'normal' in SCHEDULER_CHOICES else SCHEDULER_CHOICES[0])
53
  with gr.Row():
54
- components[f'steps_{prefix}'] = gr.Slider(label="Steps", minimum=1, maximum=100, step=1, value=28)
55
- components[f'cfg_{prefix}'] = gr.Slider(label="CFG Scale", minimum=1.0, maximum=20.0, step=0.1, value=7.5)
56
  with gr.Row():
57
  components[f'seed_{prefix}'] = gr.Number(label="Seed (-1 for random)", value=-1, precision=0)
58
  components[f'batch_size_{prefix}'] = gr.Slider(label="Batch Size", minimum=1, maximum=16, step=1, value=1)
59
  with gr.Row():
60
- components[f'clip_skip_{prefix}'] = gr.Slider(label="Clip Skip", minimum=1, maximum=2, step=1, value=1)
61
  components[f'zero_gpu_{prefix}'] = gr.Number(label="ZeroGPU Duration (s)", value=None, placeholder="Default: 60s, Max: 120s", info="Optional: Set how long to reserve the GPU.")
62
 
 
63
  components[f'width_{prefix}'] = gr.State(value=512)
64
  components[f'height_{prefix}'] = gr.State(value=512)
65
 
@@ -72,10 +72,9 @@ def create_ui():
72
  components.update(create_api_key_ui(prefix))
73
  components.update(create_lora_settings_ui(prefix))
74
  components.update(create_controlnet_ui(prefix))
75
- components.update(create_ipadapter_ui(prefix))
76
- components.update(create_embedding_ui(prefix))
77
  components.update(create_conditioning_ui(prefix))
78
- components.update(create_vae_override_ui(prefix))
79
  components[f'accordion_wrapper_{prefix}'] = accordion_wrapper
80
 
81
  return components
 
2
  from core.settings import MODEL_MAP_CHECKPOINT
3
  from .ui_components import (
4
  create_base_parameter_ui, create_lora_settings_ui,
5
+ create_controlnet_ui, create_embedding_ui,
6
  create_conditioning_ui, create_vae_override_ui, create_api_key_ui
7
  )
8
 
 
40
 
41
  with gr.Column(scale=2) as prompts_column:
42
  components[f'prompt_{prefix}'] = gr.Text(label="Prompt", lines=6, placeholder="Describe what to fill in the mask...")
43
+ components[f'neg_prompt_{prefix}'] = gr.Text(label="Negative prompt", lines=6, value="")
44
  components[f'prompts_column_{prefix}'] = prompts_column
45
 
46
  with gr.Row() as params_and_gallery_row:
 
48
  param_defaults = {'w': 1024, 'h': 1024, 'cs_vis': False, 'cs_val': 1}
49
  from comfy_integration.nodes import SAMPLER_CHOICES, SCHEDULER_CHOICES
50
  with gr.Row():
51
+ components[f'sampler_{prefix}'] = gr.Dropdown(label="Sampler", choices=SAMPLER_CHOICES, value="er_sde")
52
+ components[f'scheduler_{prefix}'] = gr.Dropdown(label="Scheduler", choices=SCHEDULER_CHOICES, value="simple")
53
  with gr.Row():
54
+ components[f'steps_{prefix}'] = gr.Slider(label="Steps", minimum=1, maximum=100, step=1, value=30)
55
+ components[f'cfg_{prefix}'] = gr.Slider(label="CFG Scale", minimum=1.0, maximum=20.0, step=0.1, value=4.0)
56
  with gr.Row():
57
  components[f'seed_{prefix}'] = gr.Number(label="Seed (-1 for random)", value=-1, precision=0)
58
  components[f'batch_size_{prefix}'] = gr.Slider(label="Batch Size", minimum=1, maximum=16, step=1, value=1)
59
  with gr.Row():
 
60
  components[f'zero_gpu_{prefix}'] = gr.Number(label="ZeroGPU Duration (s)", value=None, placeholder="Default: 60s, Max: 120s", info="Optional: Set how long to reserve the GPU.")
61
 
62
+ components[f'clip_skip_{prefix}'] = gr.State(value=1)
63
  components[f'width_{prefix}'] = gr.State(value=512)
64
  components[f'height_{prefix}'] = gr.State(value=512)
65
 
 
72
  components.update(create_api_key_ui(prefix))
73
  components.update(create_lora_settings_ui(prefix))
74
  components.update(create_controlnet_ui(prefix))
75
+ # components.update(create_embedding_ui(prefix))
 
76
  components.update(create_conditioning_ui(prefix))
77
+ # components.update(create_vae_override_ui(prefix))
78
  components[f'accordion_wrapper_{prefix}'] = accordion_wrapper
79
 
80
  return components
ui/shared/outpaint_ui.py CHANGED
@@ -3,7 +3,7 @@ from core.settings import MODEL_MAP_CHECKPOINT
3
  from comfy_integration.nodes import SAMPLER_CHOICES, SCHEDULER_CHOICES
4
  from .ui_components import (
5
  create_lora_settings_ui,
6
- create_controlnet_ui, create_ipadapter_ui, create_embedding_ui,
7
  create_conditioning_ui, create_vae_override_ui, create_api_key_ui
8
  )
9
 
@@ -27,7 +27,7 @@ def create_ui():
27
  components[f'input_image_{prefix}'] = gr.Image(type="pil", label="Input Image", height=255)
28
  with gr.Column(scale=2):
29
  components[f'prompt_{prefix}'] = gr.Text(label="Prompt", lines=3, placeholder="Describe the content for the expanded areas...")
30
- components[f'neg_prompt_{prefix}'] = gr.Text(label="Negative prompt", lines=3, value="monochrome, (low quality, worst quality:1.2), 3d, watermark, signature, ugly, poorly drawn,")
31
 
32
  with gr.Row():
33
  with gr.Column(scale=1):
@@ -39,18 +39,18 @@ def create_ui():
39
  components[f'outpaint_bottom_{prefix}'] = gr.Slider(label="Pad Bottom", minimum=0, maximum=512, step=64, value=0)
40
 
41
  with gr.Row():
42
- components[f'sampler_{prefix}'] = gr.Dropdown(label="Sampler", choices=SAMPLER_CHOICES, value=SAMPLER_CHOICES[0])
43
- components[f'scheduler_{prefix}'] = gr.Dropdown(label="Scheduler", choices=SCHEDULER_CHOICES, value='normal' if 'normal' in SCHEDULER_CHOICES else SCHEDULER_CHOICES[0])
44
  with gr.Row():
45
- components[f'steps_{prefix}'] = gr.Slider(label="Steps", minimum=1, maximum=100, step=1, value=28)
46
- components[f'cfg_{prefix}'] = gr.Slider(label="CFG Scale", minimum=1.0, maximum=20.0, step=0.1, value=7.5)
47
  with gr.Row():
48
  components[f'seed_{prefix}'] = gr.Number(label="Seed (-1 for random)", value=-1, precision=0)
49
  components[f'batch_size_{prefix}'] = gr.Slider(label="Batch Size", minimum=1, maximum=16, step=1, value=1)
50
  with gr.Row():
51
- components[f'clip_skip_{prefix}'] = gr.Slider(label="Clip Skip", minimum=1, maximum=2, step=1, value=1)
52
  components[f'zero_gpu_{prefix}'] = gr.Number(label="ZeroGPU Duration (s)", value=None, placeholder="Default: 60s, Max: 120s", info="Optional: Set how long to reserve the GPU.")
53
 
 
54
  components[f'width_{prefix}'] = gr.State(value=512)
55
  components[f'height_{prefix}'] = gr.State(value=512)
56
 
@@ -60,9 +60,8 @@ def create_ui():
60
  components.update(create_api_key_ui(prefix))
61
  components.update(create_lora_settings_ui(prefix))
62
  components.update(create_controlnet_ui(prefix))
63
- components.update(create_ipadapter_ui(prefix))
64
- components.update(create_embedding_ui(prefix))
65
  components.update(create_conditioning_ui(prefix))
66
- components.update(create_vae_override_ui(prefix))
67
 
68
  return components
 
3
  from comfy_integration.nodes import SAMPLER_CHOICES, SCHEDULER_CHOICES
4
  from .ui_components import (
5
  create_lora_settings_ui,
6
+ create_controlnet_ui, create_embedding_ui,
7
  create_conditioning_ui, create_vae_override_ui, create_api_key_ui
8
  )
9
 
 
27
  components[f'input_image_{prefix}'] = gr.Image(type="pil", label="Input Image", height=255)
28
  with gr.Column(scale=2):
29
  components[f'prompt_{prefix}'] = gr.Text(label="Prompt", lines=3, placeholder="Describe the content for the expanded areas...")
30
+ components[f'neg_prompt_{prefix}'] = gr.Text(label="Negative prompt", lines=3, value="")
31
 
32
  with gr.Row():
33
  with gr.Column(scale=1):
 
39
  components[f'outpaint_bottom_{prefix}'] = gr.Slider(label="Pad Bottom", minimum=0, maximum=512, step=64, value=0)
40
 
41
  with gr.Row():
42
+ components[f'sampler_{prefix}'] = gr.Dropdown(label="Sampler", choices=SAMPLER_CHOICES, value="er_sde")
43
+ components[f'scheduler_{prefix}'] = gr.Dropdown(label="Scheduler", choices=SCHEDULER_CHOICES, value="simple")
44
  with gr.Row():
45
+ components[f'steps_{prefix}'] = gr.Slider(label="Steps", minimum=1, maximum=100, step=1, value=30)
46
+ components[f'cfg_{prefix}'] = gr.Slider(label="CFG Scale", minimum=1.0, maximum=20.0, step=0.1, value=4.0)
47
  with gr.Row():
48
  components[f'seed_{prefix}'] = gr.Number(label="Seed (-1 for random)", value=-1, precision=0)
49
  components[f'batch_size_{prefix}'] = gr.Slider(label="Batch Size", minimum=1, maximum=16, step=1, value=1)
50
  with gr.Row():
 
51
  components[f'zero_gpu_{prefix}'] = gr.Number(label="ZeroGPU Duration (s)", value=None, placeholder="Default: 60s, Max: 120s", info="Optional: Set how long to reserve the GPU.")
52
 
53
+ components[f'clip_skip_{prefix}'] = gr.State(value=1)
54
  components[f'width_{prefix}'] = gr.State(value=512)
55
  components[f'height_{prefix}'] = gr.State(value=512)
56
 
 
60
  components.update(create_api_key_ui(prefix))
61
  components.update(create_lora_settings_ui(prefix))
62
  components.update(create_controlnet_ui(prefix))
63
+ # components.update(create_embedding_ui(prefix))
 
64
  components.update(create_conditioning_ui(prefix))
65
+ # components.update(create_vae_override_ui(prefix))
66
 
67
  return components
ui/shared/txt2img_ui.py CHANGED
@@ -2,7 +2,7 @@ import gradio as gr
2
  from core.settings import MODEL_MAP_CHECKPOINT
3
  from .ui_components import (
4
  create_base_parameter_ui, create_lora_settings_ui,
5
- create_controlnet_ui, create_ipadapter_ui, create_embedding_ui,
6
  create_conditioning_ui, create_vae_override_ui, create_api_key_ui
7
  )
8
 
@@ -18,11 +18,11 @@ def create_ui():
18
  components[f'run_{prefix}'] = gr.Button("Run", variant="primary")
19
 
20
  components[f'prompt_{prefix}'] = gr.Text(label="Prompt", lines=3, placeholder="Enter your prompt")
21
- components[f'neg_prompt_{prefix}'] = gr.Text(label="Negative prompt", lines=3, value="monochrome, (low quality, worst quality:1.2), 3d, watermark, signature, ugly, poorly drawn,")
22
 
23
  with gr.Row():
24
  with gr.Column(scale=1):
25
- param_defaults = {'w': 512, 'h': 512, 'cs_vis': False, 'cs_val': 1}
26
  components.update(create_base_parameter_ui(prefix, param_defaults))
27
  with gr.Column(scale=1):
28
  components[f'result_{prefix}'] = gr.Gallery(label="Result", show_label=False, columns=2, object_fit="contain", height=627)
@@ -30,9 +30,8 @@ def create_ui():
30
  components.update(create_api_key_ui(prefix))
31
  components.update(create_lora_settings_ui(prefix))
32
  components.update(create_controlnet_ui(prefix))
33
- components.update(create_ipadapter_ui(prefix))
34
- components.update(create_embedding_ui(prefix))
35
  components.update(create_conditioning_ui(prefix))
36
- components.update(create_vae_override_ui(prefix))
37
 
38
  return components
 
2
  from core.settings import MODEL_MAP_CHECKPOINT
3
  from .ui_components import (
4
  create_base_parameter_ui, create_lora_settings_ui,
5
+ create_controlnet_ui, create_embedding_ui,
6
  create_conditioning_ui, create_vae_override_ui, create_api_key_ui
7
  )
8
 
 
18
  components[f'run_{prefix}'] = gr.Button("Run", variant="primary")
19
 
20
  components[f'prompt_{prefix}'] = gr.Text(label="Prompt", lines=3, placeholder="Enter your prompt")
21
+ components[f'neg_prompt_{prefix}'] = gr.Text(label="Negative prompt", lines=3, value="")
22
 
23
  with gr.Row():
24
  with gr.Column(scale=1):
25
+ param_defaults = {'w': 1024, 'h': 1024, 'cs_vis': False, 'cs_val': 1}
26
  components.update(create_base_parameter_ui(prefix, param_defaults))
27
  with gr.Column(scale=1):
28
  components[f'result_{prefix}'] = gr.Gallery(label="Result", show_label=False, columns=2, object_fit="contain", height=627)
 
30
  components.update(create_api_key_ui(prefix))
31
  components.update(create_lora_settings_ui(prefix))
32
  components.update(create_controlnet_ui(prefix))
33
+ # components.update(create_embedding_ui(prefix))
 
34
  components.update(create_conditioning_ui(prefix))
35
+ # components.update(create_vae_override_ui(prefix))
36
 
37
  return components
ui/shared/ui_components.py CHANGED
@@ -2,30 +2,12 @@ import gradio as gr
2
  from comfy_integration.nodes import SAMPLER_CHOICES, SCHEDULER_CHOICES
3
  from core.settings import (
4
  MAX_LORAS, LORA_SOURCE_CHOICES, MAX_EMBEDDINGS, MAX_CONDITIONINGS,
5
- MAX_CONTROLNETS, MAX_IPADAPTERS, RESOLUTION_MAP
6
  )
7
  import yaml
8
  import os
9
  from functools import lru_cache
10
 
11
- @lru_cache(maxsize=1)
12
- def get_ipadapter_presets_from_yaml():
13
- try:
14
- _PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
15
- _IPADAPTER_LIST_PATH = os.path.join(_PROJECT_ROOT, 'yaml', 'ipadapter.yaml')
16
- with open(_IPADAPTER_LIST_PATH, 'r', encoding='utf-8') as f:
17
- config = yaml.safe_load(f)
18
- if isinstance(config, list):
19
- presets = [item.get('preset_name') for item in config if item.get('preset_name')]
20
- if "Composition" not in presets:
21
- pass
22
- return presets
23
- return []
24
- except Exception as e:
25
- print(f"Warning: Could not load ipadapter.yaml for UI components: {e}")
26
- return ["STANDARD (medium strength)"]
27
-
28
-
29
  def create_base_parameter_ui(prefix, defaults=None):
30
  if defaults is None:
31
  defaults = {}
@@ -35,25 +17,26 @@ def create_base_parameter_ui(prefix, defaults=None):
35
  with gr.Row():
36
  components[f'aspect_ratio_{prefix}'] = gr.Dropdown(
37
  label="Aspect Ratio",
38
- choices=list(RESOLUTION_MAP['sd15'].keys()),
39
  value="1:1 (Square)",
40
  interactive=True
41
  )
42
  with gr.Row():
43
- components[f'width_{prefix}'] = gr.Number(label="Width", value=defaults.get('w', 512), interactive=True)
44
- components[f'height_{prefix}'] = gr.Number(label="Height", value=defaults.get('h', 512), interactive=True)
45
  with gr.Row():
46
- components[f'sampler_{prefix}'] = gr.Dropdown(label="Sampler", choices=SAMPLER_CHOICES, value=SAMPLER_CHOICES[0])
47
- components[f'scheduler_{prefix}'] = gr.Dropdown(label="Scheduler", choices=SCHEDULER_CHOICES, value='normal' if 'normal' in SCHEDULER_CHOICES else SCHEDULER_CHOICES[0])
48
  with gr.Row():
49
- components[f'steps_{prefix}'] = gr.Slider(label="Steps", minimum=1, maximum=100, step=1, value=28)
50
- components[f'cfg_{prefix}'] = gr.Slider(label="CFG Scale", minimum=1.0, maximum=20.0, step=0.1, value=7.5)
51
  with gr.Row():
52
  components[f'seed_{prefix}'] = gr.Number(label="Seed (-1 for random)", value=-1, precision=0)
53
  components[f'batch_size_{prefix}'] = gr.Slider(label="Batch Size", minimum=1, maximum=16, step=1, value=1)
54
  with gr.Row():
55
- components[f'clip_skip_{prefix}'] = gr.Slider(label="Clip Skip", minimum=1, maximum=2, step=1, value=1)
56
  components[f'zero_gpu_{prefix}'] = gr.Number(label="ZeroGPU Duration (s)", value=None, placeholder="Default: 60s, Max: 120s", info="Optional: Set how long to reserve the GPU. Longer jobs may need more time.")
 
 
57
 
58
  return components
59
 
@@ -154,77 +137,6 @@ def create_controlnet_ui(prefix: str, max_units=MAX_CONTROLNETS):
154
 
155
  return components
156
 
157
- def create_ipadapter_ui(prefix: str, max_units=MAX_IPADAPTERS):
158
- components = {}
159
- key = lambda name: f"{name}_{prefix}"
160
-
161
- ipadapter_presets = get_ipadapter_presets_from_yaml()
162
- default_preset = ipadapter_presets[0] if ipadapter_presets else None
163
-
164
- with gr.Accordion("IPAdapter Settings", open=False) as accordion:
165
- components[key('ipadapter_accordion')] = accordion
166
- gr.Markdown("Powered by [cubiq/ComfyUI_IPAdapter_plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus).")
167
-
168
- with gr.Row():
169
- components[key('ipadapter_final_preset')] = gr.Dropdown(
170
- label="Preset (for all images)",
171
- choices=ipadapter_presets,
172
- value=default_preset,
173
- interactive=True
174
- )
175
- components[key('ipadapter_embeds_scaling')] = gr.Dropdown(
176
- label="Embeds Scaling",
177
- choices=['V only', 'K+V', 'K+V w/ C penalty', 'K+mean(V) w/ C penalty'],
178
- value='V only',
179
- interactive=True
180
- )
181
-
182
- with gr.Row():
183
- components[key('ipadapter_combine_method')] = gr.Dropdown(
184
- label="Combine Method",
185
- choices=["concat", "add", "subtract", "average", "norm average", "max", "min"],
186
- value="concat",
187
- interactive=True
188
- )
189
- components[key('ipadapter_final_weight')] = gr.Slider(label="Final Weight", minimum=0.0, maximum=2.0, step=0.05, value=1.0, interactive=True)
190
- components[key('ipadapter_final_lora_strength')] = gr.Slider(label="Final LoRA Strength", minimum=0.0, maximum=2.0, step=0.05, value=0.6, interactive=True, visible=False)
191
-
192
- gr.Markdown("---")
193
-
194
- ipa_rows, images, weights, lora_strengths = [], [], [], []
195
- components.update({
196
- key('ipadapter_rows'): ipa_rows,
197
- key('ipadapter_images'): images,
198
- key('ipadapter_weights'): weights,
199
- key('ipadapter_lora_strengths'): lora_strengths
200
- })
201
-
202
- for i in range(max_units):
203
- with gr.Row(visible=(i < 1)) as row:
204
- with gr.Column(scale=1):
205
- images.append(gr.Image(label=f"IPAdapter Image {i+1}", type="pil", sources="upload", height=256))
206
- with gr.Column(scale=2):
207
- weights.append(gr.Slider(label="Weight", minimum=0.0, maximum=2.0, step=0.05, value=1.0, interactive=True))
208
- lora_strengths.append(gr.Slider(label="LoRA Strength", minimum=0.0, maximum=2.0, step=0.05, value=0.6, interactive=True, visible=False))
209
- ipa_rows.append(row)
210
-
211
- with gr.Row():
212
- components[key('add_ipadapter_button')] = gr.Button("✚ Add IPAdapter")
213
- components[key('delete_ipadapter_button')] = gr.Button("➖ Delete IPAdapter", visible=False)
214
- components[key('ipadapter_count_state')] = gr.State(1)
215
-
216
- all_ipa_components_flat = images + weights + lora_strengths
217
- all_ipa_components_flat += [
218
- components[key('ipadapter_final_preset')],
219
- components[key('ipadapter_final_weight')],
220
- components[key('ipadapter_final_lora_strength')],
221
- components[key('ipadapter_embeds_scaling')],
222
- components[key('ipadapter_combine_method')],
223
- ]
224
- components[key('all_ipadapter_components_flat')] = all_ipa_components_flat
225
-
226
- return components
227
-
228
  def create_embedding_ui(prefix: str):
229
  components = {}
230
  key = lambda name: f"{name}_{prefix}"
 
2
  from comfy_integration.nodes import SAMPLER_CHOICES, SCHEDULER_CHOICES
3
  from core.settings import (
4
  MAX_LORAS, LORA_SOURCE_CHOICES, MAX_EMBEDDINGS, MAX_CONDITIONINGS,
5
+ MAX_CONTROLNETS, RESOLUTION_MAP
6
  )
7
  import yaml
8
  import os
9
  from functools import lru_cache
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  def create_base_parameter_ui(prefix, defaults=None):
12
  if defaults is None:
13
  defaults = {}
 
17
  with gr.Row():
18
  components[f'aspect_ratio_{prefix}'] = gr.Dropdown(
19
  label="Aspect Ratio",
20
+ choices=list(RESOLUTION_MAP['sdxl'].keys()),
21
  value="1:1 (Square)",
22
  interactive=True
23
  )
24
  with gr.Row():
25
+ components[f'width_{prefix}'] = gr.Number(label="Width", value=defaults.get('w', 1024), interactive=True)
26
+ components[f'height_{prefix}'] = gr.Number(label="Height", value=defaults.get('h', 1024), interactive=True)
27
  with gr.Row():
28
+ components[f'sampler_{prefix}'] = gr.Dropdown(label="Sampler", choices=SAMPLER_CHOICES, value="er_sde")
29
+ components[f'scheduler_{prefix}'] = gr.Dropdown(label="Scheduler", choices=SCHEDULER_CHOICES, value="simple")
30
  with gr.Row():
31
+ components[f'steps_{prefix}'] = gr.Slider(label="Steps", minimum=1, maximum=100, step=1, value=30)
32
+ components[f'cfg_{prefix}'] = gr.Slider(label="CFG Scale", minimum=1.0, maximum=20.0, step=0.1, value=4.0)
33
  with gr.Row():
34
  components[f'seed_{prefix}'] = gr.Number(label="Seed (-1 for random)", value=-1, precision=0)
35
  components[f'batch_size_{prefix}'] = gr.Slider(label="Batch Size", minimum=1, maximum=16, step=1, value=1)
36
  with gr.Row():
 
37
  components[f'zero_gpu_{prefix}'] = gr.Number(label="ZeroGPU Duration (s)", value=None, placeholder="Default: 60s, Max: 120s", info="Optional: Set how long to reserve the GPU. Longer jobs may need more time.")
38
+
39
+ components[f'clip_skip_{prefix}'] = gr.State(value=1)
40
 
41
  return components
42
 
 
137
 
138
  return components
139
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  def create_embedding_ui(prefix: str):
141
  components = {}
142
  key = lambda name: f"{name}_{prefix}"
utils/app_utils.py CHANGED
@@ -20,7 +20,6 @@ MODELS_ROOT_DIR = "ComfyUI/models"
20
 
21
  PREPROCESSOR_MODEL_MAP = None
22
  PREPROCESSOR_PARAMETER_MAP = None
23
- IPADAPTER_PRESETS = None
24
 
25
 
26
  def save_uploaded_file_with_hash(file_obj: gr.File, target_dir: str) -> str:
@@ -302,45 +301,44 @@ def get_vae_path(source: str, id_or_url: str, civitai_key: str, progress) -> tup
302
  return (local_path, status) if "Successfully" in status else (None, status)
303
 
304
 
305
- def _ensure_model_downloaded(display_name: str, progress=gr.Progress()):
306
- if display_name not in ALL_MODEL_MAP:
307
- raise ValueError(f"Model '{display_name}' not found in configuration.")
308
-
309
- _, repo_filename, model_type, _ = ALL_MODEL_MAP[display_name]
310
-
311
- type_to_dir_map = {
312
- "SDXL": CHECKPOINT_DIR, "SD1.5": CHECKPOINT_DIR, "UNET": DIFFUSION_MODELS_DIR,
313
- "VAE": VAE_DIR, "TEXT_ENCODER": TEXT_ENCODERS_DIR, "LORA": LORA_DIR,
314
- "IPADAPTER": os.path.join(os.path.dirname(LORA_DIR), "ipadapter"),
315
- "CLIP_VISION": os.path.join(os.path.dirname(LORA_DIR), "clip_vision")
 
 
316
  }
317
- dest_dir = type_to_dir_map.get(model_type)
 
 
318
  if not dest_dir:
319
- raise ValueError(f"Unknown model type '{model_type}' for '{display_name}'.")
320
 
321
- base_filename = os.path.basename(repo_filename)
322
- dest_path = os.path.join(dest_dir, base_filename)
323
 
324
  if os.path.lexists(dest_path):
325
  if not os.path.exists(dest_path):
326
  print(f"⚠️ Found and removed broken symlink: {dest_path}")
327
  os.remove(dest_path)
328
  else:
329
- return base_filename
330
-
331
- download_info = ALL_FILE_DOWNLOAD_MAP.get(base_filename)
332
- if not download_info:
333
- raise gr.Error(f"Model '{base_filename}' not found in file_list.yaml. Cannot download.")
334
 
335
  source = download_info.get("source")
336
  try:
337
- progress(0, desc=f"Downloading: {base_filename}")
338
 
339
  if source == "hf":
340
  repo_id = download_info.get("repo_id")
341
- hf_filename = download_info.get("repository_file_path", base_filename)
342
  if not repo_id:
343
- raise ValueError(f"repo_id is missing for HF model '{base_filename}'")
344
 
345
  cached_path = hf_hub_download(repo_id=repo_id, filename=hf_filename)
346
  os.makedirs(dest_dir, exist_ok=True)
@@ -350,173 +348,35 @@ def _ensure_model_downloaded(display_name: str, progress=gr.Progress()):
350
  elif source == "civitai":
351
  model_version_id = download_info.get("model_version_id")
352
  if not model_version_id:
353
- raise ValueError(f"model_version_id is missing for Civitai model '{base_filename}'")
354
 
355
  file_info = get_civitai_file_info(model_version_id)
356
  if not file_info or not file_info.get('downloadUrl'):
357
  raise ConnectionError(f"Could not get download URL for Civitai model version ID {model_version_id}")
358
 
359
  status = download_file(
360
- file_info['downloadUrl'], dest_path, progress=progress, desc=f"Downloading: {base_filename}"
361
  )
362
  if "Failed" in status:
363
  raise ConnectionError(status)
364
  else:
365
- raise NotImplementedError(f"Download source '{source}' is not implemented for '{base_filename}'")
366
 
367
- progress(1.0, desc=f"Downloaded: {base_filename}")
368
 
369
  except Exception as e:
370
  if os.path.lexists(dest_path):
371
  try:
372
  os.remove(dest_path)
373
  except OSError: pass
374
- raise gr.Error(f"Failed to download and link '{display_name}': {e}")
375
 
376
- return base_filename
377
 
378
  def ensure_controlnet_model_downloaded(filename: str, progress):
379
  if not filename or filename == "None":
380
  return
381
-
382
- dest_path = os.path.join(CONTROLNET_DIR, filename)
383
- if os.path.exists(dest_path):
384
- return
385
-
386
- download_info = ALL_FILE_DOWNLOAD_MAP.get(filename)
387
- if not download_info:
388
- raise gr.Error(f"ControlNet model '{filename}' not found in configuration (file_list.yaml). Cannot download.")
389
-
390
- source = download_info.get("source")
391
-
392
- try:
393
- if source == "hf":
394
- repo_id = download_info.get("repo_id")
395
- repo_filename = download_info.get("repository_file_path", filename)
396
- if not repo_id:
397
- raise ValueError("repo_id is missing for Hugging Face download.")
398
-
399
- progress(0, desc=f"Downloading CN: {filename}")
400
- cached_path = hf_hub_download(repo_id=repo_id, filename=repo_filename)
401
- os.makedirs(CONTROLNET_DIR, exist_ok=True)
402
- os.symlink(cached_path, dest_path)
403
- print(f"✅ Symlinked ControlNet '{cached_path}' to '{dest_path}'")
404
- progress(1.0, desc=f"Downloaded CN: {filename}")
405
-
406
- elif source == "civitai":
407
- model_version_id = download_info.get("model_version_id")
408
- if not model_version_id:
409
- raise ValueError("model_version_id is missing for Civitai download.")
410
-
411
- file_info = get_civitai_file_info(model_version_id)
412
- if not file_info or not file_info.get('downloadUrl'):
413
- raise ConnectionError(f"Could not get download URL for Civitai model version ID {model_version_id}")
414
-
415
- status = download_file(
416
- file_info['downloadUrl'],
417
- dest_path,
418
- progress=progress,
419
- desc=f"Downloading CN: {filename}"
420
- )
421
- if "Failed" in status:
422
- raise ConnectionError(status)
423
- else:
424
- raise NotImplementedError(f"Download source '{source}' is not implemented for ControlNets.")
425
-
426
- except Exception as e:
427
- if os.path.lexists(dest_path):
428
- try:
429
- os.remove(dest_path)
430
- except OSError:
431
- pass
432
- raise gr.Error(f"Failed to download ControlNet model '{filename}': {e}")
433
-
434
- def load_ipadapter_presets():
435
- global IPADAPTER_PRESETS
436
- if IPADAPTER_PRESETS is not None:
437
- return
438
-
439
- _PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
440
- _IPADAPTER_LIST_PATH = os.path.join(_PROJECT_ROOT, 'yaml', 'ipadapter.yaml')
441
-
442
- try:
443
- with open(_IPADAPTER_LIST_PATH, 'r', encoding='utf-8') as f:
444
- presets_list = yaml.safe_load(f)
445
-
446
- IPADAPTER_PRESETS = {item['preset_name']: item for item in presets_list}
447
- print("✅ IPAdapter presets loaded successfully.")
448
- except Exception as e:
449
- print(f"❌ FATAL: Could not load or parse ipadapter.yaml. IPAdapter will not work. Error: {e}")
450
- IPADAPTER_PRESETS = {}
451
-
452
- def ensure_ipadapter_models_downloaded(preset_name: str, progress):
453
- if not preset_name:
454
- return
455
-
456
- if IPADAPTER_PRESETS is None:
457
- raise RuntimeError("IPAdapter presets have not been loaded. `load_ipadapter_presets` must be called on startup.")
458
-
459
- preset_info = IPADAPTER_PRESETS.get(preset_name)
460
- if not preset_info:
461
- print(f"⚠️ Warning: IPAdapter preset '{preset_name}' not found in configuration. Skipping download.")
462
- return
463
-
464
- model_files_to_check = {
465
- preset_info.get('vision_model'): 'CLIP_VISION',
466
- preset_info.get('ipadapter_model'): 'IPADAPTER',
467
- preset_info.get('lora_model'): 'LORA'
468
- }
469
-
470
- for filename, model_type in model_files_to_check.items():
471
- if not filename:
472
- continue
473
-
474
- temp_display_name = f"ipadapter_asset_{filename}"
475
-
476
- if temp_display_name not in ALL_MODEL_MAP:
477
- ALL_MODEL_MAP[temp_display_name] = (None, filename, model_type, None)
478
-
479
- try:
480
- _ensure_model_downloaded(temp_display_name, progress)
481
- except Exception as e:
482
- print(f"❌ Error ensuring download for IPAdapter asset '{filename}': {e}")
483
-
484
-
485
- def parse_parameters(params_text: str) -> dict:
486
- data = {}
487
- lines = params_text.strip().split('\n')
488
- data['prompt'] = lines[0]
489
- data['negative_prompt'] = lines[1].replace("Negative prompt:", "").strip() if len(lines) > 1 and lines[1].startswith("Negative prompt:") else ""
490
-
491
- params_line = '\n'.join(lines[2:])
492
-
493
- def find_param(key, default, cast_type=str):
494
- match = re.search(fr"\b{key}: ([^,]+?)(,|$|\n)", params_line)
495
- return cast_type(match.group(1).strip()) if match else default
496
-
497
- data['steps'] = find_param("Steps", 28, int)
498
- data['sampler'] = find_param("Sampler", "euler", str)
499
- data['scheduler'] = find_param("Scheduler", "normal", str)
500
- data['cfg_scale'] = find_param("CFG scale", 7.5, float)
501
- data['seed'] = find_param("Seed", -1, int)
502
- data['clip_skip'] = find_param("Clip skip", 1, int)
503
- data['base_model'] = find_param("Base Model", list(ALL_MODEL_MAP.keys())[0] if ALL_MODEL_MAP else "", str)
504
- data['model_hash'] = find_param("Model hash", None, str)
505
-
506
- size_match = re.search(r"Size: (\d+)x(\d+)", params_line)
507
- data['width'], data['height'] = (int(size_match.group(1)), int(size_match.group(2))) if size_match else (512, 512)
508
-
509
- return data
510
-
511
- def get_png_info(image) -> tuple[str, str, str]:
512
- if not image or not (params := image.info.get('parameters')):
513
- return "", "", "No metadata found in the image."
514
-
515
- parsed_data = parse_parameters(params)
516
- raw_params_list = '\n'.join(params.strip().split('\n')[2:]).split(',')
517
- other_params_text = "\n".join([p.strip() for p in raw_params_list])
518
-
519
- return parsed_data.get('prompt', ''), parsed_data.get('negative_prompt', ''), other_params_text
520
 
521
 
522
  def build_preprocessor_model_map():
 
20
 
21
  PREPROCESSOR_MODEL_MAP = None
22
  PREPROCESSOR_PARAMETER_MAP = None
 
23
 
24
 
25
  def save_uploaded_file_with_hash(file_obj: gr.File, target_dir: str) -> str:
 
301
  return (local_path, status) if "Successfully" in status else (None, status)
302
 
303
 
304
+ def _ensure_model_downloaded(filename: str, progress=gr.Progress()):
305
+ download_info = ALL_FILE_DOWNLOAD_MAP.get(filename)
306
+ if not download_info:
307
+ raise gr.Error(f"Model component '{filename}' not found in file_list.yaml. Cannot download.")
308
+
309
+ category_to_dir_map = {
310
+ "diffusion_models": DIFFUSION_MODELS_DIR,
311
+ "text_encoders": TEXT_ENCODERS_DIR,
312
+ "vae": VAE_DIR,
313
+ "checkpoints": CHECKPOINT_DIR,
314
+ "loras": LORA_DIR,
315
+ "controlnet": CONTROLNET_DIR,
316
+ "clip_vision": os.path.join(os.path.dirname(LORA_DIR), "clip_vision")
317
  }
318
+
319
+ category = download_info.get('category')
320
+ dest_dir = category_to_dir_map.get(category)
321
  if not dest_dir:
322
+ raise ValueError(f"Unknown model category '{category}' for file '{filename}'.")
323
 
324
+ dest_path = os.path.join(dest_dir, filename)
 
325
 
326
  if os.path.lexists(dest_path):
327
  if not os.path.exists(dest_path):
328
  print(f"⚠️ Found and removed broken symlink: {dest_path}")
329
  os.remove(dest_path)
330
  else:
331
+ return filename
 
 
 
 
332
 
333
  source = download_info.get("source")
334
  try:
335
+ progress(0, desc=f"Downloading: {filename}")
336
 
337
  if source == "hf":
338
  repo_id = download_info.get("repo_id")
339
+ hf_filename = download_info.get("repository_file_path", filename)
340
  if not repo_id:
341
+ raise ValueError(f"repo_id is missing for HF model '{filename}'")
342
 
343
  cached_path = hf_hub_download(repo_id=repo_id, filename=hf_filename)
344
  os.makedirs(dest_dir, exist_ok=True)
 
348
  elif source == "civitai":
349
  model_version_id = download_info.get("model_version_id")
350
  if not model_version_id:
351
+ raise ValueError(f"model_version_id is missing for Civitai model '{filename}'")
352
 
353
  file_info = get_civitai_file_info(model_version_id)
354
  if not file_info or not file_info.get('downloadUrl'):
355
  raise ConnectionError(f"Could not get download URL for Civitai model version ID {model_version_id}")
356
 
357
  status = download_file(
358
+ file_info['downloadUrl'], dest_path, progress=progress, desc=f"Downloading: {filename}"
359
  )
360
  if "Failed" in status:
361
  raise ConnectionError(status)
362
  else:
363
+ raise NotImplementedError(f"Download source '{source}' is not implemented for '{filename}'")
364
 
365
+ progress(1.0, desc=f"Downloaded: {filename}")
366
 
367
  except Exception as e:
368
  if os.path.lexists(dest_path):
369
  try:
370
  os.remove(dest_path)
371
  except OSError: pass
372
+ raise gr.Error(f"Failed to download and link '{filename}': {e}")
373
 
374
+ return filename
375
 
376
  def ensure_controlnet_model_downloaded(filename: str, progress):
377
  if not filename or filename == "None":
378
  return
379
+ _ensure_model_downloaded(filename, progress)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
380
 
381
 
382
  def build_preprocessor_model_map():
yaml/constants.yaml CHANGED
@@ -1,32 +1,15 @@
1
  MAX_LORAS: 5
2
  MAX_CONTROLNETS: 5
3
- MAX_IPADAPTERS: 5
4
  MAX_EMBEDDINGS: 5
5
  MAX_CONDITIONINGS: 10
6
  LORA_SOURCE_CHOICES: ["Civitai", "File"]
7
 
8
  RESOLUTION_MAP:
9
- sd15:
10
- "1:1 (Square)": [512, 512]
11
- "16:9 (Landscape)": [896, 512]
12
- "9:16 (Portrait)": [512, 896]
13
- "4:3 (Classic Landscape)": [683, 512]
14
- "3:4 (Classic Portrait)": [512, 683]
15
- "3:2 (Landscape)": [768, 512]
16
- "2:3 (Portrait)": [512, 768]
17
-
18
- SAMPLER_MAP:
19
- euler a: "euler_ancestral"
20
- dpm++ 2s a: "dpmpp_2s_ancestral"
21
- dpm++ 2m: "dpmpp_2m"
22
- dpm++ sde: "dpmpp_sde"
23
- dpm++ 2m sde: "dpmpp_2m_sde"
24
- dpm++ 3m sde: "dpmpp_3m_sde"
25
- ddim: "ddim"
26
- uni_pc: "uni_pc"
27
- euler_a: "euler_ancestral"
28
- dpm++ 2s a karras: "dpmpp_2s_ancestral"
29
- dpm++ 2m karras: "dpmpp_2m"
30
- dpm++ sde karras: "dpmpp_sde"
31
- dpm++ 2m sde karras: "dpmpp_2m_sde"
32
- dpm++ 3m sde karras: "dpmpp_3m_sde"
 
1
  MAX_LORAS: 5
2
  MAX_CONTROLNETS: 5
 
3
  MAX_EMBEDDINGS: 5
4
  MAX_CONDITIONINGS: 10
5
  LORA_SOURCE_CHOICES: ["Civitai", "File"]
6
 
7
  RESOLUTION_MAP:
8
+ sdxl:
9
+ "1:1 (Square)": [1024, 1024]
10
+ "16:9 (Landscape)": [1344, 768]
11
+ "9:16 (Portrait)": [768, 1344]
12
+ "4:3 (Classic)": [1152, 896]
13
+ "3:4 (Classic Portrait)": [896, 1152]
14
+ "3:2 (Photography)": [1216, 832]
15
+ "2:3 (Photography Portrait)": [832, 1216]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
yaml/controlnet_models.yaml CHANGED
@@ -1,44 +1,5 @@
1
  ControlNet:
2
- SD1.5:
3
- - Filepath: "control_v11p_sd15_canny_fp16.safetensors"
4
- Series: "Standard"
5
- Type: ["Canny"]
6
- - Filepath: "control_v11f1p_sd15_depth_fp16.safetensors"
7
- Series: "Standard"
8
- Type: ["Depth"]
9
- - Filepath: "control_v11p_sd15_openpose_fp16.safetensors"
10
- Series: "Standard"
11
- Type: ["OpenPose"]
12
- - Filepath: "control_v11p_sd15_lineart_fp16.safetensors"
13
- Series: "Standard"
14
- Type: ["Lineart"]
15
- - Filepath: "control_v11p_sd15_softedge_fp16.safetensors"
16
- Series: "Standard"
17
- Type: ["SoftEdge"]
18
- - Filepath: "control_v11p_sd15_scribble_fp16.safetensors"
19
- Series: "Standard"
20
- Type: ["Scribble"]
21
- - Filepath: "control_v11p_sd15_seg_fp16.safetensors"
22
- Series: "Standard"
23
- Type: ["Segmentation"]
24
- - Filepath: "control_v11p_sd15_normalbae_fp16.safetensors"
25
- Series: "Standard"
26
- Type: ["Normal BAE"]
27
- - Filepath: "control_v11p_sd15_mlsd_fp16.safetensors"
28
- Series: "Standard"
29
- Type: ["MLSD"]
30
- - Filepath: "control_v11p_sd15_inpaint_fp16.safetensors"
31
- Series: "Standard"
32
- Type: ["Inpaint"]
33
- - Filepath: "control_v11f1e_sd15_tile_fp16.safetensors"
34
- Series: "Standard"
35
- Type: ["Tile"]
36
- - Filepath: "control_v11e_sd15_shuffle_fp16.safetensors"
37
- Series: "Standard"
38
- Type: ["Shuffle"]
39
- - Filepath: "control_v11e_sd15_ip2p_fp16.safetensors"
40
- Series: "Standard"
41
- Type: ["Instruct P2P"]
42
- - Filepath: "control_v11p_sd15s2_lineart_anime_fp16.safetensors"
43
- Series: "Standard"
44
- Type: ["Anime Lineart"]
 
1
  ControlNet:
2
+ Anima:
3
+ - Filepath: "anima-preview-canny-v0.2.safetensors"
4
+ Series: "levzzz"
5
+ Type: ["Canny"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
yaml/file_list.yaml CHANGED
@@ -1,174 +1,27 @@
1
  file:
2
- checkpoints:
3
- - filename: "AnythingV5V3_v5PrtRE.safetensors"
4
- source: hf
5
- repo_id: "ckpt/anything-v5.0"
6
- repository_file_path: "AnythingV5V3_v5PrtRE.safetensors"
7
- - filename: "Anything-V3.0-pruned.safetensors"
8
- source: hf
9
- repo_id: "ckpt/anything-v3.0"
10
- repository_file_path: "Anything-V3.0-pruned.safetensors"
11
- - filename: "blue_pencil-v10.safetensors"
12
- source: hf
13
- repo_id: "bluepen5805/blue_pencil"
14
- repository_file_path: "blue_pencil-v10.safetensors"
15
- - filename: "AOM3_orangemixs.safetensors"
16
- source: hf
17
- repo_id: "WarriorMama777/OrangeMixs"
18
- repository_file_path: "Models/AbyssOrangeMix3/AOM3_orangemixs.safetensors"
19
- - filename: "AOM3A1_orangemixs.safetensors"
20
- source: hf
21
- repo_id: "WarriorMama777/OrangeMixs"
22
- repository_file_path: "Models/AbyssOrangeMix3/AOM3A1_orangemixs.safetensors"
23
- - filename: "AOM3A2_orangemixs.safetensors"
24
- source: hf
25
- repo_id: "WarriorMama777/OrangeMixs"
26
- repository_file_path: "Models/AbyssOrangeMix3/AOM3A2_orangemixs.safetensors"
27
- - filename: "AOM3A3_orangemixs.safetensors"
28
- source: hf
29
- repo_id: "WarriorMama777/OrangeMixs"
30
- repository_file_path: "Models/AbyssOrangeMix3/AOM3A3_orangemixs.safetensors"
31
- - filename: "AOM3A1B_orangemixs.safetensors"
32
- source: hf
33
- repo_id: "WarriorMama777/OrangeMixs"
34
- repository_file_path: "Models/AbyssOrangeMix3/AOM3A1B_orangemixs.safetensors"
35
- - filename: "AOM3B2_orangemixs.safetensors"
36
- source: hf
37
- repo_id: "WarriorMama777/OrangeMixs"
38
- repository_file_path: "Models/AbyssOrangeMix3/AOM3B2_orangemixs.safetensors"
39
- - filename: "AOM3B3_orangemixs.safetensors"
40
- source: hf
41
- repo_id: "WarriorMama777/OrangeMixs"
42
- repository_file_path: "Models/AbyssOrangeMix3/AOM3B3_orangemixs.safetensors"
43
- - filename: "AOM3B4_orangemixs.safetensors"
44
- source: hf
45
- repo_id: "WarriorMama777/OrangeMixs"
46
- repository_file_path: "Models/AbyssOrangeMix3/AOM3B4_orangemixs.safetensors"
47
-
48
- clip_vision:
49
- - filename: "CLIP-ViT-bigG-14-laion2B-39B-b160k.safetensors"
50
  source: "hf"
51
- repo_id: "h94/IP-Adapter"
52
- repository_file_path: "sdxl_models/image_encoder/model.safetensors"
53
- - filename: "CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors"
54
  source: "hf"
55
- repo_id: "h94/IP-Adapter"
56
- repository_file_path: "models/image_encoder/model.safetensors"
57
 
58
- controlnet:
59
- - filename: "control_v11e_sd15_ip2p_fp16.safetensors"
60
- source: "hf"
61
- repo_id: "comfyanonymous/ControlNet-v1-1_fp16_safetensors"
62
- repository_file_path: "control_v11e_sd15_ip2p_fp16.safetensors"
63
- - filename: "control_v11e_sd15_shuffle_fp16.safetensors"
64
- source: "hf"
65
- repo_id: "comfyanonymous/ControlNet-v1-1_fp16_safetensors"
66
- repository_file_path: "control_v11e_sd15_shuffle_fp16.safetensors"
67
- - filename: "control_v11f1e_sd15_tile_fp16.safetensors"
68
- source: "hf"
69
- repo_id: "comfyanonymous/ControlNet-v1-1_fp16_safetensors"
70
- repository_file_path: "control_v11f1e_sd15_tile_fp16.safetensors"
71
- - filename: "control_v11f1p_sd15_depth_fp16.safetensors"
72
- source: "hf"
73
- repo_id: "comfyanonymous/ControlNet-v1-1_fp16_safetensors"
74
- repository_file_path: "control_v11f1p_sd15_depth_fp16.safetensors"
75
- - filename: "control_v11p_sd15_canny_fp16.safetensors"
76
- source: "hf"
77
- repo_id: "comfyanonymous/ControlNet-v1-1_fp16_safetensors"
78
- repository_file_path: "control_v11p_sd15_canny_fp16.safetensors"
79
- - filename: "control_v11p_sd15_inpaint_fp16.safetensors"
80
- source: "hf"
81
- repo_id: "comfyanonymous/ControlNet-v1-1_fp16_safetensors"
82
- repository_file_path: "control_v11p_sd15_inpaint_fp16.safetensors"
83
- - filename: "control_v11p_sd15_lineart_fp16.safetensors"
84
- source: "hf"
85
- repo_id: "comfyanonymous/ControlNet-v1-1_fp16_safetensors"
86
- repository_file_path: "control_v11p_sd15_lineart_fp16.safetensors"
87
- - filename: "control_v11p_sd15_mlsd_fp16.safetensors"
88
- source: "hf"
89
- repo_id: "comfyanonymous/ControlNet-v1-1_fp16_safetensors"
90
- repository_file_path: "control_v11p_sd15_mlsd_fp16.safetensors"
91
- - filename: "control_v11p_sd15_normalbae_fp16.safetensors"
92
- source: "hf"
93
- repo_id: "comfyanonymous/ControlNet-v1-1_fp16_safetensors"
94
- repository_file_path: "control_v11p_sd15_normalbae_fp16.safetensors"
95
- - filename: "control_v11p_sd15_openpose_fp16.safetensors"
96
- source: "hf"
97
- repo_id: "comfyanonymous/ControlNet-v1-1_fp16_safetensors"
98
- repository_file_path: "control_v11p_sd15_openpose_fp16.safetensors"
99
- - filename: "control_v11p_sd15_scribble_fp16.safetensors"
100
- source: "hf"
101
- repo_id: "comfyanonymous/ControlNet-v1-1_fp16_safetensors"
102
- repository_file_path: "control_v11p_sd15_scribble_fp16.safetensors"
103
- - filename: "control_v11p_sd15_seg_fp16.safetensors"
104
- source: "hf"
105
- repo_id: "comfyanonymous/ControlNet-v1-1_fp16_safetensors"
106
- repository_file_path: "control_v11p_sd15_seg_fp16.safetensors"
107
- - filename: "control_v11p_sd15_softedge_fp16.safetensors"
108
- source: "hf"
109
- repo_id: "comfyanonymous/ControlNet-v1-1_fp16_safetensors"
110
- repository_file_path: "control_v11p_sd15_softedge_fp16.safetensors"
111
- - filename: "control_v11p_sd15s2_lineart_anime_fp16.safetensors"
112
  source: "hf"
113
- repo_id: "comfyanonymous/ControlNet-v1-1_fp16_safetensors"
114
- repository_file_path: "control_v11p_sd15s2_lineart_anime_fp16.safetensors"
115
- - filename: "control_v11u_sd15_tile_fp16.safetensors"
116
- source: "hf"
117
- repo_id: "comfyanonymous/ControlNet-v1-1_fp16_safetensors"
118
- repository_file_path: "control_v11u_sd15_tile_fp16.safetensors"
119
 
120
- ipadapter:
121
- - filename: "ip-adapter_sd15.safetensors"
122
- source: "hf"
123
- repo_id: "h94/IP-Adapter"
124
- repository_file_path: "models/ip-adapter_sd15.safetensors"
125
- - filename: "ip-adapter_sd15_light_v11.bin"
126
- source: "hf"
127
- repo_id: "h94/IP-Adapter"
128
- repository_file_path: "models/ip-adapter_sd15_light_v11.bin"
129
- - filename: "ip-adapter-plus_sd15.safetensors"
130
- source: "hf"
131
- repo_id: "h94/IP-Adapter"
132
- repository_file_path: "models/ip-adapter-plus_sd15.safetensors"
133
- - filename: "ip-adapter-plus-face_sd15.safetensors"
134
- source: "hf"
135
- repo_id: "h94/IP-Adapter"
136
- repository_file_path: "models/ip-adapter-plus-face_sd15.safetensors"
137
- - filename: "ip-adapter-full-face_sd15.safetensors"
138
- source: "hf"
139
- repo_id: "h94/IP-Adapter"
140
- repository_file_path: "models/ip-adapter-full-face_sd15.safetensors"
141
- - filename: "ip-adapter_sd15_vit-G.safetensors"
142
- source: "hf"
143
- repo_id: "h94/IP-Adapter"
144
- repository_file_path: "models/ip-adapter_sd15_vit-G.safetensors"
145
- - filename: "ip-adapter-faceid_sd15.bin"
146
  source: "hf"
147
- repo_id: "h94/IP-Adapter-FaceID"
148
- repository_file_path: "ip-adapter-faceid_sd15.bin"
149
- - filename: "ip-adapter-faceid-plus_sd15.bin"
150
- source: "hf"
151
- repo_id: "h94/IP-Adapter-FaceID"
152
- repository_file_path: "ip-adapter-faceid-plus_sd15.bin"
153
- - filename: "ip-adapter-faceid-plusv2_sd15.bin"
154
- source: "hf"
155
- repo_id: "h94/IP-Adapter-FaceID"
156
- repository_file_path: "ip-adapter-faceid-plusv2_sd15.bin"
157
- - filename: "ip-adapter-faceid-portrait-v11_sd15.bin"
158
- source: "hf"
159
- repo_id: "h94/IP-Adapter-FaceID"
160
- repository_file_path: "ip-adapter-faceid-portrait-v11_sd15.bin"
161
 
162
- loras:
163
- - filename: "ip-adapter-faceid_sd15_lora.safetensors"
164
- source: "hf"
165
- repo_id: "h94/IP-Adapter-FaceID"
166
- repository_file_path: "ip-adapter-faceid_sd15_lora.safetensors"
167
- - filename: "ip-adapter-faceid-plus_sd15_lora.safetensors"
168
- source: "hf"
169
- repo_id: "h94/IP-Adapter-FaceID"
170
- repository_file_path: "ip-adapter-faceid-plus_sd15_lora.safetensors"
171
- - filename: "ip-adapter-faceid-plusv2_sd15_lora.safetensors"
172
- source: "hf"
173
- repo_id: "h94/IP-Adapter-FaceID"
174
- repository_file_path: "ip-adapter-faceid-plusv2_sd15_lora.safetensors"
 
1
  file:
2
+ diffusion_models:
3
+ - filename: "anima-preview3-base.safetensors"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  source: "hf"
5
+ repo_id: "circlestone-labs/Anima"
6
+ repository_file_path: "split_files/diffusion_models/anima-preview3-base.safetensors"
7
+ - filename: "AnimaYume_tuned_v04.safetensors"
8
  source: "hf"
9
+ repo_id: "duongve/AnimaYume"
10
+ repository_file_path: "split_files/diffusion_models/AnimaYume_tuned_v04.safetensors"
11
 
12
+ text_encoders:
13
+ - filename: "qwen_3_06b_base.safetensors"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  source: "hf"
15
+ repo_id: "circlestone-labs/Anima"
16
+ repository_file_path: "split_files/text_encoders/qwen_3_06b_base.safetensors"
 
 
 
 
17
 
18
+ vae:
19
+ - filename: "qwen_image_vae.safetensors"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  source: "hf"
21
+ repo_id: "Comfy-Org/Qwen-Image_ComfyUI"
22
+ repository_file_path: "split_files/vae/qwen_image_vae.safetensors"
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
+ controlnet:
25
+ - filename: "anima-preview-canny-v0.2.safetensors"
26
+ source: "civitai"
27
+ model_version_id: "2748244"
 
 
 
 
 
 
 
 
 
yaml/injectors.yaml CHANGED
@@ -1,12 +1,12 @@
1
  injector_definitions:
 
 
2
  dynamic_controlnet_chains:
3
  module: "chain_injectors.controlnet_injector"
4
- dynamic_ipadapter_chains:
5
- module: "chain_injectors.ipadapter_injector"
6
  dynamic_conditioning_chains:
7
  module: "chain_injectors.conditioning_injector"
8
 
9
  injector_order:
10
- - dynamic_ipadapter_chains
11
  - dynamic_conditioning_chains
12
  - dynamic_controlnet_chains
 
1
  injector_definitions:
2
+ dynamic_lora_chains:
3
+ module: "chain_injectors.lora_injector"
4
  dynamic_controlnet_chains:
5
  module: "chain_injectors.controlnet_injector"
 
 
6
  dynamic_conditioning_chains:
7
  module: "chain_injectors.conditioning_injector"
8
 
9
  injector_order:
10
+ - dynamic_lora_chains
11
  - dynamic_conditioning_chains
12
  - dynamic_controlnet_chains
yaml/ipadapter.yaml DELETED
@@ -1,42 +0,0 @@
1
- - preset_name: "LIGHT - SD1.5 only (low strength)"
2
- vision_model: "CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors"
3
- ipadapter_model: "ip-adapter_sd15_light_v11.bin"
4
-
5
- - preset_name: "STANDARD (medium strength)"
6
- vision_model: "CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors"
7
- ipadapter_model: "ip-adapter_sd15.safetensors"
8
-
9
- - preset_name: "VIT-G (medium strength)"
10
- vision_model: "CLIP-ViT-bigG-14-laion2B-39B-b160k.safetensors"
11
- ipadapter_model: "ip-adapter_sd15_vit-G.safetensors"
12
-
13
- - preset_name: "PLUS (high strength)"
14
- vision_model: "CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors"
15
- ipadapter_model: "ip-adapter-plus_sd15.safetensors"
16
-
17
- - preset_name: "PLUS FACE (portraits)"
18
- vision_model: "CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors"
19
- ipadapter_model: "ip-adapter-plus-face_sd15.safetensors"
20
-
21
- - preset_name: "FULL FACE - SD1.5 only (portraits stronger)"
22
- vision_model: "CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors"
23
- ipadapter_model: "ip-adapter-full-face_sd15.safetensors"
24
-
25
- - preset_name: "FACEID"
26
- vision_model: "CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors"
27
- ipadapter_model: "ip-adapter-faceid_sd15.bin"
28
- lora_model: "ip-adapter-faceid_sd15_lora.safetensors"
29
-
30
- - preset_name: "FACEID PLUS - SD1.5 only"
31
- vision_model: "CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors"
32
- ipadapter_model: "ip-adapter-faceid-plus_sd15.bin"
33
- lora_model: "ip-adapter-faceid-plus_sd15_lora.safetensors"
34
-
35
- - preset_name: "FACEID PLUS V2"
36
- vision_model: "CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors"
37
- ipadapter_model: "ip-adapter-faceid-plusv2_sd15.bin"
38
- lora_model: "ip-adapter-faceid-plusv2_sd15_lora.safetensors"
39
-
40
- - preset_name: "FACEID PORTRAIT (style transfer)"
41
- vision_model: "CLIP-ViT-H-14-laion2B-s32B-b79K.safetensors"
42
- ipadapter_model: "ip-adapter-faceid-portrait-v11_sd15.bin"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
yaml/model_list.yaml CHANGED
@@ -1,23 +1,11 @@
1
  Checkpoint:
2
- - display_name: "Yuno779/Anything V5"
3
- path: "AnythingV5V3_v5PrtRE.safetensors"
4
- - display_name: "Yuno779/Anything V3"
5
- path: "Anything-V3.0-pruned.safetensors"
6
- - display_name: "blue_pen5805/blue_pencil v10"
7
- path: "blue_pencil-v10.safetensors"
8
- - display_name: "WarriorMama777/AOM3"
9
- path: "AOM3_orangemixs.safetensors"
10
- - display_name: "WarriorMama777/AOM3A1"
11
- path: "AOM3A1_orangemixs.safetensors"
12
- - display_name: "WarriorMama777/AOM3A2"
13
- path: "AOM3A2_orangemixs.safetensors"
14
- - display_name: "WarriorMama777/AOM3A3"
15
- path: "AOM3A3_orangemixs.safetensors"
16
- - display_name: "WarriorMama777/AOM3A1B"
17
- path: "AOM3A1B_orangemixs.safetensors"
18
- - display_name: "WarriorMama777/AOM3B2"
19
- path: "AOM3B2_orangemixs.safetensors"
20
- - display_name: "WarriorMama777/AOM3B3"
21
- path: "AOM3B3_orangemixs.safetensors"
22
- - display_name: "WarriorMama777/AOM3B4"
23
- path: "AOM3B4_orangemixs.safetensors"
 
1
  Checkpoint:
2
+ - display_name: "circlestone-labs/Anima-preview3-base"
3
+ components:
4
+ unet: "anima-preview3-base.safetensors"
5
+ vae: "qwen_image_vae.safetensors"
6
+ clip: "qwen_3_06b_base.safetensors"
7
+ - display_name: "duongve/AnimaYume-v0.4"
8
+ components:
9
+ unet: "AnimaYume_tuned_v04.safetensors"
10
+ vae: "qwen_image_vae.safetensors"
11
+ clip: "qwen_3_06b_base.safetensors"