Download workflow_api.py from HyperHail/C: direct link, hf CLI and curl.
- Browser
- Download file 43.7 kB
-
https://huggingface.co/spaces/HyperHail/C/resolve/main/workflow_api.py
- Command line
-
hf download hf://spaces/HyperHail/C/workflow_api.py
-
curl -L -o workflow_api.py https://huggingface.co/spaces/HyperHail/C/resolve/main/workflow_api.py
43.7 kB
| # Imports | |
| import json | |
| import os | |
| import sys | |
| from typing import Sequence, Mapping, Any, Union | |
| ALIGN_MODEL_TYPE = "SDXL" | |
| ALIGN_SCHEDULER = "AlignYourSteps" | |
| GENERATION = 2 | |
| ANIMA_CLIP = "2_qwen_3_06b_base.safetensors" | |
| GRID_SIZE = 5 | |
| LATENT_SCALE = 8 | |
| REGIONAL_FEATHER = .5 | |
| DETAILER_GUIDE_SIZE = 768 | |
| DETAILER_MAX_SIZE = 1024 | |
| DETAILER_THRESHOLD = .5 | |
| DETAILER_DILATION = 10 | |
| DETAILER_CROP = 3 | |
| DETAILER_FEATHER = 5 | |
| DETAILER_DROP_SIZE = 10 | |
| STYLE_IPADAPTER = "2_ip-adapter-plus_sdxl_vit-h.safetensors" | |
| STYLE_CLIP_VISION = "1_CLIP-ViT-H-fp16.safetensors" | |
| STYLE_WEIGHT_TYPE = "style transfer" | |
| STYLE_EMBEDS_SCALING = "V only" | |
| STYLE_IMAGE_SIZE = 1024 | |
| def upscale_size(width, height, scale): | |
| return tuple( | |
| round(value / LATENT_SCALE * scale) * LATENT_SCALE | |
| for value in (width, height) | |
| ) | |
| def mask_box(x, y, width, height, image_width, image_height): | |
| x1 = round(x * image_width) | |
| y1 = round(y * image_height) | |
| x2 = round((x + width) * image_width) | |
| y2 = round((y + height) * image_height) | |
| box_width = x2 - x1 | |
| box_height = y2 - y1 | |
| x_edges = int(x1 > 0) + int(x2 < image_width) | |
| y_edges = int(y1 > 0) + int(y2 < image_height) | |
| feather_x = min( | |
| round(image_width / GRID_SIZE * REGIONAL_FEATHER), | |
| box_width // max(1, x_edges), | |
| ) | |
| feather_y = min( | |
| round(image_height / GRID_SIZE * REGIONAL_FEATHER), | |
| box_height // max(1, y_edges), | |
| ) | |
| return ( | |
| x1, | |
| y1, | |
| box_width, | |
| box_height, | |
| feather_x if x1 else 0, | |
| feather_y if y1 else 0, | |
| feather_x if x2 < image_width else 0, | |
| feather_y if y2 < image_height else 0, | |
| ) | |
| def is_anima_model(name): | |
| number, separator, model = ( | |
| name.rsplit("/", 1)[-1].casefold().partition("_") | |
| ) | |
| return ( | |
| bool(separator) | |
| and number.isdigit() | |
| and model.startswith("anima") | |
| and not model.startswith("animag") | |
| ) | |
| def get_value_at_index(obj: Union[Sequence, Mapping], index: int) -> Any: | |
| """Return a sequence or mapping result item by index.""" | |
| try: | |
| return obj[index] | |
| except KeyError: | |
| return obj["result"][index] | |
| def get_comfyui_path() -> str: | |
| """Return the configured ComfyUI path, preferring COMFYUI_PATH when set.""" | |
| comfyui_path = os.environ.get("COMFYUI_PATH") | |
| if comfyui_path: | |
| return comfyui_path | |
| return find_path("ComfyUI") | |
| def find_path(name: str, path: str = None) -> str: | |
| """Recursively search parent folders until the named entry is found.""" | |
| if path is None: | |
| path = os.getcwd() | |
| if name in os.listdir(path): | |
| path_name = os.path.join(path, name) | |
| print(f"{name} found: {path_name}") | |
| return path_name | |
| parent_directory = os.path.dirname(path) | |
| if parent_directory == path: | |
| return None | |
| return find_path(name, parent_directory) | |
| def add_comfyui_directory_to_sys_path() -> None: | |
| """Add the ComfyUI checkout to sys.path.""" | |
| comfyui_path = get_comfyui_path() | |
| if comfyui_path is not None and os.path.isdir(comfyui_path): | |
| if comfyui_path in sys.path: | |
| sys.path.remove(comfyui_path) | |
| sys.path.insert(0, comfyui_path) | |
| print(f"'{comfyui_path}' added to sys.path") | |
| def add_extra_model_paths() -> None: | |
| """Load ComfyUI extra model paths configuration when available.""" | |
| try: | |
| from main import load_extra_path_config | |
| except ImportError: | |
| print( | |
| "Could not import load_extra_path_config from main.py. Looking in utils.extra_config instead." | |
| ) | |
| from utils.extra_config import load_extra_path_config | |
| extra_model_paths = find_path("extra_model_paths.yaml") | |
| if extra_model_paths is not None: | |
| load_extra_path_config(extra_model_paths) | |
| else: | |
| print("Could not find the extra_model_paths config file.") | |
| def bootstrap_comfyui_runtime() -> None: | |
| """Mirror the allocator-related ComfyUI startup steps before torch import.""" | |
| add_comfyui_directory_to_sys_path() | |
| import comfy.options | |
| comfy.options.enable_args_parsing() | |
| from comfy.cli_args import args | |
| if os.name == "nt": | |
| os.environ["MIMALLOC_PURGE_DELAY"] = "0" | |
| if args.default_device is not None: | |
| default_dev = args.default_device | |
| devices = list(range(32)) | |
| devices.remove(default_dev) | |
| devices.insert(0, default_dev) | |
| devices = ",".join(map(str, devices)) | |
| os.environ["CUDA_VISIBLE_DEVICES"] = str(devices) | |
| os.environ["HIP_VISIBLE_DEVICES"] = str(devices) | |
| if args.cuda_device is not None: | |
| os.environ["CUDA_VISIBLE_DEVICES"] = str(args.cuda_device) | |
| os.environ["HIP_VISIBLE_DEVICES"] = str(args.cuda_device) | |
| os.environ["ASCEND_RT_VISIBLE_DEVICES"] = str(args.cuda_device) | |
| if args.oneapi_device_selector is not None: | |
| os.environ["ONEAPI_DEVICE_SELECTOR"] = args.oneapi_device_selector | |
| if args.deterministic and "CUBLAS_WORKSPACE_CONFIG" not in os.environ: | |
| os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":4096:8" | |
| import cuda_malloc | |
| if "rocm" in cuda_malloc.get_torch_version_noimport(): | |
| os.environ["OCL_SET_SVM_SIZE"] = "262144" | |
| def cleanup_comfyui_runtime(unload_models: bool | None = None) -> None: | |
| """Best-effort cleanup for embedded or repeated generated-script execution.""" | |
| import gc | |
| def run_cleanup_hook(name: str, should_run: bool = True) -> None: | |
| if not should_run or not hasattr(model_management, name): | |
| return | |
| cleanup_fn = getattr(model_management, name) | |
| try: | |
| cleanup_fn() | |
| except Exception as exc: | |
| warnings.warn( | |
| f"ComfyUI cleanup hook {name} failed during teardown: {exc}", | |
| RuntimeWarning, | |
| stacklevel=2, | |
| ) | |
| should_unload = unload_models | |
| if should_unload is None: | |
| should_unload = os.environ.get( | |
| "COMFYUI_TOPYTHON_UNLOAD_MODELS", "" | |
| ).lower() in { | |
| "1", | |
| "true", | |
| "yes", | |
| "on", | |
| } | |
| try: | |
| import comfy.model_management as model_management | |
| except ModuleNotFoundError: | |
| gc.collect() | |
| return | |
| run_cleanup_hook("cleanup_models_gc") | |
| run_cleanup_hook("unload_all_models", should_run=should_unload) | |
| run_cleanup_hook("soft_empty_cache") | |
| gc.collect() | |
| def import_custom_nodes() -> None: | |
| """Initialize ComfyUI custom nodes in the exporter runtime.""" | |
| comfyui_path = get_comfyui_path() | |
| if comfyui_path and comfyui_path not in sys.path: | |
| sys.path.insert(0, comfyui_path) | |
| import asyncio | |
| import execution | |
| from nodes import init_extra_nodes | |
| if comfyui_path in sys.path: | |
| sys.path.remove(comfyui_path) | |
| sys.path.insert(0, comfyui_path) | |
| import server | |
| from app.assets.manager import default_asset_manager | |
| loop = asyncio.new_event_loop() | |
| asyncio.set_event_loop(loop) | |
| try: | |
| server_instance = server.PromptServer(loop, default_asset_manager()) | |
| execution.PromptQueue(server_instance) | |
| loop.run_until_complete(init_extra_nodes()) | |
| finally: | |
| asyncio.set_event_loop(None) | |
| loop.close() | |
| # Workflow data | |
| def build_workflow() -> dict[str, Any]: | |
| return { | |
| "1": { | |
| "inputs": {"ckpt_name": "52_novaAnimeXL_ilV190.safetensors"}, | |
| "class_type": "CheckpointLoaderSimple", | |
| "_meta": {"title": "Loader"}, | |
| }, | |
| "2": { | |
| "inputs": {"text": ["118", 0], "clip": ["117", 1]}, | |
| "class_type": "CLIPTextEncode", | |
| "_meta": {"title": "CLIP Text Encode (Prompt)"}, | |
| }, | |
| "3": { | |
| "inputs": { | |
| "text": "(censored, mosaic censoring, bar censor:1.1), bad " | |
| "quality, worst quality, worst detail, bad anatomy, " | |
| "extra fingers, extra toes, extra legs, 4 toes, 6 " | |
| "toes, 4 fingers, 6 fingers, malformed fingers, " | |
| "extra limbs, missing fingers, extra arms, censored, " | |
| "deformed, disfigured, text, (multiple views:1.1)", | |
| "clip": ["28", 1], | |
| }, | |
| "class_type": "CLIPTextEncode", | |
| "_meta": {"title": "CLIP Text Encode (Prompt)"}, | |
| }, | |
| "5": { | |
| "inputs": { | |
| "seed": 809278554234612, | |
| "steps": 16, | |
| "cfg": 4, | |
| "sampler_name": "euler_ancestral", | |
| "scheduler": "karras", | |
| "denoise": 1, | |
| "model": ["117", 0], | |
| "positive": ["2", 0], | |
| "negative": ["3", 0], | |
| "latent_image": ["27", 0], | |
| }, | |
| "class_type": "KSampler", | |
| "_meta": {"title": "KSampler"}, | |
| }, | |
| "10": { | |
| "inputs": { | |
| "lora_name": "8_bikabaka.safetensors", | |
| "strength_model": 0.3, | |
| "strength_clip": 0, | |
| "model": ["1", 0], | |
| "clip": ["1", 1], | |
| }, | |
| "class_type": "LoraLoader", | |
| "_meta": {"title": "Load LoRA"}, | |
| }, | |
| "27": { | |
| "inputs": {"width": 1152, "height": 896, "batch_size": 1}, | |
| "class_type": "EmptyLatentImage", | |
| "_meta": {"title": "Empty Landscape"}, | |
| }, | |
| "28": { | |
| "inputs": { | |
| "lora_name": "43_5cm-illustriousXL_v01_V1-CAME-000035.safetensors", | |
| "strength_model": 0.4, | |
| "strength_clip": 0, | |
| "model": ["38", 0], | |
| "clip": ["38", 1], | |
| }, | |
| "class_type": "LoraLoader", | |
| "_meta": {"title": "Load LoRA"}, | |
| }, | |
| "38": { | |
| "inputs": { | |
| "lora_name": "42_アップスケール_remacri_original.pt", | |
| "strength_model": 0.4, | |
| "strength_clip": 0, | |
| "model": ["10", 0], | |
| "clip": ["10", 1], | |
| }, | |
| "class_type": "LoraLoader", | |
| "_meta": {"title": "Load LoRA"}, | |
| }, | |
| "45": { | |
| "inputs": {"vae_name": "3_sdxlVAE_sdxlVAE.safetensors"}, | |
| "class_type": "VAELoader", | |
| "_meta": {"title": "Load VAE"}, | |
| }, | |
| "56": { | |
| "inputs": {"samples": ["5", 0], "vae": ["45", 0]}, | |
| "class_type": "VAEDecode", | |
| "_meta": {"title": "VAE Decode"}, | |
| }, | |
| "72": { | |
| "inputs": {"images": ["56", 0]}, | |
| "class_type": "PreviewImage", | |
| "_meta": {"title": "Preview Image"}, | |
| }, | |
| "117": { | |
| "inputs": { | |
| "lora_name": "5_add_saturation_XL.safetensors", | |
| "strength_model": -1.4, | |
| "strength_clip": 0, | |
| "model": ["28", 0], | |
| "clip": ["28", 1], | |
| }, | |
| "class_type": "LoraLoader", | |
| "_meta": {"title": "Load LoRA (Model and CLIP)"}, | |
| }, | |
| "118": { | |
| "inputs": { | |
| "string_a": "%prompt%", | |
| "string_b": "", | |
| "delimiter": "", | |
| }, | |
| "class_type": "StringConcatenate", | |
| "_meta": {"title": "Concatenate Text"}, | |
| }, | |
| } | |
| def build_extra_pnginfo() -> dict[str, Any] | None: | |
| return { | |
| "workflow": { | |
| "id": "e69619af-5ceb-4a83-821d-68180291905e", | |
| "revision": 0, | |
| "last_node_id": 121, | |
| "last_link_id": 57, | |
| "nodes": [ | |
| { | |
| "id": 27, | |
| "type": "EmptyLatentImage", | |
| "pos": [100, 358], | |
| "size": [270, 106], | |
| "flags": {}, | |
| "order": 0, | |
| "mode": 0, | |
| "inputs": [], | |
| "outputs": [{"name": "LATENT", "type": "LATENT", "links": [24]}], | |
| "title": "Empty Landscape", | |
| "properties": {"Node name for S&R": "EmptyLatentImage"}, | |
| "widgets_values": [1152, 896, 1], | |
| }, | |
| { | |
| "id": 45, | |
| "type": "VAELoader", | |
| "pos": [100, 594], | |
| "size": [270, 58], | |
| "flags": {}, | |
| "order": 1, | |
| "mode": 0, | |
| "inputs": [], | |
| "outputs": [{"name": "VAE", "type": "VAE", "links": [32]}], | |
| "properties": {"Node name for S&R": "VAELoader"}, | |
| "widgets_values": ["3_sdxlVAE_sdxlVAE.safetensors"], | |
| }, | |
| { | |
| "id": 56, | |
| "type": "VAEDecode", | |
| "pos": [2948.649165895271, 134.76727061509087], | |
| "size": [140, 46], | |
| "flags": {}, | |
| "order": 11, | |
| "mode": 0, | |
| "inputs": [ | |
| {"name": "samples", "type": "LATENT", "link": 31}, | |
| {"name": "vae", "type": "VAE", "link": 32}, | |
| ], | |
| "outputs": [{"name": "IMAGE", "type": "IMAGE", "links": [33]}], | |
| "properties": {"Node name for S&R": "VAEDecode"}, | |
| "widgets_values": [], | |
| }, | |
| { | |
| "id": 10, | |
| "type": "LoraLoader", | |
| "pos": [600, 130], | |
| "size": [290.43334045410154, 126], | |
| "flags": {}, | |
| "order": 4, | |
| "mode": 0, | |
| "inputs": [ | |
| {"name": "model", "type": "MODEL", "link": 25}, | |
| {"name": "clip", "type": "CLIP", "link": 26}, | |
| ], | |
| "outputs": [ | |
| {"name": "MODEL", "type": "MODEL", "links": [29]}, | |
| {"name": "CLIP", "type": "CLIP", "links": [30]}, | |
| ], | |
| "title": "Load LoRA", | |
| "properties": {"Node name for S&R": "LoraLoader"}, | |
| "widgets_values": ["8_bikabaka.safetensors", 0.3, 0], | |
| }, | |
| { | |
| "id": 72, | |
| "type": "PreviewImage", | |
| "pos": [3188.649165895271, 134.76727061509087], | |
| "size": [285.77604360195164, 258], | |
| "flags": {}, | |
| "order": 12, | |
| "mode": 0, | |
| "inputs": [{"name": "images", "type": "IMAGE", "link": 33}], | |
| "outputs": [{"name": "images", "type": "IMAGE", "links": None}], | |
| "properties": {"Node name for S&R": "PreviewImage"}, | |
| "widgets_values": [], | |
| }, | |
| { | |
| "id": 1, | |
| "type": "CheckpointLoaderSimple", | |
| "pos": [100, 130], | |
| "size": [270, 98], | |
| "flags": {}, | |
| "order": 2, | |
| "mode": 0, | |
| "inputs": [], | |
| "outputs": [ | |
| {"name": "MODEL", "type": "MODEL", "links": [25]}, | |
| {"name": "CLIP", "type": "CLIP", "links": [26]}, | |
| {"name": "VAE", "type": "VAE", "links": None}, | |
| ], | |
| "title": "Loader", | |
| "properties": {"Node name for S&R": "CheckpointLoaderSimple"}, | |
| "widgets_values": ["52_novaAnimeXL_ilV190.safetensors"], | |
| }, | |
| { | |
| "id": 2, | |
| "type": "CLIPTextEncode", | |
| "pos": [1880.866680908203, 130], | |
| "size": [400, 200], | |
| "flags": {}, | |
| "order": 9, | |
| "mode": 0, | |
| "inputs": [ | |
| {"name": "clip", "type": "CLIP", "link": 49}, | |
| { | |
| "name": "text", | |
| "type": "STRING", | |
| "widget": {"name": "text"}, | |
| "link": 54, | |
| }, | |
| ], | |
| "outputs": [ | |
| {"name": "CONDITIONING", "type": "CONDITIONING", "links": [39]} | |
| ], | |
| "properties": {"Node name for S&R": "CLIPTextEncode"}, | |
| "widgets_values": [""], | |
| }, | |
| { | |
| "id": 5, | |
| "type": "KSampler", | |
| "pos": [2578.649165895271, 134.76727061509087], | |
| "size": [270, 262], | |
| "flags": {}, | |
| "order": 10, | |
| "mode": 0, | |
| "inputs": [ | |
| {"name": "model", "type": "MODEL", "link": 50}, | |
| {"name": "positive", "type": "CONDITIONING", "link": 39}, | |
| {"name": "negative", "type": "CONDITIONING", "link": 23}, | |
| {"name": "latent_image", "type": "LATENT", "link": 24}, | |
| ], | |
| "outputs": [{"name": "LATENT", "type": "LATENT", "links": [31]}], | |
| "properties": {"Node name for S&R": "KSampler"}, | |
| "widgets_values": [ | |
| 809278554234612, | |
| "randomize", | |
| 16, | |
| 4, | |
| "euler_ancestral", | |
| "karras", | |
| 1, | |
| ], | |
| }, | |
| { | |
| "id": 38, | |
| "type": "LoraLoader", | |
| "pos": [990, 130], | |
| "size": [290.43334045410154, 126], | |
| "flags": {}, | |
| "order": 5, | |
| "mode": 0, | |
| "inputs": [ | |
| {"name": "model", "type": "MODEL", "link": 29}, | |
| {"name": "clip", "type": "CLIP", "link": 30}, | |
| ], | |
| "outputs": [ | |
| {"name": "MODEL", "type": "MODEL", "links": [27]}, | |
| {"name": "CLIP", "type": "CLIP", "links": [28]}, | |
| ], | |
| "title": "Load LoRA", | |
| "properties": {"Node name for S&R": "LoraLoader"}, | |
| "widgets_values": ["42_アップスケール_remacri_original.pt", 0.4, 0], | |
| }, | |
| { | |
| "id": 28, | |
| "type": "LoraLoader", | |
| "pos": [1380, 130], | |
| "size": [290.43334045410154, 126], | |
| "flags": {}, | |
| "order": 6, | |
| "mode": 0, | |
| "inputs": [ | |
| {"name": "model", "type": "MODEL", "link": 27}, | |
| {"name": "clip", "type": "CLIP", "link": 28}, | |
| ], | |
| "outputs": [ | |
| {"name": "MODEL", "type": "MODEL", "links": [47]}, | |
| {"name": "CLIP", "type": "CLIP", "links": [20, 48]}, | |
| ], | |
| "title": "Load LoRA", | |
| "properties": {"Node name for S&R": "LoraLoader"}, | |
| "widgets_values": [ | |
| "43_5cm-illustriousXL_v01_V1-CAME-000035.safetensors", | |
| 0.4, | |
| 0, | |
| ], | |
| }, | |
| { | |
| "id": 117, | |
| "type": "LoraLoader", | |
| "pos": [1523.7427746854546, 341.08039710943746], | |
| "size": [290.43334045410154, 126], | |
| "flags": {}, | |
| "order": 8, | |
| "mode": 0, | |
| "inputs": [ | |
| {"name": "model", "type": "MODEL", "link": 47}, | |
| {"name": "clip", "type": "CLIP", "link": 48}, | |
| ], | |
| "outputs": [ | |
| {"name": "MODEL", "type": "MODEL", "links": [50]}, | |
| {"name": "CLIP", "type": "CLIP", "links": [49]}, | |
| ], | |
| "properties": {"Node name for S&R": "LoraLoader"}, | |
| "widgets_values": ["5_add_saturation_XL.safetensors", -1.4, 0], | |
| }, | |
| { | |
| "id": 118, | |
| "type": "StringConcatenate", | |
| "pos": [1363.7030337022063, -256.7007293998441], | |
| "size": [400, 200], | |
| "flags": {}, | |
| "order": 3, | |
| "mode": 0, | |
| "inputs": [], | |
| "outputs": [{"name": "STRING", "type": "STRING", "links": [54]}], | |
| "properties": {"Node name for S&R": "StringConcatenate"}, | |
| "widgets_values": [ | |
| "%prompt%", | |
| "", | |
| "", | |
| ], | |
| }, | |
| { | |
| "id": 3, | |
| "type": "CLIPTextEncode", | |
| "pos": [1881.5394309031356, 459.32725000506747], | |
| "size": [400, 200], | |
| "flags": {}, | |
| "order": 7, | |
| "mode": 0, | |
| "inputs": [{"name": "clip", "type": "CLIP", "link": 20}], | |
| "outputs": [ | |
| {"name": "CONDITIONING", "type": "CONDITIONING", "links": [23]} | |
| ], | |
| "properties": {"Node name for S&R": "CLIPTextEncode"}, | |
| "widgets_values": [ | |
| "(censored, mosaic censoring, bar " | |
| "censor:1.1), bad quality, worst " | |
| "quality, worst detail, bad " | |
| "anatomy, extra fingers, extra " | |
| "toes, extra legs, 4 toes, 6 toes, " | |
| "4 fingers, 6 fingers, malformed " | |
| "fingers, extra limbs, missing " | |
| "fingers, extra arms, censored, " | |
| "deformed, disfigured, text, " | |
| "(multiple views:1.1)" | |
| ], | |
| }, | |
| ], | |
| "links": [ | |
| [20, 28, 1, 3, 0, "CLIP"], | |
| [23, 3, 0, 5, 2, "CONDITIONING"], | |
| [24, 27, 0, 5, 3, "LATENT"], | |
| [25, 1, 0, 10, 0, "MODEL"], | |
| [26, 1, 1, 10, 1, "CLIP"], | |
| [27, 38, 0, 28, 0, "MODEL"], | |
| [28, 38, 1, 28, 1, "CLIP"], | |
| [29, 10, 0, 38, 0, "MODEL"], | |
| [30, 10, 1, 38, 1, "CLIP"], | |
| [31, 5, 0, 56, 0, "LATENT"], | |
| [32, 45, 0, 56, 1, "VAE"], | |
| [33, 56, 0, 72, 0, "IMAGE"], | |
| [39, 2, 0, 5, 1, "CONDITIONING"], | |
| [47, 28, 0, 117, 0, "MODEL"], | |
| [48, 28, 1, 117, 1, "CLIP"], | |
| [49, 117, 1, 2, 0, "CLIP"], | |
| [50, 117, 0, 5, 0, "MODEL"], | |
| [54, 118, 0, 2, 1, "STRING"], | |
| ], | |
| "groups": [], | |
| "config": {}, | |
| "extra": { | |
| "ds": { | |
| "scale": 0.6303940863128564, | |
| "offset": [-602.8886169463092, 486.2591310892753], | |
| }, | |
| "frontendVersion": "1.45.20", | |
| }, | |
| "version": 0.4, | |
| } | |
| } | |
| def image_metadata( | |
| config, | |
| seeds, | |
| detailer_seeds, | |
| detailer_vaes, | |
| vaes, | |
| regions, | |
| environment_start, | |
| global_strength, | |
| ): | |
| api = {} | |
| def add(class_type, inputs): | |
| node_id = str(len(api) + 1) | |
| api[node_id] = {"inputs": inputs, "class_type": class_type} | |
| return node_id | |
| style_images = {} | |
| style_pipeline = None | |
| style_clip_vision = None | |
| def style_config(stage): | |
| if stage == "second" and config.get("second_style_images"): | |
| return ( | |
| "second", | |
| config["second_style_images"], | |
| config["second_style_weight"], | |
| config["second_style_end"], | |
| ) | |
| images = config.get("style_images") | |
| scope = config.get("style_scope", "generation") | |
| enabled = ( | |
| stage == "first" | |
| or stage == "second" and scope in ("generation", "all") | |
| or stage == "detailer" and scope == "all" | |
| ) | |
| if images and enabled: | |
| return "first", images, config["style_weight"], config["style_end"] | |
| return None | |
| def apply_style(model, stage): | |
| nonlocal style_pipeline, style_clip_vision | |
| values = style_config(stage) | |
| if values is None: | |
| return model | |
| key, names, weight, end = values | |
| if key not in style_images: | |
| style_image = None | |
| for name in names: | |
| image = [add("LoadImage", {"image": name}), 0] | |
| image = [add("ImageScale", { | |
| "image": image, | |
| "upscale_method": "lanczos", | |
| "width": STYLE_IMAGE_SIZE, | |
| "height": STYLE_IMAGE_SIZE, | |
| "crop": "center", | |
| }), 0] | |
| if style_image is None: | |
| style_image = image | |
| else: | |
| style_image = [add("ImageBatch", { | |
| "image1": style_image, | |
| "image2": image, | |
| }), 0] | |
| style_images[key] = style_image | |
| if style_pipeline is None: | |
| style_pipeline = [add("IPAdapterModelLoader", { | |
| "ipadapter_file": STYLE_IPADAPTER, | |
| }), 0] | |
| style_clip_vision = [add("CLIPVisionLoader", { | |
| "clip_name": STYLE_CLIP_VISION, | |
| }), 0] | |
| return [add("IPAdapterAdvanced", { | |
| "model": model, | |
| "ipadapter": style_pipeline, | |
| "clip_vision": style_clip_vision, | |
| "image": style_images[key], | |
| "weight": weight, | |
| "weight_type": STYLE_WEIGHT_TYPE, | |
| "combine_embeds": "average", | |
| "start_at": 0, | |
| "end_at": end, | |
| "embeds_scaling": STYLE_EMBEDS_SCALING, | |
| }), 0] | |
| def load_chain(model_name, loras): | |
| if is_anima_model(model_name): | |
| model = [add("UNETLoader", { | |
| "unet_name": model_name, | |
| "weight_dtype": "default", | |
| }), 0] | |
| clip = [add("CLIPLoader", { | |
| "clip_name": ANIMA_CLIP, | |
| "type": "stable_diffusion", | |
| "device": "default", | |
| }), 0] | |
| else: | |
| node_id = add( | |
| "CheckpointLoaderSimple", | |
| {"ckpt_name": model_name}, | |
| ) | |
| model = [node_id, 0] | |
| clip = [node_id, 1] | |
| for lora in loras: | |
| node_id = add("LoraLoader", { | |
| "lora_name": lora["name"], | |
| "strength_model": lora["strength"], | |
| "strength_clip": lora["clip"], | |
| "model": model, | |
| "clip": clip, | |
| }) | |
| model = [node_id, 0] | |
| clip = [node_id, 1] | |
| return model, clip | |
| def custom_sampler(sampler_name, model): | |
| prefix, separator, name = sampler_name.partition(":") | |
| if not separator: | |
| return None | |
| if prefix == "ppm-dyn": | |
| return [add("DynSamplerSelect", { | |
| "sampler_name": name, | |
| "eta": 1, | |
| "s_dy_pow": -1, | |
| "s_extra_steps": False, | |
| }), 0] | |
| if prefix == "ppm-cfgpp": | |
| return [add("CFGPPSamplerSelect", { | |
| "sampler_name": name, | |
| "eta": 1, | |
| "s_gamma_start": 0, | |
| "s_gamma_end": 1, | |
| "s_extra_steps": False, | |
| }), 0] | |
| if prefix == "ppm": | |
| return [add("PPMSamplerSelect", { | |
| "sampler_name": name, | |
| "model": model, | |
| "cfg_pp": False, | |
| "s_sigma_diff": 2, | |
| }), 0] | |
| return None | |
| def sample( | |
| model, | |
| seed, | |
| steps, | |
| cfg, | |
| sampler_name, | |
| scheduler, | |
| positive, | |
| negative, | |
| latent, | |
| denoise, | |
| ): | |
| sampler = custom_sampler(sampler_name, model) | |
| if scheduler != ALIGN_SCHEDULER and sampler is None: | |
| return [add("KSampler", { | |
| "seed": seed, | |
| "steps": steps, | |
| "cfg": cfg, | |
| "sampler_name": sampler_name, | |
| "scheduler": scheduler, | |
| "denoise": denoise, | |
| "model": model, | |
| "positive": positive, | |
| "negative": negative, | |
| "latent_image": latent, | |
| }), 0] | |
| if scheduler == ALIGN_SCHEDULER: | |
| sigmas = [add("AlignYourStepsScheduler", { | |
| "model_type": ALIGN_MODEL_TYPE, | |
| "steps": steps, | |
| "denoise": denoise, | |
| }), 0] | |
| else: | |
| sigmas = [add("BasicScheduler", { | |
| "model": model, | |
| "scheduler": scheduler, | |
| "steps": steps, | |
| "denoise": denoise, | |
| }), 0] | |
| if sampler is None: | |
| sampler = [add("KSamplerSelect", { | |
| "sampler_name": sampler_name, | |
| }), 0] | |
| return [add("SamplerCustom", { | |
| "model": model, | |
| "add_noise": True, | |
| "noise_seed": seed, | |
| "cfg": cfg, | |
| "positive": positive, | |
| "negative": negative, | |
| "sampler": sampler, | |
| "sigmas": sigmas, | |
| "latent_image": latent, | |
| }), 0] | |
| def encode_positive(model, clip, prompt, image_width, image_height): | |
| mask_width = image_width // LATENT_SCALE | |
| mask_height = image_height // LATENT_SCALE | |
| positive = [add("CLIPTextEncode", { | |
| "text": prompt, "clip": clip, | |
| }), 0] | |
| regional_mode = config.get("regional_mode", "conditioning") | |
| if regions: | |
| positive = [add("ConditioningSetAreaStrength", { | |
| "conditioning": positive, | |
| "strength": global_strength, | |
| }), 0] | |
| if regions and regional_mode == "conditioning": | |
| positive = [add("ConditioningSetTimestepRange", { | |
| "conditioning": positive, | |
| "start": environment_start, | |
| "end": 1, | |
| }), 0] | |
| regional_inputs = {} | |
| for index, (prompt, x, y, width, height, strength) in enumerate( | |
| regions, | |
| 1, | |
| ): | |
| conditioning = [add("CLIPTextEncode", { | |
| "text": prompt, "clip": clip, | |
| }), 0] | |
| x, y, width, height, left, top, right, bottom = mask_box( | |
| x, | |
| y, | |
| width, | |
| height, | |
| mask_width, | |
| mask_height, | |
| ) | |
| mask = [add("SolidMask", { | |
| "value": 1, | |
| "width": width, | |
| "height": height, | |
| }), 0] | |
| if any((left, top, right, bottom)): | |
| mask = [add("FeatherMask", { | |
| "mask": mask, | |
| "left": left, | |
| "top": top, | |
| "right": right, | |
| "bottom": bottom, | |
| }), 0] | |
| background = [add("SolidMask", { | |
| "value": 0, | |
| "width": mask_width, | |
| "height": mask_height, | |
| }), 0] | |
| mask = [add("MaskComposite", { | |
| "destination": background, | |
| "source": mask, | |
| "x": x, | |
| "y": y, | |
| "operation": "add", | |
| }), 0] | |
| if regional_mode == "attention": | |
| conditioning = [add("ConditioningSetAreaStrength", { | |
| "conditioning": conditioning, | |
| "strength": strength, | |
| }), 0] | |
| regional_inputs[f"cond_{index}"] = conditioning | |
| regional_inputs[f"mask_{index}"] = mask | |
| else: | |
| conditioning = [add("ConditioningSetMask", { | |
| "conditioning": conditioning, | |
| "mask": mask, | |
| "strength": strength, | |
| "set_cond_area": "mask bounds", | |
| }), 0] | |
| positive = [add("ConditioningCombine", { | |
| "conditioning_1": positive, | |
| "conditioning_2": conditioning, | |
| }), 0] | |
| if regional_inputs: | |
| base_mask = [add("SolidMask", { | |
| "value": 1, | |
| "width": mask_width, | |
| "height": mask_height, | |
| }), 0] | |
| model = [add("AttentionCouplePPM", { | |
| "model": model, | |
| "base_cond": positive, | |
| "base_mask": base_mask, | |
| **regional_inputs, | |
| }), 0] | |
| return model, positive | |
| first_model = config["model"] | |
| second_model = config["second_model"] or first_model | |
| first_vae, second_vae = vaes | |
| base_model, clip = load_chain(first_model, config["loras"]) | |
| model = apply_style(base_model, "first") | |
| model, positive = encode_positive( | |
| model, | |
| clip, | |
| config["prompt"], | |
| config["width"], | |
| config["height"], | |
| ) | |
| negative = [add("CLIPTextEncode", { | |
| "text": config["negative"], "clip": clip, | |
| }), 0] | |
| latent = [add("EmptyLatentImage", { | |
| "width": config["width"], | |
| "height": config["height"], | |
| "batch_size": config["batch_size"], | |
| }), 0] | |
| samples = sample( | |
| model, | |
| seeds[0], | |
| config["steps"], | |
| config["cfg"], | |
| config["sampler"], | |
| config["scheduler"], | |
| positive, | |
| negative, | |
| latent, | |
| 1, | |
| ) | |
| if config["upscale"]: | |
| width, height = upscale_size( | |
| config["width"], | |
| config["height"], | |
| config["upscale_scale"], | |
| ) | |
| samples = [add("LatentUpscale", { | |
| "upscale_method": config["upscale_method"], | |
| "width": width, | |
| "height": height, | |
| "crop": "disabled", | |
| "samples": samples, | |
| }), 0] | |
| if is_anima_model(first_model) != is_anima_model(second_model): | |
| source_vae = [add("VAELoader", {"vae_name": first_vae}), 0] | |
| image = [add("VAEDecode", { | |
| "samples": samples, | |
| "vae": source_vae, | |
| }), 0] | |
| target_vae = [add("VAELoader", {"vae_name": second_vae}), 0] | |
| samples = [add("VAEEncode", { | |
| "pixels": image, | |
| "vae": target_vae, | |
| }), 0] | |
| if config["second_model"]: | |
| base_model, clip = load_chain( | |
| config["second_model"], config["second_loras"], | |
| ) | |
| model = apply_style(base_model, "second") | |
| model, positive = encode_positive( | |
| model, | |
| clip, | |
| config.get("second_prompt") or config["prompt"], | |
| width, | |
| height, | |
| ) | |
| negative = [add("CLIPTextEncode", { | |
| "text": config.get("second_negative") or config["negative"], | |
| "clip": clip, | |
| }), 0] | |
| samples = sample( | |
| model, | |
| seeds[1], | |
| config["second_steps"], | |
| config["second_cfg"], | |
| config["second_sampler"], | |
| config["second_scheduler"], | |
| positive, | |
| negative, | |
| samples, | |
| config["denoise"], | |
| ) | |
| vae = second_vae if config["upscale"] else first_vae | |
| vae_node = add("VAELoader", {"vae_name": vae}) | |
| image = add("VAEDecode", {"samples": samples, "vae": [vae_node, 0]}) | |
| base_clip, base_vae = clip, [vae_node, 0] | |
| final_prompt = config.get("second_prompt") or config["prompt"] \ | |
| if config["upscale"] else config["prompt"] | |
| final_negative = config.get("second_negative") or config["negative"] \ | |
| if config["upscale"] else config["negative"] | |
| for detailer, seed, detailer_vae in zip( | |
| config["detailers"], | |
| detailer_seeds, | |
| detailer_vaes, | |
| ): | |
| if detailer["model"]: | |
| model, clip = load_chain(detailer["model"], []) | |
| vae = [add("VAELoader", { | |
| "vae_name": detailer_vae, | |
| }), 0] | |
| prompt, negative_prompt = config["prompt"], config["negative"] | |
| else: | |
| model, clip, vae = base_model, base_clip, base_vae | |
| prompt, negative_prompt = final_prompt, final_negative | |
| model = apply_style(model, "detailer") | |
| positive = [add("CLIPTextEncode", { | |
| "text": detailer["prompt"] or prompt, "clip": clip, | |
| }), 0] | |
| negative = [add("CLIPTextEncode", { | |
| "text": detailer["negative"] or negative_prompt, "clip": clip, | |
| }), 0] | |
| detector = add("UltralyticsDetectorProvider", { | |
| "model_name": f"bbox/{detailer['detector']}", | |
| }) | |
| image = add("FaceDetailer", { | |
| "image": [image, 0], | |
| "model": model, | |
| "clip": clip, | |
| "vae": vae, | |
| "guide_size": DETAILER_GUIDE_SIZE, | |
| "guide_size_for": True, | |
| "max_size": DETAILER_MAX_SIZE, | |
| "seed": seed, | |
| "steps": detailer["steps"], | |
| "cfg": detailer["cfg"], | |
| "sampler_name": detailer["sampler"], | |
| "scheduler": detailer["scheduler"], | |
| "positive": positive, | |
| "negative": negative, | |
| "denoise": detailer["denoise"], | |
| "feather": DETAILER_FEATHER, | |
| "noise_mask": True, | |
| "force_inpaint": True, | |
| "bbox_threshold": DETAILER_THRESHOLD, | |
| "bbox_dilation": DETAILER_DILATION, | |
| "bbox_crop_factor": DETAILER_CROP, | |
| "sam_detection_hint": "none", | |
| "sam_dilation": 0, | |
| "sam_threshold": .93, | |
| "sam_bbox_expansion": 0, | |
| "sam_mask_hint_threshold": .7, | |
| "sam_mask_hint_use_negative": "False", | |
| "drop_size": DETAILER_DROP_SIZE, | |
| "bbox_detector": [detector, 0], | |
| "wildcard": "", | |
| "cycle": 1, | |
| }) | |
| if config["upscale"] and config["upscale_model"]: | |
| upscale_model = [add("UpscaleModelLoader", { | |
| "model_name": config["upscale_model"], | |
| }), 0] | |
| image = add("ImageUpscaleWithModel", { | |
| "upscale_model": upscale_model, | |
| "image": [image, 0], | |
| }) | |
| add("PreviewImage", {"images": [image, 0]}) | |
| return { | |
| "prompt": json.dumps(api, separators=(",", ":")), | |
| "parameters": json.dumps(config, separators=(",", ":")), | |
| } | |
| workflow = build_workflow() | |
| prompt = json.loads(json.dumps(workflow)) | |
| extra_pnginfo = build_extra_pnginfo() | |
| # Workflow execution | |
| def main(unload_models: bool | None = None): | |
| bootstrap_comfyui_runtime() | |
| add_extra_model_paths() | |
| import_custom_nodes() | |
| # Node imports | |
| from nodes import ( | |
| CLIPTextEncode, | |
| CheckpointLoaderSimple, | |
| EmptyLatentImage, | |
| KSampler, | |
| LoraLoader, | |
| NODE_CLASS_MAPPINGS, | |
| VAEDecode, | |
| VAELoader, | |
| ) | |
| import torch | |
| try: | |
| with torch.inference_mode(): | |
| checkpointloadersimple = CheckpointLoaderSimple() | |
| checkpointloadersimple_1 = checkpointloadersimple.load_checkpoint( | |
| ckpt_name="52_novaAnimeXL_ilV190.safetensors" | |
| ) | |
| stringconcatenate = NODE_CLASS_MAPPINGS["StringConcatenate"]() | |
| stringconcatenate_118 = stringconcatenate.EXECUTE_NORMALIZED( | |
| string_a="%prompt%", | |
| string_b="", | |
| delimiter="", | |
| ) | |
| loraloader = LoraLoader() | |
| loraloader_10 = loraloader.load_lora( | |
| lora_name="8_bikabaka.safetensors", | |
| strength_model=0.3, | |
| strength_clip=0, | |
| model=get_value_at_index(checkpointloadersimple_1, 0), | |
| clip=get_value_at_index(checkpointloadersimple_1, 1), | |
| ) | |
| loraloader_38 = loraloader.load_lora( | |
| lora_name="42_\u30a2\u30c3\u30d7\u30b9\u30b1\u30fc\u30eb_remacri_original.pt", | |
| strength_model=0.4, | |
| strength_clip=0, | |
| model=get_value_at_index(loraloader_10, 0), | |
| clip=get_value_at_index(loraloader_10, 1), | |
| ) | |
| loraloader_28 = loraloader.load_lora( | |
| lora_name="43_5cm-illustriousXL_v01_V1-CAME-000035.safetensors", | |
| strength_model=0.4, | |
| strength_clip=0, | |
| model=get_value_at_index(loraloader_38, 0), | |
| clip=get_value_at_index(loraloader_38, 1), | |
| ) | |
| loraloader_117 = loraloader.load_lora( | |
| lora_name="5_add_saturation_XL.safetensors", | |
| strength_model=-1.4, | |
| strength_clip=0, | |
| model=get_value_at_index(loraloader_28, 0), | |
| clip=get_value_at_index(loraloader_28, 1), | |
| ) | |
| cliptextencode = CLIPTextEncode() | |
| cliptextencode_2 = cliptextencode.encode( | |
| text=get_value_at_index(stringconcatenate_118, 0), | |
| clip=get_value_at_index(loraloader_117, 1), | |
| ) | |
| cliptextencode_3 = cliptextencode.encode( | |
| text="(censored, mosaic censoring, bar censor:1.1), bad quality, worst quality, worst detail, bad anatomy, extra fingers, extra toes, extra legs, 4 toes, 6 toes, 4 fingers, 6 fingers, malformed fingers, extra limbs, missing fingers, extra arms, censored, deformed, disfigured, text, (multiple views:1.1)", | |
| clip=get_value_at_index(loraloader_28, 1), | |
| ) | |
| emptylatentimage = EmptyLatentImage() | |
| emptylatentimage_27 = emptylatentimage.generate( | |
| width=1152, height=896, batch_size=1 | |
| ) | |
| vaeloader = VAELoader() | |
| vaeloader_45 = vaeloader.load_vae(vae_name="3_sdxlVAE_sdxlVAE.safetensors") | |
| ksampler = KSampler() | |
| vaedecode = VAEDecode() | |
| for q in range(1): | |
| node_5_seed = prompt["5"]["inputs"]["seed"] = GENERATION | |
| ksampler_5 = ksampler.sample( | |
| seed=node_5_seed, | |
| steps=16, | |
| cfg=4, | |
| sampler_name="euler_ancestral", | |
| scheduler="karras", | |
| denoise=1, | |
| model=get_value_at_index(loraloader_117, 0), | |
| positive=get_value_at_index(cliptextencode_2, 0), | |
| negative=get_value_at_index(cliptextencode_3, 0), | |
| latent_image=get_value_at_index(emptylatentimage_27, 0), | |
| ) | |
| vaedecode_56 = vaedecode.decode( | |
| samples=get_value_at_index(ksampler_5, 0), | |
| vae=get_value_at_index(vaeloader_45, 0), | |
| ) | |
| finally: | |
| cleanup_comfyui_runtime(unload_models=unload_models) | |
| # Entrypoint | |
| if __name__ == "__main__": | |
| main() | |