malazjanbeih commited on
Commit
2ac82d8
Β·
verified Β·
1 Parent(s): 106019c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +43 -142
app.py CHANGED
@@ -1,13 +1,6 @@
1
  # ============================================================================
2
  # ULTIMATE FACE SWAP - 100% QUALITY + HEAD SWAP (WITH HAIR!)
3
- #
4
- # UPGRADES:
5
- # 1. βœ… CodeFormer instead of GFPGAN (superior quality - 100%!)
6
- # 2. βœ… Head swap mode (includes hair, ears, neck!)
7
- # 3. βœ… Dual restoration (CodeFormer + GFPGAN together = maximum quality)
8
- # 4. βœ… Higher fidelity weight (0.5 β†’ 0.2 for more detail)
9
- # 5. βœ… Small previews (400x300)
10
- # 6. βœ… FIXED: MoviePy import error
11
  # ============================================================================
12
 
13
  print("="*80)
@@ -19,9 +12,9 @@ import subprocess, sys
19
  print("\n[1/7] Installing packages...")
20
  subprocess.check_call([
21
  sys.executable, "-m", "pip", "install", "-q",
22
- "gradio", "insightface==0.7.3", "onnxruntime-gpu",
23
- "opencv-python-headless", "moviepy==2.0.0.dev2", "numpy", "scipy", "tqdm",
24
- "gfpgan", "basicsr", "facexlib", "imageio-ffmpeg"
25
  ])
26
  print("βœ“ Installed")
27
 
@@ -38,27 +31,21 @@ from insightface.model_zoo import get_model
38
  try:
39
  from moviepy.editor import VideoFileClip, ImageSequenceClip
40
  except ImportError:
41
- try:
42
- from moviepy import VideoFileClip, ImageSequenceClip
43
- except ImportError:
44
- # Final fallback - install older stable version
45
- print(" Installing moviepy 1.0.3...")
46
- subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", "moviepy==1.0.3"])
47
- from moviepy.editor import VideoFileClip, ImageSequenceClip
48
 
49
  from tqdm import tqdm
50
  print("βœ“ Imported")
51
 
52
  # ============================================================================
53
- # SECTION 1: FACE DETECTION
54
  # ============================================================================
55
  print("\n[3/7] Loading face detector...")
56
- face_app = FaceAnalysis(name="buffalo_l")
57
- face_app.prepare(ctx_id=0, det_size=(640, 640))
58
- print("βœ“ Face detector loaded")
59
 
60
  # ============================================================================
61
- # SECTION 2: INSWAPPER MODEL
62
  # ============================================================================
63
  print("\n[4/7] Loading INSwapper...")
64
 
@@ -75,18 +62,18 @@ try:
75
  urllib.request.urlretrieve(url, model_path)
76
  print(f" βœ“ Downloaded ({os.path.getsize(model_path) // 1_000_000}MB)")
77
 
78
- swapper = get_model(model_path, download=False, download_zip=False)
79
 
80
  SWAPPER_LOADED = True
81
- print("βœ“ INSwapper loaded")
82
 
83
  except Exception as e:
84
  print(f"βœ— INSwapper failed: {e}")
85
 
86
  # ============================================================================
87
- # SECTION 3: CODEFORMER (SUPERIOR TO GFPGAN!)
88
  # ============================================================================
89
- print("\n[5/7] Loading CodeFormer (best quality)...")
90
 
91
  codeformer_net = None
92
  CODEFORMER_LOADED = False
@@ -96,7 +83,6 @@ try:
96
  from basicsr.utils.download_util import load_file_from_url
97
  from basicsr.utils import imwrite, img2tensor, tensor2img
98
  from facexlib.utils.face_restoration_helper import FaceRestoreHelper
99
- from torchvision.transforms.functional import normalize
100
  import torch
101
 
102
  # Download CodeFormer model
@@ -110,7 +96,6 @@ try:
110
  print(" βœ“ Downloaded")
111
 
112
  # Load CodeFormer network
113
- from basicsr.utils import get_root_logger
114
  from basicsr.archs import build_network
115
 
116
  codeformer_net = build_network({
@@ -125,7 +110,8 @@ try:
125
  codeformer_net.load_state_dict(checkpoint['params_ema'])
126
  codeformer_net.eval()
127
 
128
- device = 'cuda' if torch.cuda.is_available() else 'cpu'
 
129
  codeformer_net = codeformer_net.to(device)
130
 
131
  # Face helper for detection and alignment
@@ -140,7 +126,7 @@ try:
140
  )
141
 
142
  CODEFORMER_LOADED = True
143
- print("βœ“ CodeFormer loaded - Maximum quality mode!")
144
 
145
  except Exception as e:
146
  print(f"⚠ CodeFormer failed: {e}")
@@ -149,7 +135,7 @@ except Exception as e:
149
  # ============================================================================
150
  # SECTION 4: GFPGAN (BACKUP/COMPLEMENTARY)
151
  # ============================================================================
152
- print("\n[6/7] Loading GFPGAN (complementary)...")
153
 
154
  gfpgan_restorer = None
155
  GFPGAN_LOADED = False
@@ -172,11 +158,12 @@ try:
172
  upscale=2,
173
  arch='clean',
174
  channel_multiplier=2,
175
- bg_upsampler=None
 
176
  )
177
 
178
  GFPGAN_LOADED = True
179
- print("βœ“ GFPGAN loaded (complementary mode)")
180
 
181
  except Exception as e:
182
  print(f"⚠ GFPGAN unavailable: {e}")
@@ -230,18 +217,15 @@ def detect_faces_with_preview(image):
230
  return cv2.cvtColor(preview_small, cv2.COLOR_BGR2RGB), faces
231
 
232
  # ============================================================================
233
- # CODEFORMER RESTORATION FUNCTION (100% QUALITY!)
234
  # ============================================================================
235
 
236
  def restore_with_codeformer(face_img, fidelity_weight=0.2):
237
- """
238
- Apply CodeFormer restoration with LOW fidelity (0.2 = more AI detail)
239
- Lower fidelity = more enhancement, higher quality!
240
- """
241
  import torch
242
- from torchvision.transforms.functional import normalize
243
 
244
- device = 'cuda' if torch.cuda.is_available() else 'cpu'
245
 
246
  # Prepare image
247
  face_img = cv2.resize(face_img, (512, 512), interpolation=cv2.INTER_LINEAR)
@@ -249,7 +233,7 @@ def restore_with_codeformer(face_img, fidelity_weight=0.2):
249
  face_img = torch.from_numpy(face_img).permute(2, 0, 1).unsqueeze(0).to(device)
250
 
251
  # Normalize
252
- normalize(face_img, (0.5, 0.5, 0.5), (0.5, 0.5, 0.5), inplace=True)
253
 
254
  # Run CodeFormer
255
  with torch.no_grad():
@@ -262,15 +246,11 @@ def restore_with_codeformer(face_img, fidelity_weight=0.2):
262
  return output
263
 
264
  # ============================================================================
265
- # ENHANCED FACE SWAP (100% QUALITY + HEAD SWAP MODE!)
266
  # ============================================================================
267
 
268
  def swap_face_in_frame(frame, source_face, target_face_idx=None, include_hair=False):
269
- """
270
- Enhanced face swap with:
271
- - CodeFormer for maximum quality
272
- - Optional head swap mode (includes hair!)
273
- """
274
  if not SWAPPER_LOADED:
275
  return frame
276
 
@@ -289,40 +269,31 @@ def swap_face_in_frame(frame, source_face, target_face_idx=None, include_hair=Fa
289
  for target_face in target_faces:
290
  result = swapper.get(result, target_face, source_face, paste_back=True)
291
 
292
- # CRITICAL: Apply CodeFormer for 100% quality!
293
  if CODEFORMER_LOADED and codeformer_net:
294
  try:
295
  swapped_faces = face_app.get(result)
296
 
297
  for face in swapped_faces:
298
  x1, y1, x2, y2 = face.bbox.astype(int)
299
-
300
- # Expand region for head swap mode
301
  h, w = result.shape[:2]
302
 
303
  if include_hair:
304
- # HEAD SWAP: Include hair, ears, neck!
305
- pad = int(max(x2-x1, y2-y1) * 0.6) # 60% padding
306
  else:
307
- # FACE SWAP: Just face
308
- pad = int(max(x2-x1, y2-y1) * 0.3) # 30% padding
309
 
310
  x1 = max(0, x1 - pad)
311
  y1 = max(0, y1 - pad)
312
  x2 = min(w, x2 + pad)
313
  y2 = min(h, y2 + pad)
314
 
315
- # Extract region
316
  face_region = result[y1:y2, x1:x2].copy()
317
  original_size = (x2-x1, y2-y1)
318
 
319
- # Apply CodeFormer with LOW fidelity (0.2 = maximum quality!)
320
  restored_face = restore_with_codeformer(face_region, fidelity_weight=0.2)
321
-
322
- # Resize back
323
  restored_face = cv2.resize(restored_face, original_size, interpolation=cv2.INTER_LANCZOS4)
324
 
325
- # Optional: Apply GFPGAN too for dual restoration
326
  if GFPGAN_LOADED and gfpgan_restorer:
327
  try:
328
  _, _, restored_face = gfpgan_restorer.enhance(
@@ -334,16 +305,14 @@ def swap_face_in_frame(frame, source_face, target_face_idx=None, include_hair=Fa
334
  except:
335
  pass
336
 
337
- # Put restored face back
338
  result[y1:y2, x1:x2] = restored_face
339
 
340
- print(" βœ“ CodeFormer applied - 100% quality!")
341
 
342
  except Exception as e:
343
  print(f" ⚠ CodeFormer error: {e}")
344
 
345
  elif GFPGAN_LOADED and gfpgan_restorer:
346
- # Fallback to GFPGAN only
347
  try:
348
  swapped_faces = face_app.get(result)
349
 
@@ -368,7 +337,7 @@ def swap_face_in_frame(frame, source_face, target_face_idx=None, include_hair=Fa
368
 
369
  result[y1:y2, x1:x2] = restored_face
370
 
371
- print(" βœ“ GFPGAN applied - 90% quality")
372
 
373
  except Exception as e:
374
  print(f" ⚠ GFPGAN error: {e}")
@@ -380,7 +349,7 @@ def swap_face_in_frame(frame, source_face, target_face_idx=None, include_hair=Fa
380
  # ============================================================================
381
 
382
  def process_video(video_path, source_face, target_face_index, include_hair, progress_fn):
383
- """Process video with 100% quality + optional head swap"""
384
 
385
  if not SWAPPER_LOADED:
386
  raise ValueError("INSwapper not loaded!")
@@ -395,11 +364,6 @@ def process_video(video_path, source_face, target_face_index, include_hair, prog
395
  else:
396
  print("FACE SWAP MODE: Swapping face only")
397
 
398
- if CODEFORMER_LOADED:
399
- print("Using CodeFormer - 100% quality!")
400
- elif GFPGAN_LOADED:
401
- print("Using GFPGAN - 90% quality")
402
-
403
  processed_frames = []
404
 
405
  for i, frame in enumerate(clip.iter_frames()):
@@ -528,7 +492,7 @@ def handle_generate(source_choice, target_choice, include_hair, progress=gr.Prog
528
 
529
  progress(1.0, desc="Complete!")
530
 
531
- status = "βœ… DONE - 100% QUALITY!\n\n"
532
  status += "Applied:\n"
533
  status += "βœ“ INSwapper face swap\n"
534
  if include_hair:
@@ -537,9 +501,9 @@ def handle_generate(source_choice, target_choice, include_hair, progress=gr.Prog
537
  status += "βœ“ FACE SWAP (face only)\n"
538
 
539
  if CODEFORMER_LOADED:
540
- status += "βœ“ CodeFormer restoration (100% quality!)\n"
541
  elif GFPGAN_LOADED:
542
- status += "βœ“ GFPGAN restoration (90% quality)\n"
543
 
544
  return result, status
545
 
@@ -555,8 +519,8 @@ print("\n[7/7] Building interface...")
555
 
556
  with gr.Blocks(theme=gr.themes.Soft(), title="Ultimate Face Swap") as demo:
557
 
558
- gr.Markdown("# πŸ”₯ ULTIMATE - 100% QUALITY + HEAD SWAP!")
559
- gr.Markdown("### CodeFormer (superior to GFPGAN) + Head Swap Mode!")
560
 
561
  if SWAPPER_LOADED:
562
  gr.Markdown("βœ… **INSwapper Loaded**")
@@ -564,77 +528,14 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Ultimate Face Swap") as demo:
564
  gr.Markdown("❌ **INSwapper Failed**")
565
 
566
  if CODEFORMER_LOADED:
567
- gr.Markdown("βœ… **CodeFormer Active** - 100% quality guaranteed!")
568
  elif GFPGAN_LOADED:
569
- gr.Markdown("⚠️ **GFPGAN Only** - 90% quality")
570
  else:
571
- gr.Markdown("⚠️ **No restoration** - 85% quality")
572
 
573
  with gr.Row():
574
  with gr.Column():
575
  gr.Markdown("### πŸ“Έ Source Image")
576
  source_image = gr.Image(type="numpy", label="Upload Source Face")
577
- source_preview = gr.Image(label="Detected (1/4 size)", height=300)
578
- source_status = gr.Textbox(label="Status", lines=2)
579
- source_dropdown = gr.Dropdown(label="Select Face")
580
-
581
- with gr.Column():
582
- gr.Markdown("### 🎬 Target Video")
583
- target_video = gr.Video(label="Upload Target Video")
584
- target_preview = gr.Image(label="Detected (1/4 size)", height=300)
585
- target_status = gr.Textbox(label="Status", lines=2)
586
- target_dropdown = gr.Dropdown(label="Select Person")
587
-
588
- gr.Markdown("### πŸš€ Generate Video")
589
-
590
- head_swap_checkbox = gr.Checkbox(
591
- value=False,
592
- label="πŸ”₯ HEAD SWAP MODE (includes hair, ears, neck!)"
593
- )
594
-
595
- generate_button = gr.Button(
596
- "🎭 Generate 100% Quality Video!",
597
- variant="primary",
598
- size="lg"
599
- )
600
-
601
- generation_status = gr.Textbox(label="Status", lines=6)
602
- result_video = gr.Video(label="Result")
603
-
604
- # Events
605
- source_image.change(
606
- handle_source_image,
607
- inputs=[source_image],
608
- outputs=[source_preview, source_status, source_dropdown]
609
- )
610
-
611
- target_video.change(
612
- handle_target_video,
613
- inputs=[target_video],
614
- outputs=[target_preview, target_status, target_dropdown]
615
- )
616
-
617
- generate_button.click(
618
- handle_generate,
619
- inputs=[source_dropdown, target_dropdown, head_swap_checkbox],
620
- outputs=[result_video, generation_status]
621
- )
622
-
623
- print("βœ“ Interface built")
624
-
625
- print("\n" + "="*80)
626
- print("LAUNCHING - 100% QUALITY + HEAD SWAP MODE!")
627
- print("="*80)
628
-
629
- if SWAPPER_LOADED and CODEFORMER_LOADED:
630
- print("βœ… All systems ready - 100% quality + head swap available!")
631
- elif SWAPPER_LOADED:
632
- print("⚠️ CodeFormer unavailable - quality limited to 90%")
633
- else:
634
- print("❌ INSwapper failed")
635
-
636
- demo.queue()
637
- demo.launch(share=True)
638
-
639
- print("\nβœ… Running!")
640
- print("="*80)
 
1
  # ============================================================================
2
  # ULTIMATE FACE SWAP - 100% QUALITY + HEAD SWAP (WITH HAIR!)
3
+ # Fixed for Hugging Face Spaces deployment
 
 
 
 
 
 
 
4
  # ============================================================================
5
 
6
  print("="*80)
 
12
  print("\n[1/7] Installing packages...")
13
  subprocess.check_call([
14
  sys.executable, "-m", "pip", "install", "-q",
15
+ "gradio==4.44.1", "insightface==0.7.3", "onnxruntime",
16
+ "opencv-python-headless", "moviepy==1.0.3", "numpy", "scipy", "tqdm",
17
+ "gfpgan", "basicsr", "facexlib", "torch", "torchvision"
18
  ])
19
  print("βœ“ Installed")
20
 
 
31
  try:
32
  from moviepy.editor import VideoFileClip, ImageSequenceClip
33
  except ImportError:
34
+ from moviepy import VideoFileClip, ImageSequenceClip
 
 
 
 
 
 
35
 
36
  from tqdm import tqdm
37
  print("βœ“ Imported")
38
 
39
  # ============================================================================
40
+ # SECTION 1: FACE DETECTION (CPU MODE)
41
  # ============================================================================
42
  print("\n[3/7] Loading face detector...")
43
+ face_app = FaceAnalysis(name="buffalo_l", providers=['CPUExecutionProvider'])
44
+ face_app.prepare(ctx_id=-1, det_size=(640, 640)) # ctx_id=-1 for CPU
45
+ print("βœ“ Face detector loaded (CPU mode)")
46
 
47
  # ============================================================================
48
+ # SECTION 2: INSWAPPER MODEL (CPU MODE)
49
  # ============================================================================
50
  print("\n[4/7] Loading INSwapper...")
51
 
 
62
  urllib.request.urlretrieve(url, model_path)
63
  print(f" βœ“ Downloaded ({os.path.getsize(model_path) // 1_000_000}MB)")
64
 
65
+ swapper = get_model(model_path, download=False, download_zip=False, providers=['CPUExecutionProvider'])
66
 
67
  SWAPPER_LOADED = True
68
+ print("βœ“ INSwapper loaded (CPU mode)")
69
 
70
  except Exception as e:
71
  print(f"βœ— INSwapper failed: {e}")
72
 
73
  # ============================================================================
74
+ # SECTION 3: CODEFORMER (SIMPLIFIED FOR CPU)
75
  # ============================================================================
76
+ print("\n[5/7] Loading CodeFormer...")
77
 
78
  codeformer_net = None
79
  CODEFORMER_LOADED = False
 
83
  from basicsr.utils.download_util import load_file_from_url
84
  from basicsr.utils import imwrite, img2tensor, tensor2img
85
  from facexlib.utils.face_restoration_helper import FaceRestoreHelper
 
86
  import torch
87
 
88
  # Download CodeFormer model
 
96
  print(" βœ“ Downloaded")
97
 
98
  # Load CodeFormer network
 
99
  from basicsr.archs import build_network
100
 
101
  codeformer_net = build_network({
 
110
  codeformer_net.load_state_dict(checkpoint['params_ema'])
111
  codeformer_net.eval()
112
 
113
+ # Always use CPU for Spaces
114
+ device = 'cpu'
115
  codeformer_net = codeformer_net.to(device)
116
 
117
  # Face helper for detection and alignment
 
126
  )
127
 
128
  CODEFORMER_LOADED = True
129
+ print("βœ“ CodeFormer loaded (CPU mode)")
130
 
131
  except Exception as e:
132
  print(f"⚠ CodeFormer failed: {e}")
 
135
  # ============================================================================
136
  # SECTION 4: GFPGAN (BACKUP/COMPLEMENTARY)
137
  # ============================================================================
138
+ print("\n[6/7] Loading GFPGAN...")
139
 
140
  gfpgan_restorer = None
141
  GFPGAN_LOADED = False
 
158
  upscale=2,
159
  arch='clean',
160
  channel_multiplier=2,
161
+ bg_upsampler=None,
162
+ device='cpu' # Force CPU
163
  )
164
 
165
  GFPGAN_LOADED = True
166
+ print("βœ“ GFPGAN loaded (CPU mode)")
167
 
168
  except Exception as e:
169
  print(f"⚠ GFPGAN unavailable: {e}")
 
217
  return cv2.cvtColor(preview_small, cv2.COLOR_BGR2RGB), faces
218
 
219
  # ============================================================================
220
+ # CODEFORMER RESTORATION FUNCTION
221
  # ============================================================================
222
 
223
  def restore_with_codeformer(face_img, fidelity_weight=0.2):
224
+ """Apply CodeFormer restoration"""
 
 
 
225
  import torch
226
+ from torchvision.transforms import functional as F
227
 
228
+ device = 'cpu'
229
 
230
  # Prepare image
231
  face_img = cv2.resize(face_img, (512, 512), interpolation=cv2.INTER_LINEAR)
 
233
  face_img = torch.from_numpy(face_img).permute(2, 0, 1).unsqueeze(0).to(device)
234
 
235
  # Normalize
236
+ face_img = F.normalize(face_img, (0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
237
 
238
  # Run CodeFormer
239
  with torch.no_grad():
 
246
  return output
247
 
248
  # ============================================================================
249
+ # ENHANCED FACE SWAP
250
  # ============================================================================
251
 
252
  def swap_face_in_frame(frame, source_face, target_face_idx=None, include_hair=False):
253
+ """Enhanced face swap with restoration"""
 
 
 
 
254
  if not SWAPPER_LOADED:
255
  return frame
256
 
 
269
  for target_face in target_faces:
270
  result = swapper.get(result, target_face, source_face, paste_back=True)
271
 
272
+ # Apply restoration
273
  if CODEFORMER_LOADED and codeformer_net:
274
  try:
275
  swapped_faces = face_app.get(result)
276
 
277
  for face in swapped_faces:
278
  x1, y1, x2, y2 = face.bbox.astype(int)
 
 
279
  h, w = result.shape[:2]
280
 
281
  if include_hair:
282
+ pad = int(max(x2-x1, y2-y1) * 0.6)
 
283
  else:
284
+ pad = int(max(x2-x1, y2-y1) * 0.3)
 
285
 
286
  x1 = max(0, x1 - pad)
287
  y1 = max(0, y1 - pad)
288
  x2 = min(w, x2 + pad)
289
  y2 = min(h, y2 + pad)
290
 
 
291
  face_region = result[y1:y2, x1:x2].copy()
292
  original_size = (x2-x1, y2-y1)
293
 
 
294
  restored_face = restore_with_codeformer(face_region, fidelity_weight=0.2)
 
 
295
  restored_face = cv2.resize(restored_face, original_size, interpolation=cv2.INTER_LANCZOS4)
296
 
 
297
  if GFPGAN_LOADED and gfpgan_restorer:
298
  try:
299
  _, _, restored_face = gfpgan_restorer.enhance(
 
305
  except:
306
  pass
307
 
 
308
  result[y1:y2, x1:x2] = restored_face
309
 
310
+ print(" βœ“ CodeFormer applied")
311
 
312
  except Exception as e:
313
  print(f" ⚠ CodeFormer error: {e}")
314
 
315
  elif GFPGAN_LOADED and gfpgan_restorer:
 
316
  try:
317
  swapped_faces = face_app.get(result)
318
 
 
337
 
338
  result[y1:y2, x1:x2] = restored_face
339
 
340
+ print(" βœ“ GFPGAN applied")
341
 
342
  except Exception as e:
343
  print(f" ⚠ GFPGAN error: {e}")
 
349
  # ============================================================================
350
 
351
  def process_video(video_path, source_face, target_face_index, include_hair, progress_fn):
352
+ """Process video with face swap"""
353
 
354
  if not SWAPPER_LOADED:
355
  raise ValueError("INSwapper not loaded!")
 
364
  else:
365
  print("FACE SWAP MODE: Swapping face only")
366
 
 
 
 
 
 
367
  processed_frames = []
368
 
369
  for i, frame in enumerate(clip.iter_frames()):
 
492
 
493
  progress(1.0, desc="Complete!")
494
 
495
+ status = "βœ… DONE!\n\n"
496
  status += "Applied:\n"
497
  status += "βœ“ INSwapper face swap\n"
498
  if include_hair:
 
501
  status += "βœ“ FACE SWAP (face only)\n"
502
 
503
  if CODEFORMER_LOADED:
504
+ status += "βœ“ CodeFormer restoration\n"
505
  elif GFPGAN_LOADED:
506
+ status += "βœ“ GFPGAN restoration\n"
507
 
508
  return result, status
509
 
 
519
 
520
  with gr.Blocks(theme=gr.themes.Soft(), title="Ultimate Face Swap") as demo:
521
 
522
+ gr.Markdown("# πŸ”₯ ULTIMATE FACE SWAP + HEAD SWAP!")
523
+ gr.Markdown("### Professional face swapping with enhancement")
524
 
525
  if SWAPPER_LOADED:
526
  gr.Markdown("βœ… **INSwapper Loaded**")
 
528
  gr.Markdown("❌ **INSwapper Failed**")
529
 
530
  if CODEFORMER_LOADED:
531
+ gr.Markdown("βœ… **CodeFormer Active**")
532
  elif GFPGAN_LOADED:
533
+ gr.Markdown("βœ… **GFPGAN Active**")
534
  else:
535
+ gr.Markdown("⚠️ **No restoration available**")
536
 
537
  with gr.Row():
538
  with gr.Column():
539
  gr.Markdown("### πŸ“Έ Source Image")
540
  source_image = gr.Image(type="numpy", label="Upload Source Face")
541
+ source_preview = gr.Image(label