Max / app.py
K1Z3M1112's picture
Update app.py
1cc4460 verified
import gradio as gr
import numpy as np
from PIL import Image
import torch
import gc
import os
import warnings
# Suppress specific warnings
warnings.filterwarnings('ignore', category=FutureWarning)
warnings.filterwarnings('ignore', category=UserWarning)
warnings.filterwarnings('ignore', message='.*torch_dtype.*deprecated.*')
warnings.filterwarnings('ignore', message='.*CLIPFeatureExtractor.*deprecated.*')
# Performance optimizations
if torch.cuda.is_available():
torch.backends.cudnn.benchmark = True
torch.backends.cuda.matmul.allow_tf32 = True
torch.backends.cudnn.allow_tf32 = True
# Device
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}")
# Lazy import
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
)
# Memory optimization
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")
# ===== Model & Config =====
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
# Enhanced SDXL Models (including NSFW-capable)
SDXL_MODELS = [
"stabilityai/stable-diffusion-xl-base-1.0",
"stabilityai/stable-diffusion-xl-refiner-1.0",
"stabilityai/sdxl-turbo", # เพิ่ม 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 (fast generation)
TURBO_MODELS = [
"stabilityai/sdxl-turbo",
"stabilityai/sd-turbo"
]
# Enhanced SD1.5 Models (including NSFW-capable)
SD15_MODELS = [
# Original 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",
# Additional NSFW-capable models
"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"
]
# Specialized models
SPECIAL_MODELS = {
"waifu_colorize": "ShinoharaHare/Waifu-Colorize-XL" # โมเดลสำหรับ colorize โดยเฉพาะ
}
# Chinese Models
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 for SD1.5
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 for SDXL
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" # เพิ่ม ControlNet Lineart สำหรับ SDXL
}
# แก้ไข LoRA models ให้ใช้ชื่อที่ไม่มีช่องว่าง
LORA_MODELS = {
"None": None,
# Style LoRAs
"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",
# Character/Face LoRAs
"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 LoRAs
"body-pose-control": "alvdansen/lora-body-pose",
"dynamic-poses": "alvdansen/dynamic-poses-lora",
"full-body": "artificialguybr/full-body-lora",
# Realism LoRAs
"photorealistic": "microsoft/lora-photorealistic",
"hyper-realistic": "dallinmackay/hyper-realistic-lora",
"ultra-realistic": "artificialguybr/ultra-realistic-lora",
"realistic-vision": "SG161222/Realistic_Vision_V5.1_noVAE",
# Lighting/Quality LoRAs
"add-detail": "ostris/add-detail-lora",
"sharp-details": "ostris/sharp-details-lora",
"better-lighting": "artificialguybr/better-lighting-lora",
"studio-lighting": "artificialguybr/studio-lighting",
# NSFW-capable LoRAs
"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 LoRAs
"colorize-xl": "ShinoharaHare/Waifu-Colorize-XL"
}
# VAE models for better quality
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"
}
# Detector instances
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:
# สำหรับ Turbo models ใช้ pipeline ที่เหมาะสม
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)
# Load custom VAE if specified
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}")
# Apply LoRA if specified
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}")
# Optimizations
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()
# ใช้ scheduler ที่เหมาะสมสำหรับแต่ละโมเดล
if is_turbo:
# สำหรับ Turbo models ใช้ scheduler ที่เร็วขึ้น
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:
# โหลด Turbo model
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
# Load custom VAE
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}")
# Apply LoRA
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}")
# Optimizations
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()
# ตั้งค่า scheduler
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))
# สำหรับ Waifu-Colorize-XL ใช้ prompt พิเศษ
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 models ใช้ steps น้อยลง
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 models ใช้ steps น้อยลง (1-10 steps)
turbo_steps = max(1, min(10, int(steps)))
if is_sdxl_model(model):
# SDXL-Turbo
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:
# SD-Turbo
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!"
# ===== Gradio UI =====
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], # ไม่รวม 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}")