linoyts HF Staff commited on
Commit
69d2e59
路
verified 路
1 Parent(s): 58f9482

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +17 -27
app.py CHANGED
@@ -48,6 +48,7 @@ BUDGETS = {
48
  "Fast 路 512": (512, 512 * 896),
49
  }
50
  DEFAULT_BUDGET = "Balanced 路 640"
 
51
  OUTPUT_DIR = os.path.join(tempfile.gettempdir(), "bgswap-outputs")
52
  os.makedirs(OUTPUT_DIR, exist_ok=True)
53
 
@@ -329,11 +330,10 @@ def get_duration(request, steps, seed, **_):
329
  sequence = (int(request["text_token_tags"].shape[0]) + reference_rows(references, num_frames)
330
  + target_rows(height, width, num_frames))
331
  denoise = int(steps) * (STEP_LINEAR * sequence + STEP_QUADRATIC * sequence ** 2) * SAFETY
332
- passes = 2 if request.get("harmonize") else 1 # harmonize adds a second (mask-drop) denoise + decode pass
333
  encode = 5 + reference_rows(references, num_frames) * 1e-3
334
  share = (height * width * num_frames) / DEFAULT_CANVAS_PIXELS
335
- total = (PLACEMENT_ALLOWANCE + encode + SOURCE_ENCODE_PER_DEFAULT_CANVAS * share + passes * denoise
336
- + passes * (DECODE_BASE + DECODE_PER_DEFAULT_CANVAS * share) + 10)
337
  duration = max(MIN_GPU_DURATION, min(MAX_GPU_DURATION, int(total)))
338
  print(f"[bgswap] S={sequence} -> reserving {duration}s ({denoise:.0f}s denoise at {steps} steps)", flush=True)
339
  return duration
@@ -381,31 +381,21 @@ def _generate(request, steps, seed):
381
  except Exception as error:
382
  print(f"[bgswap] turbo switch failed ({type(error).__name__}: {error})", flush=True)
383
 
384
- refs = build_references(request["references"])
385
- embeds = request["prompt_embeds"].to("cuda")
386
-
387
- def one_pass(source, mask, source_audio, sr):
388
- return PIPE(
389
- prompt_embeds=embeds, text_token_tags=request["text_token_tags"], references=refs,
390
- source_video=source, source_fps=FPS, mask=mask,
391
- source_audio=source_audio, source_audio_sample_rate=sr, audio_mask=None,
392
- height=request["height"], width=request["width"], num_frames=request["num_frames"],
393
- num_inference_steps=int(steps), generator=torch.Generator("cpu").manual_seed(int(seed)))
394
-
395
- state = one_pass(request["source_video"], request["mask"],
396
- request["source_audio"], request["source_audio_sample_rate"])
397
- audio, sr = state.get("audio"), state.get("sampling_rate")
398
- videos = state.get("videos")[0]
399
-
400
  if request.get("harmonize"):
401
- # second pass: drop the mask (uniform value everywhere) and free-refine the whole frame, so the subject's
402
- # lighting blends into the new scene. The first pass's audio is kept.
403
- src2 = np.stack([np.asarray(f) for f in videos])
404
- strength = float(request.get("harmonize_strength", 0.35))
405
- mask2 = np.full((src2.shape[0], src2.shape[1], src2.shape[2]), strength, dtype=np.float32)
406
- videos = one_pass(src2, mask2, None, None).get("videos")[0]
407
-
408
- return videos, None if audio is None else audio[0].cpu(), sr
409
 
410
 
411
  def replace_background(clip, prompt, budget, steps, seed, keep_audio, harmonize=True, remove_only=False, progress=None):
 
48
  "Fast 路 512": (512, 512 * 896),
49
  }
50
  DEFAULT_BUDGET = "Balanced 路 640"
51
+ HARMONIZE_DROP_FRAC = 0.5 # harmonize: drop the mask after this fraction of the denoise steps (midpoint)
52
  OUTPUT_DIR = os.path.join(tempfile.gettempdir(), "bgswap-outputs")
53
  os.makedirs(OUTPUT_DIR, exist_ok=True)
54
 
 
330
  sequence = (int(request["text_token_tags"].shape[0]) + reference_rows(references, num_frames)
331
  + target_rows(height, width, num_frames))
332
  denoise = int(steps) * (STEP_LINEAR * sequence + STEP_QUADRATIC * sequence ** 2) * SAFETY
 
333
  encode = 5 + reference_rows(references, num_frames) * 1e-3
334
  share = (height * width * num_frames) / DEFAULT_CANVAS_PIXELS
335
+ total = (PLACEMENT_ALLOWANCE + encode + SOURCE_ENCODE_PER_DEFAULT_CANVAS * share + denoise
336
+ + DECODE_BASE + DECODE_PER_DEFAULT_CANVAS * share + 10)
337
  duration = max(MIN_GPU_DURATION, min(MAX_GPU_DURATION, int(total)))
338
  print(f"[bgswap] S={sequence} -> reserving {duration}s ({denoise:.0f}s denoise at {steps} steps)", flush=True)
339
  return duration
 
381
  except Exception as error:
382
  print(f"[bgswap] turbo switch failed ({type(error).__name__}: {error})", flush=True)
383
 
384
+ kwargs = dict(
385
+ prompt_embeds=request["prompt_embeds"].to("cuda"), text_token_tags=request["text_token_tags"],
386
+ references=build_references(request["references"]),
387
+ source_video=request["source_video"], source_fps=FPS, mask=request["mask"],
388
+ source_audio=request["source_audio"], source_audio_sample_rate=request["source_audio_sample_rate"],
389
+ audio_mask=None, height=request["height"], width=request["width"], num_frames=request["num_frames"],
390
+ num_inference_steps=int(steps), generator=torch.Generator("cpu").manual_seed(int(seed)))
 
 
 
 
 
 
 
 
 
391
  if request.get("harmonize"):
392
+ # single pass: keep the mask until mask_drop_step, then free-refine the whole frame so the subject blends
393
+ # into the scene (the subject is re-noised to that step's level at the handoff). No second pass.
394
+ kwargs["mask_drop_step"] = max(1, min(int(steps) - 1, round(int(steps) * HARMONIZE_DROP_FRAC)))
395
+
396
+ state = PIPE(**kwargs)
397
+ audio = state.get("audio")
398
+ return state.get("videos")[0], None if audio is None else audio[0].cpu(), state.get("sampling_rate")
 
399
 
400
 
401
  def replace_background(clip, prompt, budget, steps, seed, keep_audio, harmonize=True, remove_only=False, progress=None):