appsnprojectsstpl-tech commited on
Commit ·
0cba1d4
1
Parent(s): f545704
Switch to Instruct-Pix2Pix
Browse files
app.py
CHANGED
|
@@ -1,299 +1,127 @@
|
|
| 1 |
import torch
|
| 2 |
import spaces
|
| 3 |
import gradio as gr
|
| 4 |
-
from diffusers import
|
| 5 |
from diffusers.utils import load_image
|
| 6 |
-
import PIL.Image
|
| 7 |
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
"
|
| 12 |
-
torch_dtype=torch.
|
| 13 |
-
|
| 14 |
-
)
|
| 15 |
-
pipe.to("cuda")
|
| 16 |
-
|
| 17 |
-
try:
|
| 18 |
-
print("Loading Image-to-Image pipeline...")
|
| 19 |
-
pipe_i2i = AutoPipelineForImage2Image.from_pipe(pipe)
|
| 20 |
-
except Exception as e:
|
| 21 |
-
print(f"Warning: Could not load Img2Img pipeline: {e}")
|
| 22 |
-
pipe_i2i = None
|
| 23 |
|
| 24 |
-
#
|
| 25 |
-
|
| 26 |
-
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
-
print("
|
| 29 |
|
| 30 |
@spaces.GPU
|
| 31 |
-
def
|
| 32 |
-
"""Generate or edit an image from the given prompt and optional input image."""
|
| 33 |
if randomize_seed:
|
| 34 |
seed = torch.randint(0, 2**32 - 1, (1,)).item()
|
| 35 |
-
|
| 36 |
generator = torch.Generator("cuda").manual_seed(int(seed))
|
| 37 |
|
|
|
|
|
|
|
|
|
|
| 38 |
if input_image is not None:
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
# Resize
|
| 42 |
-
input_image = input_image.resize((
|
| 43 |
-
|
| 44 |
-
|
|
|
|
| 45 |
image=input_image,
|
| 46 |
-
strength=strength,
|
| 47 |
num_inference_steps=int(num_inference_steps),
|
| 48 |
-
|
|
|
|
| 49 |
generator=generator,
|
| 50 |
).images[0]
|
| 51 |
else:
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
width=int(width),
|
| 56 |
num_inference_steps=int(num_inference_steps),
|
| 57 |
-
guidance_scale=
|
| 58 |
generator=generator,
|
| 59 |
).images[0]
|
| 60 |
-
|
| 61 |
return image, seed
|
| 62 |
|
| 63 |
-
#
|
| 64 |
-
examples = [
|
| 65 |
-
["Young Chinese woman in red Hanfu, intricate embroidery. Impeccable makeup, red floral forehead pattern. Elaborate high bun, golden phoenix headdress, red flowers, beads. Holds round folding fan with lady, trees, bird. Neon lightning-bolt lamp, bright yellow glow, above extended left palm. Soft-lit outdoor night background, silhouetted tiered pagoda, blurred colorful distant lights."],
|
| 66 |
-
["A majestic dragon soaring through clouds at sunset, scales shimmering with iridescent colors, detailed fantasy art style"],
|
| 67 |
-
["Cozy coffee shop interior, warm lighting, rain on windows, plants on shelves, vintage aesthetic, photorealistic"],
|
| 68 |
-
["Astronaut riding a horse on Mars, cinematic lighting, sci-fi concept art, highly detailed"],
|
| 69 |
-
["Portrait of a wise old wizard with a long white beard, holding a glowing crystal staff, magical forest background"],
|
| 70 |
-
]
|
| 71 |
-
|
| 72 |
-
# Custom theme with modern aesthetics (Gradio 6)
|
| 73 |
custom_theme = gr.themes.Soft(
|
| 74 |
-
primary_hue="
|
| 75 |
-
secondary_hue="
|
| 76 |
-
neutral_hue="slate",
|
| 77 |
font=gr.themes.GoogleFont("Inter"),
|
| 78 |
-
text_size="lg",
|
| 79 |
-
spacing_size="md",
|
| 80 |
-
radius_size="lg"
|
| 81 |
-
).set(
|
| 82 |
-
button_primary_background_fill="*primary_500",
|
| 83 |
-
button_primary_background_fill_hover="*primary_600",
|
| 84 |
-
block_title_text_weight="600",
|
| 85 |
)
|
| 86 |
|
| 87 |
-
|
| 88 |
-
with gr.Blocks(fill_height=True) as demo:
|
| 89 |
-
# Header
|
| 90 |
gr.Markdown(
|
| 91 |
"""
|
| 92 |
-
# 🎨
|
| 93 |
-
|
| 94 |
-
"""
|
| 95 |
-
elem_classes="header-text"
|
| 96 |
)
|
| 97 |
|
| 98 |
-
with gr.Row(
|
| 99 |
-
|
| 100 |
-
with gr.Column(scale=1, min_width=320):
|
| 101 |
prompt = gr.Textbox(
|
| 102 |
-
label="✨
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
autofocus=True,
|
| 107 |
)
|
| 108 |
-
|
| 109 |
input_image = gr.Image(
|
| 110 |
-
label="🖼️ Input Image (Optional
|
| 111 |
-
type="pil"
|
| 112 |
-
height=256,
|
| 113 |
)
|
| 114 |
|
| 115 |
with gr.Accordion("⚙️ Advanced Settings", open=False):
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
width = gr.Slider(
|
| 126 |
-
minimum=512,
|
| 127 |
-
maximum=2048,
|
| 128 |
-
value=1024,
|
| 129 |
-
step=64,
|
| 130 |
-
label="Width",
|
| 131 |
-
info="Image width in pixels"
|
| 132 |
-
)
|
| 133 |
-
|
| 134 |
-
num_inference_steps = gr.Slider(
|
| 135 |
-
minimum=1,
|
| 136 |
-
maximum=20,
|
| 137 |
-
value=9,
|
| 138 |
-
step=1,
|
| 139 |
-
label="Inference Steps",
|
| 140 |
-
info="9 steps = 8 DiT forwards (recommended)"
|
| 141 |
-
)
|
| 142 |
-
|
| 143 |
-
strength = gr.Slider(
|
| 144 |
-
minimum=0.0,
|
| 145 |
-
maximum=1.0,
|
| 146 |
-
value=0.5,
|
| 147 |
-
step=0.05,
|
| 148 |
-
label="Denoising Strength (For Image-to-Image)",
|
| 149 |
-
info="Higher values = more changes from input image"
|
| 150 |
)
|
| 151 |
|
| 152 |
with gr.Row():
|
| 153 |
-
randomize_seed = gr.Checkbox(
|
| 154 |
-
|
| 155 |
-
value=True,
|
| 156 |
-
)
|
| 157 |
-
seed = gr.Number(
|
| 158 |
-
label="Seed",
|
| 159 |
-
value=42,
|
| 160 |
-
precision=0,
|
| 161 |
-
visible=False,
|
| 162 |
-
)
|
| 163 |
-
|
| 164 |
-
def toggle_seed(randomize):
|
| 165 |
-
return gr.Number(visible=not randomize)
|
| 166 |
|
| 167 |
randomize_seed.change(
|
| 168 |
-
|
| 169 |
-
inputs=[randomize_seed],
|
| 170 |
outputs=[seed]
|
| 171 |
)
|
|
|
|
|
|
|
| 172 |
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
)
|
| 179 |
-
|
| 180 |
-
# Example prompts
|
| 181 |
-
gr.Examples(
|
| 182 |
-
examples=examples,
|
| 183 |
-
inputs=[prompt],
|
| 184 |
-
label="💡 Try these prompts",
|
| 185 |
-
examples_per_page=5,
|
| 186 |
-
)
|
| 187 |
-
|
| 188 |
-
# Right column - Output
|
| 189 |
-
with gr.Column(scale=1, min_width=320):
|
| 190 |
-
output_image = gr.Image(
|
| 191 |
-
label="Generated Image",
|
| 192 |
-
type="pil",
|
| 193 |
-
format="png",
|
| 194 |
-
show_label=False,
|
| 195 |
-
height=600,
|
| 196 |
-
buttons=["download", "share"],
|
| 197 |
-
)
|
| 198 |
-
|
| 199 |
-
used_seed = gr.Number(
|
| 200 |
-
label="🎲 Seed Used",
|
| 201 |
-
interactive=False,
|
| 202 |
-
container=True,
|
| 203 |
-
)
|
| 204 |
-
|
| 205 |
-
# Footer credits
|
| 206 |
-
gr.Markdown(
|
| 207 |
-
"""
|
| 208 |
-
---
|
| 209 |
-
<div style="text-align: center; opacity: 0.7; font-size: 0.9em; margin-top: 1rem;">
|
| 210 |
-
<strong>Model:</strong> <a href="https://huggingface.co/Tongyi-MAI/Z-Image-Turbo" target="_blank">Tongyi-MAI/Z-Image-Turbo</a> (Apache 2.0 License) •
|
| 211 |
-
<strong>Demo by:</strong> <a href="https://x.com/realmrfakename" target="_blank">@mrfakename</a> •
|
| 212 |
-
<strong>Redesign by:</strong> AnyCoder •
|
| 213 |
-
<strong>Optimizations:</strong> <a href="https://huggingface.co/multimodalart" target="_blank">@multimodalart</a> (FA3 + AoTI)
|
| 214 |
-
</div>
|
| 215 |
-
""",
|
| 216 |
-
elem_classes="footer-text"
|
| 217 |
-
)
|
| 218 |
-
|
| 219 |
-
# Connect the generate button
|
| 220 |
generate_btn.click(
|
| 221 |
-
fn=
|
| 222 |
-
inputs=[prompt, input_image,
|
| 223 |
-
outputs=[output_image, used_seed]
|
| 224 |
)
|
| 225 |
-
|
| 226 |
-
# Also allow generating by pressing Enter in the prompt box
|
| 227 |
prompt.submit(
|
| 228 |
-
fn=
|
| 229 |
-
inputs=[prompt, input_image,
|
| 230 |
-
outputs=[output_image, used_seed]
|
| 231 |
)
|
| 232 |
|
| 233 |
if __name__ == "__main__":
|
| 234 |
-
demo.launch(
|
| 235 |
-
theme=custom_theme,
|
| 236 |
-
css="""
|
| 237 |
-
.header-text h1 {
|
| 238 |
-
font-size: 2.5rem !important;
|
| 239 |
-
font-weight: 700 !important;
|
| 240 |
-
margin-bottom: 0.5rem !important;
|
| 241 |
-
background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
|
| 242 |
-
-webkit-background-clip: text;
|
| 243 |
-
-webkit-text-fill-color: transparent;
|
| 244 |
-
background-clip: text;
|
| 245 |
-
}
|
| 246 |
-
|
| 247 |
-
.header-text p {
|
| 248 |
-
font-size: 1.1rem !important;
|
| 249 |
-
color: #64748b !important;
|
| 250 |
-
margin-top: 0 !important;
|
| 251 |
-
}
|
| 252 |
-
|
| 253 |
-
.footer-text {
|
| 254 |
-
padding: 1rem 0;
|
| 255 |
-
}
|
| 256 |
-
|
| 257 |
-
.footer-text a {
|
| 258 |
-
color: #f59e0b !important;
|
| 259 |
-
text-decoration: none !important;
|
| 260 |
-
font-weight: 500;
|
| 261 |
-
}
|
| 262 |
-
|
| 263 |
-
.footer-text a:hover {
|
| 264 |
-
text-decoration: underline !important;
|
| 265 |
-
}
|
| 266 |
-
|
| 267 |
-
/* Mobile optimizations */
|
| 268 |
-
@media (max-width: 768px) {
|
| 269 |
-
.header-text h1 {
|
| 270 |
-
font-size: 1.8rem !important;
|
| 271 |
-
}
|
| 272 |
-
|
| 273 |
-
.header-text p {
|
| 274 |
-
font-size: 1rem !important;
|
| 275 |
-
}
|
| 276 |
-
}
|
| 277 |
-
|
| 278 |
-
/* Smooth transitions */
|
| 279 |
-
button, .gr-button {
|
| 280 |
-
transition: all 0.2s ease !important;
|
| 281 |
-
}
|
| 282 |
-
|
| 283 |
-
button:hover, .gr-button:hover {
|
| 284 |
-
transform: translateY(-1px);
|
| 285 |
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
|
| 286 |
-
}
|
| 287 |
-
|
| 288 |
-
/* Better spacing */
|
| 289 |
-
.gradio-container {
|
| 290 |
-
max-width: 1400px !important;
|
| 291 |
-
margin: 0 auto !important;
|
| 292 |
-
}
|
| 293 |
-
""",
|
| 294 |
-
footer_links=[
|
| 295 |
-
"api",
|
| 296 |
-
"gradio"
|
| 297 |
-
],
|
| 298 |
-
mcp_server=True
|
| 299 |
-
)
|
|
|
|
| 1 |
import torch
|
| 2 |
import spaces
|
| 3 |
import gradio as gr
|
| 4 |
+
from diffusers import StableDiffusionInstructPix2PixPipeline, StableDiffusionPipeline
|
| 5 |
from diffusers.utils import load_image
|
|
|
|
| 6 |
|
| 7 |
+
print("Loading Models...")
|
| 8 |
+
# 1. Text-to-Image Model (Standard Generation)
|
| 9 |
+
pipe_t2i = StableDiffusionPipeline.from_pretrained(
|
| 10 |
+
"runwayml/stable-diffusion-v1-5",
|
| 11 |
+
torch_dtype=torch.float16,
|
| 12 |
+
safety_checker=None
|
| 13 |
+
).to("cuda")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
+
# 2. Instruct-Pix2Pix Model (Instruction-Based Editing)
|
| 16 |
+
pipe_edit = StableDiffusionInstructPix2PixPipeline.from_pretrained(
|
| 17 |
+
"timbrooks/instruct-pix2pix",
|
| 18 |
+
torch_dtype=torch.float16,
|
| 19 |
+
safety_checker=None
|
| 20 |
+
).to("cuda")
|
| 21 |
|
| 22 |
+
print("Models loaded successfully!")
|
| 23 |
|
| 24 |
@spaces.GPU
|
| 25 |
+
def generate_or_edit(prompt, input_image, image_guidance_scale, guidance_scale, num_inference_steps, seed, randomize_seed, progress=gr.Progress(track_tqdm=True)):
|
|
|
|
| 26 |
if randomize_seed:
|
| 27 |
seed = torch.randint(0, 2**32 - 1, (1,)).item()
|
|
|
|
| 28 |
generator = torch.Generator("cuda").manual_seed(int(seed))
|
| 29 |
|
| 30 |
+
if not prompt:
|
| 31 |
+
raise gr.Error("Please enter a prompt or instruction!")
|
| 32 |
+
|
| 33 |
if input_image is not None:
|
| 34 |
+
# Edit mode
|
| 35 |
+
input_image = input_image.convert("RGB")
|
| 36 |
+
# Resize image for SD1.5 (InstructPix2Pix)
|
| 37 |
+
input_image = input_image.resize((512, 512))
|
| 38 |
+
|
| 39 |
+
image = pipe_edit(
|
| 40 |
+
prompt,
|
| 41 |
image=input_image,
|
|
|
|
| 42 |
num_inference_steps=int(num_inference_steps),
|
| 43 |
+
image_guidance_scale=image_guidance_scale,
|
| 44 |
+
guidance_scale=guidance_scale,
|
| 45 |
generator=generator,
|
| 46 |
).images[0]
|
| 47 |
else:
|
| 48 |
+
# Generate mode
|
| 49 |
+
image = pipe_t2i(
|
| 50 |
+
prompt,
|
|
|
|
| 51 |
num_inference_steps=int(num_inference_steps),
|
| 52 |
+
guidance_scale=guidance_scale,
|
| 53 |
generator=generator,
|
| 54 |
).images[0]
|
| 55 |
+
|
| 56 |
return image, seed
|
| 57 |
|
| 58 |
+
# Build the Gradio interface
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
custom_theme = gr.themes.Soft(
|
| 60 |
+
primary_hue="blue",
|
| 61 |
+
secondary_hue="indigo",
|
|
|
|
| 62 |
font=gr.themes.GoogleFont("Inter"),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
)
|
| 64 |
|
| 65 |
+
with gr.Blocks(theme=custom_theme, fill_height=True) as demo:
|
|
|
|
|
|
|
| 66 |
gr.Markdown(
|
| 67 |
"""
|
| 68 |
+
# 🎨 AI Image Studio (Generation & Instruction Editing)
|
| 69 |
+
Generate images from scratch, or upload an image and use a prompt like *"Make him wear sunglasses"* to edit it seamlessly.
|
| 70 |
+
"""
|
|
|
|
| 71 |
)
|
| 72 |
|
| 73 |
+
with gr.Row():
|
| 74 |
+
with gr.Column(scale=1):
|
|
|
|
| 75 |
prompt = gr.Textbox(
|
| 76 |
+
label="✨ Instruction / Prompt",
|
| 77 |
+
lines=3,
|
| 78 |
+
placeholder="e.g. 'A futuristic city at night' (for generation) OR 'Turn the daytime into nighttime' (for editing)",
|
| 79 |
+
autofocus=True
|
|
|
|
| 80 |
)
|
|
|
|
| 81 |
input_image = gr.Image(
|
| 82 |
+
label="🖼️ Input Image (Optional - Leave blank to generate from scratch)",
|
| 83 |
+
type="pil"
|
|
|
|
| 84 |
)
|
| 85 |
|
| 86 |
with gr.Accordion("⚙️ Advanced Settings", open=False):
|
| 87 |
+
num_inference_steps = gr.Slider(minimum=10, maximum=50, value=30, step=1, label="Inference Steps")
|
| 88 |
+
guidance_scale = gr.Slider(minimum=1.0, maximum=15.0, value=7.5, step=0.5, label="Text Guidance Scale")
|
| 89 |
+
image_guidance_scale = gr.Slider(
|
| 90 |
+
minimum=1.0,
|
| 91 |
+
maximum=3.0,
|
| 92 |
+
value=1.5,
|
| 93 |
+
step=0.1,
|
| 94 |
+
label="Image Guidance Scale (Editing Only)",
|
| 95 |
+
info="Lower values = more changes. Higher values = stays closer to original image."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
)
|
| 97 |
|
| 98 |
with gr.Row():
|
| 99 |
+
randomize_seed = gr.Checkbox(label="🎲 Random Seed", value=True)
|
| 100 |
+
seed = gr.Number(label="Seed", value=42, precision=0, visible=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
|
| 102 |
randomize_seed.change(
|
| 103 |
+
lambda r: gr.Number(visible=not r),
|
| 104 |
+
inputs=[randomize_seed],
|
| 105 |
outputs=[seed]
|
| 106 |
)
|
| 107 |
+
|
| 108 |
+
generate_btn = gr.Button("🚀 Generate / Edit Image", variant="primary", size="lg")
|
| 109 |
|
| 110 |
+
with gr.Column(scale=1):
|
| 111 |
+
output_image = gr.Image(label="Result", type="pil", interactive=False)
|
| 112 |
+
used_seed = gr.Number(label="Seed Used", interactive=False)
|
| 113 |
+
|
| 114 |
+
# Connections
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
generate_btn.click(
|
| 116 |
+
fn=generate_or_edit,
|
| 117 |
+
inputs=[prompt, input_image, image_guidance_scale, guidance_scale, num_inference_steps, seed, randomize_seed],
|
| 118 |
+
outputs=[output_image, used_seed]
|
| 119 |
)
|
|
|
|
|
|
|
| 120 |
prompt.submit(
|
| 121 |
+
fn=generate_or_edit,
|
| 122 |
+
inputs=[prompt, input_image, image_guidance_scale, guidance_scale, num_inference_steps, seed, randomize_seed],
|
| 123 |
+
outputs=[output_image, used_seed]
|
| 124 |
)
|
| 125 |
|
| 126 |
if __name__ == "__main__":
|
| 127 |
+
demo.launch()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|