Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -4,6 +4,7 @@ import time
|
|
| 4 |
import tempfile
|
| 5 |
|
| 6 |
import gradio as gr
|
|
|
|
| 7 |
from PIL import Image
|
| 8 |
from gradio_client import Client, handle_file
|
| 9 |
from huggingface_hub import login
|
|
@@ -35,7 +36,11 @@ def reset_client():
|
|
| 35 |
def get_client():
|
| 36 |
global _client
|
| 37 |
if _client is None:
|
| 38 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
return _client
|
| 40 |
|
| 41 |
|
|
@@ -55,6 +60,10 @@ def save_pil_temp(pil_img: Image.Image, suffix: str = ".png") -> str:
|
|
| 55 |
return path
|
| 56 |
|
| 57 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
def tryon_remote(person_pil, garment_pil, garment_desc, auto_mask, crop_center, denoise_steps, seed):
|
| 59 |
if person_pil is None:
|
| 60 |
return None, "❌ Загрузите фото человека"
|
|
@@ -64,6 +73,11 @@ def tryon_remote(person_pil, garment_pil, garment_desc, auto_mask, crop_center,
|
|
| 64 |
denoise_steps = clamp_int(denoise_steps, 10, 40)
|
| 65 |
seed = clamp_int(seed, 0, 999999)
|
| 66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
p_path = save_pil_temp(person_pil)
|
| 68 |
g_path = save_pil_temp(garment_pil)
|
| 69 |
|
|
@@ -77,7 +91,7 @@ def tryon_remote(person_pil, garment_pil, garment_desc, auto_mask, crop_center,
|
|
| 77 |
result = client.predict(
|
| 78 |
dict={"background": handle_file(p_path), "layers": [], "composite": None},
|
| 79 |
garm_img=handle_file(g_path),
|
| 80 |
-
garment_des=garment_desc,
|
| 81 |
is_checked=bool(auto_mask),
|
| 82 |
is_checked_crop=bool(crop_center),
|
| 83 |
denoise_steps=int(denoise_steps),
|
|
@@ -88,6 +102,8 @@ def tryon_remote(person_pil, garment_pil, garment_desc, auto_mask, crop_center,
|
|
| 88 |
if isinstance(result, (list, tuple)):
|
| 89 |
result = result[0]
|
| 90 |
|
|
|
|
|
|
|
| 91 |
out = Image.open(result).convert("RGB")
|
| 92 |
return out, f"✅ Готово (steps={denoise_steps}, seed={seed}, crop={crop_center})"
|
| 93 |
|
|
@@ -110,9 +126,12 @@ def tryon_remote(person_pil, garment_pil, garment_desc, auto_mask, crop_center,
|
|
| 110 |
or "zerogpu" in msg
|
| 111 |
)
|
| 112 |
|
| 113 |
-
|
|
|
|
|
|
|
|
|
|
| 114 |
reset_client()
|
| 115 |
-
time.sleep(
|
| 116 |
continue
|
| 117 |
|
| 118 |
time.sleep(1.2 * attempt)
|
|
@@ -128,7 +147,7 @@ def tryon_remote(person_pil, garment_pil, garment_desc, auto_mask, crop_center,
|
|
| 128 |
|
| 129 |
|
| 130 |
def reset_ui():
|
| 131 |
-
return None, None,
|
| 132 |
|
| 133 |
|
| 134 |
CUSTOM_CSS = """
|
|
@@ -138,7 +157,8 @@ div[class*="footer"] {display:none !important;}
|
|
| 138 |
button[aria-label="Settings"] {display:none !important;}
|
| 139 |
"""
|
| 140 |
|
| 141 |
-
|
|
|
|
| 142 |
gr.Markdown("# Virtual Try-On Rendez-vous")
|
| 143 |
|
| 144 |
with gr.Row():
|
|
@@ -148,7 +168,7 @@ with gr.Blocks(title="Virtual Try-On Rendez-vous") as demo:
|
|
| 148 |
|
| 149 |
garment_desc = gr.Textbox(
|
| 150 |
label="Описание одежды",
|
| 151 |
-
value=""
|
| 152 |
)
|
| 153 |
|
| 154 |
with gr.Accordion("Настройки", open=False):
|
|
@@ -175,7 +195,7 @@ with gr.Blocks(title="Virtual Try-On Rendez-vous") as demo:
|
|
| 175 |
reset.click(
|
| 176 |
fn=reset_ui,
|
| 177 |
inputs=[],
|
| 178 |
-
outputs=[person, garment,
|
| 179 |
)
|
| 180 |
|
| 181 |
if __name__ == "__main__":
|
|
@@ -184,6 +204,5 @@ if __name__ == "__main__":
|
|
| 184 |
server_port=7860,
|
| 185 |
share=False,
|
| 186 |
debug=False,
|
| 187 |
-
css=CUSTOM_CSS,
|
| 188 |
ssr_mode=False
|
| 189 |
)
|
|
|
|
| 4 |
import tempfile
|
| 5 |
|
| 6 |
import gradio as gr
|
| 7 |
+
import spaces # ✅ required for ZeroGPU (needs at least one @spaces.GPU function)
|
| 8 |
from PIL import Image
|
| 9 |
from gradio_client import Client, handle_file
|
| 10 |
from huggingface_hub import login
|
|
|
|
| 36 |
def get_client():
|
| 37 |
global _client
|
| 38 |
if _client is None:
|
| 39 |
+
# HF_TOKEN может помочь при приватных спейсах / ограничениях
|
| 40 |
+
if HF_TOKEN:
|
| 41 |
+
_client = Client(SPACE, hf_token=HF_TOKEN)
|
| 42 |
+
else:
|
| 43 |
+
_client = Client(SPACE)
|
| 44 |
return _client
|
| 45 |
|
| 46 |
|
|
|
|
| 60 |
return path
|
| 61 |
|
| 62 |
|
| 63 |
+
# ✅ ZeroGPU: должна быть хотя бы одна функция, помеченная @spaces.GPU
|
| 64 |
+
# ВАЖНО: в твоём текущем решении GPU локально не используется (ты вызываешь удалённый Space),
|
| 65 |
+
# но декоратор нужен, чтобы ZeroGPU runtime не падал на старте.
|
| 66 |
+
@spaces.GPU(duration=180)
|
| 67 |
def tryon_remote(person_pil, garment_pil, garment_desc, auto_mask, crop_center, denoise_steps, seed):
|
| 68 |
if person_pil is None:
|
| 69 |
return None, "❌ Загрузите фото человека"
|
|
|
|
| 73 |
denoise_steps = clamp_int(denoise_steps, 10, 40)
|
| 74 |
seed = clamp_int(seed, 0, 999999)
|
| 75 |
|
| 76 |
+
# если описание пустое — дадим нейтральный дефолт (повышает стабильность)
|
| 77 |
+
garment_desc = (garment_desc or "").strip()
|
| 78 |
+
if not garment_desc:
|
| 79 |
+
garment_desc = "a photo of a garment"
|
| 80 |
+
|
| 81 |
p_path = save_pil_temp(person_pil)
|
| 82 |
g_path = save_pil_temp(garment_pil)
|
| 83 |
|
|
|
|
| 91 |
result = client.predict(
|
| 92 |
dict={"background": handle_file(p_path), "layers": [], "composite": None},
|
| 93 |
garm_img=handle_file(g_path),
|
| 94 |
+
garment_des=garment_desc,
|
| 95 |
is_checked=bool(auto_mask),
|
| 96 |
is_checked_crop=bool(crop_center),
|
| 97 |
denoise_steps=int(denoise_steps),
|
|
|
|
| 102 |
if isinstance(result, (list, tuple)):
|
| 103 |
result = result[0]
|
| 104 |
|
| 105 |
+
# result обычно путь к файлу (temp) или URL — Image.open умеет путь,
|
| 106 |
+
# но если придёт нечто странное, поймаем исключение ниже.
|
| 107 |
out = Image.open(result).convert("RGB")
|
| 108 |
return out, f"✅ Готово (steps={denoise_steps}, seed={seed}, crop={crop_center})"
|
| 109 |
|
|
|
|
| 126 |
or "zerogpu" in msg
|
| 127 |
)
|
| 128 |
|
| 129 |
+
# ✅ ключевая правка под ZeroGPU-прокси
|
| 130 |
+
is_expired = "expired zerogpu proxy token" in msg or "zerogpu proxy token" in msg
|
| 131 |
+
|
| 132 |
+
if is_timeout or is_busy or is_expired:
|
| 133 |
reset_client()
|
| 134 |
+
time.sleep(4.0 * attempt)
|
| 135 |
continue
|
| 136 |
|
| 137 |
time.sleep(1.2 * attempt)
|
|
|
|
| 147 |
|
| 148 |
|
| 149 |
def reset_ui():
|
| 150 |
+
return None, None, "", "Ожидание...", None
|
| 151 |
|
| 152 |
|
| 153 |
CUSTOM_CSS = """
|
|
|
|
| 157 |
button[aria-label="Settings"] {display:none !important;}
|
| 158 |
"""
|
| 159 |
|
| 160 |
+
# ✅ CSS правильно задаём на уровне Blocks
|
| 161 |
+
with gr.Blocks(title="Virtual Try-On Rendez-vous", css=CUSTOM_CSS) as demo:
|
| 162 |
gr.Markdown("# Virtual Try-On Rendez-vous")
|
| 163 |
|
| 164 |
with gr.Row():
|
|
|
|
| 168 |
|
| 169 |
garment_desc = gr.Textbox(
|
| 170 |
label="Описание одежды",
|
| 171 |
+
value=""
|
| 172 |
)
|
| 173 |
|
| 174 |
with gr.Accordion("Настройки", open=False):
|
|
|
|
| 195 |
reset.click(
|
| 196 |
fn=reset_ui,
|
| 197 |
inputs=[],
|
| 198 |
+
outputs=[person, garment, garment_desc, status, out]
|
| 199 |
)
|
| 200 |
|
| 201 |
if __name__ == "__main__":
|
|
|
|
| 204 |
server_port=7860,
|
| 205 |
share=False,
|
| 206 |
debug=False,
|
|
|
|
| 207 |
ssr_mode=False
|
| 208 |
)
|