Spaces:
Sleeping
Sleeping
Fix: remove gr.Progress (breaks API schema in Gradio 5.20, kills all inference)
Browse files
app.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
| 1 |
"""
|
| 2 |
Virtual Try-On — Paint-by-Example + Hugging Face ZeroGPU
|
| 3 |
-
Uses an exemplar garment image to guide inpainting on a person photo.
|
| 4 |
No local GPU or model storage needed.
|
| 5 |
"""
|
| 6 |
|
|
@@ -13,7 +12,7 @@ import torch
|
|
| 13 |
from PIL import Image, ImageDraw
|
| 14 |
|
| 15 |
# ---------------------------------------------------------------------------
|
| 16 |
-
# Persistent storage
|
| 17 |
# ---------------------------------------------------------------------------
|
| 18 |
DATA_DIR = "/data" if os.path.exists("/data") else "/tmp"
|
| 19 |
OUTPUT_DIR = os.path.join(DATA_DIR, "outputs")
|
|
@@ -46,13 +45,22 @@ def _make_mask(size: int, cloth_type: str) -> Image.Image:
|
|
| 46 |
return mask
|
| 47 |
|
| 48 |
# ---------------------------------------------------------------------------
|
| 49 |
-
# GPU
|
| 50 |
# ---------------------------------------------------------------------------
|
| 51 |
_pipe = None
|
| 52 |
|
| 53 |
@spaces.GPU(duration=120)
|
| 54 |
-
def
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
global _pipe
|
| 57 |
if _pipe is None:
|
| 58 |
from diffusers import PaintByExamplePipeline
|
|
@@ -64,6 +72,10 @@ def _run_inference(person: Image.Image, garment: Image.Image, mask: Image.Image,
|
|
| 64 |
_pipe.set_progress_bar_config(disable=True)
|
| 65 |
print("Pipeline ready.")
|
| 66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
rng = torch.Generator(device="cuda")
|
| 68 |
rng.manual_seed(int(seed) if seed != -1 else torch.randint(0, 2**32, (1,)).item())
|
| 69 |
|
|
@@ -75,32 +87,7 @@ def _run_inference(person: Image.Image, garment: Image.Image, mask: Image.Image,
|
|
| 75 |
guidance_scale=guidance_scale,
|
| 76 |
generator=rng,
|
| 77 |
)
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
# ---------------------------------------------------------------------------
|
| 81 |
-
# Gradio inference — uses gr.Progress for live status updates
|
| 82 |
-
# ---------------------------------------------------------------------------
|
| 83 |
-
def run_tryon(
|
| 84 |
-
person_image: Image.Image,
|
| 85 |
-
garment_image: Image.Image,
|
| 86 |
-
cloth_type: str,
|
| 87 |
-
num_steps: int,
|
| 88 |
-
guidance_scale: float,
|
| 89 |
-
seed: int,
|
| 90 |
-
progress=gr.Progress(track_tqdm=True),
|
| 91 |
-
):
|
| 92 |
-
if person_image is None or garment_image is None:
|
| 93 |
-
raise gr.Error("Please upload both a person photo and a garment image.")
|
| 94 |
-
|
| 95 |
-
progress(0, desc="⏳ Requesting GPU + loading model (first run ~3 min)…")
|
| 96 |
-
|
| 97 |
-
person = _fit_to_square(person_image)
|
| 98 |
-
garment = _fit_to_square(garment_image)
|
| 99 |
-
mask = _make_mask(TARGET_SIZE, cloth_type)
|
| 100 |
-
|
| 101 |
-
output_images = _run_inference(person, garment, mask, num_steps, guidance_scale, seed)
|
| 102 |
-
|
| 103 |
-
progress(0.9, desc="💾 Saving result…")
|
| 104 |
|
| 105 |
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
| 106 |
saved_paths = []
|
|
@@ -109,8 +96,7 @@ def run_tryon(
|
|
| 109 |
img.save(path, format="PNG")
|
| 110 |
saved_paths.append(path)
|
| 111 |
|
| 112 |
-
|
| 113 |
-
return output_images, saved_paths, "✅ Done! Download your result below."
|
| 114 |
|
| 115 |
# ---------------------------------------------------------------------------
|
| 116 |
# Gradio UI
|
|
@@ -119,8 +105,9 @@ with gr.Blocks(title="Virtual Try-On", theme=gr.themes.Soft()) as demo:
|
|
| 119 |
gr.Markdown(
|
| 120 |
"# 👗 Virtual Try-On\n"
|
| 121 |
"Upload a **person photo** and a **garment image**, select the type, then click **Try On**.\n\n"
|
| 122 |
-
"> Runs on **Hugging Face ZeroGPU** (free A10G) — no local GPU needed.
|
| 123 |
-
">
|
|
|
|
| 124 |
)
|
| 125 |
|
| 126 |
with gr.Row():
|
|
@@ -140,7 +127,6 @@ with gr.Blocks(title="Virtual Try-On", theme=gr.themes.Soft()) as demo:
|
|
| 140 |
try_btn = gr.Button("👗 Try On", variant="primary", size="lg")
|
| 141 |
|
| 142 |
with gr.Column():
|
| 143 |
-
status_text = gr.Textbox(label="Status", value="Ready", interactive=False, max_lines=1)
|
| 144 |
output_gallery = gr.Gallery(label="Result", columns=1, height=380)
|
| 145 |
output_files = gr.File(
|
| 146 |
label="⬇ Download to your device",
|
|
@@ -151,7 +137,7 @@ with gr.Blocks(title="Virtual Try-On", theme=gr.themes.Soft()) as demo:
|
|
| 151 |
try_btn.click(
|
| 152 |
fn=run_tryon,
|
| 153 |
inputs=[person_input, garment_input, cloth_type, num_steps, guidance, seed_input],
|
| 154 |
-
outputs=[output_gallery, output_files
|
| 155 |
)
|
| 156 |
|
| 157 |
gr.Markdown(
|
|
|
|
| 1 |
"""
|
| 2 |
Virtual Try-On — Paint-by-Example + Hugging Face ZeroGPU
|
|
|
|
| 3 |
No local GPU or model storage needed.
|
| 4 |
"""
|
| 5 |
|
|
|
|
| 12 |
from PIL import Image, ImageDraw
|
| 13 |
|
| 14 |
# ---------------------------------------------------------------------------
|
| 15 |
+
# Persistent storage
|
| 16 |
# ---------------------------------------------------------------------------
|
| 17 |
DATA_DIR = "/data" if os.path.exists("/data") else "/tmp"
|
| 18 |
OUTPUT_DIR = os.path.join(DATA_DIR, "outputs")
|
|
|
|
| 45 |
return mask
|
| 46 |
|
| 47 |
# ---------------------------------------------------------------------------
|
| 48 |
+
# GPU inference
|
| 49 |
# ---------------------------------------------------------------------------
|
| 50 |
_pipe = None
|
| 51 |
|
| 52 |
@spaces.GPU(duration=120)
|
| 53 |
+
def run_tryon(
|
| 54 |
+
person_image: Image.Image,
|
| 55 |
+
garment_image: Image.Image,
|
| 56 |
+
cloth_type: str,
|
| 57 |
+
num_steps: int,
|
| 58 |
+
guidance_scale: float,
|
| 59 |
+
seed: int,
|
| 60 |
+
):
|
| 61 |
+
if person_image is None or garment_image is None:
|
| 62 |
+
raise gr.Error("Please upload both a person photo and a garment image.")
|
| 63 |
+
|
| 64 |
global _pipe
|
| 65 |
if _pipe is None:
|
| 66 |
from diffusers import PaintByExamplePipeline
|
|
|
|
| 72 |
_pipe.set_progress_bar_config(disable=True)
|
| 73 |
print("Pipeline ready.")
|
| 74 |
|
| 75 |
+
person = _fit_to_square(person_image)
|
| 76 |
+
garment = _fit_to_square(garment_image)
|
| 77 |
+
mask = _make_mask(TARGET_SIZE, cloth_type)
|
| 78 |
+
|
| 79 |
rng = torch.Generator(device="cuda")
|
| 80 |
rng.manual_seed(int(seed) if seed != -1 else torch.randint(0, 2**32, (1,)).item())
|
| 81 |
|
|
|
|
| 87 |
guidance_scale=guidance_scale,
|
| 88 |
generator=rng,
|
| 89 |
)
|
| 90 |
+
output_images = result.images
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
|
| 92 |
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
| 93 |
saved_paths = []
|
|
|
|
| 96 |
img.save(path, format="PNG")
|
| 97 |
saved_paths.append(path)
|
| 98 |
|
| 99 |
+
return output_images, saved_paths
|
|
|
|
| 100 |
|
| 101 |
# ---------------------------------------------------------------------------
|
| 102 |
# Gradio UI
|
|
|
|
| 105 |
gr.Markdown(
|
| 106 |
"# 👗 Virtual Try-On\n"
|
| 107 |
"Upload a **person photo** and a **garment image**, select the type, then click **Try On**.\n\n"
|
| 108 |
+
"> Runs on **Hugging Face ZeroGPU** (free A10G) — no local GPU needed.\n\n"
|
| 109 |
+
"> ⏳ After clicking, the button shows a **loading spinner** — that means it is working. \n"
|
| 110 |
+
"> **First run:** ~2-3 min (model download). **Subsequent runs:** ~15-30s."
|
| 111 |
)
|
| 112 |
|
| 113 |
with gr.Row():
|
|
|
|
| 127 |
try_btn = gr.Button("👗 Try On", variant="primary", size="lg")
|
| 128 |
|
| 129 |
with gr.Column():
|
|
|
|
| 130 |
output_gallery = gr.Gallery(label="Result", columns=1, height=380)
|
| 131 |
output_files = gr.File(
|
| 132 |
label="⬇ Download to your device",
|
|
|
|
| 137 |
try_btn.click(
|
| 138 |
fn=run_tryon,
|
| 139 |
inputs=[person_input, garment_input, cloth_type, num_steps, guidance, seed_input],
|
| 140 |
+
outputs=[output_gallery, output_files],
|
| 141 |
)
|
| 142 |
|
| 143 |
gr.Markdown(
|