import os import random import uuid import gradio as gr import numpy as np from PIL import Image import spaces import torch from diffusers import StableDiffusionXLPipeline, EulerAncestralDiscreteScheduler from typing import Tuple css = ''' .gradio-container{max-width: 575px !important} h1{text-align:center} footer { visibility: hidden } ''' DESCRIPTIONXX = """## LENNOX TEXT 2 IMAGE🥠""" examples = [ "Neon-lit futuristic city at night, towering skyscrapers, flying cars, and glowing billboards. People in cyberpunk attire walk below a starry sky.", "Mystical forest with glowing plants, bioluminescent trees, and magical creatures like fairies and fireflies. Mist and soft light create a dreamlike feel.", "Medieval knight in detailed armor on a cliff, sword in hand, sunset light highlighting a kingdom and castle in the background.", "Modern, minimalist living room with soft gray and wood tones, large window with natural light, a simple couch, and potted plants for a cozy vibe.", "Majestic lion on a rock in the African savanna at sunrise, mane blowing in the wind, with acacia trees and golden grass under warm light." ] MODEL_OPTIONS = { "LENNOX-AI V2.0": "SG161222/RealVisXL_V5.0_Lightning", "LENNOX-AI V1.0": "SG161222/RealVisXL_V4.0_Lightning", } MAX_IMAGE_SIZE = int(os.getenv("MAX_IMAGE_SIZE", "4096")) USE_TORCH_COMPILE = os.getenv("USE_TORCH_COMPILE", "0") == "1" ENABLE_CPU_OFFLOAD = os.getenv("ENABLE_CPU_OFFLOAD", "0") == "1" BATCH_SIZE = int(os.getenv("BATCH_SIZE", "1")) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") style_list = [ { "name": "3840 x 2160", "prompt": "hyper-realistic 8K image of {prompt}. ultra-detailed, lifelike, high-resolution, sharp, vibrant colors, photorealistic", "negative_prompt": "cartoonish, low resolution, blurry, simplistic, abstract, deformed, ugly", }, { "name": "2560 x 1440", "prompt": "hyper-realistic 4K image of {prompt}. ultra-detailed, lifelike, high-resolution, sharp, vibrant colors, photorealistic", "negative_prompt": "cartoonish, low resolution, blurry, simplistic, abstract, deformed, ugly", }, { "name": "HD+", "prompt": "hyper-realistic 2K image of {prompt}. ultra-detailed, lifelike, high-resolution, sharp, vibrant colors, photorealistic", "negative_prompt": "cartoonish, low resolution, blurry, simplistic, abstract, deformed, ugly", }, { "name": "Style Zero", "prompt": "{prompt}", "negative_prompt": "", }, ] styles = {k["name"]: (k["prompt"], k["negative_prompt"]) for k in style_list} DEFAULT_STYLE_NAME = "3840 x 2160" STYLE_NAMES = list(styles.keys()) def apply_style(style_name: str, positive: str, negative: str = "") -> Tuple[str, str]: if style_name in styles: p, n = styles.get(style_name, styles[DEFAULT_STYLE_NAME]) else: p, n = styles[DEFAULT_STYLE_NAME] if not negative: negative = "" return p.replace("{prompt}", positive), n + negative def load_and_prepare_model(model_id): pipe = StableDiffusionXLPipeline.from_pretrained( model_id, torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32, use_safetensors=True, add_watermarker=False, ).to(device) pipe.scheduler = EulerAncestralDiscreteScheduler.from_config(pipe.scheduler.config) if USE_TORCH_COMPILE: pipe.compile() if ENABLE_CPU_OFFLOAD: pipe.enable_model_cpu_offload() return pipe # Preload and compile both models models = {key: load_and_prepare_model(value) for key, value in MODEL_OPTIONS.items()} MAX_SEED = np.iinfo(np.int32).max def save_image(img): unique_name = str(uuid.uuid4()) + ".png" img.save(unique_name) return unique_name def randomize_seed_fn(seed: int, randomize_seed: bool) -> int: if randomize_seed: seed = random.randint(0, MAX_SEED) return seed @spaces.GPU(duration=60, enable_queue=True) def generate( model_choice: str, prompt: str, negative_prompt: str = "", use_negative_prompt: bool = False, style_selection: str = DEFAULT_STYLE_NAME, seed: int = 1, width: int = 1024, height: int = 1024, guidance_scale: float = 3, num_inference_steps: int = 25, randomize_seed: bool = False, use_resolution_binning: bool = True, num_images: int = 1, progress=gr.Progress(track_tqdm=True), ): global models pipe = models[model_choice] seed = int(randomize_seed_fn(seed, randomize_seed)) generator = torch.Generator(device=device).manual_seed(seed) prompt, negative_prompt = apply_style(style_selection, prompt, negative_prompt) options = { "prompt": [prompt] * num_images, "negative_prompt": [negative_prompt] * num_images if use_negative_prompt else None, "width": width, "height": height, "guidance_scale": guidance_scale, "num_inference_steps": num_inference_steps, "generator": generator, "output_type": "pil", } if use_resolution_binning: options["use_resolution_binning"] = True images = [] for i in range(0, num_images, BATCH_SIZE): batch_options = options.copy() batch_options["prompt"] = options["prompt"][i:i+BATCH_SIZE] if "negative_prompt" in batch_options: batch_options["negative_prompt"] = options["negative_prompt"][i:i+BATCH_SIZE] images.extend(pipe(**batch_options).images) image_paths = [save_image(img) for img in images] return image_paths, seed with gr.Blocks(css=css, theme="bethecloud/storj_theme") as demo: gr.Markdown(DESCRIPTIONXX) with gr.Row(): prompt = gr.Text( label="Prompt", show_label=False, max_lines=1, placeholder="Enter your prompt", container=False, ) run_button = gr.Button("Run", scale=0) result = gr.Gallery(label="Result", columns=1, show_label=False) with gr.Row(): model_choice = gr.Dropdown( label="Model Selection⬇️", choices=list(MODEL_OPTIONS.keys()), value="LENNOX-AI V2.0" ) with gr.Accordion("Advanced options", open=False, visible=False): style_selection = gr.Radio( show_label=True, container=True, interactive=True, choices=STYLE_NAMES, value=DEFAULT_STYLE_NAME, label="Quality Style", ) num_images = gr.Slider( label="Number of Images", minimum=1, maximum=5, step=1, value=1, ) with gr.Row(): with gr.Column(scale=1): use_negative_prompt = gr.Checkbox(label="Use negative prompt", value=True) negative_prompt = gr.Text( label="Negative prompt", max_lines=5, lines=4, placeholder="Enter a negative prompt", value="(deformed, distorted, disfigured:1.3), poorly drawn, bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, (mutated hands and fingers:1.4), disconnected limbs, mutation, mutated, ugly, disgusting, blurry, amputation", visible=True, ) seed = gr.Slider( label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0, ) randomize_seed = gr.Checkbox(label="Randomize seed", value=True) with gr.Row(): width = gr.Slider( label="Width", minimum=512, maximum=MAX_IMAGE_SIZE, step=8, value=1024, ) height = gr.Slider( label="Height", minimum=512, maximum=MAX_IMAGE_SIZE, step=8, value=1024, ) with gr.Row(): guidance_scale = gr.Slider( label="Guidance Scale", minimum=0.1, maximum=6, step=0.1, value=3.0, ) num_inference_steps = gr.Slider( label="Number of inference steps", minimum=1, maximum=60, step=1, value=28, ) gr.Examples( examples=examples, inputs=prompt, cache_examples=False ) use_negative_prompt.change( fn=lambda x: gr.update(visible=x), inputs=use_negative_prompt, outputs=negative_prompt, api_name=False, ) gr.on( triggers=[ prompt.submit, negative_prompt.submit, run_button.click, ], fn=generate, inputs=[ model_choice, prompt, negative_prompt, use_negative_prompt, style_selection, seed, width, height, guidance_scale, num_inference_steps, randomize_seed, num_images, ], outputs=[result, seed], ) #gr.Markdown("### Image Gallery") #predefined_gallery = gr.Gallery(label="Image Gallery", columns=3, show_label=False, value=load_predefined_images()) gr.Markdown( """
🖌️ Image Generation by Omindu Dissanayaka: Using LENNOX-AI V2.0 and LENNOX-AI V1.0 models for high-quality images. This demo space showcases image generation with the Stable Diffusion XL model variants, available for experimenting with different styles and models.
""" ) gr.Markdown( """
🎨 Explore the demo space for Stable Diffusion XL, designed by Omindu Dissanayaka. Generate images with diverse styles and models for higher-quality results. Experiment with sample prompts to create unique, high-quality images.
""" ) gr.Markdown( """
⚠️ Disclaimer: Users are responsible for ensuring that generated content complies with ethical standards.
""" ) if __name__ == "__main__": demo.queue(max_size=50).launch(show_api=True)