M3st3rJ4k3l commited on
Commit
26df397
Β·
1 Parent(s): 5277d21

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +81 -18
app.py CHANGED
@@ -5,9 +5,15 @@ import numpy as np
5
  import spaces
6
  import torch
7
  import random
 
8
  from PIL import Image
9
  from typing import Iterable
10
 
 
 
 
 
 
11
  from diffusers import Flux2KleinPipeline
12
  from huggingface_hub import hf_hub_download
13
 
@@ -225,7 +231,7 @@ def on_gallery_change(images):
225
  img = Image.open(path if isinstance(path, str) else path.name)
226
  orig_w, orig_h = img.size
227
  base_w, base_h = compute_base_dimensions(img)
228
- size_text = f"Input: **{orig_w} Γ— {orig_h}** px β†’ Base output (1Γ—): **{base_w} Γ— {base_h}** px"
229
  return count_info, size_text
230
  except Exception as e:
231
  return count_info, f"*Could not read dimensions: {e}*"
@@ -293,6 +299,47 @@ def update_weight_sliders(selected_titles):
293
 
294
  # ── Inference ─────────────────────────────────────────────────────────────────
295
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  @spaces.GPU
297
  def infer(
298
  input_images,
@@ -303,7 +350,7 @@ def infer(
303
  randomize_seed,
304
  guidance_scale,
305
  steps,
306
- output_scale,
307
  *slider_values,
308
  progress=gr.Progress(track_tqdm=True)
309
  ):
@@ -365,11 +412,9 @@ def infer(
365
  else:
366
  full_prompt = user_prompt or lora_extra
367
 
368
- # Compute output dimensions: base size Γ— output_scale, aligned to 16px grid
369
- base_w, base_h = compute_base_dimensions(pil_images[0])
370
- width = max(16, (int(base_w * output_scale) // 16) * 16)
371
- height = max(16, (int(base_h * output_scale) // 16) * 16)
372
- print(f"Output size: {width} Γ— {height} px (scale {output_scale}Γ—)")
373
 
374
  processed_images = [img.resize((width, height), Image.LANCZOS).convert("RGB") for img in pil_images]
375
  image_input = processed_images if len(processed_images) > 1 else processed_images[0]
@@ -384,12 +429,23 @@ def infer(
384
  num_inference_steps=steps,
385
  generator=torch.Generator(device=device).manual_seed(seed),
386
  ).images[0]
387
- return image, seed
388
  except Exception as e:
389
  raise gr.Error(f"Inference failed: {e}")
390
- finally:
391
- gc.collect()
392
- torch.cuda.empty_cache()
 
 
 
 
 
 
 
 
 
 
 
 
393
 
394
  # ── Dynamic LoRA loader ───────────────────────────────────────────────────────
395
 
@@ -482,16 +538,23 @@ with gr.Blocks(css=css, theme=orange_red_theme) as demo:
482
  randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
483
  guidance_scale = gr.Slider(label="Guidance Scale", minimum=0.0, maximum=10.0, step=0.1, value=1.0)
484
  steps = gr.Slider(label="Steps", minimum=1, maximum=50, value=4, step=1)
485
- output_scale = gr.Slider(
486
- label="Output Scale",
487
- info="Multiplier applied to the auto-detected base size shown above. 1Γ— keeps the default behaviour.",
488
- minimum=0.25, maximum=4.0, step=0.25, value=1.0,
 
489
  )
490
 
491
  # ── Right column ─────────────────────────────────────────────────
492
  with gr.Column(scale=1):
493
  output_image = gr.Image(label="Output", interactive=False, format="png", height=320)
494
- used_seed = gr.Textbox(label="Used Seed", interactive=False, visible=False)
 
 
 
 
 
 
495
 
496
  # ── LoRA selector ─────────────────────────────────────────────────────
497
  gr.Markdown("### 🎨 Select LoRA(s)")
@@ -537,7 +600,7 @@ with gr.Blocks(css=css, theme=orange_red_theme) as demo:
537
  ],
538
  inputs=[input_images, prompt, lora_selector, seed, randomize_seed, guidance_scale, steps],
539
  outputs=[output_image, used_seed],
540
- fn=lambda imgs, p, sel, sd, rs, gs, st: infer(imgs, p, "", sel, sd, rs, gs, st, 1.0, *([1.0] * MAX_LORA_SLOTS)),
541
  cache_examples=False,
542
  label="Examples",
543
  )
@@ -566,7 +629,7 @@ with gr.Blocks(css=css, theme=orange_red_theme) as demo:
566
 
567
  run_button.click(
568
  fn=infer,
569
- inputs=[input_images, prompt, lora_prompt_display, lora_selector, seed, randomize_seed, guidance_scale, steps, output_scale] + weight_sliders,
570
  outputs=[output_image, used_seed],
571
  )
572
 
 
5
  import spaces
6
  import torch
7
  import random
8
+ import cv2
9
  from PIL import Image
10
  from typing import Iterable
11
 
12
+ # ── requirements.txt should include: ─────────────────────────────────────────
13
+ # basicsr
14
+ # realesrgan
15
+ # ─────────────────────────────────────────────────────────────────────────────
16
+
17
  from diffusers import Flux2KleinPipeline
18
  from huggingface_hub import hf_hub_download
19
 
 
231
  img = Image.open(path if isinstance(path, str) else path.name)
232
  orig_w, orig_h = img.size
233
  base_w, base_h = compute_base_dimensions(img)
234
+ size_text = f"Input: **{orig_w} Γ— {orig_h}** px β†’ Output (pre-upscale): **{base_w} Γ— {base_h}** px"
235
  return count_info, size_text
236
  except Exception as e:
237
  return count_info, f"*Could not read dimensions: {e}*"
 
299
 
300
  # ── Inference ─────────────────────────────────────────────────────────────────
301
 
302
+ def apply_realesrgan(image: Image.Image, scale: int) -> Image.Image:
303
+ """
304
+ Upscale a PIL image using Real-ESRGAN.
305
+ scale=2 uses RealESRGAN_x2plus; scale=4 uses RealESRGAN_x4plus.
306
+ Imports are lazy so the packages are only required when upscaling is used.
307
+ """
308
+ try:
309
+ from basicsr.archs.rrdbnet_arch import RRDBNet
310
+ from realesrgan import RealESRGANer
311
+ except ImportError:
312
+ raise gr.Error(
313
+ "Real-ESRGAN is not installed. Add 'basicsr' and 'realesrgan' to requirements.txt."
314
+ )
315
+
316
+ if scale == 2:
317
+ model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=23, num_grow_ch=32, scale=2)
318
+ model_url = "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.1/RealESRGAN_x2plus.pth"
319
+ sr_scale = 2
320
+ else: # 4Γ—
321
+ model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=23, num_grow_ch=32, scale=4)
322
+ model_url = "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth"
323
+ sr_scale = 4
324
+
325
+ upsampler = RealESRGANer(
326
+ scale=sr_scale,
327
+ model_path=model_url,
328
+ model=model,
329
+ tile=512, # tile to keep VRAM usage manageable
330
+ tile_pad=10,
331
+ pre_pad=0,
332
+ half=True, # bfloat16/fp16 β€” matches the rest of the pipeline
333
+ device=device,
334
+ )
335
+
336
+ img_np = np.array(image)
337
+ img_bgr = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR)
338
+ output_bgr, _ = upsampler.enhance(img_bgr, outscale=sr_scale)
339
+ output_rgb = cv2.cvtColor(output_bgr, cv2.COLOR_BGR2RGB)
340
+ return Image.fromarray(output_rgb)
341
+
342
+
343
  @spaces.GPU
344
  def infer(
345
  input_images,
 
350
  randomize_seed,
351
  guidance_scale,
352
  steps,
353
+ upscale_factor,
354
  *slider_values,
355
  progress=gr.Progress(track_tqdm=True)
356
  ):
 
412
  else:
413
  full_prompt = user_prompt or lora_extra
414
 
415
+ # Always generate at base 1024-capped resolution
416
+ width, height = compute_base_dimensions(pil_images[0])
417
+ print(f"Generating at: {width} Γ— {height} px")
 
 
418
 
419
  processed_images = [img.resize((width, height), Image.LANCZOS).convert("RGB") for img in pil_images]
420
  image_input = processed_images if len(processed_images) > 1 else processed_images[0]
 
429
  num_inference_steps=steps,
430
  generator=torch.Generator(device=device).manual_seed(seed),
431
  ).images[0]
 
432
  except Exception as e:
433
  raise gr.Error(f"Inference failed: {e}")
434
+
435
+ # ── Post-generation upscaling ─────────────────────────────────────────────
436
+ if upscale_factor and upscale_factor != "None":
437
+ scale_int = int(upscale_factor[0]) # "2Γ—" β†’ 2, "4Γ—" β†’ 4
438
+ print(f"Upscaling {scale_int}Γ— with Real-ESRGAN…")
439
+ try:
440
+ image = apply_realesrgan(image, scale_int)
441
+ print(f"Upscaled to: {image.width} Γ— {image.height} px")
442
+ except Exception as e:
443
+ gr.Warning(f"Upscaling failed, returning 1024px result: {e}")
444
+ # ─────────────────────────────────────────────────────────────────────────
445
+
446
+ gc.collect()
447
+ torch.cuda.empty_cache()
448
+ return image, str(seed)
449
 
450
  # ── Dynamic LoRA loader ───────────────────────────────────────────────────────
451
 
 
538
  randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
539
  guidance_scale = gr.Slider(label="Guidance Scale", minimum=0.0, maximum=10.0, step=0.1, value=1.0)
540
  steps = gr.Slider(label="Steps", minimum=1, maximum=50, value=4, step=1)
541
+ upscale_factor = gr.Radio(
542
+ label="Upscale (Real-ESRGAN)",
543
+ info="Applied after generation. 2Γ— β‰ˆ 2048px, 4Γ— β‰ˆ 4096px on the longest side.",
544
+ choices=["None", "2Γ—", "4Γ—"],
545
+ value="None",
546
  )
547
 
548
  # ── Right column ─────────────────────────────────────────────────
549
  with gr.Column(scale=1):
550
  output_image = gr.Image(label="Output", interactive=False, format="png", height=320)
551
+ used_seed = gr.Textbox(
552
+ label="🌱 Seed used",
553
+ info="Re-enter this seed in Advanced Settings to reproduce the result exactly.",
554
+ interactive=False,
555
+ visible=True,
556
+ max_lines=1,
557
+ )
558
 
559
  # ── LoRA selector ─────────────────────────────────────────────────────
560
  gr.Markdown("### 🎨 Select LoRA(s)")
 
600
  ],
601
  inputs=[input_images, prompt, lora_selector, seed, randomize_seed, guidance_scale, steps],
602
  outputs=[output_image, used_seed],
603
+ fn=lambda imgs, p, sel, sd, rs, gs, st: infer(imgs, p, "", sel, sd, rs, gs, st, "None", *([1.0] * MAX_LORA_SLOTS)),
604
  cache_examples=False,
605
  label="Examples",
606
  )
 
629
 
630
  run_button.click(
631
  fn=infer,
632
+ inputs=[input_images, prompt, lora_prompt_display, lora_selector, seed, randomize_seed, guidance_scale, steps, upscale_factor] + weight_sliders,
633
  outputs=[output_image, used_seed],
634
  )
635