#!/usr/bin/env python from __future__ import annotations import argparse import os import sys import random import gradio as gr import numpy as np import uuid import spaces from diffusers import ConsistencyDecoderVAE, DPMSolverMultistepScheduler, Transformer2DModel, AutoencoderKL import torch from typing import Tuple from datetime import datetime from peft import PeftModel from diffusers_patches import pixart_sigma_init_patched_inputs, PixArtSigmaPipeline DESCRIPTION = """ # Instant Image ### Super fast text to Image Generator. ### You may change the steps from 9 to 15, if you didn't get satisfied results. """ if not torch.cuda.is_available(): DESCRIPTION += "\n

Running on CPU 🥶 This demo does not work on CPU.

" MAX_SEED = np.iinfo(np.int32).max CACHE_EXAMPLES = torch.cuda.is_available() and os.getenv("CACHE_EXAMPLES", "1") == "1" MAX_IMAGE_SIZE = int(os.getenv("MAX_IMAGE_SIZE", "6000")) USE_TORCH_COMPILE = os.getenv("USE_TORCH_COMPILE", "0") == "1" ENABLE_CPU_OFFLOAD = os.getenv("ENABLE_CPU_OFFLOAD", "0") == "1" PORT = int(os.getenv("DEMO_PORT", "15432")) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") style_list = [ { "name": "(No style)", "prompt": "{prompt}", "negative_prompt": "", }, { "name": "Cinematic", "prompt": "cinematic still {prompt} . emotional, harmonious, vignette, highly detailed, high budget, bokeh, cinemascope, moody, epic, gorgeous, film grain, grainy", "negative_prompt": "anime, cartoon, graphic, text, painting, crayon, graphite, abstract, glitch, deformed, mutated, ugly, disfigured", }, { "name": "Realistic", "prompt": "Photorealistic {prompt} . Ulta-realistic, professional, 4k, highly detailed", "negative_prompt": "drawing, painting, crayon, sketch, graphite, impressionist, noisy, blurry, soft, deformed, ugly, disfigured", }, { "name": "Anime", "prompt": "anime artwork {prompt} . anime style, key visual, vibrant, studio anime, highly detailed", "negative_prompt": "photo, deformed, black and white, realism, disfigured, low contrast", }, { "name": "Manga", "prompt": "manga style {prompt} . vibrant, high-energy, detailed, iconic, Japanese comic style", "negative_prompt": "ugly, deformed, noisy, blurry, low contrast, realism, photorealistic, Western comic style", }, { "name": "Digital Art", "prompt": "concept art {prompt} . digital artwork, illustrative, painterly, matte painting, highly detailed", "negative_prompt": "photo, photorealistic, realism, ugly", }, { "name": "Pixel art", "prompt": "pixel-art {prompt} . low-res, blocky, pixel art style, 8-bit graphics", "negative_prompt": "sloppy, messy, blurry, noisy, highly detailed, ultra textured, photo, realistic", }, { "name": "Fantasy art", "prompt": "ethereal fantasy concept art of {prompt} . magnificent, celestial, ethereal, painterly, epic, majestic, magical, fantasy art, cover art, dreamy", "negative_prompt": "photographic, realistic, realism, 35mm film, dslr, cropped, frame, text, deformed, glitch, noise, noisy, off-center, deformed, cross-eyed, closed eyes, bad anatomy, ugly, disfigured, sloppy, duplicate, mutated, black and white", }, { "name": "Neonpunk", "prompt": "neonpunk style {prompt} . cyberpunk, vaporwave, neon, vibes, vibrant, stunningly beautiful, crisp, detailed, sleek, ultramodern, magenta highlights, dark purple shadows, high contrast, cinematic, ultra detailed, intricate, professional", "negative_prompt": "painting, drawing, illustration, glitch, deformed, mutated, cross-eyed, ugly, disfigured", }, { "name": "3D Model", "prompt": "professional 3d model {prompt} . octane render, highly detailed, volumetric, dramatic lighting", "negative_prompt": "ugly, deformed, noisy, low poly, blurry, painting", }, ] styles = {k["name"]: (k["prompt"], k["negative_prompt"]) for k in style_list} STYLE_NAMES = list(styles.keys()) DEFAULT_STYLE_NAME = "(No style)" " SCHEDULE_NAME = ["DPM-Solver"] DEFAULT_SCHEDULE_NAME = "DPM-Solver" NUM_IMAGES_PER_PROMPT = 1 def apply_style(style_name: str, positive: str, negative: str = "") -> Tuple[str, str]: p, n = styles.get(style_name, styles[DEFAULT_STYLE_NAME]) if not negative: negative = "" return p.replace("{prompt}", positive), n + negative if torch.cuda.is_available(): weight_dtype = torch.float16 T5_token_max_length = 300 # tmp patches for diffusers PixArtSigmaPipeline Implementation print( "Changing _init_patched_inputs method of diffusers.models.Transformer2DModel " "using scripts.diffusers_patches.pixart_sigma_init_patched_inputs") setattr(Transformer2DModel, '_init_patched_inputs', pixart_sigma_init_patched_inputs) transformer = Transformer2DModel.from_pretrained( "PixArt-alpha/PixArt-Sigma-XL-2-1024-MS", subfolder='transformer', torch_dtype=weight_dtype, ) pipe = PixArtSigmaPipeline.from_pretrained( "PixArt-alpha/pixart_sigma_sdxlvae_T5_diffusers", transformer=transformer, torch_dtype=weight_dtype, use_safetensors=True, ) if os.getenv('CONSISTENCY_DECODER', False): print("Using DALL-E 3 Consistency Decoder") pipe.vae = ConsistencyDecoderVAE.from_pretrained("openai/consistency-decoder", torch_dtype=torch.float16) if ENABLE_CPU_OFFLOAD: pipe.enable_model_cpu_offload() else: pipe.to(device) print("Loaded on Device!") # speed-up T5 pipe.text_encoder.to_bettertransformer() if USE_TORCH_COMPILE: pipe.transformer = torch.compile(pipe.transformer, mode="reduce-overhead", fullgraph=True) print("Model Compiled!") 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 @torch.no_grad() @torch.inference_mode() @spaces.GPU(duration=120) def generate( prompt: str, negative_prompt: str = "", style: str = DEFAULT_STYLE_NAME, use_negative_prompt: bool = False, num_imgs: int = 1, seed: int = 0, width: int = 400, height: int = 400, schedule: str = 'DPM-Solver', dpms_guidance_scale: float = 3.5, dpms_inference_steps: int = 9, randomize_seed: bool = False, use_resolution_binning: bool = True, progress=gr.Progress(track_tqdm=True), ): seed = int(randomize_seed_fn(seed, randomize_seed)) generator = torch.Generator().manual_seed(seed) if schedule == 'DPM-Solver': if not isinstance(pipe.scheduler, DPMSolverMultistepScheduler): pipe.scheduler = DPMSolverMultistepScheduler() num_inference_steps = dpms_inference_steps guidance_scale = dpms_guidance_scale else: raise ValueError(f"Unknown schedule: {schedule}") if not use_negative_prompt: negative_prompt = None # type: ignore prompt, negative_prompt = apply_style(style, prompt, negative_prompt) images = pipe( prompt=prompt, width=width, height=height, negative_prompt=negative_prompt, guidance_scale=guidance_scale, num_inference_steps=num_inference_steps, generator=generator, num_images_per_prompt=num_imgs, use_resolution_binning=use_resolution_binning, output_type="pil", max_sequence_length=T5_token_max_length, ).images image_paths = [save_image(img) for img in images] print(image_paths) return image_paths, seed examples = [ "A Monkey with a happy face in the Sahara desert.", "Eiffel Tower was Made up of ICE to look like a cloud, with the bell tower at the top of the building.", "3D small, round, fluffy creature with big, expressive eyes explores a vibrant, enchanted forest. The creature, a whimsical blend of a rabbit and a squirrel, has soft blue fur and a bushy, striped tail. It hops along a sparkling stream, its eyes wide with wonder. The forest is alive with magical elements: flowers that glow and change colors, trees with leaves in shades of purple and silver, and small floating lights that resemble fireflies. The creature stops to interact playfully with a group of tiny, fairy-like beings dancing around a mushroom ring. The creature looks up in awe at a large, glowing tree that seems to be the heart of the forest.", "Color photo of a corgi made of transparent glass, standing on the riverside in Yosemite National Park.", "A close-up photo of a woman. She wore a blue coat with a gray dress underneath. She has blue eyes and blond hair, and wears a pair of earrings. Behind are blurred city buildings and streets.", "A litter of golden retriever puppies playing in the snow. Their heads pop out of the snow, covered in.", "a handsome young boy in the middle with sky color background wearing eye glasses, it's super detailed with anime style, it's a portrait with delicated eyes and nice looking face", "an astronaut sitting in a diner, eating fries, cinematic, analog film", "Pirate ship trapped in a cosmic maelstrom nebula, rendered in cosmic beach whirlpool engine, volumetric lighting, spectacular, ambient lights, intricate detail.", "professional portrait photo of an anthropomorphic cat wearing fancy gentleman hat and jacket walking in autumn forest.", "Outside View from Hotel Made up of Chocolate in space.", ] with gr.Blocks(css="style.css") as demo: gr.Markdown(DESCRIPTION) gr.DuplicateButton( value="Duplicate Space for private use", elem_id="duplicate-button", visible=os.getenv("SHOW_DUPLICATE_BUTTON") == "1", ) with gr.Row(equal_height=False): with gr.Group(): 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=NUM_IMAGES_PER_PROMPT, show_label=False) # with gr.Accordion("Advanced options", open=False): with gr.Group(): with gr.Row(): use_negative_prompt = gr.Checkbox(label="Use negative prompt", value=False, visible=True) with gr.Row(visible=True): schedule = gr.Radio( show_label=True, container=True, interactive=True, choices=SCHEDULE_NAME, value=DEFAULT_SCHEDULE_NAME, label="Sampler Schedule", visible=True, ) num_imgs = gr.Slider( label="Num Images", minimum=1, maximum=8, step=1, value=1, ) style_selection = gr.Radio( show_label=True, container=True, interactive=True, choices=STYLE_NAMES, value=DEFAULT_STYLE_NAME, label="Image Style", ) negative_prompt = gr.Text( label="Negative prompt", max_lines=1, placeholder="Enter a negative prompt", 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(visible=True): width = gr.Slider( label="Width", minimum=256, maximum=MAX_IMAGE_SIZE, step=32, value=400, ) height = gr.Slider( label="Height", minimum=256, maximum=MAX_IMAGE_SIZE, step=32, value=400, ) with gr.Row(): dpms_guidance_scale = gr.Slider( label="Temprature", minimum=3, maximum=4, step=0.1, value=3.5, ) dpms_inference_steps = gr.Slider( label="Steps", minimum=5, maximum=25, step=1, value=9, ) gr.Examples( examples=examples, inputs=prompt, outputs=[result, seed], fn=generate, cache_examples=CACHE_EXAMPLES, ) 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=[ prompt, negative_prompt, style_selection, use_negative_prompt, num_imgs, seed, width, height, schedule, dpms_guidance_scale, dpms_inference_steps, randomize_seed, ], outputs=[result, seed], api_name="run", ) if __name__ == "__main__": demo.queue(max_size=20).launch() # demo.queue(max_size=20).launch(server_name="0.0.0.0", server_port=11900, debug=True)