# Qwen Subtitle

> 用阿里云百炼(千问)系列模型给视频做字幕智能纠错,并可进一步翻译成多语言、用克隆原声配音做视频出海,全程百炼模型。纠错:语音识别出带词级时间戳的字幕,用视觉模型看视频画面上"屏幕里真实写着的字"来纠正被听错的术语/产品名/代码/命令/文件名,再断长句、去水词。出海:把纠错后的字幕翻译成多语言,并用从视频克隆出的原声(中/英/日/韩)配音。核心价值是用画面校正声音——单通道字幕工具永远修不了的同音术语错(cloud→Claude、html2pptx、class q→Claude)它能修对,且带画面证据。 当用户有视频(尤其录屏、教程、讲解、带货类)需要以下任一时,使用本 skill:① 生成或纠正字幕、ASR/语音转写有错别字(尤其专有名词/英文/代码/文件名被听错)、去掉"呃啊嗯"水词、拆短过长字幕;② 把视频或字幕翻译成其他语言、做多语言字幕、用克隆的原声配音(中/英/日/韩)、或做视频出海/本地化。即使用户只说"给这个视频做字幕""字幕有错别字""字幕纠错""转写一下这个视频""字幕太长了断一下""把这个视频翻译成英文""做个英文配音""克隆我的声音说外语""做多语言字幕""视频出海""本地化"而没有点名工具,也应主动使用本 skill。

- Skill: `oil-oil/qwen-subtitle` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add oil-oil/qwen-subtitle`
- Raw SKILL.md: https://api.skillmd.com/api/skills/oil-oil/qwen-subtitle/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: oil-oil (https://skillmd.com/u/oil-oil)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/oil-oil/qwen-subtitle

---


# qwen-subtitle — 百炼字幕智能纠错 + 多语言出海配音

## 它解决什么问题

录屏 / 教程类视频的字幕,无论用哪家 ASR,**专有名词永远会被听错**:`Claude` 听成 `cloud`、`Codex` 听成 `class q`、`html2pptx` 听成 `html to ppt`、`OOXML` 听成 `OOCML`。靠一份手工维护的术语表去替换,既累又补不全。

本 skill 的核心洞察:**录屏视频里,正确的词往往就明明白白写在屏幕上**。所以——让视觉模型按时间戳去看那一帧,读屏幕上的真实文字来纠正。这是单通道(纯语音)工具做不到的事。

判断标准(避免按字面例子过拟合):凡是"屏幕上写着、却被听成同音词"的术语 / 产品名 / 代码 / 命令 / 文件名 / 路径,都属此类。

## 组合了千问的哪些能力

| 能力 | 模型 | 走的命令 | 角色 |
|---|---|---|---|
| 🎙️ 语音识别 | FunAudio-ASR | `bl speech recognize` | 出字幕,带**句级+词级毫秒时间戳**——后续抽帧、断句、对齐配音都靠它 |
| 🧠 标错 | qwen3.7-max | `bl text chat` | 高精度扫出"明显听错"的点,分 screen / semantic 两类 |
| 👁️ 看屏纠正 | qwen3-vl-plus | `bl vision describe` | 对 screen 类按时间戳抽帧、读屏上真实文字定夺,带画面证据 |
| ✨ 去水词 | qwen-plus | `bl text chat` | 删呃啊嗯、口吃重复,顺滑 |

模型分工是**实测**定下来的:标错用 qwen3.7-max(精度命门,plus 会漏真错、且重新误标);去水词用 qwen-plus(低风险,快 5 倍)。这些在脚本顶部 `FLAG_MODEL / VL_MODEL / FILLER_MODEL` 常量里,需要时直接改。

## 流程(5 步,一条命令跑完)

```
视频
 ├─[1] FunAudio ASR ───────► 字幕轨道(句+词级毫秒时间戳)
 ├─[2] qwen3.7-max 标错 ───► 可疑点(screen=看画面 / semantic=纯语义)
 ├─[3] qwen3-vl-plus 看帧 ─► screen 类逐帧读屏纠正(带证据)
 │                           └ 取不到证据 → 保留原文+标记待确认〔零误改〕
 ├─[4] 词级时间戳断句 ─────► 按标点拆长句(>24字 / >6秒)
 ├─[5] qwen-plus 去水词 ───► 删语气词/口吃,顺滑
 └─► corrected.srt + transcript.json + report.md(画面证据)
```

## 准备

**认证**:`bl` 已登录就什么都不用设——脚本直接用 bl 自己的认证(`bl auth status` 验证)。克隆配音那步要 curl 直调原始 API,脚本会**自动从 `~/.bailian/config.json` 读 key**(或环境变量 `DASHSCOPE_API_KEY`,两者皆可)。**不需要每次手动 export**,也绝不把 key 写进任何文件。仅当 bl 从未配置过时,才 `export DASHSCOPE_API_KEY=sk-xxx`。

依赖:
- `bl`(百炼 CLI,v1.4+;`bl --version` 验证)
- `ffmpeg`(抽音频 + 抽帧;脚本自动从 PATH 找,或设 `FFMPEG` 环境变量)
- `python3`
- `flask`(**仅预览页需要**:`pip install flask`;纠错/翻译/配音不需要)

`bl speech recognize` 和 `bl vision describe` 都**直接吃本地文件路径**(CLI 内部已处理上传),所以不需要手动上传文件拿 URL。

## 第一步:先问需要哪些语言(默认行为,**菜单一律用中文问**)

每次运行,**先用中文问**用户要哪些语言(给编号,可多选如 `1,3,5`)。**问答和 tab 标签都用中文**(用户不一定看得懂外文/原生写法):

```
请选择要生成的语言(可多选,用逗号分隔):

  〔配音 + 字幕〕用你的克隆声音说外语
    1. 中文(原声,仅纠错字幕)
    2. 英语    3. 日语    4. 韩语

  〔仅字幕〕qwen 翻译,视频保留原声
    5. 西班牙语   6. 葡萄牙语   7. 阿拉伯语
    8. 印尼语     9. 越南语    10. 泰语
```

- 只选「中文」→ 纯纠错(A)。选了**配音语言**(英/日/韩)→ A + 克隆配音(B)。选了**仅字幕语言** → A + 翻译出字幕(B,不配音,视频留原声)。
- **配音只支持 中/英/日/韩**(CosyVoice 限制);其余语言只出字幕(qwen 支持 92 语种,这里列几个出海主流,要别的随加)。
- code 对照:英 en / 日 ja / 韩 ko / 西 es / 葡 pt / 阿 ar / 印尼 id / 越 vi / 泰 th(脚本 `LANGS` 表里改)。

## A. 纠错中文字幕(基础,所有情况都先跑)

```bash
python3 scripts/subfix.py <video.mp4> [--out DIR]
```

参数:`--out DIR`(默认 `<视频名>.subfix/`)、`--max-seconds N`(试跑前 N 秒)、`--lang zh`、`--reuse`(复用 asr.json/suspects.json 只重跑后续)。

产出:`corrected.srt`(纠错+断句+去水词的中文字幕)、`transcript.json`(`[{start,end,text}]`)、`report.md`(每处改动 + **画面证据** + "取不到证据保留原文待确认"清单);另有 `corrected.json`(句级结构化结果)与 `report.json`(机器可读证据)。中间产物:`asr.json`/`suspects.json`。

> 给用户看结果时:念 `report.md` 的改动+证据(最有说服力);诚实区分"已改(有画面铁证)"与"保留原文待确认",别把后者说成已修复。

## B. 多语言出海:克隆原声 + 翻译 + 配音

用户选了外语时,在 A 的基础上跑:

```bash
python3 scripts/dub_multi.py <video.mp4> \
  --transcript <A的transcript.json> --langs en,ja,es,pt --out <DIR> [--clip-seconds N] [--voice-id ID]
```

> ⚠️ `--clip-seconds` **默认 0 = 整片**;它会**限制字幕/配音的实际范围**(不只是裁预览),只在试跑前 N 秒时才设。要整片就别带它(且上游 `subfix.py` 也别带 `--max-seconds`)。

`--langs` 传 code(en/ja/ko/es/pt/ar/id/vi/th…)。脚本自动判档:
1. **配音语言(`DUB`={en,ja,ko})**:克隆原声(扒 18s → `bl file upload` → 复刻 API → voice_id,`--voice-id` 可跳过)→ **按整句、限定词数翻译**(配音=字幕同一份文案,要在镜头时长内说完)→ **克隆音色 TTS** → `atempo` 卡时长 → 出 `<code>.json` + `<code>.m4a`(配音轨)。
2. **仅字幕语言(其余)**:只翻译 → 出 `<code>.json`;视频保留原声。
3. 全选了仅字幕时**不克隆**(省一步)。产出 `manifest.json` + 各语言 transcript(+配音轨) + `clip.mp4`。

翻译分两路(脚本 `translate()` 按 `for_dub` 自动选):**配音语言走 `qwen-plus`**——同一份稿子既配音又当字幕,按词数(`≈时长×2.6`)压到能在时长内说完;**纯字幕语言走 `qwen-mt-turbo`**(`TRANSLATE_MODEL` 常量,百炼专用翻译模型,忠实、品牌/型号天然保留)。支持:**配音=中/英/日/韩**(CosyVoice v2 官方);**字幕=92 语种**(`LANGS` 表里加 code 即可)。英文配音已充分验证;日韩配音用同一克隆音色,质量需实跑确认。

配音的三条关键设计(踩坑换来的,改前先懂):
- **按整句念,不按字幕碎段**——碎段会念成半句、听着"没说完";所以先把字幕碎段合并回整句再配音。
- **字幕 = 配音同一份译文**,按句计时——否则屏幕显示的字和嘴里说的对不上。
- **只压缩不拉慢**(atempo 上限 1.5):译文短了就自然播放留空,不拉慢拖沓。

## 多语言预览(tab 切字幕 + 切音轨)

预览页**已自带**(`scripts/preview_editor.py`,基于 Flask 的本地交互页)。需要 `flask`(`pip install flask`;纠错/翻译/配音本身不需要)。把 manifest 交给它:

```bash
python3 scripts/preview_editor.py <out>/manifest.json        # 多语言(manifest)
python3 scripts/preview_editor.py <video> <transcript.json>  # 单语言
```

预览页右上角按语言出 **tab**,切 tab → 右侧换该语言字幕、左侧视频换该语言音轨(源语言用原声,外语用克隆配音轨,与视频帧同步)。人工过一遍后保存,再交烧录。

## 设计原则:零误改优先

字幕工具里,**错误的"纠正"比不纠正更糟**——把对的词改成错的会主动污染字幕。所以这套流程的每一步都在"宁可不改,不可改错":

- **标错别越界**:只标明显听错的;本身通顺、像名字的中文(哪怕疑似音译)和本身正确只是"不够具体"的词,都不标。
- **VL 禁幻觉**:只认画面上能逐字读到的文字;靠图标/logo/常识推断的一律不算数。
- **最小替换 + 发音一致**:只替换听错的那几个字,不带进相邻路径段;改后的词必须和原文读音对得上。
- **证不了就留原文**:screen 类取不到画面证据,保留原文 + 标记待确认,绝不套用模型盲猜。

这些闸门是踩了一轮坑(误标 ooxml、把"超级麦吉"改成"超级码力/Supermario")才加上的。每条闸门的来龙去脉、对应的提示词写法,见 **[references/design-gates.md](references/design-gates.md)**——改提示词前务必先读,否则容易把精度调回原形。

## 调参(脚本顶部常量)

- `FLAG_MODEL / VL_MODEL / FILLER_MODEL` —— 三阶段模型
- `MAX_CHARS=24` / `MAX_DUR_MS=6000` —— 断句阈值(单条字幕最大字数/时长)
- `MIN_BREAK_CHARS=12` —— 到标点且已够这么长就断
- 甜区:录屏 / 屏幕共享 / 教程类(术语都写在屏上)。纯口播、谈话头(术语不在画面)时,VL 取不到证据会更多保留原文——这是预期行为,不是 bug。

