Spaces:
Sleeping
Sleeping
Fix streaming: split into outer generator + inner @spaces.GPU function
Browse files
app.py
CHANGED
|
@@ -23,25 +23,6 @@ os.makedirs(OUTPUT_DIR, exist_ok=True)
|
|
| 23 |
os.environ["HF_HOME"] = os.path.join(DATA_DIR, "hf_cache")
|
| 24 |
os.environ["HUGGINGFACE_HUB_CACHE"] = os.path.join(DATA_DIR, "hf_cache", "hub")
|
| 25 |
|
| 26 |
-
# ---------------------------------------------------------------------------
|
| 27 |
-
# Pipeline (loaded lazily inside @spaces.GPU to avoid wasting GPU quota)
|
| 28 |
-
# ---------------------------------------------------------------------------
|
| 29 |
-
_pipe = None
|
| 30 |
-
|
| 31 |
-
def _get_pipe():
|
| 32 |
-
global _pipe
|
| 33 |
-
if _pipe is not None:
|
| 34 |
-
return _pipe
|
| 35 |
-
from diffusers import PaintByExamplePipeline
|
| 36 |
-
print("Loading Paint-by-Example pipeline (~5 GB, first run only)…")
|
| 37 |
-
_pipe = PaintByExamplePipeline.from_pretrained(
|
| 38 |
-
"Fantasy-Studio/Paint-by-Example",
|
| 39 |
-
torch_dtype=torch.float16,
|
| 40 |
-
).to("cuda")
|
| 41 |
-
_pipe.set_progress_bar_config(disable=True)
|
| 42 |
-
print("Pipeline ready on CUDA.")
|
| 43 |
-
return _pipe
|
| 44 |
-
|
| 45 |
# ---------------------------------------------------------------------------
|
| 46 |
# Image helpers
|
| 47 |
# ---------------------------------------------------------------------------
|
|
@@ -66,9 +47,40 @@ def _make_mask(size: int, cloth_type: str) -> Image.Image:
|
|
| 66 |
return mask
|
| 67 |
|
| 68 |
# ---------------------------------------------------------------------------
|
| 69 |
-
#
|
| 70 |
# ---------------------------------------------------------------------------
|
|
|
|
|
|
|
| 71 |
@spaces.GPU(duration=120)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
def run_tryon(
|
| 73 |
person_image: Image.Image,
|
| 74 |
garment_image: Image.Image,
|
|
@@ -80,28 +92,13 @@ def run_tryon(
|
|
| 80 |
if person_image is None or garment_image is None:
|
| 81 |
raise gr.Error("Please upload both a person photo and a garment image.")
|
| 82 |
|
| 83 |
-
yield [], [], "⏳ GPU
|
| 84 |
-
|
| 85 |
-
pipe = _get_pipe()
|
| 86 |
|
| 87 |
person = _fit_to_square(person_image)
|
| 88 |
garment = _fit_to_square(garment_image)
|
| 89 |
mask = _make_mask(TARGET_SIZE, cloth_type)
|
| 90 |
|
| 91 |
-
|
| 92 |
-
rng.manual_seed(int(seed) if seed != -1 else torch.randint(0, 2**32, (1,)).item())
|
| 93 |
-
|
| 94 |
-
yield [], [], f"🎨 Running {num_steps} diffusion steps…"
|
| 95 |
-
|
| 96 |
-
result = pipe(
|
| 97 |
-
image=person,
|
| 98 |
-
mask_image=mask,
|
| 99 |
-
example_image=garment,
|
| 100 |
-
num_inference_steps=num_steps,
|
| 101 |
-
guidance_scale=guidance_scale,
|
| 102 |
-
generator=rng,
|
| 103 |
-
)
|
| 104 |
-
output_images = result.images
|
| 105 |
|
| 106 |
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
| 107 |
saved_paths = []
|
|
|
|
| 23 |
os.environ["HF_HOME"] = os.path.join(DATA_DIR, "hf_cache")
|
| 24 |
os.environ["HUGGINGFACE_HUB_CACHE"] = os.path.join(DATA_DIR, "hf_cache", "hub")
|
| 25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
# ---------------------------------------------------------------------------
|
| 27 |
# Image helpers
|
| 28 |
# ---------------------------------------------------------------------------
|
|
|
|
| 47 |
return mask
|
| 48 |
|
| 49 |
# ---------------------------------------------------------------------------
|
| 50 |
+
# GPU-decorated inference — plain return, no yield (spaces.GPU doesn't stream)
|
| 51 |
# ---------------------------------------------------------------------------
|
| 52 |
+
_pipe = None
|
| 53 |
+
|
| 54 |
@spaces.GPU(duration=120)
|
| 55 |
+
def _run_inference(person: Image.Image, garment: Image.Image, mask: Image.Image,
|
| 56 |
+
num_steps: int, guidance_scale: float, seed: int):
|
| 57 |
+
global _pipe
|
| 58 |
+
if _pipe is None:
|
| 59 |
+
from diffusers import PaintByExamplePipeline
|
| 60 |
+
print("Loading Paint-by-Example pipeline (~5 GB, first run only)…")
|
| 61 |
+
_pipe = PaintByExamplePipeline.from_pretrained(
|
| 62 |
+
"Fantasy-Studio/Paint-by-Example",
|
| 63 |
+
torch_dtype=torch.float16,
|
| 64 |
+
).to("cuda")
|
| 65 |
+
_pipe.set_progress_bar_config(disable=True)
|
| 66 |
+
print("Pipeline ready on CUDA.")
|
| 67 |
+
|
| 68 |
+
rng = torch.Generator(device="cuda")
|
| 69 |
+
rng.manual_seed(int(seed) if seed != -1 else torch.randint(0, 2**32, (1,)).item())
|
| 70 |
+
|
| 71 |
+
result = _pipe(
|
| 72 |
+
image=person,
|
| 73 |
+
mask_image=mask,
|
| 74 |
+
example_image=garment,
|
| 75 |
+
num_inference_steps=num_steps,
|
| 76 |
+
guidance_scale=guidance_scale,
|
| 77 |
+
generator=rng,
|
| 78 |
+
)
|
| 79 |
+
return result.images
|
| 80 |
+
|
| 81 |
+
# ---------------------------------------------------------------------------
|
| 82 |
+
# Outer generator — handles status streaming to Gradio UI
|
| 83 |
+
# ---------------------------------------------------------------------------
|
| 84 |
def run_tryon(
|
| 85 |
person_image: Image.Image,
|
| 86 |
garment_image: Image.Image,
|
|
|
|
| 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 |
+
yield [], [], "⏳ Requesting GPU + loading model… (first run ~3 min, then ~30s)"
|
|
|
|
|
|
|
| 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 |
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
| 104 |
saved_paths = []
|