Gemini899 commited on
Commit
de2c401
·
verified ·
1 Parent(s): 1e31957

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +71 -183
app.py CHANGED
@@ -11,31 +11,20 @@ from pipeline_fill_sd_xl import StableDiffusionXLFillPipeline
11
 
12
  from PIL import Image, ImageDraw
13
 
14
- # =========================
15
- # LOAD MODELS (original)
16
- # =========================
17
- config_file = hf_hub_download(
18
- "xinsir/controlnet-union-sdxl-1.0",
19
- filename="config_promax.json",
20
- )
21
  config = ControlNetModel_Union.load_config(config_file)
22
  controlnet_model = ControlNetModel_Union.from_config(config)
23
 
24
- model_file = hf_hub_download(
25
- "xinsir/controlnet-union-sdxl-1.0",
26
- filename="diffusion_pytorch_model_promax.safetensors",
27
- )
28
  state_dict = load_state_dict(model_file)
29
  loaded_keys = list(state_dict.keys())
30
-
31
  result = ControlNetModel_Union._load_pretrained_model(
32
  controlnet_model, state_dict, model_file, "xinsir/controlnet-union-sdxl-1.0", loaded_keys
33
  )
34
  model = result[0].to(device="cuda", dtype=torch.float16)
35
 
36
- vae = AutoencoderKL.from_pretrained(
37
- "madebyollin/sdxl-vae-fp16-fix", torch_dtype=torch.float16
38
- ).to("cuda")
39
 
40
  pipe = StableDiffusionXLFillPipeline.from_pretrained(
41
  "SG161222/RealVisXL_V5.0_Lightning",
@@ -47,9 +36,7 @@ pipe = StableDiffusionXLFillPipeline.from_pretrained(
47
 
48
  pipe.scheduler = TCDScheduler.from_config(pipe.scheduler.config)
49
 
50
- # =========================
51
- # HELPERS
52
- # =========================
53
  def can_expand(source_width, source_height, target_width, target_height, alignment):
54
  if alignment in ("Left", "Right") and source_width >= target_width:
55
  return False
@@ -57,9 +44,9 @@ def can_expand(source_width, source_height, target_width, target_height, alignme
57
  return False
58
  return True
59
 
60
- def prepare_image_and_mask(image, width, height, overlap_percentage, resize_option, custom_resize_percentage, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom):
 
61
  target_size = (width, height)
62
-
63
  scale_factor = min(target_size[0] / image.width, target_size[1] / image.height)
64
  new_width = int(image.width * scale_factor)
65
  new_height = int(image.height * scale_factor)
@@ -123,18 +110,24 @@ def prepare_image_and_mask(image, width, height, overlap_percentage, resize_opti
123
  mask_draw.rectangle([(left_overlap, top_overlap), (right_overlap, bottom_overlap)], fill=0)
124
  return background, mask
125
 
126
- def preview_image_and_mask(image, width, height, overlap_percentage, resize_option, custom_resize_percentage, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom):
127
- background, mask = prepare_image_and_mask(image, width, height, overlap_percentage, resize_option, custom_resize_percentage, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom)
 
 
 
128
  preview = background.copy().convert('RGBA')
129
  red_overlay = Image.new('RGBA', background.size, (255, 0, 0, 64))
130
  red_mask = Image.new('RGBA', background.size, (0, 0, 0, 0))
131
  red_mask.paste(red_overlay, (0, 0), mask)
132
  return Image.alpha_composite(preview, red_mask)
133
 
134
- # ===== Streaming infer for the UI (original) =====
135
  @spaces.GPU(duration=24)
136
- def infer(image, width, height, overlap_percentage, num_inference_steps, resize_option, custom_resize_percentage, prompt_input, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom):
137
- background, mask = prepare_image_and_mask(image, width, height, overlap_percentage, resize_option, custom_resize_percentage, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom)
 
 
 
138
  if not can_expand(background.width, background.height, width, height, alignment):
139
  alignment = "Middle"
140
 
@@ -165,14 +158,15 @@ def infer(image, width, height, overlap_percentage, num_inference_steps, resize_
165
  cnet_image.paste(image, (0, 0), mask)
166
  yield background, cnet_image
167
 
168
- # ===== Non-streaming wrapper used by REST Interface =====
169
- def infer_rest(image, width, height, overlap_percentage, num_inference_steps, resize_option, custom_resize_percentage, prompt_input, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom):
170
- # Run generator to completion and return final pair
171
- gen = infer(image, width, height, overlap_percentage, num_inference_steps, resize_option, custom_resize_percentage, prompt_input, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom)
 
172
  last = None
173
  for last in gen:
174
  pass
175
- return last # (background, outpainted)
176
 
177
  def clear_result():
178
  return gr.update(value=None)
@@ -207,69 +201,33 @@ def update_history(new_image, history):
207
  return history
208
 
209
  css = """
210
- .gradio-container {
211
- width: 1200px !important;
212
- }
213
  """
214
-
215
  title = """<h1 align="center">Re-Size Image Outpaint</h1>"""
216
 
217
- # ---- UI (original Blocks) ----
218
  with gr.Blocks(theme="soft", css=css) as ui_app:
219
  with gr.Column():
220
  gr.HTML(title)
221
-
222
  with gr.Row():
223
  with gr.Column():
224
  input_image = gr.Image(type="pil", label="Input Image")
225
-
226
  with gr.Row():
227
  with gr.Column(scale=2):
228
  prompt_input = gr.Textbox(label="Prompt (Optional)")
229
  with gr.Column(scale=1):
230
  run_button = gr.Button("Generate")
231
-
232
  with gr.Row():
233
- target_ratio = gr.Radio(
234
- label="Expected Ratio",
235
- choices=["9:16", "16:9", "1:1", "Custom"],
236
- value="9:16",
237
- scale=2
238
- )
239
-
240
- alignment_dropdown = gr.Dropdown(
241
- choices=["Middle", "Left", "Right", "Top", "Bottom"],
242
- value="Middle",
243
- label="Alignment"
244
- )
245
-
246
  with gr.Accordion(label="Advanced settings", open=False) as settings_panel:
247
  with gr.Column():
248
  with gr.Row():
249
- width_slider = gr.Slider(
250
- label="Target Width",
251
- minimum=720,
252
- maximum=1536,
253
- step=8,
254
- value=720,
255
- )
256
- height_slider = gr.Slider(
257
- label="Target Height",
258
- minimum=720,
259
- maximum=1536,
260
- step=8,
261
- value=1280,
262
- )
263
-
264
  num_inference_steps = gr.Slider(label="Steps", minimum=4, maximum=12, step=1, value=8)
265
  with gr.Group():
266
- overlap_percentage = gr.Slider(
267
- label="Mask overlap (%)",
268
- minimum=1,
269
- maximum=50,
270
- value=10,
271
- step=1
272
- )
273
  with gr.Row():
274
  overlap_top = gr.Checkbox(label="Overlap Top", value=True)
275
  overlap_right = gr.Checkbox(label="Overlap Right", value=True)
@@ -277,20 +235,8 @@ with gr.Blocks(theme="soft", css=css) as ui_app:
277
  overlap_left = gr.Checkbox(label="Overlap Left", value=True)
278
  overlap_bottom = gr.Checkbox(label="Overlap Bottom", value=True)
279
  with gr.Row():
280
- resize_option = gr.Radio(
281
- label="Resize input image",
282
- choices=["Full", "50%", "33%", "25%", "Custom"],
283
- value="Full"
284
- )
285
- custom_resize_percentage = gr.Slider(
286
- label="Custom resize (%)",
287
- minimum=1,
288
- maximum=100,
289
- step=1,
290
- value=50,
291
- visible=False
292
- )
293
-
294
  with gr.Column():
295
  preview_button = gr.Button("Preview alignment and mask")
296
 
@@ -304,101 +250,46 @@ with gr.Blocks(theme="soft", css=css) as ui_app:
304
  )
305
 
306
  with gr.Column():
307
- result = ImageSlider(
308
- interactive=False,
309
- label="Generated Image",
310
- )
311
  use_as_input_button = gr.Button("Use as Input Image", visible=False)
312
-
313
  history_gallery = gr.Gallery(label="History", columns=6, object_fit="contain", interactive=False)
314
  preview_image = gr.Image(label="Preview")
315
 
316
  def use_output_as_input(output_image):
317
  return gr.update(value=output_image[1])
318
 
319
- use_as_input_button.click(
320
- fn=use_output_as_input,
321
- inputs=[result],
322
- outputs=[input_image]
323
- )
324
-
325
- target_ratio.change(
326
- fn=preload_presets,
327
- inputs=[target_ratio, width_slider, height_slider],
328
- outputs=[width_slider, height_slider, settings_panel],
329
- queue=False
330
- )
331
-
332
- width_slider.change(
333
- fn=select_the_right_preset,
334
- inputs=[width_slider, height_slider],
335
- outputs=[target_ratio],
336
- queue=False
337
- )
338
-
339
- height_slider.change(
340
- fn=select_the_right_preset,
341
- inputs=[width_slider, height_slider],
342
- outputs=[target_ratio],
343
- queue=False
344
- )
345
-
346
- resize_option.change(
347
- fn=toggle_custom_resize_slider,
348
- inputs=[resize_option],
349
- outputs=[custom_resize_percentage],
350
- queue=False
351
- )
352
-
353
- run_button.click(
354
- fn=clear_result,
355
- inputs=None,
356
- outputs=result,
357
- ).then(
358
- fn=infer,
359
- inputs=[input_image, width_slider, height_slider, overlap_percentage, num_inference_steps,
360
- resize_option, custom_resize_percentage, prompt_input, alignment_dropdown,
361
- overlap_left, overlap_right, overlap_top, overlap_bottom],
362
- outputs=result,
363
- ).then(
364
- fn=lambda x, history: update_history(x[1], history) if x else history,
365
- inputs=[result, history_gallery],
366
- outputs=history_gallery,
367
- ).then(
368
- fn=lambda: gr.update(visible=True),
369
- inputs=None,
370
- outputs=use_as_input_button,
371
- )
372
-
373
- prompt_input.submit(
374
- fn=clear_result,
375
- inputs=None,
376
- outputs=result,
377
- ).then(
378
- fn=infer,
379
- inputs=[input_image, width_slider, height_slider, overlap_percentage, num_inference_steps,
380
- resize_option, custom_resize_percentage, prompt_input, alignment_dropdown,
381
- overlap_left, overlap_right, overlap_top, overlap_bottom],
382
- outputs=result,
383
- ).then(
384
- fn=lambda x, history: update_history(x[1], history) if x else history,
385
- inputs=[result, history_gallery],
386
- outputs=history_gallery,
387
- ).then(
388
- fn=lambda: gr.update(visible=True),
389
- inputs=None,
390
- outputs=use_as_input_button,
391
- )
392
-
393
- preview_button.click(
394
- fn=preview_image_and_mask,
395
- inputs=[input_image, width_slider, height_slider, overlap_percentage, resize_option, custom_resize_percentage, alignment_dropdown,
396
- overlap_left, overlap_right, overlap_top, overlap_bottom],
397
- outputs=preview_image,
398
- queue=False
399
- )
400
-
401
- # ---- API (minimal Interface to guarantee REST route) ----
402
  api_app = gr.Interface(
403
  fn=infer_rest,
404
  inputs=[
@@ -416,18 +307,15 @@ api_app = gr.Interface(
416
  gr.Checkbox(value=True, label="Overlap Top"),
417
  gr.Checkbox(value=True, label="Overlap Bottom"),
418
  ],
419
- outputs=[
420
- gr.Image(label="Background"),
421
- gr.Image(label="Generated"),
422
- ],
423
  allow_flagging="never",
424
- api_name="infer", # <-- this creates /api/predict/infer
425
  title="Re-Size Image Outpaint API",
426
  description="Non-streaming endpoint for programmatic access.",
427
  )
428
 
429
- # ---- Publish both (UI + API) together ----
430
- demo = gr.TabbedInterface([ui_app, api_app], tab_names=["App", "API"])
431
 
432
- # IMPORTANT: expose REST
433
  demo.queue(max_size=12, api_open=True).launch(share=False)
 
11
 
12
  from PIL import Image, ImageDraw
13
 
14
+ # ===== Load models (original from your Space) =====
15
+ config_file = hf_hub_download("xinsir/controlnet-union-sdxl-1.0", filename="config_promax.json")
 
 
 
 
 
16
  config = ControlNetModel_Union.load_config(config_file)
17
  controlnet_model = ControlNetModel_Union.from_config(config)
18
 
19
+ model_file = hf_hub_download("xinsir/controlnet-union-sdxl-1.0", filename="diffusion_pytorch_model_promax.safetensors")
 
 
 
20
  state_dict = load_state_dict(model_file)
21
  loaded_keys = list(state_dict.keys())
 
22
  result = ControlNetModel_Union._load_pretrained_model(
23
  controlnet_model, state_dict, model_file, "xinsir/controlnet-union-sdxl-1.0", loaded_keys
24
  )
25
  model = result[0].to(device="cuda", dtype=torch.float16)
26
 
27
+ vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", torch_dtype=torch.float16).to("cuda")
 
 
28
 
29
  pipe = StableDiffusionXLFillPipeline.from_pretrained(
30
  "SG161222/RealVisXL_V5.0_Lightning",
 
36
 
37
  pipe.scheduler = TCDScheduler.from_config(pipe.scheduler.config)
38
 
39
+ # ===== Helpers (original) =====
 
 
40
  def can_expand(source_width, source_height, target_width, target_height, alignment):
41
  if alignment in ("Left", "Right") and source_width >= target_width:
42
  return False
 
44
  return False
45
  return True
46
 
47
+ def prepare_image_and_mask(image, width, height, overlap_percentage, resize_option, custom_resize_percentage,
48
+ alignment, overlap_left, overlap_right, overlap_top, overlap_bottom):
49
  target_size = (width, height)
 
50
  scale_factor = min(target_size[0] / image.width, target_size[1] / image.height)
51
  new_width = int(image.width * scale_factor)
52
  new_height = int(image.height * scale_factor)
 
110
  mask_draw.rectangle([(left_overlap, top_overlap), (right_overlap, bottom_overlap)], fill=0)
111
  return background, mask
112
 
113
+ def preview_image_and_mask(image, width, height, overlap_percentage, resize_option, custom_resize_percentage,
114
+ alignment, overlap_left, overlap_right, overlap_top, overlap_bottom):
115
+ background, mask = prepare_image_and_mask(image, width, height, overlap_percentage, resize_option,
116
+ custom_resize_percentage, alignment, overlap_left, overlap_right,
117
+ overlap_top, overlap_bottom)
118
  preview = background.copy().convert('RGBA')
119
  red_overlay = Image.new('RGBA', background.size, (255, 0, 0, 64))
120
  red_mask = Image.new('RGBA', background.size, (0, 0, 0, 0))
121
  red_mask.paste(red_overlay, (0, 0), mask)
122
  return Image.alpha_composite(preview, red_mask)
123
 
124
+ # ===== Streaming infer (UI) =====
125
  @spaces.GPU(duration=24)
126
+ def infer(image, width, height, overlap_percentage, num_inference_steps, resize_option, custom_resize_percentage,
127
+ prompt_input, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom):
128
+ background, mask = prepare_image_and_mask(image, width, height, overlap_percentage, resize_option,
129
+ custom_resize_percentage, alignment, overlap_left, overlap_right,
130
+ overlap_top, overlap_bottom)
131
  if not can_expand(background.width, background.height, width, height, alignment):
132
  alignment = "Middle"
133
 
 
158
  cnet_image.paste(image, (0, 0), mask)
159
  yield background, cnet_image
160
 
161
+ # ===== Non-streaming wrapper (returns final pair) =====
162
+ def infer_rest(image, width, height, overlap_percentage, num_inference_steps, resize_option, custom_resize_percentage,
163
+ prompt_input, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom):
164
+ gen = infer(image, width, height, overlap_percentage, num_inference_steps, resize_option, custom_resize_percentage,
165
+ prompt_input, alignment, overlap_left, overlap_right, overlap_top, overlap_bottom)
166
  last = None
167
  for last in gen:
168
  pass
169
+ return last # (background, generated)
170
 
171
  def clear_result():
172
  return gr.update(value=None)
 
201
  return history
202
 
203
  css = """
204
+ .gradio-container { width: 1200px !important; }
 
 
205
  """
 
206
  title = """<h1 align="center">Re-Size Image Outpaint</h1>"""
207
 
208
+ # ---- Full UI (unchanged) ----
209
  with gr.Blocks(theme="soft", css=css) as ui_app:
210
  with gr.Column():
211
  gr.HTML(title)
 
212
  with gr.Row():
213
  with gr.Column():
214
  input_image = gr.Image(type="pil", label="Input Image")
 
215
  with gr.Row():
216
  with gr.Column(scale=2):
217
  prompt_input = gr.Textbox(label="Prompt (Optional)")
218
  with gr.Column(scale=1):
219
  run_button = gr.Button("Generate")
 
220
  with gr.Row():
221
+ target_ratio = gr.Radio(label="Expected Ratio", choices=["9:16", "16:9", "1:1", "Custom"], value="9:16", scale=2)
222
+ alignment_dropdown = gr.Dropdown(choices=["Middle", "Left", "Right", "Top", "Bottom"], value="Middle", label="Alignment")
 
 
 
 
 
 
 
 
 
 
 
223
  with gr.Accordion(label="Advanced settings", open=False) as settings_panel:
224
  with gr.Column():
225
  with gr.Row():
226
+ width_slider = gr.Slider(label="Target Width", minimum=720, maximum=1536, step=8, value=720)
227
+ height_slider = gr.Slider(label="Target Height", minimum=720, maximum=1536, step=8, value=1280)
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  num_inference_steps = gr.Slider(label="Steps", minimum=4, maximum=12, step=1, value=8)
229
  with gr.Group():
230
+ overlap_percentage = gr.Slider(label="Mask overlap (%)", minimum=1, maximum=50, value=10, step=1)
 
 
 
 
 
 
231
  with gr.Row():
232
  overlap_top = gr.Checkbox(label="Overlap Top", value=True)
233
  overlap_right = gr.Checkbox(label="Overlap Right", value=True)
 
235
  overlap_left = gr.Checkbox(label="Overlap Left", value=True)
236
  overlap_bottom = gr.Checkbox(label="Overlap Bottom", value=True)
237
  with gr.Row():
238
+ resize_option = gr.Radio(label="Resize input image", choices=["Full", "50%", "33%", "25%", "Custom"], value="Full")
239
+ custom_resize_percentage = gr.Slider(label="Custom resize (%)", minimum=1, maximum=100, step=1, value=50, visible=False)
 
 
 
 
 
 
 
 
 
 
 
 
240
  with gr.Column():
241
  preview_button = gr.Button("Preview alignment and mask")
242
 
 
250
  )
251
 
252
  with gr.Column():
253
+ result = ImageSlider(interactive=False, label="Generated Image")
 
 
 
254
  use_as_input_button = gr.Button("Use as Input Image", visible=False)
 
255
  history_gallery = gr.Gallery(label="History", columns=6, object_fit="contain", interactive=False)
256
  preview_image = gr.Image(label="Preview")
257
 
258
  def use_output_as_input(output_image):
259
  return gr.update(value=output_image[1])
260
 
261
+ use_as_input_button.click(fn=use_output_as_input, inputs=[result], outputs=[input_image])
262
+
263
+ target_ratio.change(fn=preload_presets, inputs=[target_ratio, width_slider, height_slider], outputs=[width_slider, height_slider, settings_panel], queue=False)
264
+ width_slider.change(fn=select_the_right_preset, inputs=[width_slider, height_slider], outputs=[target_ratio], queue=False)
265
+ height_slider.change(fn=select_the_right_preset, inputs=[width_slider, height_slider], outputs=[target_ratio], queue=False)
266
+ resize_option.change(fn=toggle_custom_resize_slider, inputs=[resize_option], outputs=[custom_resize_percentage], queue=False)
267
+
268
+ run_button.click(fn=clear_result, inputs=None, outputs=result) \
269
+ .then(fn=infer,
270
+ inputs=[input_image, width_slider, height_slider, overlap_percentage, num_inference_steps,
271
+ resize_option, custom_resize_percentage, prompt_input, alignment_dropdown,
272
+ overlap_left, overlap_right, overlap_top, overlap_bottom],
273
+ outputs=result) \
274
+ .then(fn=lambda x, history: update_history(x[1], history) if x else history, inputs=[result, history_gallery], outputs=history_gallery) \
275
+ .then(fn=lambda: gr.update(visible=True), inputs=None, outputs=use_as_input_button)
276
+
277
+ prompt_input.submit(fn=clear_result, inputs=None, outputs=result) \
278
+ .then(fn=infer,
279
+ inputs=[input_image, width_slider, height_slider, overlap_percentage, num_inference_steps,
280
+ resize_option, custom_resize_percentage, prompt_input, alignment_dropdown,
281
+ overlap_left, overlap_right, overlap_top, overlap_bottom],
282
+ outputs=result) \
283
+ .then(fn=lambda x, history: update_history(x[1], history) if x else history, inputs=[result, history_gallery], outputs=history_gallery) \
284
+ .then(fn=lambda: gr.update(visible=True), inputs=None, outputs=use_as_input_button)
285
+
286
+ preview_button.click(fn=preview_image_and_mask,
287
+ inputs=[input_image, width_slider, height_slider, overlap_percentage, resize_option,
288
+ custom_resize_percentage, alignment_dropdown, overlap_left, overlap_right,
289
+ overlap_top, overlap_bottom],
290
+ outputs=preview_image, queue=False)
291
+
292
+ # ---- Minimal Interface tab that DEFINITELY exposes /api/predict/infer ----
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  api_app = gr.Interface(
294
  fn=infer_rest,
295
  inputs=[
 
307
  gr.Checkbox(value=True, label="Overlap Top"),
308
  gr.Checkbox(value=True, label="Overlap Bottom"),
309
  ],
310
+ outputs=[gr.Image(label="Background"), gr.Image(label="Generated")],
 
 
 
311
  allow_flagging="never",
312
+ api_name="infer", # <--- THIS creates /api/predict/infer
313
  title="Re-Size Image Outpaint API",
314
  description="Non-streaming endpoint for programmatic access.",
315
  )
316
 
317
+ # Publish BOTH tabs put API FIRST to be extra safe on older Gradio builds
318
+ demo = gr.TabbedInterface([api_app, ui_app], tab_names=["API", "App"])
319
 
320
+ # Open REST API
321
  demo.queue(max_size=12, api_open=True).launch(share=False)