CREATORJD commited on
Commit
d9f2395
·
verified ·
1 Parent(s): ed88b1e

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -28
app.py CHANGED
@@ -43,56 +43,88 @@ _PIPE = None
43
  _MESH = None
44
 
45
  def _load():
 
 
 
46
  global _PIPE, _MESH
47
  if _PIPE is not None:
48
  return
 
49
  from diffusers import StableDiffusionControlNetInpaintPipeline, ControlNetModel, UniPCMultistepScheduler
50
  from controlnet_aux import MeshGraphormerDetector
51
- _MESH = MeshGraphormerDetector.from_pretrained(MESHGRAPHORMER_ID).to("cuda")
 
 
 
52
  cn = ControlNetModel.from_pretrained(CONTROLNET_ID, torch_dtype=torch.float16)
53
  pipe = StableDiffusionControlNetInpaintPipeline.from_pretrained(
54
  SD_INPAINT_ID, controlnet=cn, torch_dtype=torch.float16, safety_checker=None
55
  )
56
  pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
57
- _PIPE = pipe.to("cuda")
 
 
 
 
 
 
 
 
 
 
 
58
 
59
  def _fit(img):
60
  w, h = img.size
61
  s = min(1.0, MAX_SIDE / max(w, h))
62
  return img.resize((max(8, int(round(w*s/8))*8), max(8, int(round(h*s/8))*8)), Image.LANCZOS), (w, h)
63
 
64
- @spaces.GPU(duration=90)
65
  def fix_hands(image, mask_layers, prompt, strength):
66
- """ZeroGPU-allocated worker, wired directly into the Gradio Interface below."""
 
 
67
  if image is None:
68
  raise gr.Error("Upload an image first.")
69
- _load()
70
- init, (ow, oh) = _fit(image.convert("RGB"))
71
- W, H = init.size
 
 
 
 
 
 
72
 
73
- # optional hand-drawn mask from the ImageMask/Sketchpad component
74
- sent_mask = None
75
- if isinstance(mask_layers, dict):
76
- layers = mask_layers.get("layers") or []
77
- if layers:
78
- m = layers[0].convert("L").resize((W, H), Image.LANCZOS)
79
- if m.getbbox() is not None:
80
- sent_mask = m
81
 
82
- mg = _MESH(init)
83
- depth_img, auto_mask = (mg[0], (mg[1] if len(mg) > 1 else None)) if isinstance(mg, tuple) else (mg, None)
84
- depth_img = depth_img.convert("RGB").resize((W, H), Image.LANCZOS)
85
- mask_img = sent_mask or (auto_mask.convert("L").resize((W, H), Image.LANCZOS) if auto_mask else None)
86
- if mask_img is None:
87
- raise gr.Error("No hands detected. Paint a mask over the hand and try again.")
 
88
 
89
- mask_img = mask_img.filter(ImageFilter.GaussianBlur(2))
90
- out = _PIPE(
91
- prompt=prompt or DEFAULT_PROMPT, negative_prompt=NEG, image=init, mask_image=mask_img,
92
- control_image=depth_img, num_inference_steps=30, strength=float(strength),
93
- guidance_scale=7.5, controlnet_conditioning_scale=0.7,
94
- ).images[0]
95
- return out.resize((ow, oh), Image.LANCZOS)
 
 
 
 
 
96
 
97
  with gr.Blocks(title="DARKROOM HandRefiner", theme=gr.themes.Base()) as demo:
98
  gr.Markdown("## 🖐️ DARKROOM HandRefiner\nUpload AI art with bad hands. It auto-detects hands "
 
43
  _MESH = None
44
 
45
  def _load():
46
+ """Load on CPU at import time. Models are moved to GPU inside the @spaces.GPU call,
47
+ so the timed GPU window is spent on inference, not on multi-GB model loading —
48
+ which is what caused first-call stalls/timeouts."""
49
  global _PIPE, _MESH
50
  if _PIPE is not None:
51
  return
52
+ import time
53
  from diffusers import StableDiffusionControlNetInpaintPipeline, ControlNetModel, UniPCMultistepScheduler
54
  from controlnet_aux import MeshGraphormerDetector
55
+ t0 = time.time()
56
+ print("[load] starting model load on CPU…", flush=True)
57
+ _MESH = MeshGraphormerDetector.from_pretrained(MESHGRAPHORMER_ID)
58
+ print(f"[load] meshgraphormer ok ({time.time()-t0:.0f}s)", flush=True)
59
  cn = ControlNetModel.from_pretrained(CONTROLNET_ID, torch_dtype=torch.float16)
60
  pipe = StableDiffusionControlNetInpaintPipeline.from_pretrained(
61
  SD_INPAINT_ID, controlnet=cn, torch_dtype=torch.float16, safety_checker=None
62
  )
63
  pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
64
+ try: pipe.enable_attention_slicing()
65
+ except Exception as e: print("[load] attn-slicing skip:", e, flush=True)
66
+ try: pipe.enable_vae_tiling()
67
+ except Exception as e: print("[load] vae-tiling skip:", e, flush=True)
68
+ _PIPE = pipe
69
+ print(f"[load] pipeline ready on CPU ({time.time()-t0:.0f}s total)", flush=True)
70
+
71
+ # preload at import — runs once when the container boots, OUTSIDE any GPU-timed window
72
+ try:
73
+ _load()
74
+ except Exception as _e:
75
+ print("[load] preload deferred:", _e, flush=True)
76
 
77
  def _fit(img):
78
  w, h = img.size
79
  s = min(1.0, MAX_SIDE / max(w, h))
80
  return img.resize((max(8, int(round(w*s/8))*8), max(8, int(round(h*s/8))*8)), Image.LANCZOS), (w, h)
81
 
82
+ @spaces.GPU(duration=120)
83
  def fix_hands(image, mask_layers, prompt, strength):
84
+ """ZeroGPU-allocated worker. Models are already loaded (CPU) at import;
85
+ here we move them onto the GPU that ZeroGPU just attached, then infer."""
86
+ import time, traceback
87
  if image is None:
88
  raise gr.Error("Upload an image first.")
89
+ try:
90
+ t0 = time.time()
91
+ _load() # no-op if already loaded
92
+ _MESH.to("cuda")
93
+ _PIPE.to("cuda")
94
+ print(f"[fix] models on GPU, t={time.time()-t0:.0f}s", flush=True)
95
+ init, (ow, oh) = _fit(image.convert("RGB"))
96
+ W, H = init.size
97
+ print(f"[fix] input fitted to {W}x{H}", flush=True)
98
 
99
+ # optional hand-drawn mask from the ImageMask component
100
+ sent_mask = None
101
+ if isinstance(mask_layers, dict):
102
+ layers = mask_layers.get("layers") or []
103
+ if layers:
104
+ m = layers[0].convert("L").resize((W, H), Image.LANCZOS)
105
+ if m.getbbox() is not None:
106
+ sent_mask = m
107
 
108
+ print("[fix] running MeshGraphormer…", flush=True)
109
+ mg = _MESH(init)
110
+ depth_img, auto_mask = (mg[0], (mg[1] if len(mg) > 1 else None)) if isinstance(mg, tuple) else (mg, None)
111
+ depth_img = depth_img.convert("RGB").resize((W, H), Image.LANCZOS)
112
+ mask_img = sent_mask or (auto_mask.convert("L").resize((W, H), Image.LANCZOS) if auto_mask else None)
113
+ if mask_img is None:
114
+ raise gr.Error("No hands detected. Paint a mask over the hand and try again.")
115
 
116
+ mask_img = mask_img.filter(ImageFilter.GaussianBlur(2))
117
+ print("[fix] running diffusion…", flush=True)
118
+ out = _PIPE(
119
+ prompt=prompt or DEFAULT_PROMPT, negative_prompt=NEG, image=init, mask_image=mask_img,
120
+ control_image=depth_img, num_inference_steps=25, strength=float(strength),
121
+ guidance_scale=7.5, controlnet_conditioning_scale=0.7,
122
+ ).images[0]
123
+ print(f"[fix] done, total {time.time()-t0:.0f}s", flush=True)
124
+ return out.resize((ow, oh), Image.LANCZOS)
125
+ except Exception as e:
126
+ print("[fix] ERROR:\n" + traceback.format_exc(), flush=True)
127
+ raise gr.Error(f"Fix failed: {e}")
128
 
129
  with gr.Blocks(title="DARKROOM HandRefiner", theme=gr.themes.Base()) as demo:
130
  gr.Markdown("## 🖐️ DARKROOM HandRefiner\nUpload AI art with bad hands. It auto-detects hands "