Spaces:
Running on Zero
Running on Zero
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,10 +1,8 @@
|
|
| 1 |
"""`Plaguekind/Minimax-H3` — the PlagueKind V1.5 ComfyUI workflow for MiniMax-H3, as a Space.
|
| 2 |
-
|
| 3 |
The candidate repository holds no weights: it is a ComfyUI graph over `Comfy-Org/MiniMax-H3`, so what is
|
| 4 |
reproduced here is the *graph*, on the `MiniMaxAI/MiniMax-H3` diffusers checkpoint. See `pk_workflow.py` for the
|
| 5 |
node-by-node mapping; the short version is euler + `linear_quadratic` at 15 steps, FSR RCAS sharpening at 0.3, and
|
| 6 |
FILM 2x frame interpolation to 48 fps.
|
| 7 |
-
|
| 8 |
Deployment is the split one the unquantized MiniMax-H3 needs: 195.9 GiB of bfloat16 does not fit under a Space's
|
| 9 |
150 GB storage quota, so the 62.14 GiB Qwen3-VL text encoder runs in a separate Space
|
| 10 |
(`multimodalart/qwen3vl-conditioner`) that this one calls per request, and this Space holds the 61.73 GiB
|
|
@@ -82,7 +80,6 @@ DEFAULT_STEPS = 15
|
|
| 82 |
|
| 83 |
def snap_frames(seconds: float) -> int:
|
| 84 |
"""The frame count MiniMax-H3's video VAE can decode: the next `17 * n + 5` at 24 fps.
|
| 85 |
-
|
| 86 |
Identical to the workflow's `ComfyMathExpression`,
|
| 87 |
`max(5, round(a*24)) + (5 - (max(5, round(a*24)) % 17)) % 17` — 5 s is 124 frames, i.e. 5.167 s.
|
| 88 |
"""
|
|
@@ -123,7 +120,6 @@ def status() -> str:
|
|
| 123 |
|
| 124 |
def load_models() -> str | None:
|
| 125 |
"""Load the denoising half at startup, plus FILM.
|
| 126 |
-
|
| 127 |
`MiniMaxH3GeneratorBlocks` declares `transformer`, `vae`, `audio_vae`, the two schedulers and `video_processor`,
|
| 128 |
so `load_components` fetches exactly those subfolders — `text_encoder/` and `transformer_ref/` are never
|
| 129 |
touched. Both autoencoders carry `_keep_in_fp32_modules` over every module and stay float32: a bfloat16 audio
|
|
@@ -138,31 +134,15 @@ def load_models() -> str | None:
|
|
| 138 |
try:
|
| 139 |
import torch
|
| 140 |
from diffusers import ComponentsManager
|
|
|
|
| 141 |
from h3_split_blocks import MiniMaxH3GeneratorBlocks
|
| 142 |
-
|
| 143 |
lower_duration_floor()
|
| 144 |
-
|
| 145 |
manager = ComponentsManager()
|
| 146 |
blocks = MiniMaxH3GeneratorBlocks()
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
f"[gen] loading {[c.name for c in blocks.expected_components]} from {MODEL_REPO} ...",
|
| 150 |
-
flush=True,
|
| 151 |
-
)
|
| 152 |
-
|
| 153 |
-
pipe = blocks.init_pipeline(
|
| 154 |
-
MODEL_REPO,
|
| 155 |
-
components_manager=manager,
|
| 156 |
-
collection="h3",
|
| 157 |
-
)
|
| 158 |
-
|
| 159 |
pipe.load_components(dtype=torch.bfloat16)
|
| 160 |
-
# Load TenStrip fine-tuned checkpoint into the transformer
|
| 161 |
-
from huggingface_hub import hf_hub_download
|
| 162 |
-
from safetensors.torch import load_model
|
| 163 |
-
finetune_path = hf_hub_download(repo_id="TenStrip/10Eros-Max", filename="10Eros_Max_h3_fl2va_bf16_test2_pruned.safetensors")
|
| 164 |
-
load_model(pipe.transformer, finetune_path, strict=False, device="cpu")
|
| 165 |
-
pipe.transformer.to(torch.bfloat16)
|
| 166 |
pipe.transformer.set_attention_backend(ATTENTION)
|
| 167 |
|
| 168 |
# Still startup, still free: an AoTI package carries no weights and opens its archive lazily inside the GPU
|
|
@@ -300,7 +280,6 @@ def _generate(
|
|
| 300 |
seed,
|
| 301 |
):
|
| 302 |
"""The only thing on GPU time: the denoise loop, the two decoders and the workflow's post chain.
|
| 303 |
-
|
| 304 |
The mp4 is muxed here rather than in the caller: a `@spaces.GPU` return crosses a process boundary by pickling,
|
| 305 |
and a 2x-interpolated 124-frame clip is several hundred MB of frames against a few MB of h264.
|
| 306 |
"""
|
|
@@ -502,19 +481,16 @@ def _fit_keyframe(image_path, current_canvas):
|
|
| 502 |
|
| 503 |
load_models()
|
| 504 |
|
| 505 |
-
INTRO = """# PlagueKind ·
|
| 506 |
-
|
| 507 |
<div align="center">
|
| 508 |
<a href="https://huggingface.co/Plaguekind/Minimax-H3" target="_blank" rel="noopener"><strong>[ workflow ]</strong></a>
|
| 509 |
<a href="https://huggingface.co/MiniMaxAI/MiniMax-H3" target="_blank" rel="noopener"><strong>[ model ]</strong></a>
|
| 510 |
<a href="https://github.com/PlagueKind/Comfyui-PlagueKind-Nodes" target="_blank" rel="noopener"><strong>[ nodes ]</strong></a>
|
| 511 |
-
<a href="https://huggingface.co/TenStrip/10Eros-Max" target="_blank" rel="noopener"><strong>[ 10Eros-Max ]</strong></a>
|
| 512 |
</div>
|
| 513 |
-
|
| 514 |
**MiniMax-H3** is a 33B parameter video generation model that produces video and a fully synchronized soundtrack
|
| 515 |
(ambience, foley, speech) in one pass. **PlagueKind's V1.5 workflow** is a tuning of it: euler on a
|
| 516 |
`linear_quadratic` sigma grid at 15 steps, FSR **RCAS** sharpening at 0.3, and **FILM** 2x frame interpolation to
|
| 517 |
-
48 fps. Text-to-video, first frame, last frame, or both.
|
| 518 |
"""
|
| 519 |
|
| 520 |
CSS = """
|
|
@@ -523,7 +499,7 @@ CSS = """
|
|
| 523 |
.status p {font-size: 0.8rem; opacity: 0.65; text-align: center;}
|
| 524 |
"""
|
| 525 |
|
| 526 |
-
with gr.Blocks(title="PlagueKind ·
|
| 527 |
gr.Markdown(INTRO)
|
| 528 |
gr.Markdown(status(), elem_classes="status")
|
| 529 |
|
|
@@ -652,7 +628,6 @@ with gr.Blocks(title="PlagueKind · 10Eros-Max · MiniMax-H3") as demo:
|
|
| 652 |
"""
|
| 653 |
`Plaguekind/Minimax-H3` ships no weights — it is a ComfyUI graph over `Comfy-Org/MiniMax-H3`. Its nodes map onto
|
| 654 |
this Space as:
|
| 655 |
-
|
| 656 |
| ComfyUI node | widget | here |
|
| 657 |
|---|---|---|
|
| 658 |
| `KSamplerSelect` | `euler` | MiniMax-H3's only sampler; the checkpoint is CFG-distilled, so one forward per step and no negative prompt |
|
|
@@ -664,13 +639,11 @@ this Space as:
|
|
| 664 |
| `CreateVideo` | fps `24 * 2` | 48 fps output |
|
| 665 |
| `RTXVideoSuperResolution` | 2x `ULTRA` | **not reproduced** |
|
| 666 |
| `PathchSageAttentionKJ` | `sageattn_qk_int8_pv_fp8_cuda++` | cuDNN fused attention |
|
| 667 |
-
|
| 668 |
Two deliberate deviations. `RTXVideoSuperResolution` is NVIDIA's NGX super-resolution, shipped as a driver-level
|
| 669 |
Windows/RTX component with no Linux Python path, so the 2x upscale is missing — pick a larger **Target dimension**
|
| 670 |
instead of upscaling a small one. And SageAttention's `qk_int8_pv_fp8_cuda++` kernel is not built for this pool's
|
| 671 |
sm120 cards, so attention runs cuDNN's fused kernel, which is the fastest available here and is numerically the
|
| 672 |
faithful one (SageAttention is a quantized approximation).
|
| 673 |
-
|
| 674 |
One upgrade: the workflow loads `minimax_h3_fl2va_pruned_int8_convrot.safetensors` and a
|
| 675 |
`qwen3vl_32b_..._int8_convrot` text encoder because that is what fits a consumer card. This Space runs both
|
| 676 |
**unquantized bfloat16**, off `MiniMaxAI/MiniMax-H3`, with the 62 GiB text encoder in a
|
|
@@ -683,4 +656,4 @@ One upgrade: the workflow loads `minimax_h3_fl2va_pruned_int8_convrot.safetensor
|
|
| 683 |
|
| 684 |
if __name__ == "__main__":
|
| 685 |
# `theme` and `css` belong to `launch()` from Gradio 6.0 on; on `Blocks` they warn and are ignored.
|
| 686 |
-
demo.launch(show_error=True, theme=gr.themes.Citrus(), css=CSS)
|
|
|
|
| 1 |
"""`Plaguekind/Minimax-H3` — the PlagueKind V1.5 ComfyUI workflow for MiniMax-H3, as a Space.
|
|
|
|
| 2 |
The candidate repository holds no weights: it is a ComfyUI graph over `Comfy-Org/MiniMax-H3`, so what is
|
| 3 |
reproduced here is the *graph*, on the `MiniMaxAI/MiniMax-H3` diffusers checkpoint. See `pk_workflow.py` for the
|
| 4 |
node-by-node mapping; the short version is euler + `linear_quadratic` at 15 steps, FSR RCAS sharpening at 0.3, and
|
| 5 |
FILM 2x frame interpolation to 48 fps.
|
|
|
|
| 6 |
Deployment is the split one the unquantized MiniMax-H3 needs: 195.9 GiB of bfloat16 does not fit under a Space's
|
| 7 |
150 GB storage quota, so the 62.14 GiB Qwen3-VL text encoder runs in a separate Space
|
| 8 |
(`multimodalart/qwen3vl-conditioner`) that this one calls per request, and this Space holds the 61.73 GiB
|
|
|
|
| 80 |
|
| 81 |
def snap_frames(seconds: float) -> int:
|
| 82 |
"""The frame count MiniMax-H3's video VAE can decode: the next `17 * n + 5` at 24 fps.
|
|
|
|
| 83 |
Identical to the workflow's `ComfyMathExpression`,
|
| 84 |
`max(5, round(a*24)) + (5 - (max(5, round(a*24)) % 17)) % 17` — 5 s is 124 frames, i.e. 5.167 s.
|
| 85 |
"""
|
|
|
|
| 120 |
|
| 121 |
def load_models() -> str | None:
|
| 122 |
"""Load the denoising half at startup, plus FILM.
|
|
|
|
| 123 |
`MiniMaxH3GeneratorBlocks` declares `transformer`, `vae`, `audio_vae`, the two schedulers and `video_processor`,
|
| 124 |
so `load_components` fetches exactly those subfolders — `text_encoder/` and `transformer_ref/` are never
|
| 125 |
touched. Both autoencoders carry `_keep_in_fp32_modules` over every module and stay float32: a bfloat16 audio
|
|
|
|
| 134 |
try:
|
| 135 |
import torch
|
| 136 |
from diffusers import ComponentsManager
|
| 137 |
+
|
| 138 |
from h3_split_blocks import MiniMaxH3GeneratorBlocks
|
| 139 |
+
|
| 140 |
lower_duration_floor()
|
|
|
|
| 141 |
manager = ComponentsManager()
|
| 142 |
blocks = MiniMaxH3GeneratorBlocks()
|
| 143 |
+
print(f"[gen] loading {[c.name for c in blocks.expected_components]} from {MODEL_REPO} ...", flush=True)
|
| 144 |
+
pipe = blocks.init_pipeline(MODEL_REPO, components_manager=manager, collection="h3")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
pipe.load_components(dtype=torch.bfloat16)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
pipe.transformer.set_attention_backend(ATTENTION)
|
| 147 |
|
| 148 |
# Still startup, still free: an AoTI package carries no weights and opens its archive lazily inside the GPU
|
|
|
|
| 280 |
seed,
|
| 281 |
):
|
| 282 |
"""The only thing on GPU time: the denoise loop, the two decoders and the workflow's post chain.
|
|
|
|
| 283 |
The mp4 is muxed here rather than in the caller: a `@spaces.GPU` return crosses a process boundary by pickling,
|
| 284 |
and a 2x-interpolated 124-frame clip is several hundred MB of frames against a few MB of h264.
|
| 285 |
"""
|
|
|
|
| 481 |
|
| 482 |
load_models()
|
| 483 |
|
| 484 |
+
INTRO = """# PlagueKind · MiniMax-H3
|
|
|
|
| 485 |
<div align="center">
|
| 486 |
<a href="https://huggingface.co/Plaguekind/Minimax-H3" target="_blank" rel="noopener"><strong>[ workflow ]</strong></a>
|
| 487 |
<a href="https://huggingface.co/MiniMaxAI/MiniMax-H3" target="_blank" rel="noopener"><strong>[ model ]</strong></a>
|
| 488 |
<a href="https://github.com/PlagueKind/Comfyui-PlagueKind-Nodes" target="_blank" rel="noopener"><strong>[ nodes ]</strong></a>
|
|
|
|
| 489 |
</div>
|
|
|
|
| 490 |
**MiniMax-H3** is a 33B parameter video generation model that produces video and a fully synchronized soundtrack
|
| 491 |
(ambience, foley, speech) in one pass. **PlagueKind's V1.5 workflow** is a tuning of it: euler on a
|
| 492 |
`linear_quadratic` sigma grid at 15 steps, FSR **RCAS** sharpening at 0.3, and **FILM** 2x frame interpolation to
|
| 493 |
+
48 fps. Text-to-video, first frame, last frame, or both.
|
| 494 |
"""
|
| 495 |
|
| 496 |
CSS = """
|
|
|
|
| 499 |
.status p {font-size: 0.8rem; opacity: 0.65; text-align: center;}
|
| 500 |
"""
|
| 501 |
|
| 502 |
+
with gr.Blocks(title="PlagueKind · MiniMax-H3") as demo:
|
| 503 |
gr.Markdown(INTRO)
|
| 504 |
gr.Markdown(status(), elem_classes="status")
|
| 505 |
|
|
|
|
| 628 |
"""
|
| 629 |
`Plaguekind/Minimax-H3` ships no weights — it is a ComfyUI graph over `Comfy-Org/MiniMax-H3`. Its nodes map onto
|
| 630 |
this Space as:
|
|
|
|
| 631 |
| ComfyUI node | widget | here |
|
| 632 |
|---|---|---|
|
| 633 |
| `KSamplerSelect` | `euler` | MiniMax-H3's only sampler; the checkpoint is CFG-distilled, so one forward per step and no negative prompt |
|
|
|
|
| 639 |
| `CreateVideo` | fps `24 * 2` | 48 fps output |
|
| 640 |
| `RTXVideoSuperResolution` | 2x `ULTRA` | **not reproduced** |
|
| 641 |
| `PathchSageAttentionKJ` | `sageattn_qk_int8_pv_fp8_cuda++` | cuDNN fused attention |
|
|
|
|
| 642 |
Two deliberate deviations. `RTXVideoSuperResolution` is NVIDIA's NGX super-resolution, shipped as a driver-level
|
| 643 |
Windows/RTX component with no Linux Python path, so the 2x upscale is missing — pick a larger **Target dimension**
|
| 644 |
instead of upscaling a small one. And SageAttention's `qk_int8_pv_fp8_cuda++` kernel is not built for this pool's
|
| 645 |
sm120 cards, so attention runs cuDNN's fused kernel, which is the fastest available here and is numerically the
|
| 646 |
faithful one (SageAttention is a quantized approximation).
|
|
|
|
| 647 |
One upgrade: the workflow loads `minimax_h3_fl2va_pruned_int8_convrot.safetensors` and a
|
| 648 |
`qwen3vl_32b_..._int8_convrot` text encoder because that is what fits a consumer card. This Space runs both
|
| 649 |
**unquantized bfloat16**, off `MiniMaxAI/MiniMax-H3`, with the 62 GiB text encoder in a
|
|
|
|
| 656 |
|
| 657 |
if __name__ == "__main__":
|
| 658 |
# `theme` and `css` belong to `launch()` from Gradio 6.0 on; on `Blocks` they warn and are ignored.
|
| 659 |
+
demo.launch(show_error=True, theme=gr.themes.Citrus(), css=CSS)
|