bann commited on
Commit
6f83a93
·
1 Parent(s): 3573fa3

fix(gradio): fix OpenAPI bool schema crash and add Base NSFW Adapter slot with Civitai 1307155

Browse files
Files changed (1) hide show
  1. app.py +85 -17
app.py CHANGED
@@ -33,7 +33,31 @@ LORA_MAX_BYTES = 2 * 1024**3
33
  DEFAULT_FPS = 16
34
 
35
  # =========================================================================
36
- # Preset Catalog for Wan 2.1 / 2.2 LoRAs
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  # =========================================================================
38
  LORA_PRESETS = {
39
  "None / Desativado": {
@@ -42,6 +66,13 @@ LORA_PRESETS = {
42
  "default_strength": 1.0,
43
  "description": "Nenhum LoRA selecionado neste slot.",
44
  },
 
 
 
 
 
 
 
45
  "HMNSFW AIO V2 / hmmotion (Wan 2.1 / 2.2)": {
46
  "type": "civitai",
47
  "source": "https://civitai.com/api/download/models/3206518",
@@ -402,10 +433,10 @@ def _fit_keyframe(image_input, target_width: int, target_height: int) -> Image.I
402
  return img
403
 
404
 
405
- def get_duration(prompt, negative_prompt, input_image, canvas, num_frames, fps, steps, *a, **k):
406
  steps = int(steps)
407
  num_frames = int(num_frames)
408
- h, w = CANVACES_GET = CANVASES.get(canvas, (480, 832))
409
  pixels_per_frame = h * w
410
  total_tokens = (pixels_per_frame / 256) * (num_frames / 4)
411
  estimated = int(steps * (total_tokens * 0.00012) + 20)
@@ -488,6 +519,8 @@ def generate_video(
488
  prompt: str,
489
  negative_prompt: str,
490
  input_image: Image.Image | str | None,
 
 
491
  canvas: str,
492
  num_frames: int,
493
  fps: int,
@@ -527,6 +560,17 @@ def generate_video(
527
  lora_configs = []
528
  active_labels = []
529
 
 
 
 
 
 
 
 
 
 
 
 
530
  l1_path, l1_label, l1_scale = resolve_single_lora(
531
  lora1_preset, lora1_custom_url, lora1_hf_repo, lora1_hf_file, lora1_local_file, lora1_strength, civitai_api_key
532
  )
@@ -534,6 +578,7 @@ def generate_video(
534
  lora_configs.append((l1_path, l1_scale))
535
  active_labels.append(f"{l1_label} (@ {lora1_strength:g})")
536
 
 
537
  l2_path, l2_label, l2_scale = resolve_single_lora(
538
  lora2_preset, lora2_custom_url, lora2_hf_repo, lora2_hf_file, lora2_local_file, lora2_strength, civitai_api_key
539
  )
@@ -661,11 +706,11 @@ with gr.Blocks(css=custom_css, title="Wan 2.1 / 2.2 Video Studio") as app:
661
  <div class="header-card">
662
  <div style="margin-bottom: 12px;">
663
  <span class="badge badge-zerogpu">⚡ ZeroGPU</span>
664
- <span class="badge badge-model">🎬 Wan 2.1 (14B Diffusers)</span>
665
- <span class="badge badge-multilora">🧩 Multi-LoRA Engine</span>
666
  </div>
667
  <h1>Wan 2.1 / 2.2 AI Video Studio</h1>
668
- <p>Image-to-Video (I2V) & Text-to-Video (T2V) com suporte a múltiplos LoRAs e resoluções otimizadas (Múltiplos de 16).</p>
669
  </div>
670
  """
671
  )
@@ -676,14 +721,14 @@ with gr.Blocks(css=custom_css, title="Wan 2.1 / 2.2 Video Studio") as app:
676
  label="Prompt",
677
  placeholder="Descreva a cena detalhada do vídeo...",
678
  lines=4,
679
- value="A cinematic shot of a beautiful woman with glowing eyes, dramatic lighting, 8k masterpiece",
680
  )
681
 
682
  negative_prompt = gr.Textbox(
683
  label="Negative Prompt",
684
  placeholder="Elementos indesejados (distorções, membros extras, baixa qualidade)...",
685
  lines=2,
686
- value="deformed, bad anatomy, extra limbs, blurry, low resolution, bad quality, distortion",
687
  )
688
 
689
  with gr.Accordion("📖 Guia & Modelos de Prompt HMNSFW / hmmotion (Wan 2.1 / 2.2)", open=False):
@@ -702,15 +747,32 @@ with gr.Blocks(css=custom_css, title="Wan 2.1 / 2.2 Video Studio") as app:
702
  hmnsfw_example_btn = gr.Button("💡 Inserir Exemplo Completo de Prompt HMNSFW", elem_classes=["trigger-btn"])
703
 
704
  with gr.Tabs():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
705
  with gr.TabItem("🖼️ Image-to-Video (I2V)"):
706
  gr.Markdown("Faça upload de uma imagem inicial (`First Frame`). O sistema ajustará o corte automaticamente para a proporção múltipla de 16 selecionada.")
707
- input_image = gr.Image(label="First Frame (Imagem Inicial)", type="filepath")
708
 
709
- with gr.TabItem("🎨 LoRA Slot 1 (Estilo / Ação)"):
710
  lora1_preset = gr.Dropdown(
711
  label="LoRA Slot 1 Preset / Fonte",
712
  choices=all_preset_choices,
713
- value="None / Desativado",
714
  )
715
  with gr.Group(visible=False) as lora1_custom_url_grp:
716
  lora1_custom_url = gr.Textbox(
@@ -726,7 +788,7 @@ with gr.Blocks(css=custom_css, title="Wan 2.1 / 2.2 Video Studio") as app:
726
 
727
  lora1_trigger_display = gr.Textbox(
728
  label="Trigger Words",
729
- value="",
730
  interactive=False,
731
  )
732
  add_lora1_triggers_btn = gr.Button("📋 Inserir Trigger Words no Prompt", elem_classes=["trigger-btn"])
@@ -736,7 +798,7 @@ with gr.Blocks(css=custom_css, title="Wan 2.1 / 2.2 Video Studio") as app:
736
  minimum=0.0,
737
  maximum=2.0,
738
  step=0.05,
739
- value=1.0,
740
  )
741
 
742
  with gr.TabItem("🎬 LoRA Slot 2 (Movimento / Câmera)"):
@@ -855,6 +917,7 @@ with gr.Blocks(css=custom_css, title="Wan 2.1 / 2.2 Video Studio") as app:
855
  fn=on_lora1_change,
856
  inputs=[lora1_preset],
857
  outputs=[lora1_custom_url_grp, lora1_hf_grp, lora1_local_grp, lora1_trigger_display, lora1_strength],
 
858
  )
859
 
860
  def on_lora2_change(preset_val):
@@ -873,6 +936,7 @@ with gr.Blocks(css=custom_css, title="Wan 2.1 / 2.2 Video Studio") as app:
873
  fn=on_lora2_change,
874
  inputs=[lora2_preset],
875
  outputs=[lora2_custom_url_grp, lora2_hf_grp, lora2_local_grp, lora2_trigger_display, lora2_strength],
 
876
  )
877
 
878
  def append_triggers(curr_prompt, triggers):
@@ -904,9 +968,10 @@ with gr.Blocks(css=custom_css, title="Wan 2.1 / 2.2 Video Studio") as app:
904
  "The setting is a bed with dark grey sheets under warm, low indoor lighting."
905
  )
906
 
907
- hmnsfw_example_btn.click(fn=load_hmnsfw_example, outputs=[prompt])
908
- add_lora1_triggers_btn.click(fn=append_triggers, inputs=[prompt, lora1_trigger_display], outputs=[prompt])
909
- add_lora2_triggers_btn.click(fn=append_triggers, inputs=[prompt, lora2_trigger_display], outputs=[prompt])
 
910
 
911
  generate_btn.click(
912
  fn=generate_video,
@@ -914,6 +979,8 @@ with gr.Blocks(css=custom_css, title="Wan 2.1 / 2.2 Video Studio") as app:
914
  prompt,
915
  negative_prompt,
916
  input_image,
 
 
917
  canvas,
918
  num_frames,
919
  fps,
@@ -937,7 +1004,8 @@ with gr.Blocks(css=custom_css, title="Wan 2.1 / 2.2 Video Studio") as app:
937
  civitai_api_key,
938
  ],
939
  outputs=[output_video, output_report, seed],
 
940
  )
941
 
942
  if __name__ == "__main__":
943
- app.launch(show_error=True, allowed_paths=[OUTPUT_DIR])
 
33
  DEFAULT_FPS = 16
34
 
35
  # =========================================================================
36
+ # Base NSFW Adapters (Unlocks adult generation on Wan Base Models)
37
+ # =========================================================================
38
+ NSFW_BASE_ADAPTERS = {
39
+ "WAN General NSFW Model (Civitai 1307155 - Recomendado)": {
40
+ "source": "https://civitai.com/models/1307155",
41
+ "trigger_words": "nsfwsks, uncensored, naked, explicit",
42
+ "default_strength": 1.0,
43
+ "description": "Desbloqueia anatomia e geração explícita no modelo base Wan (Civitai Model 1307155).",
44
+ },
45
+ "HMNSFW AIO V2 Base (Civitai 2834417)": {
46
+ "source": "https://civitai.com/api/download/models/3206518",
47
+ "trigger_words": "hmmotion",
48
+ "default_strength": 0.5,
49
+ "description": "Adaptador anatômico geral HMNSFW V2 para Wan 2.1/2.2.",
50
+ },
51
+ "Desativado / Apenas Base SFW": {
52
+ "source": "",
53
+ "trigger_words": "",
54
+ "default_strength": 0.0,
55
+ "description": "Usa apenas o modelo base padrão sem adaptador NSFW adicional.",
56
+ },
57
+ }
58
+
59
+ # =========================================================================
60
+ # Preset Catalog for Wan 2.1 / 2.2 LoRAs (Actions, Motions & Styles)
61
  # =========================================================================
62
  LORA_PRESETS = {
63
  "None / Desativado": {
 
66
  "default_strength": 1.0,
67
  "description": "Nenhum LoRA selecionado neste slot.",
68
  },
69
+ "WAN General NSFW model (Civitai 1307155)": {
70
+ "type": "civitai",
71
+ "source": "https://civitai.com/models/1307155",
72
+ "trigger_words": "nsfwsks, uncensored, naked, explicit",
73
+ "default_strength": 1.0,
74
+ "description": "LoRA Geral NSFW para Wan 2.1 / 2.2 (Civitai 1307155).",
75
+ },
76
  "HMNSFW AIO V2 / hmmotion (Wan 2.1 / 2.2)": {
77
  "type": "civitai",
78
  "source": "https://civitai.com/api/download/models/3206518",
 
433
  return img
434
 
435
 
436
+ def get_duration(prompt, negative_prompt, input_image, nsfw_base_choice, nsfw_base_strength, canvas, num_frames, fps, steps, *a, **k):
437
  steps = int(steps)
438
  num_frames = int(num_frames)
439
+ h, w = CANVASES.get(canvas, (480, 832))
440
  pixels_per_frame = h * w
441
  total_tokens = (pixels_per_frame / 256) * (num_frames / 4)
442
  estimated = int(steps * (total_tokens * 0.00012) + 20)
 
519
  prompt: str,
520
  negative_prompt: str,
521
  input_image: Image.Image | str | None,
522
+ nsfw_base_choice: str,
523
+ nsfw_base_strength: float,
524
  canvas: str,
525
  num_frames: int,
526
  fps: int,
 
560
  lora_configs = []
561
  active_labels = []
562
 
563
+ # 1. Base NSFW Adapter
564
+ if nsfw_base_choice in NSFW_BASE_ADAPTERS and nsfw_base_strength > 0:
565
+ base_spec = NSFW_BASE_ADAPTERS[nsfw_base_choice]
566
+ if base_spec.get("source"):
567
+ b_url = normalize_civitai_url(base_spec["source"])
568
+ if b_url:
569
+ b_path, b_label = _download_lora_url(b_url, civitai_api_key)
570
+ lora_configs.append((b_path, float(nsfw_base_strength)))
571
+ active_labels.append(f"🔞 NSFW Base: {nsfw_base_choice.split('(')[0].strip()} (@ {nsfw_base_strength:g})")
572
+
573
+ # 2. Slot 1 LoRA
574
  l1_path, l1_label, l1_scale = resolve_single_lora(
575
  lora1_preset, lora1_custom_url, lora1_hf_repo, lora1_hf_file, lora1_local_file, lora1_strength, civitai_api_key
576
  )
 
578
  lora_configs.append((l1_path, l1_scale))
579
  active_labels.append(f"{l1_label} (@ {lora1_strength:g})")
580
 
581
+ # 3. Slot 2 LoRA
582
  l2_path, l2_label, l2_scale = resolve_single_lora(
583
  lora2_preset, lora2_custom_url, lora2_hf_repo, lora2_hf_file, lora2_local_file, lora2_strength, civitai_api_key
584
  )
 
706
  <div class="header-card">
707
  <div style="margin-bottom: 12px;">
708
  <span class="badge badge-zerogpu">⚡ ZeroGPU</span>
709
+ <span class="badge badge-model">🎬 Wan 2.1 / 2.2 (Diffusers)</span>
710
+ <span class="badge badge-multilora">🧩 Base NSFW + Multi-LoRA Engine</span>
711
  </div>
712
  <h1>Wan 2.1 / 2.2 AI Video Studio</h1>
713
+ <p>Image-to-Video (I2V) & Text-to-Video (T2V) com Adaptador NSFW Base, Multi-LoRA e Resoluções Múltiplas de 16.</p>
714
  </div>
715
  """
716
  )
 
721
  label="Prompt",
722
  placeholder="Descreva a cena detalhada do vídeo...",
723
  lines=4,
724
+ value="nsfwsks, a cinematic shot of a beautiful woman with glowing eyes, dramatic lighting, 8k masterpiece",
725
  )
726
 
727
  negative_prompt = gr.Textbox(
728
  label="Negative Prompt",
729
  placeholder="Elementos indesejados (distorções, membros extras, baixa qualidade)...",
730
  lines=2,
731
+ value="deformed, bad anatomy, extra limbs, blurry, low resolution, bad quality, distortion, censorship",
732
  )
733
 
734
  with gr.Accordion("📖 Guia & Modelos de Prompt HMNSFW / hmmotion (Wan 2.1 / 2.2)", open=False):
 
747
  hmnsfw_example_btn = gr.Button("💡 Inserir Exemplo Completo de Prompt HMNSFW", elem_classes=["trigger-btn"])
748
 
749
  with gr.Tabs():
750
+ with gr.TabItem("🔞 Adaptador Base NSFW (Essencial)"):
751
+ gr.Markdown("Como o modelo base do Wan é treinado sem conteúdo explícito, este adaptador é carregado como base para desbloquear anatomia sem gastar seus slots de LoRA!")
752
+ with gr.Row():
753
+ nsfw_base_choice = gr.Dropdown(
754
+ label="Adaptador Base NSFW",
755
+ choices=list(NSFW_BASE_ADAPTERS.keys()),
756
+ value="WAN General NSFW Model (Civitai 1307155 - Recomendado)",
757
+ )
758
+ nsfw_base_strength = gr.Slider(
759
+ label="Força do Adaptador Base NSFW",
760
+ minimum=0.0,
761
+ maximum=1.5,
762
+ step=0.05,
763
+ value=1.0,
764
+ )
765
+ nsfw_base_trigger_btn = gr.Button("📋 Inserir Trigger `nsfwsks` no Prompt", elem_classes=["trigger-btn"])
766
+
767
  with gr.TabItem("🖼️ Image-to-Video (I2V)"):
768
  gr.Markdown("Faça upload de uma imagem inicial (`First Frame`). O sistema ajustará o corte automaticamente para a proporção múltipla de 16 selecionada.")
769
+ input_image = gr.Image(label="First Frame (Imagem Inicial)", type="pil")
770
 
771
+ with gr.TabItem("🎨 LoRA Slot 1 (Ação / Pose)"):
772
  lora1_preset = gr.Dropdown(
773
  label="LoRA Slot 1 Preset / Fonte",
774
  choices=all_preset_choices,
775
+ value="HMNSFW AIO V2 / hmmotion (Wan 2.1 / 2.2)",
776
  )
777
  with gr.Group(visible=False) as lora1_custom_url_grp:
778
  lora1_custom_url = gr.Textbox(
 
788
 
789
  lora1_trigger_display = gr.Textbox(
790
  label="Trigger Words",
791
+ value=LORA_PRESETS.get("HMNSFW AIO V2 / hmmotion (Wan 2.1 / 2.2)", {}).get("trigger_words", ""),
792
  interactive=False,
793
  )
794
  add_lora1_triggers_btn = gr.Button("📋 Inserir Trigger Words no Prompt", elem_classes=["trigger-btn"])
 
798
  minimum=0.0,
799
  maximum=2.0,
800
  step=0.05,
801
+ value=0.5,
802
  )
803
 
804
  with gr.TabItem("🎬 LoRA Slot 2 (Movimento / Câmera)"):
 
917
  fn=on_lora1_change,
918
  inputs=[lora1_preset],
919
  outputs=[lora1_custom_url_grp, lora1_hf_grp, lora1_local_grp, lora1_trigger_display, lora1_strength],
920
+ api_name=False,
921
  )
922
 
923
  def on_lora2_change(preset_val):
 
936
  fn=on_lora2_change,
937
  inputs=[lora2_preset],
938
  outputs=[lora2_custom_url_grp, lora2_hf_grp, lora2_local_grp, lora2_trigger_display, lora2_strength],
939
+ api_name=False,
940
  )
941
 
942
  def append_triggers(curr_prompt, triggers):
 
968
  "The setting is a bed with dark grey sheets under warm, low indoor lighting."
969
  )
970
 
971
+ hmnsfw_example_btn.click(fn=load_hmnsfw_example, outputs=[prompt], api_name=False)
972
+ nsfw_base_trigger_btn.click(fn=lambda p: append_triggers(p, "nsfwsks, uncensored, explicit"), inputs=[prompt], outputs=[prompt], api_name=False)
973
+ add_lora1_triggers_btn.click(fn=append_triggers, inputs=[prompt, lora1_trigger_display], outputs=[prompt], api_name=False)
974
+ add_lora2_triggers_btn.click(fn=append_triggers, inputs=[prompt, lora2_trigger_display], outputs=[prompt], api_name=False)
975
 
976
  generate_btn.click(
977
  fn=generate_video,
 
979
  prompt,
980
  negative_prompt,
981
  input_image,
982
+ nsfw_base_choice,
983
+ nsfw_base_strength,
984
  canvas,
985
  num_frames,
986
  fps,
 
1004
  civitai_api_key,
1005
  ],
1006
  outputs=[output_video, output_report, seed],
1007
+ api_name="generate_video",
1008
  )
1009
 
1010
  if __name__ == "__main__":
1011
+ app.launch(show_api=False, show_error=True, allowed_paths=[OUTPUT_DIR])