primerz commited on
Commit
86e1d01
·
verified ·
1 Parent(s): ef0001b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +120 -116
app.py CHANGED
@@ -38,7 +38,7 @@ from compel import Compel, ReturnedEmbeddingsType
38
 
39
  from gradio_imageslider import ImageSlider
40
 
41
- # Load LoRA configurations
42
  with open("sdxl_loras.json", "r") as file:
43
  data = json.load(file)
44
  sdxl_loras_raw = [
@@ -123,8 +123,9 @@ et = time.time()
123
  print('Loading VAE took: ', et - st, 'seconds')
124
 
125
  st = time.time()
 
126
  pipe = StableDiffusionXLInstantIDImg2ImgPipeline.from_pretrained(
127
- "SG161222/RealVisXL_V5.0",
128
  vae=vae,
129
  controlnet=[identitynet, zoedepthnet],
130
  torch_dtype=torch.float16
@@ -132,7 +133,8 @@ pipe = StableDiffusionXLInstantIDImg2ImgPipeline.from_pretrained(
132
 
133
  pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config, use_karras_sigmas=True)
134
  pipe.load_ip_adapter_instantid(face_adapter)
135
- pipe.set_ip_adapter_scale(0.9)
 
136
  et = time.time()
137
  print('Loading pipeline took: ', et - st, 'seconds')
138
 
@@ -157,10 +159,10 @@ last_lora = ""
157
  last_fused = False
158
  lora_archive = "/data"
159
 
160
- # Improved face detection with multi-face support
161
  def detect_faces(face_image, use_multiple_faces=False):
162
  """
163
- Detect faces in the image
164
  Returns: list of face info dictionaries, or empty list if no faces
165
  """
166
  try:
@@ -170,47 +172,56 @@ def detect_faces(face_image, use_multiple_faces=False):
170
  print("No faces detected")
171
  return []
172
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  # Sort faces by size (largest first)
174
- face_info_list = sorted(
175
- face_info_list,
176
  key=lambda x: (x['bbox'][2] - x['bbox'][0]) * (x['bbox'][3] - x['bbox'][1]),
177
  reverse=True
178
  )
179
 
180
  if use_multiple_faces:
181
- print(f"Detected {len(face_info_list)} faces")
182
- return face_info_list
183
  else:
184
- print(f"Using largest face (detected {len(face_info_list)} total)")
185
- return [face_info_list[0]]
186
 
187
  except Exception as e:
188
  print(f"Face detection error: {e}")
189
  return []
190
 
191
- def process_face_embeddings(face_info_list):
192
  """
193
- Process face embeddings - average multiple faces or return single face
 
194
  """
195
  if not face_info_list:
196
- return None
197
-
198
- if len(face_info_list) == 1:
199
- return face_info_list[0]['embedding']
200
 
201
- # Average embeddings for multiple faces
202
  embeddings = [face_info['embedding'] for face_info in face_info_list]
203
- avg_embedding = np.mean(embeddings, axis=0)
204
- return avg_embedding
205
 
206
  def create_face_kps_image(face_image, face_info_list):
207
  """
208
- Create keypoints image from face info
209
  """
210
  if not face_info_list:
211
  return face_image
212
 
213
- # For multiple faces, draw all keypoints
214
  if len(face_info_list) > 1:
215
  return draw_multiple_kps(face_image, [f['kps'] for f in face_info_list])
216
  else:
@@ -218,7 +229,7 @@ def create_face_kps_image(face_image, face_info_list):
218
 
219
  def draw_multiple_kps(image_pil, kps_list, color_list=[(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (255, 0, 255)]):
220
  """
221
- Draw keypoints for multiple faces
222
  """
223
  stickwidth = 4
224
  limbSeq = np.array([[0, 2], [1, 2], [3, 2], [4, 2]])
@@ -226,12 +237,14 @@ def draw_multiple_kps(image_pil, kps_list, color_list=[(255, 0, 0), (0, 255, 0),
226
  w, h = image_pil.size
227
  out_img = np.zeros([h, w, 3])
228
 
229
- for kps in kps_list:
230
  kps = np.array(kps)
 
 
231
 
232
  for i in range(len(limbSeq)):
233
  index = limbSeq[i]
234
- color = color_list[index[0]]
235
 
236
  x = kps[index][:, 0]
237
  y = kps[index][:, 1]
@@ -245,7 +258,7 @@ def draw_multiple_kps(image_pil, kps_list, color_list=[(255, 0, 0), (0, 255, 0),
245
  out_img = (out_img * 0.6).astype(np.uint8)
246
 
247
  for idx_kp, kp in enumerate(kps):
248
- color = color_list[idx_kp]
249
  x, y = kp
250
  out_img = cv2.circle(out_img.copy(), (int(x), int(y)), 10, color, -1)
251
 
@@ -260,9 +273,9 @@ def update_selection(selected_state: gr.SelectData, sdxl_loras, face_strength, i
260
 
261
  for lora_list in lora_defaults:
262
  if lora_list["model"] == sdxl_loras[selected_state.index]["repo"]:
263
- face_strength = lora_list.get("face_strength", 0.9)
264
- image_strength = lora_list.get("image_strength", 0.2)
265
- weight = lora_list.get("weight", 0.95)
266
  depth_control_scale = lora_list.get("depth_control_scale", 0.8)
267
  negative = lora_list.get("negative", "")
268
 
@@ -308,10 +321,7 @@ def run_lora(face_image, prompt, negative, lora_scale, selected_state, face_stre
308
  guidance_scale, depth_control_scale, sdxl_loras, custom_lora, use_multiple_faces=False,
309
  progress=gr.Progress(track_tqdm=True)):
310
  """
311
- Enhanced run_lora with support for:
312
- - No faces (landscape mode)
313
- - Multiple faces
314
- - Improved results
315
  """
316
  print("Custom LoRA:", custom_lora)
317
  custom_lora_path = custom_lora[0] if custom_lora else None
@@ -320,26 +330,22 @@ def run_lora(face_image, prompt, negative, lora_scale, selected_state, face_stre
320
  st = time.time()
321
  face_image = resize_image_aspect_ratio(face_image)
322
 
323
- # Validate selection FIRST before any array access
324
- if not selected_state and not custom_lora_path:
325
- raise gr.Error("❌ You must select a style before generating")
326
-
327
- # Validate index is within bounds
328
- if not custom_lora_path and (selected_state_index < 0 or selected_state_index >= len(sdxl_loras)):
329
- raise gr.Error(f"❌ Invalid selection index: {selected_state_index}")
330
-
331
  # Enhanced face detection
332
  face_info_list = detect_faces(face_image, use_multiple_faces)
333
  face_detected = len(face_info_list) > 0
334
 
335
  if face_detected:
336
- face_emb = process_face_embeddings(face_info_list)
 
337
  face_kps = create_face_kps_image(face_image, face_info_list)
338
- print(f"Processing with {len(face_info_list)} face(s)")
 
 
 
339
  else:
340
  face_emb = None
341
  face_kps = face_image
342
- print("No faces detected - using landscape/depth mode only")
343
 
344
  et = time.time()
345
  print('Face processing took:', et - st, 'seconds')
@@ -356,18 +362,27 @@ def run_lora(face_image, prompt, negative, lora_scale, selected_state, face_stre
356
  if prompt_full:
357
  prompt = prompt_full.replace("<subject>", prompt)
358
 
 
 
 
 
359
  print("Prompt:", prompt)
360
  if prompt == "":
361
- prompt = "a beautiful scene" if not face_detected else "a person"
362
  print(f"Executing prompt: {prompt}")
363
 
364
  if negative == "":
365
- # Enhanced negative prompt for better quality
366
- negative = "worst quality, low quality, blurry, distorted, deformed" if not face_detected else None
 
 
 
367
 
368
  print("Custom Loaded LoRA:", custom_lora_path)
369
 
370
- if custom_lora_path:
 
 
371
  repo_name = custom_lora_path
372
  full_path_lora = custom_lora_path
373
  else:
@@ -381,15 +396,22 @@ def run_lora(face_image, prompt, negative, lora_scale, selected_state, face_stre
381
  et = time.time()
382
  print('Prompt processing took:', et - st, 'seconds')
383
 
384
- # Adjust parameters based on face detection
385
  if not face_detected:
386
- # For landscape/no face mode, reduce face strength and increase depth control
387
  face_strength = 0.0
388
- depth_control_scale = max(depth_control_scale, 0.9)
389
- image_strength = min(image_strength, 0.4)
390
- print("Adjusted parameters for no-face mode")
 
 
 
 
 
391
 
392
  st = time.time()
 
 
393
  image = generate_image(
394
  prompt, negative, face_emb, face_image, face_kps, image_strength,
395
  guidance_scale, face_strength, depth_control_scale, repo_name,
@@ -401,7 +423,7 @@ def run_lora(face_image, prompt, negative, lora_scale, selected_state, face_stre
401
  run_lora.zerogpu = True
402
 
403
 
404
- @spaces.GPU(duration=75)
405
  def generate_image(prompt, negative, face_emb, face_image, face_kps, image_strength, guidance_scale,
406
  face_strength, depth_control_scale, repo_name, loaded_state_dict, lora_scale,
407
  sdxl_loras, selected_state_index, face_detected, st):
@@ -409,15 +431,17 @@ def generate_image(prompt, negative, face_emb, face_image, face_kps, image_stren
409
 
410
  print("Loaded state dict:", loaded_state_dict)
411
  print("Last LoRA:", last_lora, "| Current LoRA:", repo_name)
412
- print("LoRA scale:", lora_scale, "Type:", type(lora_scale))
413
 
414
- # Prepare control images and scales based on face detection
 
 
415
  if face_detected:
416
- control_images = [face_kps, zoe(face_image)]
 
417
  control_scales = [face_strength, depth_control_scale]
418
  else:
419
- # Only use depth control for landscapes
420
- control_images = [zoe(face_image)]
421
  control_scales = [depth_control_scale]
422
 
423
  # Handle custom LoRA from HuggingFace
@@ -438,46 +462,17 @@ def generate_image(prompt, negative, face_emb, face_image, face_kps, image_stren
438
  # Improved LoRA loading and caching
439
  if last_lora != repo_name:
440
  if last_fused:
441
- try:
442
- # Unload previous LoRA adapter
443
- pipe.delete_adapters(["style_lora"])
444
- print("Unloaded previous LoRA adapter")
445
- except Exception as e:
446
- print(f"Warning: Could not unload previous adapter: {e}")
447
- # Try alternative method
448
- try:
449
- pipe.unload_lora_weights()
450
- print("Unloaded LoRA weights via alternative method")
451
- except:
452
- pass
453
-
454
- try:
455
- pipe.unload_textual_inversion()
456
- print("Unloaded textual inversion")
457
- except Exception as e:
458
- print(f"Warning: Could not unload textual inversion: {e}")
459
 
460
  # Load LoRA with better error handling
461
  try:
462
- # For diffusers >= 0.27, load_lora_weights expects different parameters
463
- if full_path_lora.endswith('.safetensors') or full_path_lora.endswith('.bin'):
464
- # Single file loading
465
- import os
466
- lora_dir = os.path.dirname(full_path_lora)
467
- lora_file = os.path.basename(full_path_lora)
468
- print(f"Loading LoRA from: {lora_dir}/{lora_file}")
469
- pipe.load_lora_weights(lora_dir, weight_name=lora_file, adapter_name="style_lora")
470
- else:
471
- # Directory loading
472
- print(f"Loading LoRA from directory: {full_path_lora}")
473
- pipe.load_lora_weights(full_path_lora, adapter_name="style_lora")
474
-
475
- # Set adapter scale instead of fusing
476
- pipe.set_adapters(["style_lora"], adapter_weights=[float(lora_scale)])
477
- print(f"LoRA loaded and adapter set with scale: {lora_scale}")
478
  last_fused = True
479
 
480
- # Handle pivotal tuning embeddings
481
  is_pivotal = sdxl_loras[selected_state_index]["is_pivotal"]
482
  if is_pivotal:
483
  text_embedding_name = sdxl_loras[selected_state_index]["text_embedding_weights"]
@@ -496,20 +491,15 @@ def generate_image(prompt, negative, face_emb, face_image, face_kps, image_stren
496
  tokenizer=pipe.tokenizer_2
497
  )
498
  except Exception as e:
499
- import traceback
500
- full_error = traceback.format_exc()
501
  print(f"Error loading LoRA: {e}")
502
- print(f"Full traceback:\n{full_error}")
503
- print(f"Full path attempted: {full_path_lora}")
504
- print(f"LoRA scale attempted: {lora_scale} (type: {type(lora_scale)})")
505
- raise gr.Error(f"Failed to load LoRA: {str(e)}\n\nPath: {full_path_lora}\nScale: {lora_scale}")
506
 
507
  print("Processing prompt...")
508
  conditioning, pooled = compel(prompt)
509
  negative_conditioning, negative_pooled = compel(negative) if negative else (None, None)
510
 
511
- # Enhanced generation parameters
512
- num_inference_steps = 40 # Increased for better quality
513
 
514
  print("Generating image...")
515
  image = pipe(
@@ -521,7 +511,7 @@ def generate_image(prompt, negative, face_emb, face_image, face_kps, image_stren
521
  height=face_image.height,
522
  image_embeds=face_emb if face_detected else None,
523
  image=face_image,
524
- strength=1-image_strength,
525
  control_image=control_images,
526
  num_inference_steps=num_inference_steps,
527
  guidance_scale=guidance_scale,
@@ -656,12 +646,12 @@ with gr.Blocks(css="custom.css") as demo:
656
  gr_sdxl_loras = gr.State(value=sdxl_loras_raw)
657
  title = gr.HTML(
658
  """<h1><img src="https://i.imgur.com/DVoGw04.png">
659
- <span>Face to All - Enhanced<br><small style="
660
  font-size: 13px;
661
  display: block;
662
  font-weight: normal;
663
  opacity: 0.75;
664
- ">🔥 Supports: No faces (landscape), Multiple faces, Improved quality, Custom LoRAs<br> diffusers InstantID + ControlNet</small></span></h1>""",
665
  elem_id="title",
666
  )
667
  selected_state = gr.State()
@@ -673,7 +663,7 @@ with gr.Blocks(css="custom.css") as demo:
673
  photo = gr.Image(label="Upload a picture (with or without faces)", interactive=True, type="pil", height=300)
674
  selected_loras = gr.Gallery(label="Selected LoRAs", height=80, show_share_button=False, visible=False, elem_id="gallery_selected")
675
  gallery = gr.Gallery(
676
- label="Pick a style from the gallery",
677
  allow_preview=False,
678
  columns=4,
679
  elem_id="gallery",
@@ -700,18 +690,32 @@ with gr.Blocks(css="custom.css") as demo:
700
  share_button = gr.Button("Share to community", elem_id="share-btn")
701
 
702
  with gr.Accordion("Advanced options", open=False):
703
- use_multiple_faces = gr.Checkbox(label="Use multiple faces (if detected)", value=False)
 
 
 
 
704
  negative = gr.Textbox(label="Negative Prompt")
705
- weight = gr.Slider(0, 10, value=0.9, step=0.1, label="LoRA weight")
706
- face_strength = gr.Slider(0, 2, value=0.9, step=0.01, label="Face strength",
707
- info="Higher values increase face likeness (auto-adjusted for no-face images)")
708
- image_strength = gr.Slider(0, 1, value=0.20, step=0.01, label="Image strength",
709
- info="Higher values increase similarity with original structure/colors")
710
- guidance_scale = gr.Slider(0, 50, value=8, step=0.1, label="Guidance Scale")
711
- depth_control_scale = gr.Slider(0, 1, value=0.8, step=0.01, label="Zoe Depth ControlNet strength")
 
 
 
 
 
 
 
 
 
 
712
 
713
  prompt_title = gr.Markdown(
714
- value="### Click on a LoRA in the gallery to select it",
715
  visible=True,
716
  elem_id="selected_lora",
717
  )
@@ -761,4 +765,4 @@ with gr.Blocks(css="custom.css") as demo:
761
  demo.load(fn=classify_gallery, inputs=[gr_sdxl_loras], outputs=[gallery, gr_sdxl_loras])
762
 
763
  demo.queue(default_concurrency_limit=None, api_open=True)
764
- demo.launch()
 
38
 
39
  from gradio_imageslider import ImageSlider
40
 
41
+ # Load LoRA configurations - now only LucasArts style
42
  with open("sdxl_loras.json", "r") as file:
43
  data = json.load(file)
44
  sdxl_loras_raw = [
 
123
  print('Loading VAE took: ', et - st, 'seconds')
124
 
125
  st = time.time()
126
+ # CHANGED: Using AlbedoBase XL v2.1 for better quality
127
  pipe = StableDiffusionXLInstantIDImg2ImgPipeline.from_pretrained(
128
+ "frankjoshua/albedobaseXL_v21",
129
  vae=vae,
130
  controlnet=[identitynet, zoedepthnet],
131
  torch_dtype=torch.float16
 
133
 
134
  pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config, use_karras_sigmas=True)
135
  pipe.load_ip_adapter_instantid(face_adapter)
136
+ # IMPROVED: Higher IP adapter scale for better face preservation
137
+ pipe.set_ip_adapter_scale(1.0)
138
  et = time.time()
139
  print('Loading pipeline took: ', et - st, 'seconds')
140
 
 
159
  last_fused = False
160
  lora_archive = "/data"
161
 
162
+ # Enhanced face detection with better face quality filtering
163
  def detect_faces(face_image, use_multiple_faces=False):
164
  """
165
+ Detect faces in the image with quality filtering
166
  Returns: list of face info dictionaries, or empty list if no faces
167
  """
168
  try:
 
172
  print("No faces detected")
173
  return []
174
 
175
+ # Filter faces by quality score if available
176
+ filtered_faces = []
177
+ for face_info in face_info_list:
178
+ # Check if face has minimum quality
179
+ if 'det_score' in face_info and face_info['det_score'] > 0.5:
180
+ filtered_faces.append(face_info)
181
+ elif 'det_score' not in face_info:
182
+ filtered_faces.append(face_info)
183
+
184
+ if not filtered_faces:
185
+ print("No high-quality faces detected")
186
+ return []
187
+
188
  # Sort faces by size (largest first)
189
+ filtered_faces = sorted(
190
+ filtered_faces,
191
  key=lambda x: (x['bbox'][2] - x['bbox'][0]) * (x['bbox'][3] - x['bbox'][1]),
192
  reverse=True
193
  )
194
 
195
  if use_multiple_faces:
196
+ print(f"Detected {len(filtered_faces)} high-quality faces")
197
+ return filtered_faces
198
  else:
199
+ print(f"Using largest face (detected {len(filtered_faces)} total)")
200
+ return [filtered_faces[0]]
201
 
202
  except Exception as e:
203
  print(f"Face detection error: {e}")
204
  return []
205
 
206
+ def process_face_embeddings_separately(face_info_list):
207
  """
208
+ Process face embeddings separately for multi-face generation
209
+ Returns: list of individual face embeddings
210
  """
211
  if not face_info_list:
212
+ return []
 
 
 
213
 
 
214
  embeddings = [face_info['embedding'] for face_info in face_info_list]
215
+ return embeddings
 
216
 
217
  def create_face_kps_image(face_image, face_info_list):
218
  """
219
+ Create keypoints image from face info with enhanced visibility
220
  """
221
  if not face_info_list:
222
  return face_image
223
 
224
+ # For multiple faces, draw all keypoints with different colors
225
  if len(face_info_list) > 1:
226
  return draw_multiple_kps(face_image, [f['kps'] for f in face_info_list])
227
  else:
 
229
 
230
  def draw_multiple_kps(image_pil, kps_list, color_list=[(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (255, 0, 255)]):
231
  """
232
+ Draw keypoints for multiple faces with enhanced visibility
233
  """
234
  stickwidth = 4
235
  limbSeq = np.array([[0, 2], [1, 2], [3, 2], [4, 2]])
 
237
  w, h = image_pil.size
238
  out_img = np.zeros([h, w, 3])
239
 
240
+ for idx, kps in enumerate(kps_list):
241
  kps = np.array(kps)
242
+ # Use different colors for different faces
243
+ color_offset = idx % len(color_list)
244
 
245
  for i in range(len(limbSeq)):
246
  index = limbSeq[i]
247
+ color = color_list[(index[0] + color_offset) % len(color_list)]
248
 
249
  x = kps[index][:, 0]
250
  y = kps[index][:, 1]
 
258
  out_img = (out_img * 0.6).astype(np.uint8)
259
 
260
  for idx_kp, kp in enumerate(kps):
261
+ color = color_list[(idx_kp + color_offset) % len(color_list)]
262
  x, y = kp
263
  out_img = cv2.circle(out_img.copy(), (int(x), int(y)), 10, color, -1)
264
 
 
273
 
274
  for lora_list in lora_defaults:
275
  if lora_list["model"] == sdxl_loras[selected_state.index]["repo"]:
276
+ face_strength = lora_list.get("face_strength", 1.0)
277
+ image_strength = lora_list.get("image_strength", 0.15)
278
+ weight = lora_list.get("weight", 1.0)
279
  depth_control_scale = lora_list.get("depth_control_scale", 0.8)
280
  negative = lora_list.get("negative", "")
281
 
 
321
  guidance_scale, depth_control_scale, sdxl_loras, custom_lora, use_multiple_faces=False,
322
  progress=gr.Progress(track_tqdm=True)):
323
  """
324
+ Enhanced run_lora with improved face preservation and landscape mode
 
 
 
325
  """
326
  print("Custom LoRA:", custom_lora)
327
  custom_lora_path = custom_lora[0] if custom_lora else None
 
330
  st = time.time()
331
  face_image = resize_image_aspect_ratio(face_image)
332
 
 
 
 
 
 
 
 
 
333
  # Enhanced face detection
334
  face_info_list = detect_faces(face_image, use_multiple_faces)
335
  face_detected = len(face_info_list) > 0
336
 
337
  if face_detected:
338
+ # CHANGED: Process faces separately instead of averaging
339
+ face_embeddings = process_face_embeddings_separately(face_info_list)
340
  face_kps = create_face_kps_image(face_image, face_info_list)
341
+ print(f"Processing with {len(face_info_list)} face(s) separately")
342
+
343
+ # For multiple faces, we'll generate with the primary face (largest)
344
+ face_emb = face_embeddings[0]
345
  else:
346
  face_emb = None
347
  face_kps = face_image
348
+ print("No faces detected - using enhanced landscape/depth mode")
349
 
350
  et = time.time()
351
  print('Face processing took:', et - st, 'seconds')
 
362
  if prompt_full:
363
  prompt = prompt_full.replace("<subject>", prompt)
364
 
365
+ # Add LucasArts trigger word if not present
366
+ if "lucasarts artstyle" not in prompt.lower():
367
+ prompt = f"{prompt}, lucasarts artstyle"
368
+
369
  print("Prompt:", prompt)
370
  if prompt == "":
371
+ prompt = "a beautiful cinematic scene" if not face_detected else "a person in cinematic lighting"
372
  print(f"Executing prompt: {prompt}")
373
 
374
  if negative == "":
375
+ # Enhanced negative prompt
376
+ if not face_detected:
377
+ negative = "worst quality, low quality, blurry, distorted, deformed, ugly, bad anatomy"
378
+ else:
379
+ negative = "worst quality, low quality, blurry, distorted, deformed, ugly, bad anatomy, bad proportions"
380
 
381
  print("Custom Loaded LoRA:", custom_lora_path)
382
 
383
+ if not selected_state and not custom_lora_path:
384
+ raise gr.Error("You must select a style")
385
+ elif custom_lora_path:
386
  repo_name = custom_lora_path
387
  full_path_lora = custom_lora_path
388
  else:
 
396
  et = time.time()
397
  print('Prompt processing took:', et - st, 'seconds')
398
 
399
+ # IMPROVED: Better parameter adjustment for face/landscape modes
400
  if not face_detected:
401
+ # Enhanced landscape mode parameters
402
  face_strength = 0.0
403
+ depth_control_scale = 1.0 # Maximum depth control for landscapes
404
+ image_strength = 0.25 # Higher structure preservation
405
+ print("Adjusted parameters for enhanced landscape mode")
406
+ else:
407
+ # Enhanced face preservation
408
+ face_strength = max(face_strength, 1.0) # Ensure strong face preservation
409
+ depth_control_scale = max(depth_control_scale, 0.8) # Good depth control
410
+ print("Adjusted parameters for enhanced face preservation")
411
 
412
  st = time.time()
413
+
414
+ # Generate single image with best face (or landscape)
415
  image = generate_image(
416
  prompt, negative, face_emb, face_image, face_kps, image_strength,
417
  guidance_scale, face_strength, depth_control_scale, repo_name,
 
423
  run_lora.zerogpu = True
424
 
425
 
426
+ @spaces.GPU(duration=90) # Increased duration for better quality
427
  def generate_image(prompt, negative, face_emb, face_image, face_kps, image_strength, guidance_scale,
428
  face_strength, depth_control_scale, repo_name, loaded_state_dict, lora_scale,
429
  sdxl_loras, selected_state_index, face_detected, st):
 
431
 
432
  print("Loaded state dict:", loaded_state_dict)
433
  print("Last LoRA:", last_lora, "| Current LoRA:", repo_name)
 
434
 
435
+ # IMPROVED: Better control image preparation
436
+ depth_image = zoe(face_image)
437
+
438
  if face_detected:
439
+ # Face mode: use both face keypoints and depth
440
+ control_images = [face_kps, depth_image]
441
  control_scales = [face_strength, depth_control_scale]
442
  else:
443
+ # Landscape mode: only depth control with enhanced parameters
444
+ control_images = [depth_image]
445
  control_scales = [depth_control_scale]
446
 
447
  # Handle custom LoRA from HuggingFace
 
462
  # Improved LoRA loading and caching
463
  if last_lora != repo_name:
464
  if last_fused:
465
+ pipe.unfuse_lora()
466
+ pipe.unload_lora_weights()
467
+ pipe.unload_textual_inversion()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
468
 
469
  # Load LoRA with better error handling
470
  try:
471
+ pipe.load_lora_weights(full_path_lora)
472
+ pipe.fuse_lora(lora_scale)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
473
  last_fused = True
474
 
475
+ # Handle pivotal tuning embeddings (if needed for future LoRAs)
476
  is_pivotal = sdxl_loras[selected_state_index]["is_pivotal"]
477
  if is_pivotal:
478
  text_embedding_name = sdxl_loras[selected_state_index]["text_embedding_weights"]
 
491
  tokenizer=pipe.tokenizer_2
492
  )
493
  except Exception as e:
 
 
494
  print(f"Error loading LoRA: {e}")
495
+ raise gr.Error(f"Failed to load LoRA: {str(e)}")
 
 
 
496
 
497
  print("Processing prompt...")
498
  conditioning, pooled = compel(prompt)
499
  negative_conditioning, negative_pooled = compel(negative) if negative else (None, None)
500
 
501
+ # IMPROVED: Enhanced generation parameters for better quality
502
+ num_inference_steps = 50 # Increased for better quality
503
 
504
  print("Generating image...")
505
  image = pipe(
 
511
  height=face_image.height,
512
  image_embeds=face_emb if face_detected else None,
513
  image=face_image,
514
+ strength=1-image_strength, # Higher strength = more transformation
515
  control_image=control_images,
516
  num_inference_steps=num_inference_steps,
517
  guidance_scale=guidance_scale,
 
646
  gr_sdxl_loras = gr.State(value=sdxl_loras_raw)
647
  title = gr.HTML(
648
  """<h1><img src="https://i.imgur.com/DVoGw04.png">
649
+ <span>LucasArts Style - Enhanced Face Preservation<br><small style="
650
  font-size: 13px;
651
  display: block;
652
  font-weight: normal;
653
  opacity: 0.75;
654
+ ">🔥 Improved: Better face identity preservation, Enhanced landscape mode, Multiple face support<br>AlbedoBase XL v2.1 + InstantID + ControlNet</small></span></h1>""",
655
  elem_id="title",
656
  )
657
  selected_state = gr.State()
 
663
  photo = gr.Image(label="Upload a picture (with or without faces)", interactive=True, type="pil", height=300)
664
  selected_loras = gr.Gallery(label="Selected LoRAs", height=80, show_share_button=False, visible=False, elem_id="gallery_selected")
665
  gallery = gr.Gallery(
666
+ label="LucasArts Style",
667
  allow_preview=False,
668
  columns=4,
669
  elem_id="gallery",
 
690
  share_button = gr.Button("Share to community", elem_id="share-btn")
691
 
692
  with gr.Accordion("Advanced options", open=False):
693
+ use_multiple_faces = gr.Checkbox(
694
+ label="Process multiple faces separately",
695
+ value=False,
696
+ info="Generate separate outputs for each detected face"
697
+ )
698
  negative = gr.Textbox(label="Negative Prompt")
699
+ weight = gr.Slider(0, 10, value=1.0, step=0.1, label="LoRA weight")
700
+ face_strength = gr.Slider(
701
+ 0, 2, value=1.0, step=0.01, label="Face identity strength",
702
+ info="Higher = stronger face preservation (auto-adjusted for landscapes)"
703
+ )
704
+ image_strength = gr.Slider(
705
+ 0, 1, value=0.15, step=0.01, label="Image structure strength",
706
+ info="Lower = more transformation, Higher = more original structure"
707
+ )
708
+ guidance_scale = gr.Slider(
709
+ 0, 50, value=7.5, step=0.1, label="Guidance Scale",
710
+ info="How closely to follow the prompt"
711
+ )
712
+ depth_control_scale = gr.Slider(
713
+ 0, 1, value=0.8, step=0.01, label="Depth ControlNet strength",
714
+ info="3D structure preservation (auto-maximized for landscapes)"
715
+ )
716
 
717
  prompt_title = gr.Markdown(
718
+ value="### Click 'Run' to generate with LucasArts style",
719
  visible=True,
720
  elem_id="selected_lora",
721
  )
 
765
  demo.load(fn=classify_gallery, inputs=[gr_sdxl_loras], outputs=[gallery, gr_sdxl_loras])
766
 
767
  demo.queue(default_concurrency_limit=None, api_open=True)
768
+ demo.launch(share=True)