|
|
import gradio as gr |
|
|
import torch |
|
|
from diffusers import DiffusionPipeline |
|
|
import numpy as np |
|
|
from PIL import Image |
|
|
import random |
|
|
from typing import List, Tuple, Optional |
|
|
import time |
|
|
|
|
|
|
|
|
def load_model(): |
|
|
"""Load the Stable Diffusion XL model""" |
|
|
pipe = DiffusionPipeline.from_pretrained( |
|
|
"stabilityai/stable-diffusion-xl-base-1.0", |
|
|
torch_dtype=torch.float16, |
|
|
use_safetensors=True, |
|
|
variant="fp16" |
|
|
) |
|
|
if torch.cuda.is_available(): |
|
|
pipe = pipe.to("cuda") |
|
|
return pipe |
|
|
|
|
|
|
|
|
model = None |
|
|
|
|
|
def get_model(): |
|
|
"""Get or create the model instance""" |
|
|
global model |
|
|
if model is None: |
|
|
model = load_model() |
|
|
return model |
|
|
|
|
|
def generate_images( |
|
|
prompt: str, |
|
|
negative_prompt: str = "", |
|
|
uploaded_images: Optional[List] = None, |
|
|
guidance_scale: float = 7.5, |
|
|
num_inference_steps: int = 50, |
|
|
strength: float = 0.8 |
|
|
) -> Tuple[List[Image.Image], str]: |
|
|
""" |
|
|
Generate 4 images using Stable Diffusion XL |
|
|
""" |
|
|
try: |
|
|
pipe = get_model() |
|
|
|
|
|
|
|
|
if not prompt.strip(): |
|
|
prompt = "a beautiful landscape, professional photography, high quality" |
|
|
|
|
|
|
|
|
if uploaded_images and len(uploaded_images) > 0: |
|
|
|
|
|
init_image = uploaded_images[0] |
|
|
if isinstance(init_image, str): |
|
|
init_image = Image.open(init_image) |
|
|
|
|
|
|
|
|
images = [] |
|
|
for i in range(4): |
|
|
result = pipe( |
|
|
prompt=prompt, |
|
|
negative_prompt=negative_prompt, |
|
|
image=init_image, |
|
|
num_images_per_prompt=1, |
|
|
guidance_scale=guidance_scale, |
|
|
num_inference_steps=num_inference_steps, |
|
|
strength=strength |
|
|
) |
|
|
images.append(result.images[0]) |
|
|
else: |
|
|
|
|
|
result = pipe( |
|
|
prompt=prompt, |
|
|
negative_prompt=negative_prompt, |
|
|
num_images_per_prompt=4, |
|
|
guidance_scale=guidance_scale, |
|
|
num_inference_steps=num_inference_steps |
|
|
) |
|
|
images = result.images |
|
|
|
|
|
return images, "✅ Images generated successfully!" |
|
|
|
|
|
except Exception as e: |
|
|
error_msg = f"❌ Error generating images: {str(e)}" |
|
|
return [], error_msg |
|
|
|
|
|
def select_image_for_detail(gallery_data: List, evt: gr.SelectData) -> Tuple[Optional[Image.Image], str]: |
|
|
""" |
|
|
Handle image selection from gallery for detailed view |
|
|
""" |
|
|
if gallery_data and evt.index < len(gallery_data): |
|
|
selected_image = gallery_data[evt.index] |
|
|
if isinstance(selected_image, str): |
|
|
selected_image = Image.open(selected_image) |
|
|
return selected_image, f"📸 Selected image {evt.index + 1} for detailed view" |
|
|
return None, "No image selected" |
|
|
|
|
|
|
|
|
custom_css = """ |
|
|
.main-container { |
|
|
max-width: 1200px; |
|
|
margin: 0 auto; |
|
|
} |
|
|
.gallery-container { |
|
|
border: 2px solid #e0e0e0; |
|
|
border-radius: 8px; |
|
|
padding: 10px; |
|
|
} |
|
|
.selected-image-container { |
|
|
border: 3px solid #4CAF50; |
|
|
border-radius: 8px; |
|
|
padding: 10px; |
|
|
} |
|
|
.generate-btn { |
|
|
background: linear-gradient(45deg, #667eea 0%, #764ba2 100%) !important; |
|
|
} |
|
|
""" |
|
|
|
|
|
|
|
|
with gr.Blocks(css=custom_css, title="Stable Diffusion XL Demo") as demo: |
|
|
gr.HTML(""" |
|
|
<div style="text-align: center; margin-bottom: 20px;"> |
|
|
<h1>🎨 Stable Diffusion XL Image Generator</h1> |
|
|
<p>Generate amazing images with AI - Upload up to 4 images for img2img or use text prompts</p> |
|
|
<p style="font-size: 0.9em; color: #666;"> |
|
|
Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" style="color: #667eea;">anycoder</a> |
|
|
</p> |
|
|
</div> |
|
|
""") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=2): |
|
|
|
|
|
with gr.Group(): |
|
|
gr.Markdown("### 📝 Text Prompts") |
|
|
prompt = gr.Textbox( |
|
|
label="Prompt", |
|
|
placeholder="Describe the image you want to generate...", |
|
|
lines=3, |
|
|
value="a beautiful landscape, professional photography, high quality" |
|
|
) |
|
|
negative_prompt = gr.Textbox( |
|
|
label="Negative Prompt", |
|
|
placeholder="What you don't want in the image...", |
|
|
lines=2, |
|
|
value="blurry, low quality, distorted, deformed" |
|
|
) |
|
|
|
|
|
with gr.Group(): |
|
|
gr.Markdown("### 🖼️ Image Upload (Optional)") |
|
|
uploaded_images = gr.File( |
|
|
label="Upload images for img2img (up to 4)", |
|
|
file_count="multiple", |
|
|
file_types=["image"], |
|
|
height=120 |
|
|
) |
|
|
|
|
|
with gr.Group(): |
|
|
gr.Markdown("### ⚙️ Generation Settings") |
|
|
with gr.Row(): |
|
|
guidance_scale = gr.Slider( |
|
|
label="Guidance Scale", |
|
|
minimum=1.0, |
|
|
maximum=20.0, |
|
|
value=7.5, |
|
|
step=0.5, |
|
|
info="Higher = more prompt adherence" |
|
|
) |
|
|
num_inference_steps = gr.Slider( |
|
|
label="Steps", |
|
|
minimum=10, |
|
|
maximum=100, |
|
|
value=50, |
|
|
step=5, |
|
|
info="More steps = higher quality" |
|
|
) |
|
|
|
|
|
strength = gr.Slider( |
|
|
label="Img2Img Strength", |
|
|
minimum=0.1, |
|
|
maximum=1.0, |
|
|
value=0.8, |
|
|
step=0.1, |
|
|
info="How much to transform the input image" |
|
|
) |
|
|
|
|
|
generate_btn = gr.Button( |
|
|
"🚀 Generate Images", |
|
|
variant="primary", |
|
|
size="lg", |
|
|
elem_classes=["generate-btn"] |
|
|
) |
|
|
|
|
|
status_msg = gr.Textbox(label="Status", interactive=False) |
|
|
|
|
|
with gr.Column(scale=3): |
|
|
|
|
|
with gr.Group(elem_classes=["gallery-container"]): |
|
|
gr.Markdown("### 🎯 Generated Images (Click to select)") |
|
|
gallery = gr.Gallery( |
|
|
label="Generated Images", |
|
|
columns=2, |
|
|
rows=2, |
|
|
height=400, |
|
|
object_fit="cover", |
|
|
allow_preview=True, |
|
|
show_label=False |
|
|
) |
|
|
|
|
|
with gr.Group(elem_classes=["selected-image-container"]): |
|
|
gr.Markdown("### 🔍 Selected Image (Close-up View)") |
|
|
selected_image = gr.Image( |
|
|
label="Selected Image", |
|
|
height=400, |
|
|
show_label=False |
|
|
) |
|
|
selection_info = gr.Textbox(label="Selection Info", interactive=False) |
|
|
|
|
|
|
|
|
generate_btn.click( |
|
|
fn=generate_images, |
|
|
inputs=[ |
|
|
prompt, |
|
|
negative_prompt, |
|
|
uploaded_images, |
|
|
guidance_scale, |
|
|
num_inference_steps, |
|
|
strength |
|
|
], |
|
|
outputs=[gallery, status_msg], |
|
|
show_progress=True |
|
|
) |
|
|
|
|
|
gallery.select( |
|
|
fn=select_image_for_detail, |
|
|
inputs=[gallery], |
|
|
outputs=[selected_image, selection_info] |
|
|
) |
|
|
|
|
|
|
|
|
gr.Examples( |
|
|
examples=[ |
|
|
["a majestic dragon flying over mountains, fantasy art, highly detailed", "cartoon, blurry", None], |
|
|
["a futuristic city skyline at sunset, cyberpunk, neon lights", "daylight, rural", None], |
|
|
["a portrait of a wise old wizard with a long beard, fantasy", "young, modern", None], |
|
|
["a serene japanese garden with cherry blossoms, peaceful", "chaotic, urban", None] |
|
|
], |
|
|
inputs=[prompt, negative_prompt, uploaded_images], |
|
|
cache_examples=False |
|
|
) |
|
|
|
|
|
|
|
|
gr.HTML(""" |
|
|
<div style="text-align: center; margin-top: 30px; padding-top: 20px; border-top: 1px solid #e0e0e0;"> |
|
|
<p style="color: #666; font-size: 0.9em;"> |
|
|
Powered by <a href="https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0" target="_blank">Stability AI</a> • |
|
|
Model: SDXL Base 1.0 • |
|
|
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">Built with anycoder</a> |
|
|
</p> |
|
|
</div> |
|
|
""") |
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch(share=True) |