# MiniMax-H3 一键启动与工作流手册

> 机器：鲲鹏920 + Ascend 910B3 ×8（单卡 64GB HBM）/ 1TB RAM
> 模型：`/home/models/MiniMax-H3`（本地离线，diffusers 0.40 内置 `MiniMaxH3ModularPipeline`）
> 环境：conda `minimax_h3`（python 3.10 + torch 2.9.1 + torch_npu 2.9.1 + CANN 9.0.0）
> 本手册讲**怎么用**；部署踩坑原理见 `MiniMax-H3-部署指南.md`。

---

## 0. 30 秒上手

```bash
cd /root/cys
./h3.sh up                                   # ① 一键启动常驻服务（自动配 CANN/conda/离线，后台预热模型）
#  → 浏览器打开  http://192.168.1.103:7860   （本机 http://127.0.0.1:7860）
#  在网页里选工作流 → 填 prompt / 拖图片 → 点「生成视频」→ 看进度 → 直接播放下载

./h3.sh t2v "整段 prompt" -d 5 -s 50          # ② 或者纯命令行，一条命令出片
./h3.sh status                                # ③ 看服务/引擎/显存/队列
./h3.sh down                                  # ④ 收工（释放 8 卡显存）
```

服务是**常驻**的：模型只加载一次（约 30~60 秒），之后每个任务不再重复加载；
用 `setsid` 脱离终端，**SSH 断开也不会被杀**（此前批量任务就是这么死的）。

---

## 1. 三种启动方式

| 方式 | 命令 | 适用 |
|---|---|---|
| **Web UI（推荐）** | `./h3.sh up` → 浏览器 `http://<机器IP>:7860` | 日常出片：拖图、写 prompt、看进度、播放下载、成片库 |
| **CLI** | `./h3.sh t2v/i2v/fl2v/l2v/ref/batch ...` | 脚本化、批量、远程 ssh 一把梭；服务没起会自动拉起 |
| **老的一次性脚本** | `./run_h3.sh --workflow t2va --prompt "..."` | 保持原样可用；每次冷启动重新加载 134GB，适合"跑完就释放"的场合 |

配套运维命令：

```bash
./h3.sh status        # 服务 + 引擎 + 分区 + 每卡显存 + 队列 + 磁盘
./h3.sh jobs          # 任务列表（含进度百分比）
./h3.sh watch <id>    # 前台跟踪某个任务
./h3.sh cancel <id>   # 取消（在当前去噪步结束后生效）
./h3.sh ls            # 成片库
./h3.sh logs          # tail -f 服务日志
./h3.sh doctor        # 环境体检（CANN/conda/NPU/模型/磁盘/ffmpeg/字体/服务）
./h3.sh dry           # 干跑服务：不加载模型，用测试图案验证 UI 与后处理链
./h3.sh selftest      # 引擎自检：真加载模型，最小代价跑通三条分支
./h3.sh restart / down
```

---

## 2. 五种输入工作流

模型内部只有**三条分支**，由输入自动决定（`MiniMaxH3AutoDenoiseStep.select_block`）：

```
有 references        → ref2va  （用 transformer_ref/ 分区）
有 image / last_image → fl2va  （用 transformer/ 分区）
只有文本              → t2va   （用 transformer/ 分区）
```

h3studio 把它拆成 5 个对用户友好的模式 + 1 个批量模式：

| # | 模式 | 你给什么 | 内部分支 | CLI |
|---|---|---|---|---|
| A | **文生视频** `t2v` | 只有文字 | t2va | `./h3.sh t2v "prompt"` |
| B | **图生视频** `i2v` | 首帧图 + 文字 | fl2va | `./h3.sh i2v first.png "prompt"` |
| C | **首尾帧** `fl2v` | 首帧 + 尾帧 + 文字 | fl2va | `./h3.sh fl2v "prompt" --first first.png --last last.png` |
| D | **尾帧倒推** `l2v` | 只有尾帧 + 文字 | fl2va | `./h3.sh l2v "prompt" --last last.png` |
| E | **全参考** `ref` | 图/视频/音频素材 + 文字 | ref2va | `./h3.sh ref "prompt" -m a.png -m b.mp4` |
| F | **批量分镜** `batch` | 多章 prompt（可各带首帧） | 按需 | `./h3.sh batch --dir prompts/hongjun --assemble` |

所有模式都**同时生成视频 + 立体声音轨**（32kHz，对白/环境声/配乐都按 prompt 走），
最后由 ffmpeg 合成一个带声音的 mp4。

### A. 文生视频（t2v）

```bash
./h3.sh t2v "$(cat prompts/my.txt)" -d 5 -s 50 --seed 7 --aspect 16:9 --name my_clip
```
Web UI：选「文生视频」→ 只填 prompt（不需要图）→ 生成。

prompt 结构（官方三字段，**必须**）：
```text
integrated_multimodal_description: [Shot 1] Cinematic, ...  [Shot 2] At 00:04.000, the camera cuts to ...

overall_soundscape: 环境声/动作声/非语言人声，1~4 句。

non_diegetic_music: 观众才听得到的配乐，写配器/速度/力度，1~3 句；没有就写 N/A。
```
t2v **不需要**指令行。

### B. 图生视频（i2v，首帧）

```bash
./h3.sh i2v /path/first.png "$(cat prompts/my.txt)" -d 8 -s 50
```
Web UI：选「图生视频」→ 拖一张图进「首帧图」→ 填 prompt。

* 画布默认**跟随首帧比例**；图片会被**拉伸**到目标画布（不是裁剪），所以最好先自己裁好比例。
* prompt **第一行必须是官方指令行**（UI 的「结构化编辑 → 自动加官方指令行」会替你写）：
  ```text
  For the target video, at 0.00 seconds into the target video, <Picture 1> (from [Shot 1]) is fully referenced.
  ```
* 描述顺序建议：**首帧锚点（风格/主体/构图/场景）→ 动作起始 → 连续发展 → 结果或反应**；
  人物身份、服装、颜色、关键道具、空间关系要与首帧保持一致。

### C. 首尾帧（fl2v）

```bash
./h3.sh fl2v "prompt" --first first.png --last last.png -d 6 -s 50
```
* 官方建议**单镜头**，让模型从首帧连续过渡到尾帧；多镜头只在明确要求时用。
* 尾帧必须由最后一个 `[Shot N]` 在视频结尾达到。
* 指令行要点明两张图各自对齐的时间：
  ```text
  How the reference pictures align with the target video — Picture 1 (from Shot 1) aligns with the
  0.00-second mark of the target video; Picture 2 (from Shot N) aligns with the S.SS-second mark of the target video.
  ```
  `S.SS` = 实际时长（两位小数），`N` = 最后一个镜头号。
* 描述顺序：**首帧状态 → 可观察的中间变化 → 差异逐步缩小 → 尾帧状态**。
* 注意：首帧是**拉伸**到画布，尾帧是**cover 裁剪**到画布。

### D. 尾帧倒推（l2v）

```bash
./h3.sh l2v "prompt" --last last.png -d 6
```
只给尾帧：模型倒推一个合理的开头，最后落在你给的画面上。
结构：**合理的前置状态 → 明确的动作与转场路径 → 末镜逐步收敛 → 落在尾帧**。
指令行：
```text
How the reference pictures align with the target video — <Picture 1> (from [Shot N]) aligns with the S.SS-second mark of the target video.
```

### E. 全参考（ref）

用**多份素材**共同约束生成：人物/风格/场景图、动作参考视频、音色或配乐参考音频。

```bash
./h3.sh ref "$(cat prompts/my_ref.txt)" \
    -m character.png -m style.png -m motion.mp4 -m voice.wav \
    -d 10 -s 50 --name ref_demo
```
Web UI：选「全参考」→ 拖多个文件（也可写服务器路径）→ 填六段式 prompt。

硬约束（来自 diffusers `MiniMaxH3Blocks` 文档）：

| 素材 | 上限 | 说明 |
|---|---|---|
| 图片 `MiniMaxH3ImageReference` | ≤ 9 | 不绑定输出几何，内部按短边 2048 编码 |
| 视频 `MiniMaxH3VideoReference` | ≤ 3 | 自带 fps，**音轨也会一起被参考**；2~15s |
| 音频 `MiniMaxH3AudioReference` | ≤ 3 | **不能是唯一素材**，必须配至少一张图或一段视频 |
| 合计 | ≤ 12 | |

* **顺序有意义**：第 1 个素材就是 `<Picture 1>`/`<Video 1>`/`<Audio 1>`，顺序不同 = 不同的请求。
* prompt 用**六段结构**（顺序固定）：
  `subject_definitions` / `summary` / `retention_analysis` / `detailed_description` /
  `overall_soundscape` / `non_diegetic_music`；
  `summary` 以方括号任务类型开头，如 `[video editing + audio reuse + reference generation]`；
  `retention_analysis` 逐个标签写保留状态（`fully_preserved` / `partially_copy` / `reference` / `transferred`）。
* 本机**没装 PyAV**，视频/音频素材自动走 ffmpeg 兜底解码（帧率与音轨采样率都会带上，不会静默变速）。
* ref 用的是 `transformer_ref/` 分区（另外 62GB）：默认与 base 分区**共存**（8 卡各多占约 8GB）；
  HBM 不够时自动降级为 **swap**（用之前先卸掉另一个分区，约 20~60 秒切换）。
  可用 `H3_REF_COEXIST=0` 强制 swap。

### F. 批量分镜（batch）+ 拼接成片

做多章节项目（例如四章成片）用这个。三种给法：

```bash
# ① 一个目录 = 一个项目：每个 .txt 是一章，文件名排序即章节顺序
./h3.sh batch --dir prompts/hongjun --name 小红军 -d 8 -s 50 --assemble --title "小红军的成长历程"

# ② 章节字幕另给一个目录（<章节名>.txt），自动按各章时长推算时间轴叠到成片上
./h3.sh batch --dir prompts/hongjun --caption-dir overlay/hj_subs --assemble --title "..."

# ③ 显式 manifest（每章可单独设时长/步数/首帧图/字幕）
./h3.sh batch project.json
```

`project.json`：
```json
{
  "name": "小红军",
  "title": "小红军的成长历程",
  "chapters": [
    {"name": "ch1_changzheng", "prompt_file": "/root/cys/prompts/hongjun/ch1_changzheng.txt",
     "duration": 8, "steps": 50,
     "subtitle": [{"text": "1934年·出发", "start": 0.8, "end": 4.0}]},
    {"name": "ch2_kangri", "prompt_file": ".../ch2_kangri.txt", "image": "/abs/first_ch2.png"}
  ],
  "subtitles": [{"text": "……", "start": 0.8, "end": 4.0, "style": "sub"}]
}
```

特性：
* 章节**串行**执行（8 卡都被一个任务占满，不存在并行加速）。
* **断点续跑**：输出文件已存在的章节自动跳过（`--force` 强制重跑）。
  例如 2026-10-03 那次批量在 ch3 被中断，直接重跑同一条命令即可从 ch3 继续：
  ```bash
  ./h3.sh batch --dir prompts/hongjun --name hj -d 8 -s 50 --assemble
  ```
* `--assemble` 会无损拼接各章 + 叠标题/字幕（中文用 Noto 宋体/黑体），一次出成片。
* 单独拼接/叠字也可以事后做：
  ```bash
  ./h3.sh assemble a.mp4 b.mp4 c.mp4 -o 成片.mp4 --title "标题" --subs subs.json
  ```

---

## 3. prompt 写法速查（官方规则）

规则原文在模型目录里：
`/home/models/MiniMax-H3/docs/VIDEO_PROMPT_WRITING_GUIDE_base_en.md`（t2v/图生类）
`/home/models/MiniMax-H3/docs/VIDEO_PROMPT_WRITING_GUIDE_ref_en.md`（ref）

| 项 | 规则 |
|---|---|
| 三字段 | `integrated_multimodal_description` / `overall_soundscape` / `non_diegetic_music`，字段名后接冒号，字段之间空一行 |
| 风格 | `[Shot 1]` 开头就写风格：`Cinematic` `live-action` `2D-animated` `3D CG` `claymation` `watercolor` `vintage film` |
| 分镜 | 第一个镜头 **不写时间戳**；后续 `[Shot N] At 00:SS.mmm, the camera cuts to …`，时间**严格递增**且落在时长内 |
| 切镜用语 | `the camera cuts to` / `the shot cuts to` / `the shot transitions to` / `the shot changes to` / `the shot switches to`；只在用户明确要求时用 dissolve/fade/wipe |
| 运镜 | **类型 + 幅度 + 速度**，写成自然英文动作：`The camera pushes in with small amplitude at slow speed toward …`；中幅/常速通常省略 |
| 运镜类型 | Zoom In/Out、Push In/Pull Out、Pan Left/Right、Truck Left/Right、Tilt Up/Down、Pedestal Up/Down、Arc Shot、Tracking Shot、Static Shot、Shake Slightly/Strongly、POV、Roll Clockwise/Counterclockwise |
| 幅度/速度 | `with small amplitude` / `with large amplitude`；`at slow speed` / `at fast speed` |
| 说话人 | 稳定 ID `(S1)` `(S2)`，多人齐说 `(S1,S2)`；跨镜保持同一 ID；不出声的角色不给 ID |
| 对白 | 身份/语气/动作写在 `<d>` **外面**，`<d>` 里只放语言标签 + 原话：`says: <d>[Chinese] 打过长江去。</d>`，**原文照录不翻译** |
| 旁白 | 固定短语 `says in an off-screen voiceover:`，且紧随说明 `while his lips remain completely closed` |
| 跨镜同一句 | 在两段连接处写 `<scenetrans>`，并明确 `continues seamlessly across the cut`；被视频结尾截断用 `<cutoff>` |
| 画面内文字 | 招牌/横幅/字幕/霓虹等**看得见的文字**用英文双引号原样包住：`a red neon sign reading "营业中"` |
| 环境声 | 1~4 句，只写环境声/动作声/非语言人声；**不要重复对白与配乐**；要求全片静音才写 `N/A` |
| 配乐 | 1~3 句，写配器/速度/节奏/力度变化；**不要写抽象情绪词**（epic/emotional/tense…）；没有就 `N/A` |

### prompt 体检（写完先查一遍）

```bash
./h3.sh check prompts/my.txt --mode i2v -d 8
```
会按上表逐条检查：三字段是否齐全、图生类指令行是否存在且在第一行、时间戳是否递增且不超时长、
运镜是否缺三要素、`<d>`/`</d>` 是否配对、旁白是否写了闭嘴、画面内文字是否加引号、
声景/配乐句数与禁词……Web UI 里点「体检」是同一个接口（`POST /api/check`）。

### 模板与已有 prompt 库

```bash
./h3.sh templates          # blank / guofeng / cinematic / doc / product / ref
./h3.sh prompt guofeng     # 打印骨架，自己填空
```
Web UI 的「模板」下拉是同一批；「已有 prompt 库」下拉直接读 `/root/cys/prompts/**.txt`
（当前含仙剑、曹沐然、红军四章）。

---

## 4. 参数与硬约束

| 项 | 取值 | 说明 |
|---|---|---|
| 时长 | **5 ~ 15 秒** | 模型属性 `min_duration=5.0 / max_duration=15.0` |
| 帧数 | **17n+5**，实际 **[124, 345]** | 24fps 固定；5s→124 帧(5.17s)，8s→192 帧，14s→340 帧，15s→345 帧(14.375s，因为 17×21+5=362 越界)。你给秒数，脚本自动向上吸附 |
| 画布 | 短边 **768**，面积上限 **768×1344=1,032,192 px**，两边都是 **32 的倍数** | 比例范围 **1:4 ~ 4:1**；不给 `--height/--width` 时：文生视频按 16:9 附近，图生跟随首帧比例 |
| 步数 | 默认 **50** | 4 步只够冒烟测试；出片别低于 30。注意官方去噪循环实际迭代 **steps-1** 次（35 步 → 34 次，见历史日志），所以进度条显示 `x/49` 是正常的 |
| 种子 | 默认 0 | 同 seed + 同参数 = 可复现（`generator` 在 CPU 上） |
| **negative prompt** | ❌ 不支持 | 权重是 **CFG 蒸馏**过的，guidance 已烧进权重 |
| **guidance_scale** | ❌ 不支持 | 同上，每步只跑一次前向 |
| 精度 | bf16（默认） | fp16/fp32 可选，本机按 bf16 验证 |
| 音频 | 32kHz 立体声，自动生成 | `--no-audio` 可只出画面 |
| fps | 24 固定 | 改不了 |

---

## 5. 耗时与显存（实测）

8 卡分片（`device_map="balanced"`）、768p、bf16：

| 规模 | 帧数 | 每步 | 50 步全流程 | 输出 |
|---|---|---|---|---|
| 5 秒 | 124 | ~28 s | **~24 分钟**（实测 1442s） | ~3MB mp4 + 0.7MB wav |
| 7.3 秒 | 175 | ~31 s | **~26 分钟**（实测 1567s） | ~4.4MB mp4 + 0.9MB wav |
| 14.4 秒 | 345 | **~173 s** | 34 步实测 **100 分钟**（6027s） | ~4.3MB mp4 + 1.8MB wav |

* **首步特别慢**（算子编译，实测第一步 174s vs 稳态 173s/步在 345 帧场景；5 秒场景首步约 3 分钟）。
  编译缓存写在 `h3_outputs/.studio/kernel_meta`，服务固定在那里启动，可跨重启复用。
* 模型加载：`text_encoder` 16s + `transformer` 12s + 其余 5s ≈ **30~60 秒**；常驻服务只付一次。
* 显存：8 卡合计 **134GB**（npu:0 约 26GB，其余约 17.5GB，npu:7 约 3.6GB），每卡余量 38~60GB。
  再加 `transformer_ref` 约每卡 +8GB。
* **VAE 解码绝对不能放 CPU**：768p/5s 的 latent 在 CPU 上解码实测 **1648 秒（27.5 分钟）**。
* `offload` 模式（权重留 CPU RAM 逐层流式送单卡）只在显存紧张时用，明显更慢。

经验换算：**要出 N 段 5 秒片子，按每段 25 分钟估**；14 秒长镜头按每段 100 分钟估。

---

## 6. 出片后处理链（默认全开）

> ⚠️ **本仓库 diffusers 格式权重的 VAE 解码输出是【负片】**（色彩+亮度反相）。
> 直出画面"像胶片底片"——皮肤青蓝、仙山惨白、天空墨黑。
> 证据与排查见 `MiniMax-H3-部署指南.md` 第七节第 7 条：对输出帧做 `255-x` 后画面完全正确；
> 色条往返测试查不出来，因为 encode/decode 带同一个反相、往返互相抵消。

固化链路（`h3studio/postprocess.py`）：

```
1. negate          255-x，负片 → 正片。**三态：auto(默认)/yes/no**
                   ⚠️ 2026-10-04 实测：raw 极性**不是常数**！旧链路（cwd=OUTDIR 的算子缓存）
                   raw 是负片（亮度均值 ~64），h3studio 服务（cwd=.studio 的算子缓存）raw
                   是正片（亮度 ~120-130）。写死 negate 必然有一半运行是反的。
                   auto = 按直出亮度均值判据（<95 视为负片才反相，阈值 H3_NEGATE_LUM），
                   判定结果写进任务日志；CLI `--negate yes/no`、UI「极性修正」下拉可强制
2. fix_artifacts   修通道削顶伪影：负片里被削到 0 的通道，反相后变成高饱和纯蓝/品红斑块
                   三道判据（2026-10-03 加固版，`postprocess.artifact_color_mask`）：
                     ① 颜色：B>60 且 B-max(R,G)>30 且 B/max(R,G)>1.8（并品红/紫两式）
                     ② 削顶物理特征：min 通道 <45 且 max 通道 >190
                        —— 伪影是"一通道顶到极亮、其余被压碎"；自然深蓝天空/雪影/鲜艳蓝天
                           三通道成比例（如 30,50,130 / 40,90,230），过不了这道闸
                     ③ 连通块 ≤20000px（整片天空这类大区域一律不动）
                   晕边只在①命中区域的膨胀邻域内清理；毛边（1~2px 高饱和细边）另加
                   "与 5×5 局部中值偏差 >30" 的离群闸。修法：最近邻填充 + 高斯羽化
                   ⚠️ 为什么加固：旧判据（只有①）在"雪地+深蓝天空"这类自然内容上会
                      误填 12.6% 像素（天空出现多边形填充痕迹）；加固后同类内容 0 误伤，
                      合成伪影块/毛边仍 100% 命中（7 组合成用例全过）。
                      若你的片子是水墨淡彩（伪影即高饱和斑块），也可用环境变量收紧/放宽：
                      H3_FIX_CRUSH / H3_FIX_SAT / H3_FIX_BLOB
3. grade           eq=brightness=0.06:contrast=1.18:saturation=1.25:gamma=1.09
                   （补偿 VAE 对饱和色的固有洗白：色条实测 青(0,1,1)→(0.43,0.91,0.97)、纯白→(0.84,0.92,0.93)）
4. title/subtitle  drawtext + textfile（中文 Noto 宋体标题 / 黑体章节字 / 宋体对白）
5. mux audio       scipy 写 wav → ffmpeg aac 192k
6. color tags      显式写死 -color_range tv -colorspace/primaries/trc bt709，避免播放器按错误值域解释
```

关某一项：`--no-negate` / `--no-fix` / `--no-grade` / `--no-audio`（UI 里是四个勾选框）。
想看模型直出（negate 之前）长什么样、或事后对比修复效果：加 `--keep-raw`，
会额外存一份 `<名字>_raw.mp4`，之后可用 `./h3.sh post <raw> --no-fix ...` 任意组合重跑。

**不想重新推理、只想改后处理**（省 25 分钟）：
```bash
./h3.sh post /path/h3_xxx.mp4 -o /path/h3_xxx_v2.mp4 --no-fix --sub "新字幕" --sub-start 1 --sub-end 4
```
它会读同名 `.wav` 当音轨，重跑 negate/伪影/调色/叠字/合成。

---

## 7. 服务运维

```bash
./h3.sh up                     # 启动 + 预热 base 分区（t2v/图生共用）
./h3.sh up --preload base,ref  # 两个分区都预热（ref2va 立即可用，每卡多占 ~8GB）
./h3.sh up --no-warm           # 只起服务，等第一个任务再加载
./h3.sh down / restart / status / logs
```

| 事项 | 说明 |
|---|---|
| 端口 | 默认 `7860`（`H3_PORT=xxxx ./h3.sh up`）；监听 `0.0.0.0`（`H3_HOST=127.0.0.1` 只本机） |
| 进程 | `setsid nohup`，PID 写 `h3_outputs/.studio/service.pid`；日志 `h3_logs/service.log`；每任务日志 `h3_outputs/.studio/jobs/<id>/job.log` |
| 任务表 | `h3_outputs/.studio/jobs/jobs.json`（重启后历史仍在；重启时"运行中"的任务会被标记为中断，需重新提交） |
| 队列 | **串行**：8 卡被单任务占满，多任务排队执行（FIFO） |
| 取消 | `./h3.sh cancel <id>` 或 UI 的「取消」；在**当前去噪步结束后**生效（一步最长 3 分钟，别以为卡死） |
| 显存释放 | UI「引擎」卡片 → 卸载分区；或 `curl -XPOST localhost:7860/api/engine/unload` |
| 预热 | UI「预加载 base / ref」，或 `curl -XPOST localhost:7860/api/engine/warm -d '{"partitions":["base","ref"]}'` |
| 输出 | 一律写大盘 `H3_OUTDIR`（默认 `/run/media/root/de00b5bd-…/h3_outputs`，3.2T 空闲）；**根分区只剩 ~30G，别往那儿写** |
| 开机自启 | 两种方式二选一：① `./h3.sh up`（手动/脚本）；② systemd：`cp h3studio/deploy/h3studio.service /etc/systemd/system/ && systemctl daemon-reload && systemctl enable --now h3studio`，日志 `journalctl -u h3studio -f`。用了 systemd 就**不要**再 `./h3.sh up`（会抢端口） |

---

## 8. REST API 速查

纯标准库实现，无第三方依赖（这台机器 HF 不通、只有 pypi 镜像，装 gradio/fastapi 没必要也有风险）。

| 方法 | 路径 | 用途 |
|---|---|---|
| GET | `/` | Web UI |
| GET | `/api/status` | 服务 + 引擎 + 每卡显存 + 队列 + 磁盘 |
| GET | `/api/config` | UI 需要的默认值/模板/运镜表/比例/prompt 预设 |
| POST | `/api/check` | prompt 体检 `{prompt, mode, duration, n_refs}` |
| POST | `/api/jobs` | 提交任务（素材用 base64 内联，或给服务器绝对路径） |
| GET | `/api/jobs` / `/api/jobs/<id>` | 列表 / 详情（含进度与日志） |
| POST | `/api/jobs/<id>/cancel` | 取消 |
| DELETE | `/api/jobs/<id>` | 删记录 |
| POST | `/api/engine/warm` | 预加载分区 `{"partitions":["base","ref"]}` |
| POST | `/api/engine/unload` | 卸载分区释放显存 |
| POST | `/api/post` | 对已有 mp4 重跑后处理链 |
| POST | `/api/assemble` | 拼接 + 叠字 |
| GET | `/api/outputs` | 成片库（含 ffprobe 信息） |
| GET | `/files/<name>` | 下载/播放（**支持 Range**，网页里可拖进度条） |
| GET | `/thumbs/<name>.jpg` | 缩略图（ffmpeg 生成并缓存） |

提交示例：
```bash
curl -s localhost:7860/api/jobs -H 'Content-Type: application/json' -d '{
  "mode":"i2v","name":"demo","prompt":"...三字段 prompt...",
  "images":{"first":{"name":"a.png","data":"<base64>"}} ,
  "params":{"duration":8,"steps":50,"seed":3,"aspect":"auto"},
  "post":{"negate":true,"grade":true,"fix_artifacts":true,"audio":true}}'
```

---

## 9. 文件清单（新增部分）

```
/root/cys/h3.sh                     一键入口（配环境 + 启服务 + 转发 CLI）
/root/cys/h3studio/
├── engine.py                       常驻推理引擎（单 pipeline 三分支 / 分区管理 / 进度钩子 / 取消）
├── service.py                      HTTP 服务 + 任务队列 + REST + 静态文件（纯标准库）
├── cli.py                          命令行客户端（t2v/i2v/fl2v/l2v/ref/batch/jobs/ls/post/check…）
├── postprocess.py                  后处理链（negate/伪影/调色/叠字/合成/拼接/缩略图）
├── promptkit.py                    prompt 模板 + 组装 + 体检（官方规则实现）
├── h3meta.py                       模型常量（帧数网格/画布/上限/分区表）
├── h3common.py                     路径/默认值/任务存储
├── selftest.py                     引擎自检（真加载模型跑通三条分支）
├── test_api.py                     服务 API 干跑联调（21 个用例）
├── deploy/h3studio.service         可选的 systemd 开机自启单元
└── webui/index.html                Web UI（单文件，无 CDN）
/root/cys/minimax_h3_fact_sheet.md  diffusers API 事实速查（workflow 表 / __call__ 参数 /
                                    references 上限 / 常量 / 离线边界），与本机 0.40 源码核对过
/root/cys/prompts/hongjun/manifest.json
                                    小红军四章批量任务（ch1/ch2 已存在自动跳过，断点续跑 ch3）
```

老文件保持不变、仍然可用：`run_h3.sh`、`start_minimax_h3.py`、`fix_artifacts.py`、
`overlay/*.sh`、`prompts/**`、`MiniMax-H3-部署指南.md`。

---

## 10. 故障排查

| 现象 | 原因 / 处理 |
|---|---|
| `libhccl.so: cannot open shared object file` | 没 source CANN。用 `./h3.sh`（它会 source），或手动 `source /usr/local/Ascend/ascend-toolkit/set_env.sh` |
| `torch.npu.is_available()` 是 False | ①没 source CANN；②在 DSH 沙箱里（`/dev` 被空 tmpfs 遮住）→ 用宿主机 shell，或 `nsenter --mount=/proc/1/ns/mnt -- <命令>` |
| 没有 `MiniMaxH3ModularPipeline` | 用错 conda 环境。必须 `minimax_h3`（diffusers 0.40），`modelscope` 是 0.36 没有 |
| 卡在 `Retrying in 1s [Retry 1/5]` | 没设离线。`HF_HUB_OFFLINE=1 TRANSFORMERS_OFFLINE=1`（脚本已设） |
| `index is on npu:0, different from other tensors on npu:7` | 输出头没搬到 npu:0 / hook 没递归改。引擎里的 `move_output_heads_to` 已处理，别删 |
| `Expected all tensors to be on the same device`（RoPE inv_freq） | non-persistent buffer 留在 CPU。引擎里的 `fix_stranded_tensors` 已处理（**只搬 buffer，搬 parameter 会 OOM**） |
| `BinaryGetFunction failed` / `Conv3dv2 only support static shape` | torch_npu 与 CANN 版本不配套。CANN 9.0.0 必须配 torch_npu 2.9.x（本机已升） |
| `ValueError: AutoencoderKLMiniMaxH3Audio does not support device_map` | audio_vae 没定义 `_no_split_modules`，必须单独 `.to("npu:0")`（引擎已处理） |
| 画面像底片（青脸/墨天/红旗变青） | 极性反了。看任务日志「极性自动判定」一行；auto 判错时 `--negate yes/no` 强制，或调 `H3_NEGATE_LUM` |
| 画面发暗发蓝但不像底片 | 先确认极性（同上），再考虑 grade 强度 |
| 反相后有纯蓝/品红斑块 | 通道削顶伪影，开伪影修复（默认开）；信息已丢，只能修复不能还原 |
| 画面发灰/播放器颜色怪 | 缺 bt709/tv 色彩标签，或关了 grade |
| 生成到一半进程没了 | 之前是前台跑被 SIGHUP 杀。现在服务用 `setsid`，SSH 断开不受影响；`./h3.sh batch` 还能断点续跑 |
| 提交任务后长时间没进度 | 首次要加载模型（30~60s）+ 首步算子编译（可达 3 分钟）。`./h3.sh status` 看引擎是否 ready |
| 端口被占 | `H3_PORT=7861 ./h3.sh up` |

---

## 11. 已知边界

1. **本地只能出 768p**。官方的 `H3-Context-IR`（prompt 扩写）和 `H3-Regenerate-2K`（2K 重生成）
   **没有开源**，只能调 MiniMax 开放平台 API（要外网 + token），见模型目录 `scripts/readme/full-2k-*.sh`。
   本地替代：按官方 prompt 指南自己写细（`./h3.sh check` 帮你查），2K 用 ffmpeg 上采样只能算凑合。
2. **sparse attention 未开源**，当前是全量注意力，长视频/高分辨率的显存与时间成本降不下来。
3. **8 卡是流水线式分片，不是张量并行**。官方推荐生产部署用 SGLang（`--ulysses-degree 4` 序列并行），
   本机未安装（需先确认其 Ascend 支持）。
4. **AdaLN 裁剪可再省 26GB**：`adaln_proj` 每层 `Linear(2688, 96768)`，50 层约 13B 参数 / 26GB，
   README 说推理时可不加载（调制输出可预计算缓存，50 步全缓存仅 ~483MB）。裁掉后 transformer 降到
   ~36GB **单卡即可常驻**，能省掉跨卡搬运。尚未实现，是最明确的提速点。
5. **负片问题的源头未定**：本地顶层 diffusers 格式权重是 `convert_minimax_h3_weights.py` 自行转换的
   （`FL2VA/video_vae/` 里是原始实现的 .py 源码，不是 diffusers 格式，无法直接替换验证）。
   negate 是确定有效的修正，但如果哪天换成官方 diffusers 权重，**记得把 negate 关掉**再对比。
6. **根分区紧张**（69G，剩约 30G）：pip 装包加 `--no-cache-dir`，所有输出写大盘。
