|
|
import gradio as gr |
|
|
import numpy as np |
|
|
from PIL import Image |
|
|
import torch |
|
|
import gc |
|
|
import os |
|
|
import warnings |
|
|
|
|
|
|
|
|
warnings.filterwarnings('ignore', category=FutureWarning) |
|
|
warnings.filterwarnings('ignore', category=UserWarning) |
|
|
warnings.filterwarnings('ignore', message='.*torch_dtype.*deprecated.*') |
|
|
warnings.filterwarnings('ignore', message='.*CLIPFeatureExtractor.*deprecated.*') |
|
|
|
|
|
|
|
|
if torch.cuda.is_available(): |
|
|
torch.backends.cudnn.benchmark = True |
|
|
torch.backends.cuda.matmul.allow_tf32 = True |
|
|
torch.backends.cudnn.allow_tf32 = True |
|
|
|
|
|
|
|
|
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") |
|
|
dtype = torch.float16 if torch.cuda.is_available() else torch.float32 |
|
|
|
|
|
print(f"🖥️ Device: {device} | dtype: {dtype}") |
|
|
|
|
|
|
|
|
from diffusers import ( |
|
|
StableDiffusionControlNetPipeline, |
|
|
ControlNetModel, |
|
|
StableDiffusionPipeline, |
|
|
StableDiffusionXLPipeline, |
|
|
StableDiffusionXLControlNetPipeline, |
|
|
AutoPipelineForText2Image |
|
|
) |
|
|
from diffusers import UniPCMultistepScheduler, DPMSolverMultistepScheduler, EulerAncestralDiscreteScheduler |
|
|
from controlnet_aux import ( |
|
|
LineartDetector, |
|
|
LineartAnimeDetector, |
|
|
OpenposeDetector, |
|
|
MidasDetector, |
|
|
CannyDetector, |
|
|
MLSDdetector, |
|
|
HEDdetector, |
|
|
PidiNetDetector, |
|
|
NormalBaeDetector, |
|
|
ZoeDetector, |
|
|
MediapipeFaceDetector |
|
|
) |
|
|
|
|
|
|
|
|
if torch.cuda.is_available(): |
|
|
torch.cuda.empty_cache() |
|
|
torch.cuda.set_per_process_memory_fraction(0.95) |
|
|
print(f"🔥 GPU Memory: {torch.cuda.get_device_properties(0).total_memory / 1024**3:.2f} GB") |
|
|
else: |
|
|
print("⚠️ Running on CPU - Image generation will be significantly slower") |
|
|
|
|
|
|
|
|
CURRENT_CONTROLNET_PIPE = None |
|
|
CURRENT_CONTROLNET_KEY = None |
|
|
CURRENT_T2I_PIPE = None |
|
|
CURRENT_T2I_MODEL = None |
|
|
CURRENT_SDXL_REFINER = None |
|
|
CURRENT_TURBO_PIPE = None |
|
|
CURRENT_TURBO_MODEL = None |
|
|
|
|
|
|
|
|
SDXL_MODELS = [ |
|
|
"stabilityai/stable-diffusion-xl-base-1.0", |
|
|
"stabilityai/stable-diffusion-xl-refiner-1.0", |
|
|
"stabilityai/sdxl-turbo", |
|
|
"Laxhar/noobai-XL-1.1", |
|
|
"RunDiffusion/Juggernaut-XL-v9", |
|
|
"dataautogpt3/ProteusV0.4", |
|
|
"playgroundai/playground-v2.5-1024px-aesthetic", |
|
|
"misri/epicrealismXL_v10", |
|
|
"SG161222/RealVisXL_V4.0", |
|
|
"stablediffusionapi/juggernaut-xl-v8", |
|
|
"Lykon/dreamshaper-xl-1-0", |
|
|
"digiplay/Pony_Diffusion_V6_XL" |
|
|
] |
|
|
|
|
|
|
|
|
TURBO_MODELS = [ |
|
|
"stabilityai/sdxl-turbo", |
|
|
"stabilityai/sd-turbo" |
|
|
] |
|
|
|
|
|
|
|
|
SD15_MODELS = [ |
|
|
|
|
|
"digiplay/ChikMix_V3", |
|
|
"digiplay/chilloutmix_NiPrunedFp16Fix", |
|
|
"gsdf/Counterfeit-V2.5", |
|
|
"stablediffusionapi/anything-v5", |
|
|
"runwayml/stable-diffusion-v1-5", |
|
|
"stablediffusionapi/realistic-vision-v51", |
|
|
"stablediffusionapi/dreamshaper-v8", |
|
|
"stablediffusionapi/henmix-real-v11", |
|
|
"stablediffusionapi/rev-animated-v122", |
|
|
"stablediffusionapi/cyberrealistic-v33", |
|
|
"stablediffusionapi/meinamix-meina-v11", |
|
|
"prompthero/openjourney-v4", |
|
|
"wavymulder/Analog-Diffusion", |
|
|
"dreamlike-art/dreamlike-photoreal-2.0", |
|
|
"segmind/SSD-1B", |
|
|
"SG161222/Realistic_Vision_V5.1_noVAE", |
|
|
"Lykon/dreamshaper-8", |
|
|
"hakurei/waifu-diffusion", |
|
|
"andite/anything-v4.0", |
|
|
"Linaqruf/animagine-xl", |
|
|
|
|
|
"emilianJR/epiCRealism", |
|
|
"stablediffusionapi/deliberate-v2", |
|
|
"stablediffusionapi/edge-of-realism", |
|
|
"Yntec/epiCPhotoGasm", |
|
|
"digiplay/majicMIX_realistic_v7", |
|
|
"stablediffusionapi/perfect-world-v6", |
|
|
"stablediffusionapi/uber-realistic-merge", |
|
|
"XpucT/Deliberate", |
|
|
"prompthero/openjourney", |
|
|
"Lykon/absolute-reality-1.81", |
|
|
"digiplay/BeautyProMix_v2", |
|
|
"stablediffusionapi/3d-animation-diffusion", |
|
|
"nitrosocke/Ghibli-Diffusion", |
|
|
"nitrosocke/mo-di-diffusion", |
|
|
"Fictiverse/Stable_Diffusion_VoxelArt_Model" |
|
|
] |
|
|
|
|
|
|
|
|
SPECIAL_MODELS = { |
|
|
"waifu_colorize": "ShinoharaHare/Waifu-Colorize-XL" |
|
|
} |
|
|
|
|
|
|
|
|
CHINESE_MODELS = [ |
|
|
"AI-Chen/Chinese-Stable-Diffusion", |
|
|
"IDEA-CCNL/Taiyi-Stable-Diffusion-1B-Chinese-v0.1", |
|
|
"AI-ModelScope/stable-diffusion-v1-5-chinese" |
|
|
] |
|
|
|
|
|
|
|
|
CONTROLNET_MODELS_SD15 = { |
|
|
"lineart": "lllyasviel/control_v11p_sd15_lineart", |
|
|
"lineart_anime": "lllyasviel/control_v11p_sd15s2_lineart_anime", |
|
|
"canny": "lllyasviel/control_v11p_sd15_canny", |
|
|
"depth": "lllyasviel/control_v11p_sd15_depth", |
|
|
"normal": "lllyasviel/control_v11p_sd15_normalbae", |
|
|
"openpose": "lllyasviel/control_v11p_sd15_openpose", |
|
|
"softedge": "lllyasviel/control_v11p_sd15_softedge", |
|
|
"segmentation": "lllyasviel/control_v11p_sd15_seg", |
|
|
"mlsd": "lllyasviel/control_v11p_sd15_mlsd", |
|
|
"shuffle": "lllyasviel/control_v11p_sd15_shuffle", |
|
|
"scribble": "lllyasviel/control_v11p_sd15_scribble", |
|
|
"tile": "lllyasviel/control_v11f1e_sd15_tile" |
|
|
} |
|
|
|
|
|
|
|
|
CONTROLNET_MODELS_SDXL = { |
|
|
"canny_sdxl": "diffusers/controlnet-canny-sdxl-1.0", |
|
|
"depth_sdxl": "diffusers/controlnet-depth-sdxl-1.0", |
|
|
"openpose_sdxl": "thibaud/controlnet-openpose-sdxl-1.0", |
|
|
"lineart_sdxl": "ShermanG/ControlNet-Standard-Lineart-for-SDXL" |
|
|
} |
|
|
|
|
|
|
|
|
LORA_MODELS = { |
|
|
"None": None, |
|
|
|
|
|
"lowpoly-game-character": "nerijs/lowpoly-game-character-lora", |
|
|
"pixel-art": "nerijs/pixel-art-xl", |
|
|
"watercolor-style": "OedoSoldier/watercolor-style-lora", |
|
|
"manga-style": "raemikk/Animerge_V3.0_LoRA", |
|
|
"cyberpunk": "artificialguybr/cyberpunk-anime-diffusion", |
|
|
"fantasy-art": "artificialguybr/fantasy-art-lora", |
|
|
"chinese-style": "yfszzx/Chinese_style_xl_LoRA", |
|
|
"traditional-painting": "artificialguybr/Traditional-Painting-Style-LoRA", |
|
|
"anime-art": "Linaqruf/anime-detailer-xl-lora", |
|
|
"cinematic": "artificialguybr/cinematic-diffusion", |
|
|
"oil-painting": "artificialguybr/oil-painting-style", |
|
|
|
|
|
"japanese-doll": "Norod78/sd15-JapaneseDollLikeness_lora", |
|
|
"korean-doll": "Norod78/sd15-KoreanDollLikeness_lora", |
|
|
"detail-tweaker": "nitrosocke/detail-tweaker-lora", |
|
|
"beautiful-realistic-asians": "etok/Beautiful_Realistic_Asians", |
|
|
"asian-beauty": "digiplay/AsianBeauty_V1", |
|
|
"perfect-hands": "Sanster/perfect-hands", |
|
|
"face-detail": "ostris/face-detail-lora", |
|
|
|
|
|
"body-pose-control": "alvdansen/lora-body-pose", |
|
|
"dynamic-poses": "alvdansen/dynamic-poses-lora", |
|
|
"full-body": "artificialguybr/full-body-lora", |
|
|
|
|
|
"photorealistic": "microsoft/lora-photorealistic", |
|
|
"hyper-realistic": "dallinmackay/hyper-realistic-lora", |
|
|
"ultra-realistic": "artificialguybr/ultra-realistic-lora", |
|
|
"realistic-vision": "SG161222/Realistic_Vision_V5.1_noVAE", |
|
|
|
|
|
"add-detail": "ostris/add-detail-lora", |
|
|
"sharp-details": "ostris/sharp-details-lora", |
|
|
"better-lighting": "artificialguybr/better-lighting-lora", |
|
|
"studio-lighting": "artificialguybr/studio-lighting", |
|
|
|
|
|
"nsfw-master": "hearmeneigh/nsfw-master-lora", |
|
|
"realistic-nsfw": "digiplay/RealisticNSFW_v1", |
|
|
"anime-nsfw": "Linaqruf/anime-nsfw-lora", |
|
|
"hentai-diffusion": "Deltaadams/Hentai-Diffusion", |
|
|
"sexy-pose": "alvdansen/sexy-pose-lora", |
|
|
|
|
|
"colorize-xl": "ShinoharaHare/Waifu-Colorize-XL" |
|
|
} |
|
|
|
|
|
|
|
|
VAE_MODELS = { |
|
|
"None": None, |
|
|
"SD1.5 VAE": "stabilityai/sd-vae-ft-mse", |
|
|
"Anime VAE": "hakurei/waifu-diffusion-v1-4", |
|
|
"SDXL VAE": "madebyollin/sdxl-vae-fp16-fix", |
|
|
"Turbo VAE": "madebyollin/sdxl-vae-fp16-fix" |
|
|
} |
|
|
|
|
|
|
|
|
DETECTORS = {} |
|
|
|
|
|
def is_sdxl_model(model_name: str) -> bool: |
|
|
"""Check if model is SDXL""" |
|
|
return model_name in SDXL_MODELS or "xl" in model_name.lower() or "XL" in model_name |
|
|
|
|
|
def is_turbo_model(model_name: str) -> bool: |
|
|
"""Check if model is Turbo""" |
|
|
return model_name in TURBO_MODELS or "turbo" in model_name.lower() |
|
|
|
|
|
def load_detector(detector_type: str): |
|
|
"""Lazy load detector""" |
|
|
global DETECTORS |
|
|
|
|
|
if detector_type in DETECTORS: |
|
|
return DETECTORS[detector_type] |
|
|
|
|
|
print(f"📥 Loading {detector_type} detector...") |
|
|
|
|
|
try: |
|
|
if detector_type == "lineart": |
|
|
DETECTORS[detector_type] = LineartDetector.from_pretrained("lllyasviel/Annotators") |
|
|
elif detector_type == "lineart_anime": |
|
|
DETECTORS[detector_type] = LineartAnimeDetector.from_pretrained("lllyasviel/Annotators") |
|
|
elif detector_type == "openpose": |
|
|
DETECTORS[detector_type] = OpenposeDetector.from_pretrained("lllyasviel/Annotators") |
|
|
elif detector_type == "depth": |
|
|
DETECTORS[detector_type] = MidasDetector.from_pretrained("lllyasviel/Annotators") |
|
|
elif detector_type == "canny": |
|
|
DETECTORS[detector_type] = CannyDetector() |
|
|
elif detector_type == "normal": |
|
|
DETECTORS[detector_type] = NormalBaeDetector.from_pretrained("lllyasviel/Annotators") |
|
|
elif detector_type == "hed": |
|
|
DETECTORS[detector_type] = HEDdetector.from_pretrained("lllyasviel/Annotators") |
|
|
elif detector_type == "pidi": |
|
|
DETECTORS[detector_type] = PidiNetDetector.from_pretrained("lllyasviel/Annotators") |
|
|
elif detector_type == "mlsd": |
|
|
DETECTORS[detector_type] = MLSDdetector.from_pretrained("lllyasviel/Annotators") |
|
|
elif detector_type == "zoe": |
|
|
DETECTORS[detector_type] = ZoeDetector.from_pretrained("lllyasviel/Annotators") |
|
|
elif detector_type == "face": |
|
|
DETECTORS[detector_type] = MediapipeFaceDetector() |
|
|
else: |
|
|
raise ValueError(f"Unknown detector type: {detector_type}") |
|
|
|
|
|
return DETECTORS[detector_type] |
|
|
except Exception as e: |
|
|
print(f"❌ Error loading {detector_type} detector: {e}") |
|
|
return None |
|
|
|
|
|
def get_controlnet_model(controlnet_type: str, is_sdxl: bool = False): |
|
|
"""Get ControlNet model based on type""" |
|
|
if is_sdxl: |
|
|
if controlnet_type not in CONTROLNET_MODELS_SDXL: |
|
|
raise ValueError(f"SDXL ControlNet type must be one of: {list(CONTROLNET_MODELS_SDXL.keys())}") |
|
|
return CONTROLNET_MODELS_SDXL[controlnet_type] |
|
|
else: |
|
|
if controlnet_type not in CONTROLNET_MODELS_SD15: |
|
|
raise ValueError(f"SD1.5 ControlNet type must be one of: {list(CONTROLNET_MODELS_SD15.keys())}") |
|
|
return CONTROLNET_MODELS_SD15[controlnet_type] |
|
|
|
|
|
def prepare_condition_image(image, controlnet_type, is_sdxl=False): |
|
|
"""Prepare condition image for ControlNet""" |
|
|
if "lineart" in controlnet_type: |
|
|
detector_type = "lineart_anime" if "anime" in controlnet_type else "lineart" |
|
|
detector = load_detector(detector_type) |
|
|
if detector: |
|
|
result = detector(image, detect_resolution=512 if not is_sdxl else 1024, image_resolution=512 if not is_sdxl else 1024) |
|
|
return Image.fromarray(result) if isinstance(result, np.ndarray) else result |
|
|
|
|
|
elif "canny" in controlnet_type: |
|
|
detector = load_detector("canny") |
|
|
if detector: |
|
|
result = detector(image, detect_resolution=512 if not is_sdxl else 1024, image_resolution=512 if not is_sdxl else 1024) |
|
|
return Image.fromarray(result) if isinstance(result, np.ndarray) else result |
|
|
|
|
|
elif "depth" in controlnet_type: |
|
|
detector = load_detector("depth") |
|
|
if detector: |
|
|
result = detector(image, detect_resolution=512 if not is_sdxl else 1024, image_resolution=512 if not is_sdxl else 1024) |
|
|
return Image.fromarray(result) if isinstance(result, np.ndarray) else result |
|
|
|
|
|
elif controlnet_type == "normal": |
|
|
detector = load_detector("normal") |
|
|
if detector: |
|
|
result = detector(image, detect_resolution=512 if not is_sdxl else 1024, image_resolution=512 if not is_sdxl else 1024) |
|
|
return Image.fromarray(result) if isinstance(result, np.ndarray) else result |
|
|
|
|
|
elif "openpose" in controlnet_type: |
|
|
detector = load_detector("openpose") |
|
|
if detector: |
|
|
result = detector(image, detect_resolution=512 if not is_sdxl else 1024, image_resolution=512 if not is_sdxl else 1024) |
|
|
return Image.fromarray(result) if isinstance(result, np.ndarray) else result |
|
|
|
|
|
return image |
|
|
|
|
|
def get_pipeline(model_name: str, controlnet_type: str = "lineart", lora_model: str = None, |
|
|
lora_weight: float = 0.8, vae_model: str = None): |
|
|
"""Get or create a ControlNet pipeline with optional LoRA and VAE""" |
|
|
global CURRENT_CONTROLNET_PIPE, CURRENT_CONTROLNET_KEY |
|
|
|
|
|
key = (model_name, controlnet_type, lora_model, lora_weight, vae_model) |
|
|
|
|
|
if CURRENT_CONTROLNET_KEY == key and CURRENT_CONTROLNET_PIPE is not None: |
|
|
print(f"✅ Reusing existing ControlNet pipeline: {model_name}, type: {controlnet_type}") |
|
|
return CURRENT_CONTROLNET_PIPE |
|
|
|
|
|
if CURRENT_CONTROLNET_PIPE is not None: |
|
|
print(f"🗑️ Unloading old ControlNet pipeline: {CURRENT_CONTROLNET_KEY}") |
|
|
del CURRENT_CONTROLNET_PIPE |
|
|
CURRENT_CONTROLNET_PIPE = None |
|
|
CURRENT_CONTROLNET_KEY = None |
|
|
gc.collect() |
|
|
if torch.cuda.is_available(): |
|
|
torch.cuda.empty_cache() |
|
|
|
|
|
print(f"📥 Loading ControlNet pipeline for model: {model_name}, type: {controlnet_type}") |
|
|
|
|
|
try: |
|
|
is_sdxl = is_sdxl_model(model_name) |
|
|
is_turbo = is_turbo_model(model_name) |
|
|
|
|
|
controlnet_model_name = get_controlnet_model(controlnet_type, is_sdxl) |
|
|
controlnet = ControlNetModel.from_pretrained( |
|
|
controlnet_model_name, |
|
|
torch_dtype=dtype |
|
|
).to(device) |
|
|
|
|
|
if is_sdxl: |
|
|
if is_turbo: |
|
|
|
|
|
pipe = StableDiffusionXLControlNetPipeline.from_pretrained( |
|
|
model_name, |
|
|
controlnet=controlnet, |
|
|
torch_dtype=dtype, |
|
|
safety_checker=None, |
|
|
requires_safety_checker=False, |
|
|
use_safetensors=True, |
|
|
variant="fp16" if dtype == torch.float16 else None |
|
|
).to(device) |
|
|
else: |
|
|
pipe = StableDiffusionXLControlNetPipeline.from_pretrained( |
|
|
model_name, |
|
|
controlnet=controlnet, |
|
|
torch_dtype=dtype, |
|
|
safety_checker=None, |
|
|
requires_safety_checker=False, |
|
|
use_safetensors=True, |
|
|
variant="fp16" if dtype == torch.float16 else None |
|
|
).to(device) |
|
|
else: |
|
|
pipe = StableDiffusionControlNetPipeline.from_pretrained( |
|
|
model_name, |
|
|
controlnet=controlnet, |
|
|
torch_dtype=dtype, |
|
|
safety_checker=None, |
|
|
requires_safety_checker=False, |
|
|
use_safetensors=True, |
|
|
variant="fp16" if dtype == torch.float16 else None |
|
|
).to(device) |
|
|
|
|
|
|
|
|
if vae_model and vae_model != "None": |
|
|
try: |
|
|
from diffusers import AutoencoderKL |
|
|
print(f"🔄 Loading custom VAE: {vae_model}") |
|
|
vae = AutoencoderKL.from_pretrained(vae_model, torch_dtype=dtype).to(device) |
|
|
pipe.vae = vae |
|
|
except Exception as e: |
|
|
print(f"⚠️ Error loading VAE: {e}") |
|
|
|
|
|
|
|
|
if lora_model and lora_model != "None": |
|
|
print(f"🔄 Applying LoRA: {lora_model} with weight: {lora_weight}") |
|
|
try: |
|
|
if lora_model in LORA_MODELS: |
|
|
lora_path = LORA_MODELS[lora_model] |
|
|
pipe.load_lora_weights(lora_path) |
|
|
pipe.fuse_lora(lora_scale=lora_weight) |
|
|
else: |
|
|
pipe.load_lora_weights(lora_model) |
|
|
pipe.fuse_lora(lora_scale=lora_weight) |
|
|
except Exception as e: |
|
|
print(f"⚠️ Error loading LoRA: {e}") |
|
|
|
|
|
|
|
|
pipe.enable_attention_slicing(slice_size="max") |
|
|
|
|
|
if hasattr(pipe, 'vae') and hasattr(pipe.vae, 'enable_slicing'): |
|
|
pipe.vae.enable_slicing() |
|
|
else: |
|
|
try: |
|
|
pipe.enable_vae_slicing() |
|
|
except: |
|
|
pass |
|
|
|
|
|
if device.type == "cuda": |
|
|
try: |
|
|
pipe.enable_xformers_memory_efficient_attention() |
|
|
print("✅ xFormers enabled") |
|
|
except: |
|
|
pass |
|
|
pipe.enable_model_cpu_offload() |
|
|
|
|
|
|
|
|
if is_turbo: |
|
|
|
|
|
try: |
|
|
pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config) |
|
|
print("✅ Using UniPC scheduler for Turbo") |
|
|
except: |
|
|
pass |
|
|
else: |
|
|
try: |
|
|
pipe.scheduler = EulerAncestralDiscreteScheduler.from_config(pipe.scheduler.config) |
|
|
print("✅ Using Euler Ancestral scheduler") |
|
|
except: |
|
|
try: |
|
|
pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config) |
|
|
except: |
|
|
pass |
|
|
|
|
|
CURRENT_CONTROLNET_PIPE = pipe |
|
|
CURRENT_CONTROLNET_KEY = key |
|
|
return pipe |
|
|
|
|
|
except Exception as e: |
|
|
print(f"❌ Error loading ControlNet pipeline: {e}") |
|
|
CURRENT_CONTROLNET_PIPE = None |
|
|
CURRENT_CONTROLNET_KEY = None |
|
|
raise |
|
|
|
|
|
def load_t2i_model(model_name: str, lora_model: str = None, lora_weight: float = 0.8, |
|
|
vae_model: str = None): |
|
|
"""Load text-to-image model with optional LoRA and VAE""" |
|
|
global CURRENT_T2I_PIPE, CURRENT_T2I_MODEL, CURRENT_SDXL_REFINER, CURRENT_TURBO_PIPE, CURRENT_TURBO_MODEL |
|
|
|
|
|
is_turbo = is_turbo_model(model_name) |
|
|
use_refiner = "refiner" in model_name.lower() and not is_turbo |
|
|
|
|
|
key = (model_name, lora_model, lora_weight, vae_model, use_refiner, is_turbo) |
|
|
|
|
|
if is_turbo: |
|
|
if CURRENT_TURBO_MODEL == key and CURRENT_TURBO_PIPE is not None: |
|
|
return |
|
|
else: |
|
|
if CURRENT_T2I_MODEL == key and CURRENT_T2I_PIPE is not None: |
|
|
return |
|
|
|
|
|
if is_turbo: |
|
|
if CURRENT_TURBO_PIPE is not None: |
|
|
print(f"🗑️ Unloading old Turbo model: {CURRENT_TURBO_MODEL}") |
|
|
del CURRENT_TURBO_PIPE |
|
|
CURRENT_TURBO_PIPE = None |
|
|
else: |
|
|
if CURRENT_T2I_PIPE is not None: |
|
|
print(f"🗑️ Unloading old T2I model: {CURRENT_T2I_MODEL}") |
|
|
del CURRENT_T2I_PIPE |
|
|
CURRENT_T2I_PIPE = None |
|
|
if CURRENT_SDXL_REFINER is not None: |
|
|
del CURRENT_SDXL_REFINER |
|
|
CURRENT_SDXL_REFINER = None |
|
|
|
|
|
gc.collect() |
|
|
if torch.cuda.is_available(): |
|
|
torch.cuda.empty_cache() |
|
|
|
|
|
print(f"📥 Loading T2I model: {model_name}") |
|
|
|
|
|
try: |
|
|
if is_turbo: |
|
|
|
|
|
CURRENT_TURBO_PIPE = AutoPipelineForText2Image.from_pretrained( |
|
|
model_name, |
|
|
torch_dtype=dtype, |
|
|
safety_checker=None, |
|
|
requires_safety_checker=False, |
|
|
use_safetensors=True, |
|
|
variant="fp16" if dtype == torch.float16 else None |
|
|
).to(device) |
|
|
|
|
|
CURRENT_TURBO_MODEL = key |
|
|
pipe = CURRENT_TURBO_PIPE |
|
|
elif is_sdxl_model(model_name): |
|
|
if use_refiner: |
|
|
CURRENT_T2I_PIPE = StableDiffusionXLPipeline.from_pretrained( |
|
|
"stabilityai/stable-diffusion-xl-base-1.0", |
|
|
torch_dtype=dtype, |
|
|
safety_checker=None, |
|
|
requires_safety_checker=False, |
|
|
use_safetensors=True, |
|
|
variant="fp16" if dtype == torch.float16 else None |
|
|
).to(device) |
|
|
|
|
|
CURRENT_SDXL_REFINER = StableDiffusionXLPipeline.from_pretrained( |
|
|
model_name, |
|
|
torch_dtype=dtype, |
|
|
safety_checker=None, |
|
|
requires_safety_checker=False, |
|
|
use_safetensors=True, |
|
|
variant="fp16" if dtype == torch.float16 else None, |
|
|
text_encoder_2=CURRENT_T2I_PIPE.text_encoder_2, |
|
|
vae=CURRENT_T2I_PIPE.vae |
|
|
).to(device) |
|
|
else: |
|
|
CURRENT_T2I_PIPE = StableDiffusionXLPipeline.from_pretrained( |
|
|
model_name, |
|
|
torch_dtype=dtype, |
|
|
safety_checker=None, |
|
|
requires_safety_checker=False, |
|
|
use_safetensors=True, |
|
|
variant="fp16" if dtype == torch.float16 else None |
|
|
).to(device) |
|
|
|
|
|
CURRENT_T2I_MODEL = key |
|
|
pipe = CURRENT_T2I_PIPE |
|
|
else: |
|
|
CURRENT_T2I_PIPE = StableDiffusionPipeline.from_pretrained( |
|
|
model_name, |
|
|
torch_dtype=dtype, |
|
|
safety_checker=None, |
|
|
requires_safety_checker=False, |
|
|
use_safetensors=True, |
|
|
variant="fp16" if dtype == torch.float16 else None |
|
|
).to(device) |
|
|
|
|
|
CURRENT_T2I_MODEL = key |
|
|
pipe = CURRENT_T2I_PIPE |
|
|
|
|
|
|
|
|
if vae_model and vae_model != "None": |
|
|
try: |
|
|
from diffusers import AutoencoderKL |
|
|
print(f"🔄 Loading custom VAE: {vae_model}") |
|
|
vae = AutoencoderKL.from_pretrained(vae_model, torch_dtype=dtype).to(device) |
|
|
pipe.vae = vae |
|
|
except Exception as e: |
|
|
print(f"⚠️ Error loading VAE: {e}") |
|
|
|
|
|
|
|
|
if lora_model and lora_model != "None": |
|
|
print(f"🔄 Applying LoRA: {lora_model} with weight: {lora_weight}") |
|
|
try: |
|
|
if lora_model in LORA_MODELS: |
|
|
lora_path = LORA_MODELS[lora_model] |
|
|
pipe.load_lora_weights(lora_path) |
|
|
pipe.fuse_lora(lora_scale=lora_weight) |
|
|
else: |
|
|
pipe.load_lora_weights(lora_model) |
|
|
pipe.fuse_lora(lora_scale=lora_weight) |
|
|
except Exception as e: |
|
|
print(f"⚠️ Error loading LoRA: {e}") |
|
|
|
|
|
|
|
|
pipe.enable_attention_slicing(slice_size="max") |
|
|
|
|
|
if hasattr(pipe, 'vae') and hasattr(pipe.vae, 'enable_slicing'): |
|
|
pipe.vae.enable_slicing() |
|
|
else: |
|
|
try: |
|
|
pipe.enable_vae_slicing() |
|
|
except: |
|
|
pass |
|
|
|
|
|
if device.type == "cuda": |
|
|
try: |
|
|
pipe.enable_xformers_memory_efficient_attention() |
|
|
except: |
|
|
pass |
|
|
pipe.enable_model_cpu_offload() |
|
|
|
|
|
|
|
|
if is_turbo: |
|
|
try: |
|
|
pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config) |
|
|
print("✅ Using UniPC scheduler for Turbo") |
|
|
except: |
|
|
pass |
|
|
else: |
|
|
try: |
|
|
pipe.scheduler = EulerAncestralDiscreteScheduler.from_config(pipe.scheduler.config) |
|
|
except: |
|
|
pass |
|
|
|
|
|
except Exception as e: |
|
|
print(f"❌ Error loading T2I model: {e}") |
|
|
if is_turbo: |
|
|
CURRENT_TURBO_PIPE = None |
|
|
CURRENT_TURBO_MODEL = None |
|
|
else: |
|
|
CURRENT_T2I_PIPE = None |
|
|
CURRENT_T2I_MODEL = None |
|
|
raise |
|
|
|
|
|
def colorize_sd15(sketch, base_model, controlnet_type, lora_model, lora_weight, vae_model, |
|
|
prompt, negative_prompt, seed, steps, scale, cn_weight): |
|
|
"""Colorize function for SD1.5 models""" |
|
|
try: |
|
|
if base_model not in SD15_MODELS: |
|
|
error_img = Image.new('RGB', (512, 512), color='red') |
|
|
return error_img, Image.new('RGB', (512, 512), color='gray') |
|
|
|
|
|
if controlnet_type not in CONTROLNET_MODELS_SD15: |
|
|
error_img = Image.new('RGB', (512, 512), color='red') |
|
|
return error_img, Image.new('RGB', (512, 512), color='gray') |
|
|
|
|
|
pipe = get_pipeline(base_model, controlnet_type, lora_model, lora_weight, vae_model) |
|
|
|
|
|
status_msg = f"🎨 Using: {base_model} + {controlnet_type}" |
|
|
if lora_model and lora_model != "None": |
|
|
status_msg += f" + {lora_model}" |
|
|
print(status_msg) |
|
|
|
|
|
condition_img = prepare_condition_image(sketch, controlnet_type, is_sdxl=False) |
|
|
|
|
|
gen = torch.Generator(device=device).manual_seed(int(seed)) |
|
|
|
|
|
with torch.inference_mode(): |
|
|
out = pipe( |
|
|
prompt, |
|
|
negative_prompt=negative_prompt, |
|
|
image=condition_img, |
|
|
num_inference_steps=int(steps), |
|
|
guidance_scale=float(scale), |
|
|
controlnet_conditioning_scale=float(cn_weight), |
|
|
generator=gen, |
|
|
height=512, |
|
|
width=512 |
|
|
).images[0] |
|
|
|
|
|
if device.type == "cuda": |
|
|
torch.cuda.empty_cache() |
|
|
|
|
|
return out, condition_img |
|
|
except Exception as e: |
|
|
print(f"❌ Error in colorize_sd15: {e}") |
|
|
error_img = Image.new('RGB', (512, 512), color='red') |
|
|
return error_img, Image.new('RGB', (512, 512), color='gray') |
|
|
|
|
|
def colorize_sdxl(sketch, base_model, controlnet_type, lora_model, lora_weight, vae_model, |
|
|
prompt, negative_prompt, seed, steps, scale, cn_weight): |
|
|
"""Colorize function for SDXL models""" |
|
|
try: |
|
|
if base_model not in SDXL_MODELS: |
|
|
error_img = Image.new('RGB', (1024, 1024), color='red') |
|
|
return error_img, Image.new('RGB', (1024, 1024), color='gray') |
|
|
|
|
|
if controlnet_type not in CONTROLNET_MODELS_SDXL: |
|
|
error_img = Image.new('RGB', (1024, 1024), color='red') |
|
|
return error_img, Image.new('RGB', (1024, 1024), color='gray') |
|
|
|
|
|
pipe = get_pipeline(base_model, controlnet_type, lora_model, lora_weight, vae_model) |
|
|
|
|
|
status_msg = f"🎨 Using: {base_model} + {controlnet_type}" |
|
|
if lora_model and lora_model != "None": |
|
|
status_msg += f" + {lora_model}" |
|
|
print(status_msg) |
|
|
|
|
|
condition_img = prepare_condition_image(sketch, controlnet_type, is_sdxl=True) |
|
|
|
|
|
gen = torch.Generator(device=device).manual_seed(int(seed)) |
|
|
|
|
|
with torch.inference_mode(): |
|
|
out = pipe( |
|
|
prompt, |
|
|
negative_prompt=negative_prompt, |
|
|
image=condition_img, |
|
|
num_inference_steps=int(steps), |
|
|
guidance_scale=float(scale), |
|
|
controlnet_conditioning_scale=float(cn_weight), |
|
|
generator=gen, |
|
|
height=1024, |
|
|
width=1024 |
|
|
).images[0] |
|
|
|
|
|
if device.type == "cuda": |
|
|
torch.cuda.empty_cache() |
|
|
|
|
|
return out, condition_img |
|
|
except Exception as e: |
|
|
print(f"❌ Error in colorize_sdxl: {e}") |
|
|
error_img = Image.new('RGB', (1024, 1024), color='red') |
|
|
return error_img, Image.new('RGB', (1024, 1024), color='gray') |
|
|
|
|
|
def colorize_waifu_xl(sketch, lora_weight, vae_model, prompt, negative_prompt, seed, steps, scale, cn_weight): |
|
|
"""Colorize function specifically for Waifu-Colorize-XL model""" |
|
|
try: |
|
|
model_name = "stabilityai/stable-diffusion-xl-base-1.0" |
|
|
controlnet_type = "lineart_sdxl" |
|
|
lora_model = "colorize-xl" |
|
|
|
|
|
pipe = get_pipeline(model_name, controlnet_type, lora_model, lora_weight, vae_model) |
|
|
|
|
|
status_msg = f"🎨 Using: Waifu-Colorize-XL (Lineart ControlNet)" |
|
|
print(status_msg) |
|
|
|
|
|
condition_img = prepare_condition_image(sketch, controlnet_type, is_sdxl=True) |
|
|
|
|
|
gen = torch.Generator(device=device).manual_seed(int(seed)) |
|
|
|
|
|
|
|
|
enhanced_prompt = f"colorized, vibrant colors, anime style, {prompt}" if prompt else "colorized, vibrant colors, anime style, masterpiece" |
|
|
|
|
|
with torch.inference_mode(): |
|
|
out = pipe( |
|
|
enhanced_prompt, |
|
|
negative_prompt=negative_prompt, |
|
|
image=condition_img, |
|
|
num_inference_steps=int(steps), |
|
|
guidance_scale=float(scale), |
|
|
controlnet_conditioning_scale=float(cn_weight), |
|
|
generator=gen, |
|
|
height=1024, |
|
|
width=1024 |
|
|
).images[0] |
|
|
|
|
|
if device.type == "cuda": |
|
|
torch.cuda.empty_cache() |
|
|
|
|
|
return out, condition_img |
|
|
except Exception as e: |
|
|
print(f"❌ Error in colorize_waifu_xl: {e}") |
|
|
error_img = Image.new('RGB', (1024, 1024), color='red') |
|
|
return error_img, Image.new('RGB', (1024, 1024), color='gray') |
|
|
|
|
|
def t2i_sd15(prompt, negative_prompt, model, lora_model, lora_weight, vae_model, |
|
|
seed, steps, scale, w, h): |
|
|
"""Text-to-image for SD1.5 models""" |
|
|
try: |
|
|
if model not in SD15_MODELS: |
|
|
error_img = Image.new('RGB', (int(w), int(h)), color='red') |
|
|
return error_img |
|
|
|
|
|
load_t2i_model(model, lora_model, lora_weight, vae_model) |
|
|
|
|
|
print(f"🖼️ Using SD1.5 model: {model}") |
|
|
if lora_model and lora_model != "None": |
|
|
print(f" with LoRA: {lora_model} (weight: {lora_weight})") |
|
|
|
|
|
gen = torch.Generator(device=device).manual_seed(int(seed)) |
|
|
|
|
|
with torch.inference_mode(): |
|
|
result = CURRENT_T2I_PIPE( |
|
|
prompt, |
|
|
negative_prompt=negative_prompt, |
|
|
width=int(w), |
|
|
height=int(h), |
|
|
num_inference_steps=int(steps), |
|
|
guidance_scale=float(scale), |
|
|
generator=gen |
|
|
).images[0] |
|
|
|
|
|
if device.type == "cuda": |
|
|
torch.cuda.empty_cache() |
|
|
|
|
|
return result |
|
|
except Exception as e: |
|
|
print(f"❌ Error in t2i_sd15: {e}") |
|
|
error_img = Image.new('RGB', (int(w), int(h)), color='red') |
|
|
from PIL import ImageDraw, ImageFont |
|
|
draw = ImageDraw.Draw(error_img) |
|
|
try: |
|
|
font = ImageFont.truetype("arial.ttf", 20) |
|
|
except: |
|
|
font = ImageFont.load_default() |
|
|
draw.text((50, 50), f"Error: {str(e)[:50]}...", fill="white", font=font) |
|
|
return error_img |
|
|
|
|
|
def t2i_sdxl(prompt, negative_prompt, model, lora_model, lora_weight, vae_model, |
|
|
seed, steps, scale, w, h, use_refiner=False): |
|
|
"""Text-to-image for SDXL models""" |
|
|
try: |
|
|
if model not in SDXL_MODELS: |
|
|
error_img = Image.new('RGB', (int(w), int(h)), color='red') |
|
|
return error_img |
|
|
|
|
|
model_to_load = model |
|
|
if use_refiner and "refiner" not in model.lower() and not is_turbo_model(model): |
|
|
model_to_load = "stabilityai/stable-diffusion-xl-refiner-1.0" |
|
|
|
|
|
load_t2i_model(model_to_load, lora_model, lora_weight, vae_model) |
|
|
|
|
|
print(f"🖼️ Using SDXL model: {model}") |
|
|
if lora_model and lora_model != "None": |
|
|
print(f" with LoRA: {lora_model} (weight: {lora_weight})") |
|
|
if use_refiner: |
|
|
print(f" with refiner") |
|
|
|
|
|
gen = torch.Generator(device=device).manual_seed(int(seed)) |
|
|
|
|
|
with torch.inference_mode(): |
|
|
if use_refiner and CURRENT_SDXL_REFINER is not None and not is_turbo_model(model): |
|
|
image = CURRENT_T2I_PIPE( |
|
|
prompt=prompt, |
|
|
negative_prompt=negative_prompt, |
|
|
width=int(w), |
|
|
height=int(h), |
|
|
num_inference_steps=int(steps//2), |
|
|
guidance_scale=float(scale), |
|
|
generator=gen, |
|
|
output_type="latent" |
|
|
).images |
|
|
|
|
|
result = CURRENT_SDXL_REFINER( |
|
|
prompt=prompt, |
|
|
negative_prompt=negative_prompt, |
|
|
image=image, |
|
|
num_inference_steps=int(steps//2), |
|
|
guidance_scale=float(scale), |
|
|
generator=gen |
|
|
).images[0] |
|
|
else: |
|
|
if is_turbo_model(model): |
|
|
|
|
|
turbo_steps = max(1, min(10, int(steps))) |
|
|
result = CURRENT_TURBO_PIPE( |
|
|
prompt, |
|
|
negative_prompt=negative_prompt, |
|
|
width=int(w), |
|
|
height=int(h), |
|
|
num_inference_steps=turbo_steps, |
|
|
guidance_scale=float(scale), |
|
|
generator=gen |
|
|
).images[0] |
|
|
else: |
|
|
result = CURRENT_T2I_PIPE( |
|
|
prompt, |
|
|
negative_prompt=negative_prompt, |
|
|
width=int(w), |
|
|
height=int(h), |
|
|
num_inference_steps=int(steps), |
|
|
guidance_scale=float(scale), |
|
|
generator=gen |
|
|
).images[0] |
|
|
|
|
|
if device.type == "cuda": |
|
|
torch.cuda.empty_cache() |
|
|
|
|
|
return result |
|
|
except Exception as e: |
|
|
print(f"❌ Error in t2i_sdxl: {e}") |
|
|
error_img = Image.new('RGB', (int(w), int(h)), color='red') |
|
|
from PIL import ImageDraw, ImageFont |
|
|
draw = ImageDraw.Draw(error_img) |
|
|
try: |
|
|
font = ImageFont.truetype("arial.ttf", 20) |
|
|
except: |
|
|
font = ImageFont.load_default() |
|
|
draw.text((50, 50), f"Error: {str(e)[:50]}...", fill="white", font=font) |
|
|
return error_img |
|
|
|
|
|
def t2i_turbo(prompt, negative_prompt, model, lora_model, lora_weight, vae_model, |
|
|
seed, steps, scale, w, h): |
|
|
"""Text-to-image for Turbo models (fast generation)""" |
|
|
try: |
|
|
if model not in TURBO_MODELS: |
|
|
error_img = Image.new('RGB', (int(w), int(h)), color='red') |
|
|
return error_img |
|
|
|
|
|
load_t2i_model(model, lora_model, lora_weight, vae_model) |
|
|
|
|
|
print(f"⚡ Using Turbo model: {model}") |
|
|
if lora_model and lora_model != "None": |
|
|
print(f" with LoRA: {lora_model} (weight: {lora_weight})") |
|
|
|
|
|
gen = torch.Generator(device=device).manual_seed(int(seed)) |
|
|
|
|
|
with torch.inference_mode(): |
|
|
|
|
|
turbo_steps = max(1, min(10, int(steps))) |
|
|
|
|
|
if is_sdxl_model(model): |
|
|
|
|
|
result = CURRENT_TURBO_PIPE( |
|
|
prompt, |
|
|
negative_prompt=negative_prompt, |
|
|
width=int(w), |
|
|
height=int(h), |
|
|
num_inference_steps=turbo_steps, |
|
|
guidance_scale=float(scale), |
|
|
generator=gen |
|
|
).images[0] |
|
|
else: |
|
|
|
|
|
result = CURRENT_TURBO_PIPE( |
|
|
prompt, |
|
|
negative_prompt=negative_prompt, |
|
|
width=int(w), |
|
|
height=int(h), |
|
|
num_inference_steps=turbo_steps, |
|
|
guidance_scale=float(scale), |
|
|
generator=gen |
|
|
).images[0] |
|
|
|
|
|
if device.type == "cuda": |
|
|
torch.cuda.empty_cache() |
|
|
|
|
|
return result |
|
|
except Exception as e: |
|
|
print(f"❌ Error in t2i_turbo: {e}") |
|
|
error_img = Image.new('RGB', (int(w), int(h)), color='red') |
|
|
from PIL import ImageDraw, ImageFont |
|
|
draw = ImageDraw.Draw(error_img) |
|
|
try: |
|
|
font = ImageFont.truetype("arial.ttf", 20) |
|
|
except: |
|
|
font = ImageFont.load_default() |
|
|
draw.text((50, 50), f"Error: {str(e)[:50]}...", fill="white", font=font) |
|
|
return error_img |
|
|
|
|
|
def unload_all_models(): |
|
|
global CURRENT_CONTROLNET_PIPE, CURRENT_CONTROLNET_KEY |
|
|
global DETECTORS |
|
|
global CURRENT_T2I_PIPE, CURRENT_T2I_MODEL, CURRENT_SDXL_REFINER |
|
|
global CURRENT_TURBO_PIPE, CURRENT_TURBO_MODEL |
|
|
|
|
|
print("🗑️ Unloading all models from memory...") |
|
|
|
|
|
try: |
|
|
if CURRENT_CONTROLNET_PIPE is not None: |
|
|
del CURRENT_CONTROLNET_PIPE |
|
|
CURRENT_CONTROLNET_PIPE = None |
|
|
except: |
|
|
pass |
|
|
CURRENT_CONTROLNET_KEY = None |
|
|
|
|
|
for detector_type in list(DETECTORS.keys()): |
|
|
try: |
|
|
del DETECTORS[detector_type] |
|
|
except: |
|
|
pass |
|
|
DETECTORS.clear() |
|
|
|
|
|
try: |
|
|
if CURRENT_T2I_PIPE is not None: |
|
|
del CURRENT_T2I_PIPE |
|
|
CURRENT_T2I_PIPE = None |
|
|
except: |
|
|
pass |
|
|
|
|
|
try: |
|
|
if CURRENT_SDXL_REFINER is not None: |
|
|
del CURRENT_SDXL_REFINER |
|
|
CURRENT_SDXL_REFINER = None |
|
|
except: |
|
|
pass |
|
|
|
|
|
try: |
|
|
if CURRENT_TURBO_PIPE is not None: |
|
|
del CURRENT_TURBO_PIPE |
|
|
CURRENT_TURBO_PIPE = None |
|
|
except: |
|
|
pass |
|
|
|
|
|
CURRENT_T2I_MODEL = None |
|
|
CURRENT_TURBO_MODEL = None |
|
|
|
|
|
gc.collect() |
|
|
if torch.cuda.is_available(): |
|
|
torch.cuda.empty_cache() |
|
|
allocated = torch.cuda.memory_allocated() / 1024**3 |
|
|
reserved = torch.cuda.memory_reserved() / 1024**3 |
|
|
print(f"💾 GPU memory - Allocated: {allocated:.2f} GB, Reserved: {reserved:.2f} GB") |
|
|
|
|
|
return "✅ All models unloaded from memory!" |
|
|
|
|
|
|
|
|
with gr.Blocks(title="🎨 AI Image Generator Pro", theme=gr.themes.Soft()) as demo: |
|
|
gr.Markdown("# 🎨 AI Image Generator Pro - NSFW Capable") |
|
|
gr.Markdown("### Advanced Image Generation with ControlNet, LoRA & VAE Support") |
|
|
gr.Markdown("⚠️ **Content Warning:** This tool can generate NSFW content. Use responsibly and in compliance with applicable laws.") |
|
|
|
|
|
if torch.cuda.is_available(): |
|
|
gpu_name = torch.cuda.get_device_name(0) |
|
|
gpu_memory = torch.cuda.get_device_properties(0).total_memory / 1024**3 |
|
|
gr.Markdown(f"**GPU:** {gpu_name} ({gpu_memory:.1f} GB)") |
|
|
else: |
|
|
gr.Markdown("**⚠️ Running on CPU** - Generation will be slower") |
|
|
|
|
|
with gr.Row(): |
|
|
unload_btn = gr.Button("🗑️ Unload All Models", variant="stop", scale=1) |
|
|
status_text = gr.Textbox(label="Status", interactive=False, scale=3) |
|
|
unload_btn.click(unload_all_models, outputs=status_text) |
|
|
|
|
|
with gr.Tab("🎨 SD1.5 ControlNet"): |
|
|
gr.Markdown(""" |
|
|
### Transform sketches/images using SD1.5 with ControlNet |
|
|
- **Supports:** lineart, lineart_anime, canny, depth, normal, openpose, softedge, segmentation, mlsd, shuffle, scribble, tile |
|
|
- **Best Resolution:** 512x512 |
|
|
""") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
inp_sd15 = gr.Image(label="Input Sketch/Image", type="pil") |
|
|
|
|
|
gr.Markdown("### Model Settings") |
|
|
base_model_sd15 = gr.Dropdown( |
|
|
choices=SD15_MODELS, |
|
|
value="digiplay/ChikMix_V3", |
|
|
label="SD1.5 Base Model" |
|
|
) |
|
|
controlnet_type_sd15 = gr.Dropdown( |
|
|
choices=list(CONTROLNET_MODELS_SD15.keys()), |
|
|
value="lineart_anime", |
|
|
label="ControlNet Type" |
|
|
) |
|
|
|
|
|
gr.Markdown("### Enhancement Options") |
|
|
with gr.Row(): |
|
|
lora_model_sd15 = gr.Dropdown( |
|
|
choices=list(LORA_MODELS.keys()), |
|
|
value="None", |
|
|
label="LoRA Model" |
|
|
) |
|
|
lora_weight_sd15 = gr.Slider(0.1, 2.0, 0.8, step=0.1, label="LoRA Weight") |
|
|
|
|
|
vae_model_sd15 = gr.Dropdown( |
|
|
choices=["None", "SD1.5 VAE", "Anime VAE"], |
|
|
value="None", |
|
|
label="VAE Model (Optional)" |
|
|
) |
|
|
|
|
|
with gr.Column(scale=1): |
|
|
out_sd15 = gr.Image(label="Generated Output") |
|
|
condition_out_sd15 = gr.Image(label="Processed Condition", type="pil") |
|
|
|
|
|
gr.Markdown("### Generation Parameters") |
|
|
with gr.Row(): |
|
|
prompt_sd15 = gr.Textbox( |
|
|
label="Prompt", |
|
|
placeholder="masterpiece, best quality, 1girl, beautiful detailed eyes, long hair", |
|
|
lines=3 |
|
|
) |
|
|
negative_prompt_sd15 = gr.Textbox( |
|
|
label="Negative Prompt", |
|
|
placeholder="lowres, bad anatomy, bad hands, text, error, missing fingers", |
|
|
lines=3 |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
seed_sd15 = gr.Number(value=-1, label="Seed (-1 for random)") |
|
|
steps_sd15 = gr.Slider(10, 100, 30, step=1, label="Steps") |
|
|
scale_sd15 = gr.Slider(1, 30, 7.5, step=0.5, label="CFG Scale") |
|
|
cn_weight_sd15 = gr.Slider(0.1, 2.0, 1.0, step=0.1, label="ControlNet Weight") |
|
|
|
|
|
run_sd15 = gr.Button("🎨 Generate (SD1.5)", variant="primary", size="lg") |
|
|
run_sd15.click( |
|
|
colorize_sd15, |
|
|
[inp_sd15, base_model_sd15, controlnet_type_sd15, lora_model_sd15, lora_weight_sd15, vae_model_sd15, |
|
|
prompt_sd15, negative_prompt_sd15, seed_sd15, steps_sd15, scale_sd15, cn_weight_sd15], |
|
|
[out_sd15, condition_out_sd15] |
|
|
) |
|
|
|
|
|
with gr.Tab("🎨 SDXL ControlNet"): |
|
|
gr.Markdown(""" |
|
|
### Transform sketches/images using SDXL with ControlNet |
|
|
- **Supports:** canny_sdxl, depth_sdxl, openpose_sdxl, lineart_sdxl (new!) |
|
|
- **Best Resolution:** 1024x1024 |
|
|
- **Higher quality, more VRAM required** |
|
|
""") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
inp_sdxl = gr.Image(label="Input Sketch/Image", type="pil") |
|
|
|
|
|
gr.Markdown("### Model Settings") |
|
|
base_model_sdxl = gr.Dropdown( |
|
|
choices=SDXL_MODELS, |
|
|
value="stabilityai/stable-diffusion-xl-base-1.0", |
|
|
label="SDXL Base Model" |
|
|
) |
|
|
controlnet_type_sdxl = gr.Dropdown( |
|
|
choices=list(CONTROLNET_MODELS_SDXL.keys()), |
|
|
value="lineart_sdxl", |
|
|
label="ControlNet Type" |
|
|
) |
|
|
|
|
|
gr.Markdown("### Enhancement Options") |
|
|
with gr.Row(): |
|
|
lora_model_sdxl = gr.Dropdown( |
|
|
choices=list(LORA_MODELS.keys()), |
|
|
value="None", |
|
|
label="LoRA Model" |
|
|
) |
|
|
lora_weight_sdxl = gr.Slider(0.1, 2.0, 0.8, step=0.1, label="LoRA Weight") |
|
|
|
|
|
vae_model_sdxl = gr.Dropdown( |
|
|
choices=["None", "SDXL VAE", "Turbo VAE"], |
|
|
value="None", |
|
|
label="VAE Model (Optional)" |
|
|
) |
|
|
|
|
|
with gr.Column(scale=1): |
|
|
out_sdxl = gr.Image(label="Generated Output") |
|
|
condition_out_sdxl = gr.Image(label="Processed Condition", type="pil") |
|
|
|
|
|
gr.Markdown("### Generation Parameters") |
|
|
with gr.Row(): |
|
|
prompt_sdxl = gr.Textbox( |
|
|
label="Prompt", |
|
|
placeholder="masterpiece, best quality, 8k, ultra-detailed, photorealistic, beautiful lighting", |
|
|
lines=3 |
|
|
) |
|
|
negative_prompt_sdxl = gr.Textbox( |
|
|
label="Negative Prompt", |
|
|
placeholder="lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits", |
|
|
lines=3 |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
seed_sdxl = gr.Number(value=-1, label="Seed (-1 for random)") |
|
|
steps_sdxl = gr.Slider(10, 100, 30, step=1, label="Steps") |
|
|
scale_sdxl = gr.Slider(1, 30, 7.5, step=0.5, label="CFG Scale") |
|
|
cn_weight_sdxl = gr.Slider(0.1, 2.0, 1.0, step=0.1, label="ControlNet Weight") |
|
|
|
|
|
run_sdxl = gr.Button("🎨 Generate (SDXL)", variant="primary", size="lg") |
|
|
run_sdxl.click( |
|
|
colorize_sdxl, |
|
|
[inp_sdxl, base_model_sdxl, controlnet_type_sdxl, lora_model_sdxl, lora_weight_sdxl, vae_model_sdxl, |
|
|
prompt_sdxl, negative_prompt_sdxl, seed_sdxl, steps_sdxl, scale_sdxl, cn_weight_sdxl], |
|
|
[out_sdxl, condition_out_sdxl] |
|
|
) |
|
|
|
|
|
with gr.Tab("🌸 Waifu-Colorize-XL"): |
|
|
gr.Markdown(""" |
|
|
### Specialized Anime Lineart Colorization |
|
|
- **Model:** ShinoharaHare/Waifu-Colorize-XL |
|
|
- **Specialized for:** Anime/manga lineart coloring |
|
|
- **Features:** Automatic colorization with vibrant anime colors |
|
|
- **Best Resolution:** 1024x1024 |
|
|
""") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
inp_waifu = gr.Image(label="Input Lineart/Sketch", type="pil") |
|
|
|
|
|
gr.Markdown("### Model Settings") |
|
|
gr.Markdown("**Using:** ShinoharaHare/Waifu-Colorize-XL (Specialized Anime Colorization)") |
|
|
|
|
|
gr.Markdown("### Enhancement Options") |
|
|
with gr.Row(): |
|
|
lora_weight_waifu = gr.Slider(0.1, 2.0, 1.0, step=0.1, label="LoRA Weight") |
|
|
|
|
|
vae_model_waifu = gr.Dropdown( |
|
|
choices=["None", "SDXL VAE"], |
|
|
value="None", |
|
|
label="VAE Model (Optional)" |
|
|
) |
|
|
|
|
|
with gr.Column(scale=1): |
|
|
out_waifu = gr.Image(label="Colorized Output") |
|
|
condition_out_waifu = gr.Image(label="Processed Lineart", type="pil") |
|
|
|
|
|
gr.Markdown("### Generation Parameters") |
|
|
with gr.Row(): |
|
|
prompt_waifu = gr.Textbox( |
|
|
label="Color Style Prompt (Optional)", |
|
|
placeholder="vibrant colors, anime style, beautiful coloring, masterpiece", |
|
|
lines=2 |
|
|
) |
|
|
negative_prompt_waifu = gr.Textbox( |
|
|
label="Negative Prompt", |
|
|
placeholder="monochrome, grayscale, black and white, sketch, lineart only", |
|
|
lines=2, |
|
|
value="monochrome, grayscale, black and white, sketch, lineart only" |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
seed_waifu = gr.Number(value=-1, label="Seed (-1 for random)") |
|
|
steps_waifu = gr.Slider(10, 50, 25, step=1, label="Steps") |
|
|
scale_waifu = gr.Slider(1, 20, 7.5, step=0.5, label="CFG Scale") |
|
|
cn_weight_waifu = gr.Slider(0.1, 2.0, 1.2, step=0.1, label="ControlNet Weight") |
|
|
|
|
|
gr.Markdown("### Tips for Best Results:") |
|
|
gr.Markdown(""" |
|
|
1. Use clean lineart for best results |
|
|
2. Higher ControlNet weight (1.0-1.5) for better line following |
|
|
3. Lower CFG scale (5-8) for more natural coloring |
|
|
4. Add color hints in prompt (e.g., "blue hair, red eyes, pink dress") |
|
|
5. Keep prompts simple for this specialized model |
|
|
""") |
|
|
|
|
|
run_waifu = gr.Button("🌸 Colorize with Waifu-Colorize-XL", variant="primary", size="lg") |
|
|
run_waifu.click( |
|
|
colorize_waifu_xl, |
|
|
[inp_waifu, lora_weight_waifu, vae_model_waifu, |
|
|
prompt_waifu, negative_prompt_waifu, seed_waifu, steps_waifu, scale_waifu, cn_weight_waifu], |
|
|
[out_waifu, condition_out_waifu] |
|
|
) |
|
|
|
|
|
with gr.Tab("🖼️ SD1.5 Text-to-Image"): |
|
|
gr.Markdown(""" |
|
|
### Generate images from text descriptions using SD1.5 |
|
|
- **Best Resolution:** 512x512, 512x768, 768x512 |
|
|
- **Faster generation, lower VRAM usage** |
|
|
""") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
gr.Markdown("### Model Configuration") |
|
|
t2i_model_sd15 = gr.Dropdown( |
|
|
choices=SD15_MODELS, |
|
|
value="digiplay/ChikMix_V3", |
|
|
label="SD1.5 Base Model" |
|
|
) |
|
|
|
|
|
gr.Markdown("### Enhancement Options") |
|
|
with gr.Row(): |
|
|
t2i_lora_sd15 = gr.Dropdown( |
|
|
choices=list(LORA_MODELS.keys()), |
|
|
value="None", |
|
|
label="LoRA Model" |
|
|
) |
|
|
t2i_lora_weight_sd15 = gr.Slider(0.1, 2.0, 0.8, step=0.1, label="LoRA Weight") |
|
|
|
|
|
t2i_vae_sd15 = gr.Dropdown( |
|
|
choices=["None", "SD1.5 VAE", "Anime VAE"], |
|
|
value="None", |
|
|
label="VAE Model" |
|
|
) |
|
|
|
|
|
with gr.Column(scale=1): |
|
|
t2i_out_sd15 = gr.Image(label="Generated Image", type="pil") |
|
|
|
|
|
gr.Markdown("### Prompts") |
|
|
with gr.Row(): |
|
|
t2i_prompt_sd15 = gr.Textbox( |
|
|
label="Prompt", |
|
|
lines=4, |
|
|
placeholder="masterpiece, best quality, highly detailed, beautiful, 1girl" |
|
|
) |
|
|
t2i_negative_prompt_sd15 = gr.Textbox( |
|
|
label="Negative Prompt", |
|
|
lines=4, |
|
|
placeholder="lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality" |
|
|
) |
|
|
|
|
|
gr.Markdown("### Generation Parameters") |
|
|
with gr.Row(): |
|
|
t2i_seed_sd15 = gr.Number(value=-1, label="Seed (-1 for random)") |
|
|
t2i_steps_sd15 = gr.Slider(10, 100, 30, step=1, label="Steps") |
|
|
t2i_scale_sd15 = gr.Slider(1, 30, 7.5, step=0.5, label="CFG Scale") |
|
|
|
|
|
with gr.Row(): |
|
|
w_sd15 = gr.Slider(256, 1024, 512, step=64, label="Width") |
|
|
h_sd15 = gr.Slider(256, 1024, 768, step=64, label="Height") |
|
|
|
|
|
gen_btn_sd15 = gr.Button("🖼️ Generate (SD1.5)", variant="primary", size="lg") |
|
|
gen_btn_sd15.click( |
|
|
t2i_sd15, |
|
|
[t2i_prompt_sd15, t2i_negative_prompt_sd15, t2i_model_sd15, t2i_lora_sd15, t2i_lora_weight_sd15, |
|
|
t2i_vae_sd15, t2i_seed_sd15, t2i_steps_sd15, t2i_scale_sd15, w_sd15, h_sd15], |
|
|
t2i_out_sd15 |
|
|
) |
|
|
|
|
|
with gr.Tab("⚡ SDXL-Turbo Text-to-Image"): |
|
|
gr.Markdown(""" |
|
|
### Ultra-Fast Image Generation with SDXL-Turbo |
|
|
- **Model:** stabilityai/sdxl-turbo |
|
|
- **Features:** 1-4 steps generation, extremely fast |
|
|
- **Best Resolution:** 512x512 to 1024x1024 |
|
|
- **Warning:** Lower quality than full SDXL but much faster |
|
|
""") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
gr.Markdown("### Model Configuration") |
|
|
t2i_model_turbo = gr.Dropdown( |
|
|
choices=TURBO_MODELS, |
|
|
value="stabilityai/sdxl-turbo", |
|
|
label="Turbo Model" |
|
|
) |
|
|
|
|
|
gr.Markdown("### Enhancement Options") |
|
|
with gr.Row(): |
|
|
t2i_lora_turbo = gr.Dropdown( |
|
|
choices=list(LORA_MODELS.keys()), |
|
|
value="None", |
|
|
label="LoRA Model" |
|
|
) |
|
|
t2i_lora_weight_turbo = gr.Slider(0.1, 2.0, 0.8, step=0.1, label="LoRA Weight") |
|
|
|
|
|
t2i_vae_turbo = gr.Dropdown( |
|
|
choices=["None", "Turbo VAE", "SDXL VAE"], |
|
|
value="None", |
|
|
label="VAE Model" |
|
|
) |
|
|
|
|
|
with gr.Column(scale=1): |
|
|
t2i_out_turbo = gr.Image(label="Generated Image", type="pil") |
|
|
|
|
|
gr.Markdown("### Prompts") |
|
|
with gr.Row(): |
|
|
t2i_prompt_turbo = gr.Textbox( |
|
|
label="Prompt", |
|
|
lines=4, |
|
|
placeholder="masterpiece, best quality, highly detailed, beautiful, 1girl" |
|
|
) |
|
|
t2i_negative_prompt_turbo = gr.Textbox( |
|
|
label="Negative Prompt", |
|
|
lines=4, |
|
|
placeholder="lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality" |
|
|
) |
|
|
|
|
|
gr.Markdown("### Generation Parameters (Turbo needs only 1-4 steps!)") |
|
|
with gr.Row(): |
|
|
t2i_seed_turbo = gr.Number(value=-1, label="Seed (-1 for random)") |
|
|
t2i_steps_turbo = gr.Slider(1, 10, 4, step=1, label="Steps (1-4 recommended)") |
|
|
t2i_scale_turbo = gr.Slider(0, 10, 0.0, step=0.5, label="CFG Scale (0-2 recommended)") |
|
|
|
|
|
with gr.Row(): |
|
|
w_turbo = gr.Slider(256, 1024, 512, step=64, label="Width") |
|
|
h_turbo = gr.Slider(256, 1024, 512, step=64, label="Height") |
|
|
|
|
|
gr.Markdown("### Turbo Model Tips:") |
|
|
gr.Markdown(""" |
|
|
1. **Use very few steps:** 1-4 steps is enough! |
|
|
2. **Low CFG Scale:** 0.0-2.0 works best |
|
|
3. **Fast but lower quality:** For quick previews/testing |
|
|
4. **Works well with:** Simple prompts, concept testing |
|
|
""") |
|
|
|
|
|
gen_btn_turbo = gr.Button("⚡ Generate with Turbo (Fast!)", variant="primary", size="lg") |
|
|
gen_btn_turbo.click( |
|
|
t2i_turbo, |
|
|
[t2i_prompt_turbo, t2i_negative_prompt_turbo, t2i_model_turbo, t2i_lora_turbo, t2i_lora_weight_turbo, |
|
|
t2i_vae_turbo, t2i_seed_turbo, t2i_steps_turbo, t2i_scale_turbo, w_turbo, h_turbo], |
|
|
t2i_out_turbo |
|
|
) |
|
|
|
|
|
with gr.Tab("🖼️ SDXL Text-to-Image"): |
|
|
gr.Markdown(""" |
|
|
### Generate images from text descriptions using SDXL |
|
|
- **Best Resolution:** 1024x1024, 1024x1536, 1536x1024 |
|
|
- **Higher quality, more detail, better composition** |
|
|
""") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
gr.Markdown("### Model Configuration") |
|
|
t2i_model_sdxl = gr.Dropdown( |
|
|
choices=[m for m in SDXL_MODELS if m not in TURBO_MODELS], |
|
|
value="stabilityai/stable-diffusion-xl-base-1.0", |
|
|
label="SDXL Base Model" |
|
|
) |
|
|
|
|
|
gr.Markdown("### Enhancement Options") |
|
|
with gr.Row(): |
|
|
t2i_lora_sdxl = gr.Dropdown( |
|
|
choices=list(LORA_MODELS.keys()), |
|
|
value="None", |
|
|
label="LoRA Model" |
|
|
) |
|
|
t2i_lora_weight_sdxl = gr.Slider(0.1, 2.0, 0.8, step=0.1, label="LoRA Weight") |
|
|
|
|
|
t2i_vae_sdxl = gr.Dropdown( |
|
|
choices=["None", "SDXL VAE"], |
|
|
value="None", |
|
|
label="VAE Model" |
|
|
) |
|
|
|
|
|
use_refiner_sdxl = gr.Checkbox( |
|
|
label="Use Refiner (for better quality)", |
|
|
value=False |
|
|
) |
|
|
|
|
|
with gr.Column(scale=1): |
|
|
t2i_out_sdxl = gr.Image(label="Generated Image", type="pil") |
|
|
|
|
|
gr.Markdown("### Prompts") |
|
|
with gr.Row(): |
|
|
t2i_prompt_sdxl = gr.Textbox( |
|
|
label="Prompt", |
|
|
lines=4, |
|
|
placeholder="masterpiece, best quality, 8k, ultra-detailed, photorealistic, cinematic lighting" |
|
|
) |
|
|
t2i_negative_prompt_sdxl = gr.Textbox( |
|
|
label="Negative Prompt", |
|
|
lines=4, |
|
|
placeholder="lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, jpeg artifacts, signature, watermark, username, blurry" |
|
|
) |
|
|
|
|
|
gr.Markdown("### Generation Parameters") |
|
|
with gr.Row(): |
|
|
t2i_seed_sdxl = gr.Number(value=-1, label="Seed (-1 for random)") |
|
|
t2i_steps_sdxl = gr.Slider(10, 100, 30, step=1, label="Steps") |
|
|
t2i_scale_sdxl = gr.Slider(1, 30, 7.5, step=0.5, label="CFG Scale") |
|
|
|
|
|
with gr.Row(): |
|
|
w_sdxl = gr.Slider(512, 2048, 1024, step=64, label="Width") |
|
|
h_sdxl = gr.Slider(512, 2048, 1024, step=64, label="Height") |
|
|
|
|
|
gen_btn_sdxl = gr.Button("🖼️ Generate (SDXL)", variant="primary", size="lg") |
|
|
gen_btn_sdxl.click( |
|
|
t2i_sdxl, |
|
|
[t2i_prompt_sdxl, t2i_negative_prompt_sdxl, t2i_model_sdxl, t2i_lora_sdxl, t2i_lora_weight_sdxl, |
|
|
t2i_vae_sdxl, t2i_seed_sdxl, t2i_steps_sdxl, t2i_scale_sdxl, w_sdxl, h_sdxl, use_refiner_sdxl], |
|
|
t2i_out_sdxl |
|
|
) |
|
|
|
|
|
with gr.Tab("📚 Quick Reference"): |
|
|
gr.Markdown(""" |
|
|
# Model & Feature Guide |
|
|
|
|
|
## 🎯 Model Comparison |
|
|
|
|
|
### SD1.5 (Stable Diffusion 1.5) |
|
|
- **Pros:** Fast, low VRAM, many models |
|
|
- **Cons:** 512px max, lower quality |
|
|
- **Best for:** Quick tests, anime, lower-end hardware |
|
|
|
|
|
### SDXL (Stable Diffusion XL) |
|
|
- **Pros:** 1024px+, high quality, better composition |
|
|
- **Cons:** High VRAM, slower |
|
|
- **Best for:** Final quality, professional work |
|
|
|
|
|
### SDXL-Turbo |
|
|
- **Pros:** Extremely fast (1-4 steps!) |
|
|
- **Cons:** Lower quality than full SDXL |
|
|
- **Best for:** Quick previews, concept testing |
|
|
|
|
|
### Waifu-Colorize-XL |
|
|
- **Pros:** Specialized for anime lineart coloring |
|
|
- **Cons:** Anime-only, requires clean lineart |
|
|
- **Best for:** Anime/manga colorization |
|
|
|
|
|
## 🎨 New ControlNet for SDXL |
|
|
|
|
|
### Lineart ControlNet for SDXL |
|
|
- **Model:** ShermanG/ControlNet-Standard-Lineart-for-SDXL |
|
|
- **Purpose:** Convert lineart to colored images |
|
|
- **Best with:** Clean lineart, anime/manga styles |
|
|
- **Used in:** Waifu-Colorize-XL Tab |
|
|
|
|
|
## 💎 Recommended Workflows |
|
|
|
|
|
### For Anime/Manga Artists |
|
|
1. Draw lineart |
|
|
2. Use **Waifu-Colorize-XL** Tab for automatic coloring |
|
|
3. Or use **SDXL ControlNet** with lineart_sdxl |
|
|
|
|
|
### For Quick Concepts |
|
|
1. Use **SDXL-Turbo** Tab for 1-4 step generation |
|
|
2. Refine in **SDXL Text-to-Image** if needed |
|
|
|
|
|
### For Professional Work |
|
|
1. Use **SDXL Text-to-Image** with Refiner |
|
|
2. High steps (40-50), CFG 7-9 |
|
|
3. 1024x1024 resolution |
|
|
|
|
|
## ⚡ Turbo Model Tips |
|
|
|
|
|
### SDXL-Turbo Best Practices: |
|
|
- **Steps:** 1-4 only! |
|
|
- **CFG Scale:** 0.0-2.0 |
|
|
- **Prompts:** Keep simple |
|
|
- **Resolution:** 512x512 to 1024x1024 |
|
|
- **Use case:** Storyboarding, concept art, quick iterations |
|
|
|
|
|
## 🌸 Waifu-Colorize-XL Tips |
|
|
|
|
|
### For Best Results: |
|
|
1. **Clean lineart:** No stray marks |
|
|
2. **ControlNet weight:** 1.0-1.5 |
|
|
3. **CFG Scale:** 5-8 |
|
|
4. **Simple prompts:** "vibrant colors, anime style" |
|
|
5. **Resolution:** 1024x1024 |
|
|
|
|
|
### Example Workflow: |
|
|
1. Draw/sketch in your favorite app |
|
|
2. Export as clean lineart (black on white) |
|
|
3. Upload to Waifu-Colorize-XL Tab |
|
|
4. Adjust parameters as needed |
|
|
5. Generate and refine |
|
|
|
|
|
## 🚀 Performance Optimization |
|
|
|
|
|
### Low VRAM (<8GB) |
|
|
- Use SD1.5 models only |
|
|
- 512x512 resolution |
|
|
- Enable attention slicing |
|
|
|
|
|
### Medium VRAM (8-12GB) |
|
|
- SD1.5 and SDXL (no refiner) |
|
|
- 1024x1024 for SDXL |
|
|
- Enable xFormers |
|
|
|
|
|
### High VRAM (12GB+) |
|
|
- All models including SDXL with refiner |
|
|
- Higher resolutions |
|
|
- Multiple LoRAs |
|
|
|
|
|
## 🔄 Memory Management |
|
|
|
|
|
### When to Unload Models: |
|
|
1. Switching between SD1.5 and SDXL |
|
|
2. Getting "out of memory" errors |
|
|
3. Changing ControlNet types |
|
|
4. After long generation sessions |
|
|
|
|
|
### Memory Saving Tips: |
|
|
1. Use "Unload All Models" button |
|
|
2. Generate in batches |
|
|
3. Lower resolution for testing |
|
|
4. Close other GPU applications |
|
|
""") |
|
|
|
|
|
try: |
|
|
demo.launch( |
|
|
server_name="0.0.0.0", |
|
|
server_port=7860, |
|
|
share=False, |
|
|
show_error=True, |
|
|
quiet=False |
|
|
) |
|
|
except Exception as e: |
|
|
print(f"❌ Error launching Gradio app: {e}") |