kalamishere Claude Fable 5.1 commited on
Commit
72d8940
·
1 Parent(s): d8ac0be

api: generate_inpaint mask_soft_s — the kept context fades out of the conditioning before the mask edge instead of stopping at a wall

Browse files
Files changed (2) hide show
  1. README.md +1 -1
  2. app.py +27 -7
README.md CHANGED
@@ -118,7 +118,7 @@ Argument order matters (positional):
118
 
119
  - `/generate` — `token, model_variant, prompt, negative_prompt, seconds, steps, cfg_scale, seed`
120
  - `/generate_a2a` — `token, model_variant, init_audio, prompt, negative_prompt, init_noise_level, seconds, steps, cfg_scale, seed`
121
- - `/generate_inpaint` — `token, model_variant, inpaint_audio, prompt, negative_prompt, mask_start_s, mask_end_s, seconds, steps, cfg_scale, seed, init_noise_level` — keeps `inpaint_audio` outside `[mask_start_s, mask_end_s]` and regenerates inside (mask_end_s 0 = to the end). Continuation: pass the previous chunk's last N seconds followed by silence, mask_start_s = N. `init_noise_level` 0 = pure inpaint; > 0 also seeds the whole clip from the same audio.
122
 
123
  `seed = -1` picks a random one; the seed actually used comes back in `meta`.
124
  Inputs are clamped server-side (seconds per-model cap, steps 1–100, cfg 0–15).
 
118
 
119
  - `/generate` — `token, model_variant, prompt, negative_prompt, seconds, steps, cfg_scale, seed`
120
  - `/generate_a2a` — `token, model_variant, init_audio, prompt, negative_prompt, init_noise_level, seconds, steps, cfg_scale, seed`
121
+ - `/generate_inpaint` — `token, model_variant, inpaint_audio, prompt, negative_prompt, mask_start_s, mask_end_s, seconds, steps, cfg_scale, seed, init_noise_level` — keeps `inpaint_audio` outside `[mask_start_s, mask_end_s]` and regenerates inside (mask_end_s 0 = to the end). Continuation: pass the previous chunk's last N seconds followed by silence, mask_start_s = N. `init_noise_level` 0 = pure inpaint; > 0 also seeds the whole clip from the same audio. Optional 13th arg `mask_soft_s`: the kept context fades out of the conditioning over that many seconds before `mask_start_s` (0 = hard edge).
122
 
123
  `seed = -1` picks a random one; the seed actually used comes back in `meta`.
124
  Inputs are clamped server-side (seconds per-model cap, steps 1–100, cfg 0–15).
app.py CHANGED
@@ -263,7 +263,8 @@ def _generate(variant_key: str,
263
  init_noise_level: Optional[float] = None,
264
  inpaint_audio_path: Optional[str] = None,
265
  mask_start_s: Optional[float] = None,
266
- mask_end_s: Optional[float] = None) -> tuple[str, dict]:
 
267
  """Returns (wav_path, meta). Inputs must already be clamped.
268
  inpaint_audio_path + mask_start_s/mask_end_s: the audio is kept verbatim
269
  outside [mask_start_s, mask_end_s] and regenerated inside it (that is how
@@ -305,8 +306,24 @@ def _generate(variant_key: str,
305
  model_dtype = next(lv.model.parameters()).dtype
306
  gen_kwargs["inpaint_audio"] = _load_init_audio(
307
  inpaint_audio_path, lv.sample_rate, model_dtype)
308
- gen_kwargs["inpaint_mask_start_seconds"] = float(mask_start_s)
309
- gen_kwargs["inpaint_mask_end_seconds"] = float(mask_end_s)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
 
311
  output = generate_diffusion_cond_inpaint(lv.model, **gen_kwargs)
312
  output = rearrange(output, "b d n -> d (b n)")
@@ -334,6 +351,7 @@ def _generate(variant_key: str,
334
  init_noise_level if init_noise_level is not None else 0.4)
335
  if inpaint_audio_path:
336
  meta["inpaint_mask_s"] = [float(mask_start_s), float(mask_end_s)]
 
337
  print(f"[gen] {meta}", flush=True)
338
  return out_path, meta
339
 
@@ -408,14 +426,14 @@ def api_generate_a2a(token, variant_key, init_audio, prompt, negative_prompt,
408
 
409
  def _api_duration_inpaint(token, variant_key, inpaint_audio, prompt, negative_prompt,
410
  mask_start_s, mask_end_s, seconds, steps, cfg_scale, seed,
411
- init_noise_level):
412
  return _gpu_seconds(seconds)
413
 
414
 
415
  @spaces.GPU(duration=_api_duration_inpaint)
416
  def api_generate_inpaint(token, variant_key, inpaint_audio, prompt, negative_prompt,
417
  mask_start_s, mask_end_s, seconds, steps, cfg_scale, seed,
418
- init_noise_level):
419
  """Keep inpaint_audio outside [mask_start_s, mask_end_s], regenerate inside.
420
  For continuation: inpaint_audio = the previous chunk's tail followed by
421
  anything (silence is fine) up to `seconds`; mask_start_s = tail length,
@@ -432,7 +450,8 @@ def api_generate_inpaint(token, variant_key, inpaint_audio, prompt, negative_pro
432
  if me <= ms:
433
  raise gr.Error("mask_end_s must be greater than mask_start_s.")
434
  noise = float(init_noise_level or 0.0)
435
- kw = dict(inpaint_audio_path=inpaint_audio, mask_start_s=ms, mask_end_s=me)
 
436
  if noise > 0:
437
  kw.update(init_audio_path=inpaint_audio, init_noise_level=max(0.0, min(noise, 1.0)))
438
  path, meta = _generate(key, prompt, negative_prompt, seconds, steps, cfg_scale, seed, **kw)
@@ -1042,13 +1061,14 @@ with gr.Blocks(theme=gr.themes.Citrus(), title="abv1 sa3 engine") as demo:
1042
  _i_cfg = gr.Number(value=1.0, label="cfg_scale")
1043
  _i_seed = gr.Number(value=-1, label="seed")
1044
  _i_noise = gr.Number(value=0, label="init_noise_level (0 = pure inpaint)")
 
1045
  _i_file = gr.File(label="audio out")
1046
  _i_json = gr.JSON(label="meta")
1047
  _i_btn = gr.Button("generate_inpaint")
1048
  _i_btn.click(
1049
  fn=api_generate_inpaint,
1050
  inputs=[_i_token, _i_variant, _i_audio, _i_prompt, _i_negative,
1051
- _i_ms, _i_me, _i_seconds, _i_steps, _i_cfg, _i_seed, _i_noise],
1052
  outputs=[_i_file, _i_json],
1053
  api_name="generate_inpaint",
1054
  show_progress="hidden",
 
263
  init_noise_level: Optional[float] = None,
264
  inpaint_audio_path: Optional[str] = None,
265
  mask_start_s: Optional[float] = None,
266
+ mask_end_s: Optional[float] = None,
267
+ mask_soft_s: float = 0.0) -> tuple[str, dict]:
268
  """Returns (wav_path, meta). Inputs must already be clamped.
269
  inpaint_audio_path + mask_start_s/mask_end_s: the audio is kept verbatim
270
  outside [mask_start_s, mask_end_s] and regenerated inside it (that is how
 
306
  model_dtype = next(lv.model.parameters()).dtype
307
  gen_kwargs["inpaint_audio"] = _load_init_audio(
308
  inpaint_audio_path, lv.sample_rate, model_dtype)
309
+ if mask_soft_s and mask_soft_s > 0:
310
+ # Soft edge: the kept context fades out of the conditioning over
311
+ # mask_soft_s before mask_start_s instead of stopping at a wall.
312
+ # The library multiplies the encoded audio by this mask (fractional
313
+ # values propagate; nearest-neighbour resize to latent frames).
314
+ n = lv.sample_size
315
+ m = torch.ones(1, n, device="cuda")
316
+ a = int(float(mask_start_s) * lv.sample_rate)
317
+ b = int(float(mask_end_s) * lv.sample_rate)
318
+ m[:, a:b] = 0.0
319
+ r = int(float(mask_soft_s) * lv.sample_rate)
320
+ r0 = max(0, a - r)
321
+ if a > r0:
322
+ m[:, r0:a] = torch.linspace(1.0, 0.0, a - r0, device="cuda")
323
+ gen_kwargs["inpaint_mask"] = m
324
+ else:
325
+ gen_kwargs["inpaint_mask_start_seconds"] = float(mask_start_s)
326
+ gen_kwargs["inpaint_mask_end_seconds"] = float(mask_end_s)
327
 
328
  output = generate_diffusion_cond_inpaint(lv.model, **gen_kwargs)
329
  output = rearrange(output, "b d n -> d (b n)")
 
351
  init_noise_level if init_noise_level is not None else 0.4)
352
  if inpaint_audio_path:
353
  meta["inpaint_mask_s"] = [float(mask_start_s), float(mask_end_s)]
354
+ meta["mask_soft_s"] = float(mask_soft_s or 0.0)
355
  print(f"[gen] {meta}", flush=True)
356
  return out_path, meta
357
 
 
426
 
427
  def _api_duration_inpaint(token, variant_key, inpaint_audio, prompt, negative_prompt,
428
  mask_start_s, mask_end_s, seconds, steps, cfg_scale, seed,
429
+ init_noise_level, mask_soft_s=0):
430
  return _gpu_seconds(seconds)
431
 
432
 
433
  @spaces.GPU(duration=_api_duration_inpaint)
434
  def api_generate_inpaint(token, variant_key, inpaint_audio, prompt, negative_prompt,
435
  mask_start_s, mask_end_s, seconds, steps, cfg_scale, seed,
436
+ init_noise_level, mask_soft_s=0):
437
  """Keep inpaint_audio outside [mask_start_s, mask_end_s], regenerate inside.
438
  For continuation: inpaint_audio = the previous chunk's tail followed by
439
  anything (silence is fine) up to `seconds`; mask_start_s = tail length,
 
450
  if me <= ms:
451
  raise gr.Error("mask_end_s must be greater than mask_start_s.")
452
  noise = float(init_noise_level or 0.0)
453
+ soft = max(0.0, min(float(mask_soft_s or 0.0), ms))
454
+ kw = dict(inpaint_audio_path=inpaint_audio, mask_start_s=ms, mask_end_s=me, mask_soft_s=soft)
455
  if noise > 0:
456
  kw.update(init_audio_path=inpaint_audio, init_noise_level=max(0.0, min(noise, 1.0)))
457
  path, meta = _generate(key, prompt, negative_prompt, seconds, steps, cfg_scale, seed, **kw)
 
1061
  _i_cfg = gr.Number(value=1.0, label="cfg_scale")
1062
  _i_seed = gr.Number(value=-1, label="seed")
1063
  _i_noise = gr.Number(value=0, label="init_noise_level (0 = pure inpaint)")
1064
+ _i_soft = gr.Number(value=0, label="mask_soft_s (context fades out over this many s before mask_start_s; 0 = hard edge)")
1065
  _i_file = gr.File(label="audio out")
1066
  _i_json = gr.JSON(label="meta")
1067
  _i_btn = gr.Button("generate_inpaint")
1068
  _i_btn.click(
1069
  fn=api_generate_inpaint,
1070
  inputs=[_i_token, _i_variant, _i_audio, _i_prompt, _i_negative,
1071
+ _i_ms, _i_me, _i_seconds, _i_steps, _i_cfg, _i_seed, _i_noise, _i_soft],
1072
  outputs=[_i_file, _i_json],
1073
  api_name="generate_inpaint",
1074
  show_progress="hidden",