Spaces:
Running on Zero
Running on Zero
Upload folder using huggingface_hub
Browse files- README.md +2 -2
- app.py +26 -21
- chain_injectors/conditioning_injector.py +2 -2
- chain_injectors/controlnet_injector.py +7 -10
- chain_injectors/ipadapter_injector.py +0 -106
- chain_injectors/lora_injector.py +67 -0
- comfy_integration/setup.py +0 -7
- core/model_manager.py +19 -116
- core/pipelines/sd_image_pipeline.py +84 -104
- core/pipelines/workflow_recipes/_partials/conditioning/{sd15.yaml → anima.yaml} +46 -33
- core/pipelines/workflow_recipes/sd_unified_recipe.yaml +2 -4
- core/settings.py +7 -13
- requirements.txt +2 -2
- ui/events.py +17 -215
- ui/layout.py +4 -30
- ui/shared/hires_fix_ui.py +9 -10
- ui/shared/img2img_ui.py +10 -10
- ui/shared/inpaint_ui.py +9 -10
- ui/shared/outpaint_ui.py +9 -10
- ui/shared/txt2img_ui.py +5 -6
- ui/shared/ui_components.py +10 -98
- utils/app_utils.py +29 -169
- yaml/constants.yaml +8 -25
- yaml/controlnet_models.yaml +4 -43
- yaml/file_list.yaml +19 -166
- yaml/injectors.yaml +3 -3
- yaml/ipadapter.yaml +0 -42
- yaml/model_list.yaml +10 -22
README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
---
|
| 2 |
-
title: ImageGen -
|
| 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 |
-
|
| 82 |
-
if not
|
| 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 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
shared_state.INVALID_MODEL_URLS[display_name] = True
|
| 93 |
-
|
| 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',
|
| 52 |
-
set_area_node['inputs']['height'] = item_data.get('height',
|
| 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
|
| 3 |
|
| 4 |
-
import torch
|
| 5 |
import gradio as gr
|
| 6 |
-
from comfy import model_management
|
| 7 |
|
| 8 |
-
from core.settings import ALL_MODEL_MAP
|
| 9 |
-
from
|
| 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
|
| 31 |
-
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
|
| 40 |
-
|
| 41 |
-
|
| 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 |
-
|
| 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 /
|
| 83 |
try:
|
| 84 |
-
_ensure_model_downloaded(
|
| 85 |
except Exception as e:
|
| 86 |
-
raise gr.Error(f"Failed to download model '{
|
|
|
|
| 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,
|
| 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,
|
| 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 |
-
|
| 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 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
|
|
|
| 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 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 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 |
-
|
| 298 |
-
|
| 299 |
-
temp_files_to_clean.append(
|
| 300 |
-
|
| 301 |
-
"image": os.path.basename(
|
| 302 |
-
"
|
| 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']
|
| 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 |
-
"
|
| 383 |
-
"
|
|
|
|
|
|
|
| 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 |
-
|
| 3 |
-
class_type:
|
| 4 |
-
title: "Load
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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: "
|
| 20 |
to: "ksampler:model"
|
| 21 |
-
|
| 22 |
-
- from: "
|
| 23 |
-
to: "clip_set_last_layer:clip"
|
| 24 |
-
- from: "clip_set_last_layer:0"
|
| 25 |
to: "pos_prompt:clip"
|
| 26 |
-
- from: "
|
| 27 |
to: "neg_prompt:clip"
|
| 28 |
-
|
| 29 |
-
- from: "
|
| 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 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
dynamic_controlnet_chains:
|
| 44 |
controlnet_chain:
|
| 45 |
template: "ControlNetApplyAdvanced"
|
| 46 |
ksampler_node: "ksampler"
|
| 47 |
-
|
| 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: "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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/
|
| 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 |
-
|
| 70 |
-
|
| 71 |
-
download_info = download_map.get(filename, {})
|
| 72 |
-
repo_id = download_info.get('repo_id', '')
|
| 73 |
|
| 74 |
model_tuple = (
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
"
|
| 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
|
| 113 |
LORA_SOURCE_CHOICES = ["Civitai", "Custom URL", "File"]
|
| 114 |
-
RESOLUTION_MAP
|
| 115 |
|
| 116 |
|
| 117 |
-
DEFAULT_NEGATIVE_PROMPT = "
|
|
|
|
| 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.
|
| 2 |
-
comfyui-workflow-templates==0.9.
|
| 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,
|
| 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("
|
| 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 +
|
| 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, '
|
| 635 |
-
|
| 636 |
-
|
| 637 |
-
w, h = res_map.get(ratio_key, (512, 512))
|
| 638 |
return w, h
|
| 639 |
|
| 640 |
-
for prefix in ["txt2img", "img2img", "
|
| 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 |
-
|
| 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 |
-
|
| 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 |
-
|
| 770 |
-
|
| 771 |
-
|
| 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 -
|
| 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("
|
| 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,
|
| 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="
|
| 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=
|
| 49 |
-
components[f'scheduler_{prefix}'] = gr.Dropdown(label="Scheduler", choices=SCHEDULER_CHOICES, value=
|
| 50 |
with gr.Row():
|
| 51 |
-
components[f'steps_{prefix}'] = gr.Slider(label="Steps", minimum=1, maximum=100, step=1, value=
|
| 52 |
-
components[f'cfg_{prefix}'] = gr.Slider(label="CFG Scale", minimum=1.0, maximum=20.0, step=0.1, value=
|
| 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(
|
| 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,
|
| 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="
|
| 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=
|
| 34 |
-
components[f'scheduler_{prefix}'] = gr.Dropdown(label="Scheduler", choices=SCHEDULER_CHOICES, value=
|
| 35 |
with gr.Row():
|
| 36 |
-
components[f'steps_{prefix}'] = gr.Slider(label="Steps", minimum=1, maximum=100, step=1, value=
|
| 37 |
-
components[f'cfg_{prefix}'] = gr.Slider(label="CFG Scale", minimum=1.0, maximum=20.0, step=0.1, value=
|
| 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(
|
| 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,
|
| 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="
|
| 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=
|
| 52 |
-
components[f'scheduler_{prefix}'] = gr.Dropdown(label="Scheduler", choices=SCHEDULER_CHOICES, value=
|
| 53 |
with gr.Row():
|
| 54 |
-
components[f'steps_{prefix}'] = gr.Slider(label="Steps", minimum=1, maximum=100, step=1, value=
|
| 55 |
-
components[f'cfg_{prefix}'] = gr.Slider(label="CFG Scale", minimum=1.0, maximum=20.0, step=0.1, value=
|
| 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(
|
| 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,
|
| 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="
|
| 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=
|
| 43 |
-
components[f'scheduler_{prefix}'] = gr.Dropdown(label="Scheduler", choices=SCHEDULER_CHOICES, value=
|
| 44 |
with gr.Row():
|
| 45 |
-
components[f'steps_{prefix}'] = gr.Slider(label="Steps", minimum=1, maximum=100, step=1, value=
|
| 46 |
-
components[f'cfg_{prefix}'] = gr.Slider(label="CFG Scale", minimum=1.0, maximum=20.0, step=0.1, value=
|
| 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(
|
| 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,
|
| 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="
|
| 22 |
|
| 23 |
with gr.Row():
|
| 24 |
with gr.Column(scale=1):
|
| 25 |
-
param_defaults = {'w':
|
| 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(
|
| 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,
|
| 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['
|
| 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',
|
| 44 |
-
components[f'height_{prefix}'] = gr.Number(label="Height", value=defaults.get('h',
|
| 45 |
with gr.Row():
|
| 46 |
-
components[f'sampler_{prefix}'] = gr.Dropdown(label="Sampler", choices=SAMPLER_CHOICES, value=
|
| 47 |
-
components[f'scheduler_{prefix}'] = gr.Dropdown(label="Scheduler", choices=SCHEDULER_CHOICES, value=
|
| 48 |
with gr.Row():
|
| 49 |
-
components[f'steps_{prefix}'] = gr.Slider(label="Steps", minimum=1, maximum=100, step=1, value=
|
| 50 |
-
components[f'cfg_{prefix}'] = gr.Slider(label="CFG Scale", minimum=1.0, maximum=20.0, step=0.1, value=
|
| 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(
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
"
|
| 313 |
-
"
|
| 314 |
-
"
|
| 315 |
-
"
|
|
|
|
|
|
|
| 316 |
}
|
| 317 |
-
|
|
|
|
|
|
|
| 318 |
if not dest_dir:
|
| 319 |
-
raise ValueError(f"Unknown model
|
| 320 |
|
| 321 |
-
|
| 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
|
| 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: {
|
| 338 |
|
| 339 |
if source == "hf":
|
| 340 |
repo_id = download_info.get("repo_id")
|
| 341 |
-
hf_filename = download_info.get("repository_file_path",
|
| 342 |
if not repo_id:
|
| 343 |
-
raise ValueError(f"repo_id is missing for HF model '{
|
| 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 '{
|
| 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: {
|
| 361 |
)
|
| 362 |
if "Failed" in status:
|
| 363 |
raise ConnectionError(status)
|
| 364 |
else:
|
| 365 |
-
raise NotImplementedError(f"Download source '{source}' is not implemented for '{
|
| 366 |
|
| 367 |
-
progress(1.0, desc=f"Downloaded: {
|
| 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 '{
|
| 375 |
|
| 376 |
-
return
|
| 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 |
-
|
| 10 |
-
"1:1 (Square)": [
|
| 11 |
-
"16:9 (Landscape)": [
|
| 12 |
-
"9:16 (Portrait)": [
|
| 13 |
-
"4:3 (Classic
|
| 14 |
-
"3:4 (Classic Portrait)": [
|
| 15 |
-
"3:2 (
|
| 16 |
-
"2:3 (Portrait)": [
|
| 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 |
-
|
| 3 |
-
- Filepath: "
|
| 4 |
-
Series: "
|
| 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 |
-
|
| 3 |
-
- filename: "
|
| 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: "
|
| 52 |
-
repository_file_path: "
|
| 53 |
-
- filename: "
|
| 54 |
source: "hf"
|
| 55 |
-
repo_id: "
|
| 56 |
-
repository_file_path: "
|
| 57 |
|
| 58 |
-
|
| 59 |
-
- filename: "
|
| 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: "
|
| 114 |
-
repository_file_path: "
|
| 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 |
-
|
| 121 |
-
- filename: "
|
| 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: "
|
| 148 |
-
repository_file_path: "
|
| 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 |
-
|
| 163 |
-
- filename: "
|
| 164 |
-
source: "
|
| 165 |
-
|
| 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 |
-
-
|
| 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: "
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 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"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|