|
|
import gradio as gr |
|
|
from diffusers import StableDiffusionPipeline |
|
|
import torch |
|
|
import os |
|
|
from PIL import Image |
|
|
import warnings |
|
|
|
|
|
warnings.filterwarnings("ignore") |
|
|
|
|
|
MODEL_NAME = "stabilityai/stable-diffusion-2" |
|
|
CACHE_DIR = "./model_cache" |
|
|
os.makedirs(CACHE_DIR, exist_ok=True) |
|
|
|
|
|
|
|
|
pipe = StableDiffusionPipeline.from_pretrained( |
|
|
MODEL_NAME, |
|
|
torch_dtype=torch.float32, |
|
|
cache_dir=CACHE_DIR, |
|
|
low_cpu_mem_usage=True, |
|
|
safety_checker=None |
|
|
) |
|
|
|
|
|
DISCLAIMER = """ |
|
|
⚠️ **Content Warning** |
|
|
This app generates images based on text prompts. By using this application, you agree to comply with [HuggingFace's Acceptable Use Policy](https://huggingface.co/policies/acceptable-use ). |
|
|
""" |
|
|
|
|
|
def generate_image(prompt, width, height, num_inference_steps=20, guidance_scale=7.0): |
|
|
"""Generate image with strict validation""" |
|
|
if not prompt.strip(): |
|
|
return None, "Error: Prompt cannot be empty" |
|
|
|
|
|
try: |
|
|
|
|
|
width = int(width) if width else 512 |
|
|
height = int(height) if height else 512 |
|
|
|
|
|
|
|
|
width = width - (width % 8) |
|
|
height = height - (height % 8) |
|
|
|
|
|
with torch.inference_mode(): |
|
|
|
|
|
result = pipe( |
|
|
prompt=str(prompt), |
|
|
width=int(width), |
|
|
height=int(height), |
|
|
num_inference_steps=int(num_inference_steps), |
|
|
guidance_scale=float(guidance_scale) |
|
|
) |
|
|
|
|
|
|
|
|
if not hasattr(result, "images") or not isinstance(result.images, list): |
|
|
return None, f"Invalid pipeline output format: {type(result)}" |
|
|
|
|
|
if len(result.images) == 0: |
|
|
return None, "Pipeline returned empty image list" |
|
|
|
|
|
if result.images[0] is None: |
|
|
return None, "Pipeline returned None image" |
|
|
|
|
|
return result.images[0].convert("RGB"), f"Success ({width}x{height})" |
|
|
|
|
|
except Exception as e: |
|
|
return None, f"Generation Error: {str(e)}" |
|
|
|
|
|
|
|
|
ASPECT_RATIOS = { |
|
|
"Square (512x512)": (512, 512), |
|
|
"Portrait (512x768)": (512, 768), |
|
|
"Landscape (768x512)": (768, 512), |
|
|
"Phone (384x832)": (384, 832), |
|
|
"Custom": None |
|
|
} |
|
|
|
|
|
with gr.Blocks(theme="soft", css=".disclaimer {color: #FF4B2B; font-size: 0.9em;}") as demo: |
|
|
gr.Markdown("# 🔞 Text-to-Image Generator\n" + DISCLAIMER) |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
prompt = gr.Textbox( |
|
|
label="Prompt", |
|
|
placeholder="Describe your image...", |
|
|
lines=3 |
|
|
) |
|
|
with gr.Row(): |
|
|
width = gr.Number(value=512, label="Width", interactive=True) |
|
|
height = gr.Number(value=512, label="Height", interactive=True) |
|
|
aspect_ratio = gr.Dropdown( |
|
|
choices=list(ASPECT_RATIOS.keys()), |
|
|
value="Square (512x512)", |
|
|
label="Aspect Ratio" |
|
|
) |
|
|
generate_btn = gr.Button("Generate Image", variant="primary") |
|
|
|
|
|
with gr.Column(): |
|
|
output_image = gr.Image(label="Result", interactive=False) |
|
|
error_msg = gr.Textbox(label="Status", value="Ready", interactive=False) |
|
|
|
|
|
def update_dimensions(choice): |
|
|
if choice == "Custom": |
|
|
return [gr.Number(value=512, interactive=True), gr.Number(value=512, interactive=True)] |
|
|
else: |
|
|
w, h = ASPECT_RATIOS[choice] |
|
|
return [gr.Number(value=w, interactive=True), gr.Number(value=h, interactive=True)] |
|
|
|
|
|
aspect_ratio.change(fn=update_dimensions, inputs=[aspect_ratio], outputs=[width, height]) |
|
|
|
|
|
generate_btn.click( |
|
|
fn=generate_image, |
|
|
inputs=[prompt, width, height], |
|
|
outputs=[output_image, error_msg] |
|
|
) |
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch() |