Alissonerdx commited on
Commit
0e18837
·
1 Parent(s): cb8dc60
Files changed (1) hide show
  1. app.py +47 -78
app.py CHANGED
@@ -22,6 +22,26 @@ DEFAULT_NEGATIVE_PROMPT = "bad quality, worst quality, low resolution, blur, dis
22
  # Cache for loaded pipe
23
  pipe_cache = None
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  @spaces.GPU(duration=300)
26
  def face_swap(
27
  body_image,
@@ -127,8 +147,19 @@ def face_swap(
127
  print(f"Active LoRAs: {adapters} with weights {adapter_weights}")
128
 
129
  # Prepare images
130
- body_img = Image.fromarray(body_image).convert("RGB")
131
- face_img = Image.fromarray(face_image).convert("RGB")
 
 
 
 
 
 
 
 
 
 
 
132
 
133
  # Combine fixed prompt with any additional instructions
134
  final_prompt = FIXED_PROMPT
@@ -137,20 +168,18 @@ def face_swap(
137
 
138
  print(f"Using prompt: {final_prompt[:100]}...")
139
 
140
- # --- CORREÇÃO PRINCIPAL AQUI ---
141
- # Qwen Image Edit aceita uma lista de imagens.
142
- # Index 0 = Picture 1 (Corpo), Index 1 = Picture 2 (Rosto)
143
- input_images_list = [body_img, face_img]
144
 
145
  # Generate the head swap
146
  result = pipe(
147
- image=input_images_list, # Passamos a lista aqui
148
  prompt=final_prompt,
149
  negative_prompt=DEFAULT_NEGATIVE_PROMPT,
150
- true_cfg_scale=guidance_scale,
151
- # input_image removido pois não existe neste pipeline
 
152
  num_inference_steps=num_inference_steps,
153
- #guidance_scale=guidance_scale,
154
  generator=generator
155
  ).images[0]
156
 
@@ -163,13 +192,12 @@ def face_swap(
163
  if enable_skin_lora and skin_lora_scale > 0:
164
  active_loras.append(f"Skin({skin_lora_scale:.2f})")
165
 
166
- status = f"✅ Head swap completed | Active LoRAs: {', '.join(active_loras) if active_loras else 'None'}"
167
 
168
  return result, status
169
 
170
  except Exception as e:
171
  print(f"Error: {str(e)}")
172
- # Return a blank red image on error so UI doesn't break
173
  error_img = Image.new('RGB', (512, 512), color=(200, 50, 50))
174
  return error_img, f"❌ Error: {str(e)}"
175
 
@@ -177,8 +205,10 @@ def face_swap(
177
  with gr.Blocks(title="BFS-Best Face Swap with Qwen", theme=gr.themes.Soft(), css="""
178
  .container {max-width: 1200px; margin: auto;}
179
  .image-container {border-radius: 10px; border: 2px dashed #ccc;}
180
- .fixed-prompt {background-color: #000000; padding: 10px; border-radius: 5px; font-family: monospace;}
181
- .lora-info {background-color: #000000; padding: 8px; border-radius: 5px; margin: 5px 0; font-size: 0.9em;}
 
 
182
  """) as demo:
183
  gr.Markdown(
184
  """
@@ -274,7 +304,7 @@ with gr.Blocks(title="BFS-Best Face Swap with Qwen", theme=gr.themes.Soft(), css
274
  minimum=10,
275
  maximum=100,
276
  step=5,
277
- value=20,
278
  label="Inference Steps",
279
  info="Higher = better quality but slower"
280
  )
@@ -283,8 +313,8 @@ with gr.Blocks(title="BFS-Best Face Swap with Qwen", theme=gr.themes.Soft(), css
283
  minimum=1.0,
284
  maximum=20.0,
285
  step=0.5,
286
- value=2.5,
287
- label="Guidance Scale",
288
  info="How closely to follow the prompt"
289
  )
290
 
@@ -342,67 +372,6 @@ with gr.Blocks(title="BFS-Best Face Swap with Qwen", theme=gr.themes.Soft(), css
342
  outputs=skin_lora_scale
343
  )
344
 
345
- # # Examples
346
- # gr.Examples(
347
- # examples=[
348
- # [
349
- # None, # body_image
350
- # None, # face_image
351
- # "", # custom_prompt_addon
352
- # 1.0, # bfs_lora_scale
353
- # 0.7, # angles_lora_scale
354
- # 0.6, # skin_lora_scale
355
- # True, # enable_angles_lora
356
- # True, # enable_skin_lora
357
- # 30, # num_inference_steps
358
- # 7.5, # guidance_scale
359
- # 42 # seed
360
- # ],
361
- # [
362
- # None,
363
- # None,
364
- # "professional lighting, high resolution",
365
- # 1.2,
366
- # 0.8,
367
- # 0.5,
368
- # True,
369
- # True,
370
- # 40,
371
- # 8.0,
372
- # 123
373
- # ],
374
- # [
375
- # None,
376
- # None,
377
- # "",
378
- # 0.9,
379
- # 0.0,
380
- # 0.0,
381
- # False,
382
- # False,
383
- # 25,
384
- # 7.0,
385
- # -1
386
- # ]
387
- # ],
388
- # inputs=[
389
- # body_image,
390
- # face_image,
391
- # custom_prompt_addon,
392
- # bfs_lora_scale,
393
- # angles_lora_scale,
394
- # skin_lora_scale,
395
- # enable_angles_lora,
396
- # enable_skin_lora,
397
- # num_inference_steps,
398
- # guidance_scale,
399
- # seed
400
- # ],
401
- # outputs=[output_image, status_text],
402
- # fn=face_swap,
403
- # cache_examples=False
404
- # )
405
-
406
  # Event handlers
407
  generate_btn.click(
408
  fn=face_swap,
 
22
  # Cache for loaded pipe
23
  pipe_cache = None
24
 
25
+ # Função auxiliar para redimensionar mantendo aspect ratio
26
+ def smart_resize(image, target_long_edge=1024):
27
+ width, height = image.size
28
+
29
+ # Calcular nova proporção mantendo o aspect ratio
30
+ if width > height:
31
+ new_width = target_long_edge
32
+ new_height = int(height * (target_long_edge / width))
33
+ else:
34
+ new_height = target_long_edge
35
+ new_width = int(width * (target_long_edge / height))
36
+
37
+ # Arredondar para múltiplos de 32 (necessário para o modelo)
38
+ new_width = (new_width // 32) * 32
39
+ new_height = (new_height // 32) * 32
40
+
41
+ # Redimensionar usando LANCZOS para alta qualidade
42
+ resized_image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
43
+ return resized_image, new_width, new_height
44
+
45
  @spaces.GPU(duration=300)
46
  def face_swap(
47
  body_image,
 
147
  print(f"Active LoRAs: {adapters} with weights {adapter_weights}")
148
 
149
  # Prepare images
150
+ body_img_pil = Image.fromarray(body_image).convert("RGB")
151
+ face_img_pil = Image.fromarray(face_image).convert("RGB")
152
+
153
+ # --- LÓGICA DE REDIMENSIONAMENTO INTELIGENTE ---
154
+ # Define o tamanho alvo baseado no maior lado (1024 é um bom equilíbrio, pode subir para 1280)
155
+ # Isso corrige a distorção mantendo o aspect ratio correto
156
+ TARGET_RESOLUTION = 1024
157
+
158
+ body_resized, target_w, target_h = smart_resize(body_img_pil, target_long_edge=TARGET_RESOLUTION)
159
+ # Opcional: redimensionar a face para não ficar gigante ou minúscula comparada ao corpo
160
+ face_resized, _, _ = smart_resize(face_img_pil, target_long_edge=TARGET_RESOLUTION)
161
+
162
+ print(f"Original size: {body_img_pil.size} | Generation Target: {target_w}x{target_h}")
163
 
164
  # Combine fixed prompt with any additional instructions
165
  final_prompt = FIXED_PROMPT
 
168
 
169
  print(f"Using prompt: {final_prompt[:100]}...")
170
 
171
+ # Qwen Image Edit uses a list for inputs: [body, face]
172
+ input_images_list = [body_resized, face_resized]
 
 
173
 
174
  # Generate the head swap
175
  result = pipe(
176
+ image=input_images_list,
177
  prompt=final_prompt,
178
  negative_prompt=DEFAULT_NEGATIVE_PROMPT,
179
+ true_cfg_scale=guidance_scale,
180
+ height=target_h, # FORÇA A ALTURA CORRETA
181
+ width=target_w, # FORÇA A LARGURA CORRETA
182
  num_inference_steps=num_inference_steps,
 
183
  generator=generator
184
  ).images[0]
185
 
 
192
  if enable_skin_lora and skin_lora_scale > 0:
193
  active_loras.append(f"Skin({skin_lora_scale:.2f})")
194
 
195
+ status = f"✅ Head swap completed ({target_w}x{target_h}) | Active LoRAs: {', '.join(active_loras) if active_loras else 'None'}"
196
 
197
  return result, status
198
 
199
  except Exception as e:
200
  print(f"Error: {str(e)}")
 
201
  error_img = Image.new('RGB', (512, 512), color=(200, 50, 50))
202
  return error_img, f"❌ Error: {str(e)}"
203
 
 
205
  with gr.Blocks(title="BFS-Best Face Swap with Qwen", theme=gr.themes.Soft(), css="""
206
  .container {max-width: 1200px; margin: auto;}
207
  .image-container {border-radius: 10px; border: 2px dashed #ccc;}
208
+ .fixed-prompt {background-color: #000000; padding: 10px; border-radius: 5px; font-family: monospace; color: #00ff00;}
209
+ .lora-info {background-color: #000000; padding: 8px; border-radius: 5px; margin: 5px 0; font-size: 0.9em; color: white;}
210
+ .footer-link {text-decoration: none !important; color: #5865F2 !important; font-weight: bold;}
211
+ .footer-link:hover {text-decoration: underline !important;}
212
  """) as demo:
213
  gr.Markdown(
214
  """
 
304
  minimum=10,
305
  maximum=100,
306
  step=5,
307
+ value=30,
308
  label="Inference Steps",
309
  info="Higher = better quality but slower"
310
  )
 
313
  minimum=1.0,
314
  maximum=20.0,
315
  step=0.5,
316
+ value=5.0,
317
+ label="Guidance Scale (CFG)",
318
  info="How closely to follow the prompt"
319
  )
320
 
 
372
  outputs=skin_lora_scale
373
  )
374
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
375
  # Event handlers
376
  generate_btn.click(
377
  fn=face_swap,