observantdistressed commited on
Commit
e054b84
·
verified ·
1 Parent(s): 6e7091e

Video retention 25→200 + NSFW enhancer checkboxes

Browse files

- Increased output video rotation limit from 25 to 200 so older generations
survive longer in /tmp before cleanup.

- Replaced auto-loading of nsfw_aio whenever any NSFW LoRA is selected with
two explicit checkboxes (mutually exclusive):
• HMNSFW AIO V2.5 (motion adapter)
• Astro NSFW (quality enhancer)
Users now choose which enhancer to pair with their selected LoRAs, or none.

Files changed (1) hide show
  1. app.py +32 -8
app.py CHANGED
@@ -2158,7 +2158,7 @@ def _generate(prompt_embeds, text_token_tags, image, last_image, height, width,
2158
  return _videos, _audio, _sampling_rate
2159
 
2160
 
2161
- def _generate_impl(prompt, image_path=None, last_image_path=None, canvas=DEFAULT_CANVAS, duration=5, steps=25, seed=-1, upsample=False, turbo=False, nsfw_lora_keys=(), custom_lora_url="", custom_lora_scale=1.0, custom_lora_trigger="", progress=gr.Progress(track_tqdm=True)):
2162
  """The request pipeline: LoRA prep → remote conditioning → @spaces.GPU denoise → mux."""
2163
  if LOAD_ERROR:
2164
  raise gr.Error(LOAD_ERROR)
@@ -2212,8 +2212,10 @@ def _generate_impl(prompt, image_path=None, last_image_path=None, canvas=DEFAULT
2212
  _trigger = str(custom_lora_trigger or "").strip()
2213
  custom = [(_repo, _file, _scale, _trigger)]
2214
 
2215
- if nsfw_keys or custom:
2216
  nsfw_keys += ("nsfw_aio",)
 
 
2217
  for _key in nsfw_keys:
2218
  _ensure_nsfw_lora_loaded(_key)
2219
  for _key in nsfw_keys:
@@ -2262,7 +2264,7 @@ def _generate_impl(prompt, image_path=None, last_image_path=None, canvas=DEFAULT
2262
  directory = os.path.join(tempfile.gettempdir(), "h3-outputs")
2263
  os.makedirs(directory, exist_ok=True)
2264
  # Rotate: keep only the newest _MAX_OUTPUTS MP4s so /tmp never fills up.
2265
- _MAX_OUTPUTS = 25
2266
  for _f in sorted(glob.glob(os.path.join(directory, "*.mp4")), key=os.path.getmtime)[:-_MAX_OUTPUTS]:
2267
  try:
2268
  os.remove(_f)
@@ -2292,7 +2294,7 @@ def _generate_impl(prompt, image_path=None, last_image_path=None, canvas=DEFAULT
2292
  return path, report, refined, gr.update(visible=bool(refined)), gr.DownloadButton(value=path, visible=True), gr.update(value=lora_label_text, visible=bool(nsfw_keys) or bool(custom))
2293
 
2294
 
2295
- def generate(prompt, image_path=None, last_image_path=None, canvas=DEFAULT_CANVAS, duration=5, steps=25, seed=-1, upsample=False, turbo=False, nsfw_lora_keys=(), custom_lora_url="", custom_lora_scale=1.0, custom_lora_trigger="", progress=gr.Progress(track_tqdm=True)):
2296
  """One request. `upsample` is last among the pre-existing positional args, so a positional API client that
2297
  predates it is unaffected; the custom-LoRA args come after it.
2298
 
@@ -2307,7 +2309,8 @@ def generate(prompt, image_path=None, last_image_path=None, canvas=DEFAULT_CANVA
2307
  try:
2308
  return _generate_impl(
2309
  prompt, image_path, last_image_path, canvas, duration, steps, seed, upsample, turbo,
2310
- nsfw_lora_keys, custom_lora_url, custom_lora_scale, custom_lora_trigger, progress,
 
2311
  )
2312
  except gr.Error as _e:
2313
  _log(f"generate rejected: {_e}", "WARN")
@@ -2651,13 +2654,24 @@ with gr.Blocks(title="minimax h3 turbo + lora's") as demo:
2651
  with gr.Accordion("NSFW LoRAs", open=False):
2652
  nsfw_lora_keys = gr.Dropdown(
2653
  label="Select LoRAs to apply",
2654
- choices=[(cfg["label"], key) for key, cfg in NSFW_LORA_CONFIGS.items() if key != "nsfw_aio"],
2655
  value=[],
2656
  multiselect=True,
2657
  filterable=True,
2658
- info="Searchable — type to filter. Selected LoRAs show as removable tags; their trigger tokens are auto-appended to the prompt. The HMNSFW AIO motion adapter auto-loads whenever any LoRA is selected.",
2659
  )
2660
  lora_desc = gr.Markdown(visible=False)
 
 
 
 
 
 
 
 
 
 
 
2661
  with gr.Accordion("Custom LoRA (Hugging Face)", open=False):
2662
  gr.Markdown("Paste a Hugging Face link — a repo page or a direct `.safetensors` file link — then press "
2663
  "**Download & Verify**. The verified LoRA is applied on Generate. "
@@ -2713,7 +2727,7 @@ with gr.Blocks(title="minimax h3 turbo + lora's") as demo:
2713
  run.click(
2714
  generate,
2715
  [prompt, image, last_image, canvas, duration, steps, seed, upsample, turbo, nsfw_lora_keys,
2716
- custom_lora_url, custom_lora_scale, custom_lora_trigger],
2717
  [video, report, upsampled, upsampled_panel, download_btn, lora_label],
2718
  api_name="generate",
2719
  )
@@ -2729,6 +2743,16 @@ with gr.Blocks(title="minimax h3 turbo + lora's") as demo:
2729
 
2730
  nsfw_lora_keys.change(_lora_descriptions, [nsfw_lora_keys], [lora_desc])
2731
 
 
 
 
 
 
 
 
 
 
 
2732
  last_frame_btn.click(
2733
  export_last_frame,
2734
  [video],
 
2158
  return _videos, _audio, _sampling_rate
2159
 
2160
 
2161
+ def _generate_impl(prompt, image_path=None, last_image_path=None, canvas=DEFAULT_CANVAS, duration=5, steps=25, seed=-1, upsample=False, turbo=False, nsfw_lora_keys=(), custom_lora_url="", custom_lora_scale=1.0, custom_lora_trigger="", nsfw_aio_enabled=False, astro_nsfw_enabled=False, progress=gr.Progress(track_tqdm=True)):
2162
  """The request pipeline: LoRA prep → remote conditioning → @spaces.GPU denoise → mux."""
2163
  if LOAD_ERROR:
2164
  raise gr.Error(LOAD_ERROR)
 
2212
  _trigger = str(custom_lora_trigger or "").strip()
2213
  custom = [(_repo, _file, _scale, _trigger)]
2214
 
2215
+ if nsfw_aio_enabled and "nsfw_aio" not in nsfw_keys:
2216
  nsfw_keys += ("nsfw_aio",)
2217
+ if astro_nsfw_enabled and "nsfw_astro_nsfw" not in nsfw_keys:
2218
+ nsfw_keys += ("nsfw_astro_nsfw",)
2219
  for _key in nsfw_keys:
2220
  _ensure_nsfw_lora_loaded(_key)
2221
  for _key in nsfw_keys:
 
2264
  directory = os.path.join(tempfile.gettempdir(), "h3-outputs")
2265
  os.makedirs(directory, exist_ok=True)
2266
  # Rotate: keep only the newest _MAX_OUTPUTS MP4s so /tmp never fills up.
2267
+ _MAX_OUTPUTS = 200
2268
  for _f in sorted(glob.glob(os.path.join(directory, "*.mp4")), key=os.path.getmtime)[:-_MAX_OUTPUTS]:
2269
  try:
2270
  os.remove(_f)
 
2294
  return path, report, refined, gr.update(visible=bool(refined)), gr.DownloadButton(value=path, visible=True), gr.update(value=lora_label_text, visible=bool(nsfw_keys) or bool(custom))
2295
 
2296
 
2297
+ def generate(prompt, image_path=None, last_image_path=None, canvas=DEFAULT_CANVAS, duration=5, steps=25, seed=-1, upsample=False, turbo=False, nsfw_lora_keys=(), custom_lora_url="", custom_lora_scale=1.0, custom_lora_trigger="", nsfw_aio_enabled=False, astro_nsfw_enabled=False, progress=gr.Progress(track_tqdm=True)):
2298
  """One request. `upsample` is last among the pre-existing positional args, so a positional API client that
2299
  predates it is unaffected; the custom-LoRA args come after it.
2300
 
 
2309
  try:
2310
  return _generate_impl(
2311
  prompt, image_path, last_image_path, canvas, duration, steps, seed, upsample, turbo,
2312
+ nsfw_lora_keys, custom_lora_url, custom_lora_scale, custom_lora_trigger,
2313
+ nsfw_aio_enabled, astro_nsfw_enabled, progress,
2314
  )
2315
  except gr.Error as _e:
2316
  _log(f"generate rejected: {_e}", "WARN")
 
2654
  with gr.Accordion("NSFW LoRAs", open=False):
2655
  nsfw_lora_keys = gr.Dropdown(
2656
  label="Select LoRAs to apply",
2657
+ choices=[(cfg["label"], key) for key, cfg in NSFW_LORA_CONFIGS.items() if key not in ("nsfw_aio", "nsfw_astro_nsfw")],
2658
  value=[],
2659
  multiselect=True,
2660
  filterable=True,
2661
+ info="Searchable — type to filter. Selected LoRAs show as removable tags; their trigger tokens are auto-appended to the prompt. Pick an enhancer adapter below.",
2662
  )
2663
  lora_desc = gr.Markdown(visible=False)
2664
+ with gr.Row():
2665
+ nsfw_aio_cb = gr.Checkbox(
2666
+ label="HMNSFW AIO V2.5 (motion adapter)",
2667
+ value=False,
2668
+ info="Auto-loads the Hearmeman motion adapter — makes anatomy LoRAs move naturally. Select one enhancer only.",
2669
+ )
2670
+ astro_nsfw_cb = gr.Checkbox(
2671
+ label="Astro NSFW (quality enhancer)",
2672
+ value=False,
2673
+ info="General NSFW quality enhancer that improves human movement and anatomy. Select one enhancer only.",
2674
+ )
2675
  with gr.Accordion("Custom LoRA (Hugging Face)", open=False):
2676
  gr.Markdown("Paste a Hugging Face link — a repo page or a direct `.safetensors` file link — then press "
2677
  "**Download & Verify**. The verified LoRA is applied on Generate. "
 
2727
  run.click(
2728
  generate,
2729
  [prompt, image, last_image, canvas, duration, steps, seed, upsample, turbo, nsfw_lora_keys,
2730
+ custom_lora_url, custom_lora_scale, custom_lora_trigger, nsfw_aio_cb, astro_nsfw_cb],
2731
  [video, report, upsampled, upsampled_panel, download_btn, lora_label],
2732
  api_name="generate",
2733
  )
 
2743
 
2744
  nsfw_lora_keys.change(_lora_descriptions, [nsfw_lora_keys], [lora_desc])
2745
 
2746
+ # Mutual exclusivity: checking one NSFW enhancer unchecks the other.
2747
+ nsfw_aio_cb.change(
2748
+ lambda v: gr.Checkbox(value=False) if v else gr.update(),
2749
+ [nsfw_aio_cb], [astro_nsfw_cb], api_name=False,
2750
+ )
2751
+ astro_nsfw_cb.change(
2752
+ lambda v: gr.Checkbox(value=False) if v else gr.update(),
2753
+ [astro_nsfw_cb], [nsfw_aio_cb], api_name=False,
2754
+ )
2755
+
2756
  last_frame_btn.click(
2757
  export_last_frame,
2758
  [video],