import gradio as gr from gradio_client import Client, handle_file from PIL import Image import tempfile, os, time, random # ══════════════════════════════════════════════════════════════ # More VTON spaces to try — updated 2026 list # ══════════════════════════════════════════════════════════════ SPACES = [ ("yisol/IDM-VTON", "idmvton"), ("yisol/IDM-VTON-DC", "idmvton-dc"), ("Kwai-Kolors/Kolors-Virtual-Try-On", "kolors"), ("Nymbo/Virtual-Try-On", "nymbo"), ("multimodalart/idm-vton", "multimodal"), ] def save_tmp(img): p = tempfile.mktemp(suffix=".jpg") img.save(p, quality=95) return p def cleanup(*paths): for p in paths: try: if p and os.path.exists(p): os.remove(p) except: pass def try_kolors(client, p_path, c_path, steps, seed): """Kwai Kolors has different API signature.""" result = client.predict( human_img = handle_file(p_path), garm_img = handle_file(c_path), garment_des = "clothing item", api_name = "/tryon" ) return result[0] def try_idmvton(client, p_path, c_path, steps, seed, is_dress): """Standard IDM-VTON API signature.""" result = client.predict( dict = {"background": handle_file(p_path), "layers": [], "composite": None}, garm_img = handle_file(c_path), garment_des = "dress" if is_dress else "shirt", is_checked = True, is_checked_crop = is_dress, denoise_steps = steps, seed = seed, api_name = "/tryon" ) return result[0] def virtual_tryon(person_img, cloth_img, quality): if person_img is None: return None, "⚠️ Please upload your photo!" if cloth_img is None: return None, "⚠️ Please upload a clothing image!" steps = {"Fast ⚡": 20, "Balanced ⚖️": 30, "Best Quality 💎": 40}.get(quality, 30) seed = random.randint(0, 9999) t0 = time.time() is_dress = (cloth_img.height / max(cloth_img.width, 1)) > 1.3 p_path = save_tmp(person_img) c_path = save_tmp(cloth_img) errors = [] for space_id, space_type in SPACES: try: print(f"🔌 Trying {space_id}...") client = Client(space_id, verbose=False) if space_type == "kolors": result_path = try_kolors(client, p_path, c_path, steps, seed) else: result_path = try_idmvton(client, p_path, c_path, steps, seed, is_dress) result_img = Image.open(result_path).convert("RGB") cleanup(p_path, c_path) elapsed = time.time() - t0 name = space_id.split("/")[-1] return result_img, f"✅ Done in {elapsed:.1f}s via {name}!" except Exception as e: err = str(e) errors.append(f"{space_id}: {err[:60]}") print(f"❌ {space_id} → {err[:80]}") time.sleep(2) continue cleanup(p_path, c_path) # Show which spaces were tried print("All spaces failed:\n" + "\n".join(errors)) return None, ( "⏳ All servers are currently busy.\n\n" "Please try again in 2-3 minutes.\n" "💡 Best time to use: early morning or late night (India time)" ) # ── UI ──────────────────────────────────────────────────────── with gr.Blocks( title="AI Virtual Try-On", theme=gr.themes.Soft(primary_hue="violet", secondary_hue="pink"), css=""" footer { display:none !important } .tip { background:#f5f0ff; border-radius:12px; padding:10px 14px; font-size:.85em; color:#555; margin-top:8px; border:1px solid #e0d0ff } """ ) as demo: gr.HTML("""
Upload your photo + clothing — see how it looks on you instantly!