PEFT
Safetensors
MiniMax H3
English
lora
prompt-rewriting
text-to-audio-video
audio-video-generation
Instructions to use lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3.6-27B") model = PeftModel.from_pretrained(base_model, "lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA") - Notebooks
- Google Colab
- Kaggle
Upload folder using huggingface_hub
Browse files- README.md +332 -1
- infer.py +143 -0
- prompt_template.py +40 -0
- requirements.txt +5 -0
README.md
CHANGED
|
@@ -1,3 +1,334 @@
|
|
| 1 |
---
|
| 2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
base_model: Qwen/Qwen3.6-27B
|
| 3 |
+
library_name: peft
|
| 4 |
+
tags:
|
| 5 |
+
- peft
|
| 6 |
+
- lora
|
| 7 |
+
- prompt-rewriting
|
| 8 |
+
- minimax-h3
|
| 9 |
+
- text-to-audio-video
|
| 10 |
+
- audio-video-generation
|
| 11 |
+
- t2va
|
| 12 |
+
language:
|
| 13 |
+
- en
|
| 14 |
---
|
| 15 |
+
|
| 16 |
+
# MiniMax-H3 T2VA Prompt Rewriter LoRA
|
| 17 |
+
|
| 18 |
+
[](https://github.com/ModelTC/LightX2V)
|
| 19 |
+
[](https://github.com/ModelTC/LightX2V)
|
| 20 |
+
[](https://huggingface.co/MiniMaxAI/MiniMax-H3)
|
| 21 |
+
|
| 22 |
+
An open, local prompt rewriter for **text-to-audio-video (T2VA)** generation with
|
| 23 |
+
[MiniMax-H3](https://huggingface.co/MiniMaxAI/MiniMax-H3), fine-tuned as a LoRA
|
| 24 |
+
adapter on top of [Qwen3.6-27B](https://huggingface.co/Qwen/Qwen3.6-27B).
|
| 25 |
+
|
| 26 |
+
> **Generate the final audio-video with
|
| 27 |
+
> [LightX2V](https://github.com/ModelTC/LightX2V).** LightX2V provides optimized local
|
| 28 |
+
> MiniMax-H3 inference, including T2AV and other H3 tasks, memory offloading, tensor and
|
| 29 |
+
> sequence parallelism, quantized checkpoints, optimized attention/RMSNorm/RoPE kernels,
|
| 30 |
+
> and feature caching. If this project is useful, please consider giving
|
| 31 |
+
> **[ModelTC/LightX2V](https://github.com/ModelTC/LightX2V) a star**.
|
| 32 |
+
|
| 33 |
+
The complete local workflow is:
|
| 34 |
+
|
| 35 |
+
```text
|
| 36 |
+
Short prompt ──► this Prompt Rewriter LoRA ──► structured H3 prompt
|
| 37 |
+
│
|
| 38 |
+
Official MiniMax-H3 weights ──► LightX2V inference ◄─────┘
|
| 39 |
+
│
|
| 40 |
+
▼
|
| 41 |
+
synchronized video + audio
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
The [official MiniMax-H3 repository](https://huggingface.co/MiniMaxAI/MiniMax-H3)
|
| 45 |
+
provides the upstream model weights. **LightX2V is the recommended inference entry
|
| 46 |
+
point for the workflow documented here.**
|
| 47 |
+
|
| 48 |
+
This is an unofficial, community-trained project and is not affiliated with or
|
| 49 |
+
endorsed by MiniMax. It is intended as a local alternative for producing structured,
|
| 50 |
+
H3-oriented T2VA prompts when the hosted H3-Context-IR service is unavailable or
|
| 51 |
+
unsuitable for a workflow. It does not reproduce the proprietary H3-Context-IR system,
|
| 52 |
+
and exact output parity is not guaranteed.
|
| 53 |
+
|
| 54 |
+
## What it does
|
| 55 |
+
|
| 56 |
+
The adapter turns a short prompt plus the requested aspect ratio and duration into a
|
| 57 |
+
structured audio-video description:
|
| 58 |
+
|
| 59 |
+
```text
|
| 60 |
+
Original prompt + aspect ratio + duration
|
| 61 |
+
│
|
| 62 |
+
▼
|
| 63 |
+
Qwen3.6-27B + this LoRA
|
| 64 |
+
│
|
| 65 |
+
▼
|
| 66 |
+
integrated_multimodal_description: [Shot 1] ...
|
| 67 |
+
overall_soundscape: ...
|
| 68 |
+
non_diegetic_music: ...
|
| 69 |
+
```
|
| 70 |
+
|
| 71 |
+
The rewritten prompt expands shot structure, timing, composition, camera motion,
|
| 72 |
+
physical action, continuity, synchronized diegetic sound, and non-diegetic music while
|
| 73 |
+
preserving the original intent.
|
| 74 |
+
|
| 75 |
+
| Component | Purpose | Model |
|
| 76 |
+
|---|---|---|
|
| 77 |
+
| Inference framework | Runs MiniMax-H3 locally and generates the final synchronized video and audio | **[ModelTC/LightX2V](https://github.com/ModelTC/LightX2V)** |
|
| 78 |
+
| Generator weights | Upstream MiniMax-H3 model weights consumed by LightX2V | [MiniMaxAI/MiniMax-H3](https://huggingface.co/MiniMaxAI/MiniMax-H3) |
|
| 79 |
+
| Base language model | General instruction-following backbone | [Qwen3.6-27B](https://huggingface.co/Qwen/Qwen3.6-27B) |
|
| 80 |
+
| LoRA adapter | H3-oriented T2VA prompt rewriting | [lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA](https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA) |
|
| 81 |
+
|
| 82 |
+
## Status and roadmap
|
| 83 |
+
|
| 84 |
+
- [x] T2VA prompt rewriting
|
| 85 |
+
- [x] Duration conditioning from 4 to 15 seconds
|
| 86 |
+
- [x] Aspect-ratio conditioning: `21:9`, `16:9`, `4:3`, `1:1`, `3:4`, `9:16`
|
| 87 |
+
- [x] Single-prompt inference script
|
| 88 |
+
- [x] End-to-end MiniMax-H3 generation through [LightX2V](https://github.com/ModelTC/LightX2V)
|
| 89 |
+
- [ ] First/last-frame-to-audio-video (FL2VA) prompt rewriting
|
| 90 |
+
- [ ] Reference-to-audio-video (Ref2VA) prompt rewriting
|
| 91 |
+
- [ ] Image-to-audio-video and last-frame variants
|
| 92 |
+
- [ ] Image, video, and audio reference inputs
|
| 93 |
+
- [ ] Quantitative evaluation and a reproducible public benchmark suite
|
| 94 |
+
- [ ] Smaller and quantized rewriter variants
|
| 95 |
+
|
| 96 |
+
Only **T2VA** is supported by this release. The remaining MiniMax-H3 tasks require
|
| 97 |
+
multimodal inputs and task-specific training data; they will be added in future work.
|
| 98 |
+
|
| 99 |
+
## Installation
|
| 100 |
+
|
| 101 |
+
Clone this repository and install the inference dependencies:
|
| 102 |
+
|
| 103 |
+
```bash
|
| 104 |
+
git clone https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA
|
| 105 |
+
cd MiniMax-H3-Prompt-Rewriter-LoRA
|
| 106 |
+
pip install -r requirements.txt
|
| 107 |
+
```
|
| 108 |
+
|
| 109 |
+
The 27B base model is not included in this adapter repository and will be downloaded
|
| 110 |
+
from Hugging Face on first use. Ensure that the machine has enough GPU/CPU memory for
|
| 111 |
+
Qwen3.6-27B. `device_map="auto"` is used to distribute the model over available devices.
|
| 112 |
+
|
| 113 |
+
## Rewrite one prompt
|
| 114 |
+
|
| 115 |
+
```bash
|
| 116 |
+
python infer.py \
|
| 117 |
+
--prompt "Epic space-opera teaser: a captain watches the last fleet jump away, leaving her alone." \
|
| 118 |
+
--duration 10 \
|
| 119 |
+
--resolution 16:9 \
|
| 120 |
+
--greedy
|
| 121 |
+
```
|
| 122 |
+
|
| 123 |
+
The default model IDs are:
|
| 124 |
+
|
| 125 |
+
```text
|
| 126 |
+
Base model: Qwen/Qwen3.6-27B
|
| 127 |
+
Adapter: lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA
|
| 128 |
+
```
|
| 129 |
+
|
| 130 |
+
Local paths are supported as well:
|
| 131 |
+
|
| 132 |
+
```bash
|
| 133 |
+
python infer.py \
|
| 134 |
+
--base-model /path/to/Qwen3.6-27B \
|
| 135 |
+
--adapter /path/to/MiniMax-H3-Prompt-Rewriter-LoRA \
|
| 136 |
+
--prompt "A red fox walks through a snowy forest at dawn." \
|
| 137 |
+
--duration 15 \
|
| 138 |
+
--resolution 21:9 \
|
| 139 |
+
--output rewritten_prompt.json
|
| 140 |
+
```
|
| 141 |
+
|
| 142 |
+
Use `--output result.txt` for plain text or a `.json` path for a record containing
|
| 143 |
+
the original prompt, conditions, model IDs, and rewritten prompt.
|
| 144 |
+
|
| 145 |
+
To run the base-model baseline without the LoRA:
|
| 146 |
+
|
| 147 |
+
```bash
|
| 148 |
+
python infer.py \
|
| 149 |
+
--base-only \
|
| 150 |
+
--prompt "A red fox walks through a snowy forest at dawn." \
|
| 151 |
+
--duration 15 \
|
| 152 |
+
--resolution 21:9 \
|
| 153 |
+
--greedy
|
| 154 |
+
```
|
| 155 |
+
|
| 156 |
+
For fair comparisons, use the same decoding mode and seed for every rewriter. Greedy
|
| 157 |
+
decoding is the simplest deterministic setting; sampling is enabled when `--greedy`
|
| 158 |
+
is omitted.
|
| 159 |
+
|
| 160 |
+
## Output format
|
| 161 |
+
|
| 162 |
+
The model is trained to return exactly three fields in this order:
|
| 163 |
+
|
| 164 |
+
```text
|
| 165 |
+
integrated_multimodal_description: [Shot 1] ... [Shot 2] At 00:05.000, ...
|
| 166 |
+
overall_soundscape: ...
|
| 167 |
+
non_diegetic_music: ...
|
| 168 |
+
```
|
| 169 |
+
|
| 170 |
+
Pass the entire three-field result to the MiniMax-H3 T2VA pipeline in
|
| 171 |
+
[LightX2V](https://github.com/ModelTC/LightX2V).
|
| 172 |
+
|
| 173 |
+
## Generate audio-video with LightX2V
|
| 174 |
+
|
| 175 |
+
### 1. Install LightX2V
|
| 176 |
+
|
| 177 |
+
Building from source gives access to the latest MiniMax-H3 integration:
|
| 178 |
+
|
| 179 |
+
```bash
|
| 180 |
+
git clone https://github.com/ModelTC/LightX2V.git
|
| 181 |
+
cd LightX2V
|
| 182 |
+
uv pip install -v . # or: pip install -v .
|
| 183 |
+
```
|
| 184 |
+
|
| 185 |
+
Follow the [LightX2V Quick Start](https://lightx2v-en.readthedocs.io/en/latest/getting_started/quickstart.html)
|
| 186 |
+
to install the optional optimized attention and quantization operators required by the
|
| 187 |
+
selected configuration.
|
| 188 |
+
|
| 189 |
+
### 2. Download the MiniMax-H3 weights
|
| 190 |
+
|
| 191 |
+
The generator weights come from the upstream
|
| 192 |
+
[MiniMaxAI/MiniMax-H3](https://huggingface.co/MiniMaxAI/MiniMax-H3) repository:
|
| 193 |
+
|
| 194 |
+
```bash
|
| 195 |
+
hf download MiniMaxAI/MiniMax-H3 --local-dir /path/to/MiniMax-H3
|
| 196 |
+
```
|
| 197 |
+
|
| 198 |
+
The LoRA in this repository rewrites text; it does not replace or include the
|
| 199 |
+
MiniMax-H3 generator weights.
|
| 200 |
+
|
| 201 |
+
### 3. Rewrite the prompt
|
| 202 |
+
|
| 203 |
+
Run this command from the prompt-rewriter repository:
|
| 204 |
+
|
| 205 |
+
```bash
|
| 206 |
+
python infer.py \
|
| 207 |
+
--prompt "A red fox walks through a snowy forest at dawn." \
|
| 208 |
+
--duration 15 \
|
| 209 |
+
--resolution 16:9 \
|
| 210 |
+
--greedy \
|
| 211 |
+
--output /tmp/h3_rewritten_prompt.txt
|
| 212 |
+
```
|
| 213 |
+
|
| 214 |
+
### 4. Generate synchronized video and audio
|
| 215 |
+
|
| 216 |
+
Run the rewritten prompt with LightX2V from the `LightX2V` repository root:
|
| 217 |
+
|
| 218 |
+
```bash
|
| 219 |
+
source scripts/base/base.sh
|
| 220 |
+
export DTYPE=BF16
|
| 221 |
+
export SENSITIVE_LAYER_DTYPE=FP32
|
| 222 |
+
|
| 223 |
+
python -m lightx2v.infer \
|
| 224 |
+
--model_cls minimax_h3 \
|
| 225 |
+
--task t2av \
|
| 226 |
+
--model_path /path/to/MiniMax-H3 \
|
| 227 |
+
--config_json configs/minimax_h3/minimax_h3_t2av.json \
|
| 228 |
+
--prompt "$(</tmp/h3_rewritten_prompt.txt)" \
|
| 229 |
+
--save_result_path save_results/minimax_h3_t2av.mp4 \
|
| 230 |
+
--seed 42
|
| 231 |
+
```
|
| 232 |
+
|
| 233 |
+
The output MP4 contains both video and synchronized stereo audio. Make sure that the
|
| 234 |
+
duration and aspect ratio in the LightX2V config match the conditions passed to the
|
| 235 |
+
prompt rewriter. Ready-to-run single-GPU, block-offload, tensor-parallel, and combined
|
| 236 |
+
TP+SP examples are available in the
|
| 237 |
+
**[LightX2V MiniMax-H3 scripts](https://github.com/ModelTC/LightX2V/tree/main/scripts/minimax_h3)**.
|
| 238 |
+
|
| 239 |
+
For lower-memory or multi-GPU inference, start from one of these configurations:
|
| 240 |
+
|
| 241 |
+
| Mode | LightX2V example |
|
| 242 |
+
|---|---|
|
| 243 |
+
| Single GPU | `configs/minimax_h3/minimax_h3_t2av.json` |
|
| 244 |
+
| Block offload | `configs/minimax_h3/minimax_h3_t2av_block_offload.json` |
|
| 245 |
+
| Sequence parallelism | `configs/minimax_h3/minimax_h3_t2av_sp.json` |
|
| 246 |
+
| Tensor parallelism | `configs/minimax_h3/minimax_h3_t2av_tp.json` |
|
| 247 |
+
| Tensor + sequence parallelism | `configs/minimax_h3/minimax_h3_t2av_tp_sp.json` |
|
| 248 |
+
|
| 249 |
+
## Qualitative comparison
|
| 250 |
+
|
| 251 |
+
The following gallery is designed to compare videos generated through
|
| 252 |
+
[LightX2V](https://github.com/ModelTC/LightX2V) with the same MiniMax-H3 checkpoint and
|
| 253 |
+
identical inference settings. Only the prompt-rewriting method should differ.
|
| 254 |
+
|
| 255 |
+
| Label | Meaning |
|
| 256 |
+
|---|---|
|
| 257 |
+
| Original Prompt (No Rewrite) | The raw user prompt is sent directly to MiniMax-H3 |
|
| 258 |
+
| MiniMax Context-IR | The raw prompt is enhanced by the official hosted Context-IR workflow |
|
| 259 |
+
| Qwen3.6-27B Base Rewriter | The same template is used with the base model and no LoRA |
|
| 260 |
+
| **H3-T2VA Context Rewriter LoRA (Ours)** | Qwen3.6-27B with this task-specific LoRA |
|
| 261 |
+
|
| 262 |
+
### Prompt 1
|
| 263 |
+
|
| 264 |
+
> **Original prompt:** TODO — paste Prompt 1 here
|
| 265 |
+
> **Conditions:** TODO — duration, aspect ratio, seed, and generation configuration
|
| 266 |
+
|
| 267 |
+
| Original Prompt (No Rewrite) | MiniMax Context-IR | Qwen3.6-27B Base Rewriter | **H3-T2VA Context Rewriter LoRA (Ours)** |
|
| 268 |
+
|---|---|---|---|
|
| 269 |
+
| <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt1/original.mp4"></video> | <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt1/minimax_context_ir.mp4"></video> | <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt1/qwen_base.mp4"></video> | <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt1/ours.mp4"></video> |
|
| 270 |
+
|
| 271 |
+
### Prompt 2
|
| 272 |
+
|
| 273 |
+
> **Original prompt:** TODO — paste Prompt 2 here
|
| 274 |
+
> **Conditions:** TODO — duration, aspect ratio, seed, and generation configuration
|
| 275 |
+
|
| 276 |
+
| Original Prompt (No Rewrite) | MiniMax Context-IR | Qwen3.6-27B Base Rewriter | **H3-T2VA Context Rewriter LoRA (Ours)** |
|
| 277 |
+
|---|---|---|---|
|
| 278 |
+
| <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt2/original.mp4"></video> | <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt2/minimax_context_ir.mp4"></video> | <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt2/qwen_base.mp4"></video> | <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt2/ours.mp4"></video> |
|
| 279 |
+
|
| 280 |
+
### Prompt 3
|
| 281 |
+
|
| 282 |
+
> **Original prompt:** TODO — paste Prompt 3 here
|
| 283 |
+
> **Conditions:** TODO — duration, aspect ratio, seed, and generation configuration
|
| 284 |
+
|
| 285 |
+
| Original Prompt (No Rewrite) | MiniMax Context-IR | Qwen3.6-27B Base Rewriter | **H3-T2VA Context Rewriter LoRA (Ours)** |
|
| 286 |
+
|---|---|---|---|
|
| 287 |
+
| <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt3/original.mp4"></video> | <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt3/minimax_context_ir.mp4"></video> | <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt3/qwen_base.mp4"></video> | <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt3/ours.mp4"></video> |
|
| 288 |
+
|
| 289 |
+
### Prompt 4
|
| 290 |
+
|
| 291 |
+
> **Original prompt:** TODO — paste Prompt 4 here
|
| 292 |
+
> **Conditions:** TODO — duration, aspect ratio, seed, and generation configuration
|
| 293 |
+
|
| 294 |
+
| Original Prompt (No Rewrite) | MiniMax Context-IR | Qwen3.6-27B Base Rewriter | **H3-T2VA Context Rewriter LoRA (Ours)** |
|
| 295 |
+
|---|---|---|---|
|
| 296 |
+
| <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt4/original.mp4"></video> | <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt4/minimax_context_ir.mp4"></video> | <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt4/qwen_base.mp4"></video> | <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt4/ours.mp4"></video> |
|
| 297 |
+
|
| 298 |
+
### Prompt 5
|
| 299 |
+
|
| 300 |
+
> **Original prompt:** TODO — paste Prompt 5 here
|
| 301 |
+
> **Conditions:** TODO — duration, aspect ratio, seed, and generation configuration
|
| 302 |
+
|
| 303 |
+
| Original Prompt (No Rewrite) | MiniMax Context-IR | Qwen3.6-27B Base Rewriter | **H3-T2VA Context Rewriter LoRA (Ours)** |
|
| 304 |
+
|---|---|---|---|
|
| 305 |
+
| <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt5/original.mp4"></video> | <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt5/minimax_context_ir.mp4"></video> | <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt5/qwen_base.mp4"></video> | <video controls src="https://huggingface.co/lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA/resolve/main/assets/examples/prompt5/ours.mp4"></video> |
|
| 306 |
+
|
| 307 |
+
Expected video paths and filenames are documented in
|
| 308 |
+
[`assets/examples/UPLOAD_LAYOUT.md`](assets/examples/UPLOAD_LAYOUT.md).
|
| 309 |
+
|
| 310 |
+
## Limitations
|
| 311 |
+
|
| 312 |
+
- This release supports text-only T2VA prompt rewriting; it does not consume images,
|
| 313 |
+
videos, or audio references.
|
| 314 |
+
- It is a learned approximation, not an open-source release or exact replica of the
|
| 315 |
+
official H3-Context-IR service.
|
| 316 |
+
- The generated rewrite may add details not explicitly present in a short prompt.
|
| 317 |
+
Review the result before generation when identity, dialogue, timing, or composition
|
| 318 |
+
must be exact.
|
| 319 |
+
- Final quality depends on both prompt rewriting and the MiniMax-H3 inference settings
|
| 320 |
+
selected in LightX2V.
|
| 321 |
+
- Use of MiniMax-H3 is governed by the license and acceptable-use terms published in
|
| 322 |
+
the [official MiniMax-H3 repository](https://huggingface.co/MiniMaxAI/MiniMax-H3).
|
| 323 |
+
|
| 324 |
+
## Acknowledgements
|
| 325 |
+
|
| 326 |
+
This project is developed by the
|
| 327 |
+
[LightX2V](https://github.com/ModelTC/LightX2V) community to make local MiniMax-H3
|
| 328 |
+
prompt rewriting and audio-video generation easier and more efficient. It is built for
|
| 329 |
+
the [MiniMax-H3](https://huggingface.co/MiniMaxAI/MiniMax-H3) audio-video generation
|
| 330 |
+
model and fine-tuned from [Qwen3.6-27B](https://huggingface.co/Qwen/Qwen3.6-27B).
|
| 331 |
+
|
| 332 |
+
If you use this adapter or the MiniMax-H3 integration, please visit and star
|
| 333 |
+
**[ModelTC/LightX2V](https://github.com/ModelTC/LightX2V)**, where inference support,
|
| 334 |
+
performance optimizations, examples, and future task updates are maintained.
|
infer.py
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Rewrite one T2VA prompt with the MiniMax-H3 Prompt Rewriter LoRA."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
import argparse
|
| 7 |
+
import json
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
|
| 10 |
+
import torch
|
| 11 |
+
import transformers
|
| 12 |
+
from transformers import AutoTokenizer, set_seed
|
| 13 |
+
|
| 14 |
+
from prompt_template import build_messages
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
DEFAULT_BASE_MODEL = "Qwen/Qwen3.6-27B"
|
| 18 |
+
DEFAULT_ADAPTER = "lightx2v/MiniMax-H3-Prompt-Rewriter-LoRA"
|
| 19 |
+
RESOLUTIONS = ("21:9", "16:9", "4:3", "1:1", "3:4", "9:16")
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def get_model_class():
|
| 23 |
+
model_class = getattr(transformers, "AutoModelForImageTextToText", None)
|
| 24 |
+
if model_class is None:
|
| 25 |
+
model_class = getattr(transformers, "AutoModelForVision2Seq", None)
|
| 26 |
+
if model_class is None:
|
| 27 |
+
raise RuntimeError(
|
| 28 |
+
"A recent Transformers version with AutoModelForImageTextToText "
|
| 29 |
+
"support is required. Install the packages in requirements.txt."
|
| 30 |
+
)
|
| 31 |
+
return model_class
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def parse_args() -> argparse.Namespace:
|
| 35 |
+
parser = argparse.ArgumentParser(description=__doc__)
|
| 36 |
+
parser.add_argument("--prompt", required=True, help="Original text prompt to rewrite.")
|
| 37 |
+
parser.add_argument("--duration", type=int, choices=range(4, 16), default=10, metavar="4..15")
|
| 38 |
+
parser.add_argument("--resolution", choices=RESOLUTIONS, default="16:9", help="Target aspect ratio.")
|
| 39 |
+
parser.add_argument("--base-model", default=DEFAULT_BASE_MODEL, help="HF model ID or local base-model path.")
|
| 40 |
+
parser.add_argument("--adapter", default=DEFAULT_ADAPTER, help="HF model ID or local PEFT adapter path.")
|
| 41 |
+
parser.add_argument(
|
| 42 |
+
"--base-only",
|
| 43 |
+
action="store_true",
|
| 44 |
+
help="Skip the LoRA and run the Qwen base-model baseline.",
|
| 45 |
+
)
|
| 46 |
+
parser.add_argument("--max-new-tokens", type=int, default=2048)
|
| 47 |
+
parser.add_argument("--dtype", choices=("bfloat16", "float16", "float32"), default="bfloat16")
|
| 48 |
+
parser.add_argument("--attn-implementation", choices=("sdpa", "flash_attention_2", "eager"), default="sdpa")
|
| 49 |
+
parser.add_argument("--temperature", type=float, default=0.7)
|
| 50 |
+
parser.add_argument("--top-p", type=float, default=0.8)
|
| 51 |
+
parser.add_argument("--top-k", type=int, default=20)
|
| 52 |
+
parser.add_argument("--repetition-penalty", type=float, default=1.05)
|
| 53 |
+
parser.add_argument("--greedy", action="store_true", help="Use deterministic greedy decoding.")
|
| 54 |
+
parser.add_argument("--seed", type=int, default=42)
|
| 55 |
+
parser.add_argument(
|
| 56 |
+
"--output",
|
| 57 |
+
type=Path,
|
| 58 |
+
help="Optional output path. A .json file stores conditions and output; other suffixes store plain text.",
|
| 59 |
+
)
|
| 60 |
+
return parser.parse_args()
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def input_device(model: torch.nn.Module) -> torch.device:
|
| 64 |
+
"""Return the embedding device, including when Accelerate shards the model."""
|
| 65 |
+
embeddings = model.get_input_embeddings()
|
| 66 |
+
if embeddings is not None and hasattr(embeddings, "weight"):
|
| 67 |
+
return embeddings.weight.device
|
| 68 |
+
return next(model.parameters()).device
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def main() -> None:
|
| 72 |
+
args = parse_args()
|
| 73 |
+
set_seed(args.seed)
|
| 74 |
+
dtype = getattr(torch, args.dtype)
|
| 75 |
+
|
| 76 |
+
tokenizer = AutoTokenizer.from_pretrained(args.base_model, trust_remote_code=True)
|
| 77 |
+
if tokenizer.pad_token_id is None:
|
| 78 |
+
tokenizer.pad_token = tokenizer.eos_token
|
| 79 |
+
|
| 80 |
+
model = get_model_class().from_pretrained(
|
| 81 |
+
args.base_model,
|
| 82 |
+
torch_dtype=dtype,
|
| 83 |
+
device_map="auto",
|
| 84 |
+
low_cpu_mem_usage=True,
|
| 85 |
+
trust_remote_code=True,
|
| 86 |
+
attn_implementation=args.attn_implementation,
|
| 87 |
+
)
|
| 88 |
+
|
| 89 |
+
if not args.base_only:
|
| 90 |
+
from peft import PeftModel
|
| 91 |
+
|
| 92 |
+
model = PeftModel.from_pretrained(model, args.adapter)
|
| 93 |
+
model.eval()
|
| 94 |
+
|
| 95 |
+
rendered = tokenizer.apply_chat_template(
|
| 96 |
+
build_messages(args.prompt, args.resolution, args.duration),
|
| 97 |
+
tokenize=False,
|
| 98 |
+
add_generation_prompt=True,
|
| 99 |
+
enable_thinking=False,
|
| 100 |
+
)
|
| 101 |
+
inputs = tokenizer(rendered, return_tensors="pt", add_special_tokens=False)
|
| 102 |
+
device = input_device(model)
|
| 103 |
+
inputs = {name: tensor.to(device) for name, tensor in inputs.items()}
|
| 104 |
+
|
| 105 |
+
generation_kwargs = {
|
| 106 |
+
"max_new_tokens": args.max_new_tokens,
|
| 107 |
+
"do_sample": not args.greedy,
|
| 108 |
+
"repetition_penalty": args.repetition_penalty,
|
| 109 |
+
"pad_token_id": tokenizer.pad_token_id,
|
| 110 |
+
"eos_token_id": tokenizer.eos_token_id,
|
| 111 |
+
}
|
| 112 |
+
if not args.greedy:
|
| 113 |
+
generation_kwargs.update(
|
| 114 |
+
temperature=args.temperature,
|
| 115 |
+
top_p=args.top_p,
|
| 116 |
+
top_k=args.top_k,
|
| 117 |
+
)
|
| 118 |
+
|
| 119 |
+
with torch.inference_mode():
|
| 120 |
+
generated = model.generate(**inputs, **generation_kwargs)
|
| 121 |
+
new_tokens = generated[:, inputs["input_ids"].shape[1] :]
|
| 122 |
+
rewritten_prompt = tokenizer.batch_decode(new_tokens, skip_special_tokens=True)[0].strip()
|
| 123 |
+
|
| 124 |
+
if args.output is not None:
|
| 125 |
+
args.output.parent.mkdir(parents=True, exist_ok=True)
|
| 126 |
+
if args.output.suffix.lower() == ".json":
|
| 127 |
+
record = {
|
| 128 |
+
"prompt": args.prompt.strip(),
|
| 129 |
+
"resolution": args.resolution,
|
| 130 |
+
"duration": args.duration,
|
| 131 |
+
"rewritten_prompt": rewritten_prompt,
|
| 132 |
+
"base_model": args.base_model,
|
| 133 |
+
"adapter": None if args.base_only else args.adapter,
|
| 134 |
+
}
|
| 135 |
+
args.output.write_text(json.dumps(record, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
| 136 |
+
else:
|
| 137 |
+
args.output.write_text(rewritten_prompt + "\n", encoding="utf-8")
|
| 138 |
+
|
| 139 |
+
print(rewritten_prompt)
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
if __name__ == "__main__":
|
| 143 |
+
main()
|
prompt_template.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Prompt template shared by MiniMax-H3 T2VA prompt-rewriter inference."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
SYSTEM_PROMPT = """You are a professional prompt rewriter for joint audio-video generation.
|
| 7 |
+
Rewrite the user's original prompt into one coherent, production-ready multimodal description for the requested output aspect ratio and duration.
|
| 8 |
+
|
| 9 |
+
Return only these three fields, in this exact order:
|
| 10 |
+
integrated_multimodal_description: ...
|
| 11 |
+
overall_soundscape: ...
|
| 12 |
+
non_diegetic_music: ...
|
| 13 |
+
|
| 14 |
+
Requirements:
|
| 15 |
+
- Expand the visual narrative into clearly numbered shots such as [Shot 1], [Shot 2], and include timestamps for cuts after the first shot when useful.
|
| 16 |
+
- Make the number, timing, and pacing of shots appropriate for the requested duration.
|
| 17 |
+
- Compose the scene for the requested aspect ratio.
|
| 18 |
+
- Preserve the user's intent while adding concrete subjects, appearance, environment, lighting, composition, camera movement, physical motion, and temporal continuity.
|
| 19 |
+
- Keep characters, objects, wardrobe, locations, and spatial relationships consistent across shots.
|
| 20 |
+
- Describe synchronized diegetic audio in overall_soundscape and external score in non_diegetic_music.
|
| 21 |
+
- Do not add explanations, Markdown fences, safety commentary, or fields other than the three requested fields."""
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def build_messages(prompt: str, resolution: str, duration: int) -> list[dict[str, str]]:
|
| 25 |
+
"""Build the chat messages used during LoRA training and inference."""
|
| 26 |
+
prompt = prompt.strip()
|
| 27 |
+
if not prompt:
|
| 28 |
+
raise ValueError("prompt must not be empty")
|
| 29 |
+
|
| 30 |
+
return [
|
| 31 |
+
{"role": "system", "content": SYSTEM_PROMPT},
|
| 32 |
+
{
|
| 33 |
+
"role": "user",
|
| 34 |
+
"content": (
|
| 35 |
+
f"resolution: {resolution}\n"
|
| 36 |
+
f"duration: {duration}s\n"
|
| 37 |
+
f"original_prompt: {prompt}"
|
| 38 |
+
),
|
| 39 |
+
},
|
| 40 |
+
]
|
requirements.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
torch>=2.6
|
| 2 |
+
transformers>=4.57.1
|
| 3 |
+
accelerate>=1.10
|
| 4 |
+
peft>=0.17
|
| 5 |
+
safetensors>=0.5
|