yuwen-cool/yw-transcribe
GitHub: yuwen-cool/yw-transcribe
一个为 Codex 设计的本地优先、能力感知、产物可追溯的音视频转写 Skill,支持本地 MLX Whisper 和云端 ASR 后端,并通过确定性校验确保转写质量。
Stars: 1 | Forks: 0
# YW Transcribe
### 本地优先、能力感知、证据可追溯的音视频转写 Skill
[](https://github.com/yuwen-cool/yw-transcribe/actions/workflows/ci.yml)
[](https://www.python.org/)
[](LICENSE)
[](CHANGELOG.md)
把一个本地音频或视频文件,变成带来源、能力声明、质量状态和完整性证据的逐字稿包。
[在线展示](https://yuwen-cool.github.io/yw-transcribe/) · [30 秒选型](#30-秒选型) · [立即安装](#安装) · [首次使用](#首次使用) · [架构](#架构与设计原则)
`YW Transcribe` 面向中文与中英混合内容。它不是“调用一个 ASR 接口然后返回一段文字”的薄封装,而是一套完整的转写流水线:先锁定隐私、能力和费用边界,再执行识别、保留原始证据、生成规范化产物,最后用确定性校验器判断是否真正完成。
## 30 秒选型
| 你的需求 | 路由 | 上传 | 原生时间轴 | 主要优势 |
|---|---|---:|---:|---|
| 不上传、隐私优先 | `local` | 否 | 是 | Apple Silicon 本地 MLX Whisper,可生成 SRT/VTT |
| 只要纯文本、公开标价更低 | `stepfun` | 是 | 否 | StepAudio 2.5 ASR,纯文本与任务热词路径清晰 |
| 云端生成字幕或分句时间 | `volcengine` | 是 | 是 | 豆包 Seed ASR 2.0,提供原生分句时间 |
平台范围:
- **Apple Silicon macOS**:本地、StepFun、豆包全部可用。
- **Intel macOS、Linux、Windows**:支持两个云端后端;本地 MLX 路由会明确报告不兼容,不会假装可用。
## 架构与设计原则
flowchart LR
A["本地音频 / 视频"] --> B{"隐私与产物需求"}
B -->|"默认、离线、不上传"| L["Local · MLX Whisper"]
B -->|"明确云端 + 纯文本"| S["StepFun · StepAudio 2.5"]
B -->|"明确云端 + 字幕"| V["豆包 · Seed ASR 2.0"]
L --> R["不可变 raw.json"]
S --> R
V --> R
R --> P["逐字稿 / 时间轴 / SRT / VTT"]
P --> Q["review + validation.json"]
Q --> D{"DONE / CONCERNS / BLOCKED"}
这套架构坚持五条边界:
1. **隐私先于便利**:默认本地;否定上传的表达永远覆盖云端名称。
2. **能力先于品牌**:纯文本、分句时间、严格逐词时间分别走能够真实满足它们的后端。
3. **授权不可继承**:一次云端授权只适用于本次明确的后端和文件。
4. **失败不静默降级**:后端失败不会偷偷切换供应商、上传文件或制造额外费用。
5. **完成必须有证据**:只有产物校验通过,才会报告 `DONE`。
更完整的执行契约见 [`skills/yw-transcribe/SKILL.md`](skills/yw-transcribe/SKILL.md)。
## 安装
### 方式一:直接让 Codex 安装
把下面这句话交给 Codex:
请从 https://github.com/yuwen-cool/yw-transcribe/tree/main/skills/yw-transcribe 安装 yw-transcribe Skill。
### 方式二:运行 Codex 自带安装器
macOS / Linux:
python3 "${CODEX_HOME:-$HOME/.codex}/skills/.system/skill-installer/scripts/install-skill-from-github.py" \
--repo yuwen-cool/yw-transcribe \
--path skills/yw-transcribe
Windows PowerShell:
$CodexHome = if ($env:CODEX_HOME) { $env:CODEX_HOME } else { Join-Path $HOME ".codex" }
python (Join-Path $CodexHome "skills\.system\skill-installer\scripts\install-skill-from-github.py") `
--repo yuwen-cool/yw-transcribe `
--path skills/yw-transcribe
安装完成后,**从下一轮 Codex 对话开始可用**。如果目标目录已经存在,安装器会停止而不是覆盖;请先备份或明确处理旧版本。
如果你的个人 Skill 库里还保留着同用途的旧版转写 Skill,请只启用其中一个,或者显式调用 `$yw-transcribe`。两个功能高度重叠的 Skill 同时参与自动路由,会让触发结果变得含糊;本仓库不会自动删除或覆盖任何旧版本。
## 首次使用
### 推荐路径:直接在 Codex 里使用
1. 新开一轮对话,上传一个本地音频或视频文件。
2. 发送:
使用 $yw-transcribe 检查环境,然后转写这个文件。本地优先;如果需要上传云端,先告诉我目标服务和预计费用。
3. Skill 会先运行离线体检。缺少 FFmpeg、`uv` 或云端凭据时,它会根据当前系统给出编号修复步骤。
4. 本地首次下载模型、云端首次上传或可能产生费用前,都会先展示计划和边界。
### 手动运行离线体检
它不会联网、不会调用付费 API,也不会打印密钥值。
macOS / Linux:
SKILL_DIR="${CODEX_HOME:-$HOME/.codex}/skills/yw-transcribe"
python3 "$SKILL_DIR/scripts/doctor.py"
Windows PowerShell:
$CodexHome = if ($env:CODEX_HOME) { $env:CODEX_HOME } else { Join-Path $HOME ".codex" }
$SkillDir = Join-Path $CodexHome "skills\yw-transcribe"
python (Join-Path $SkillDir "scripts\doctor.py")
最小依赖:Python 3.10+ 与 FFmpeg(包含 `ffprobe`)。本地正式转写还需要 Apple Silicon macOS 和 [`uv`](https://docs.astral.sh/uv/getting-started/installation/);模型权重、FFmpeg 和第三方 Python 包都不随仓库分发。
常见安装命令:
| 系统 | FFmpeg | 本地后端额外依赖 |
|---|---|---|
| macOS | `brew install ffmpeg` | `brew install uv` |
| Ubuntu / Debian | `sudo apt-get install ffmpeg` | 本地 MLX 不支持 |
| Windows PowerShell | `winget install --id Gyan.FFmpeg -e` | 本地 MLX 不支持 |
## 配置云端后端
云端凭据只从环境变量读取。项目**不会自动加载 `.env`**,不会把密钥写入日志、命令参数、产物或 Git 仓库。
下面的配置默认只在当前终端会话生效。需要长期使用时,请放入操作系统的凭据管理方案或手动配置到个人 Shell profile;不要提交到项目文件。修改持久环境后,需要重新启动 Codex,让它继承新变量。
### StepFun:纯文本路径
先创建对应区域的接口密钥:
- [StepFun 全球站 API Keys](https://platform.stepfun.ai/interface-key)
- [阶跃星辰中国站接口密钥](https://platform.stepfun.com/interface-key)
macOS / Linux:
export STEPFUN_API_KEY="
"
export STEPFUN_REGION="global" # 中国站改为 cn
Windows PowerShell:
$env:STEPFUN_API_KEY = ""
$env:STEPFUN_REGION = "global" # 中国站改为 cn
`global` 固定请求 `api.stepfun.ai`,`cn` 固定请求 `api.stepfun.com`。脚本不会因鉴权失败跨区重试。全球站已通过真实集成 canary;中国站已验证官方端点、价格和静态契约,但尚未用中国站账户完成受控实测,因此不把它描述为同等强度的 live coverage。
### 豆包:云端字幕路径
1. 打开[豆包语音控制台](https://console.volcengine.com/speech/app)。
2. 开通录音文件识别 2.0 / Seed ASR,并确认资源 ID 为 `volc.seedasr.auc`。
3. 优先创建 Speech API Key。不要把火山方舟 Ark Key 当成豆包语音 Key。
4. API 约束见[官方录音文件识别 2.0 文档](https://www.volcengine.com/docs/6561/1354868)。
macOS / Linux:
export VOLCENGINE_SPEECH_API_KEY=""
Windows PowerShell:
$env:VOLCENGINE_SPEECH_API_KEY = ""
旧控制台仍可使用完整的一对 `VOLCENGINE_SPEECH_APP_ID` 与 `VOLCENGINE_SPEECH_ACCESS_TOKEN`;只配置其中一个会被拒绝。
配置后重新运行 `doctor.py`。它只验证变量是否存在,不验证余额、配额或产品权限;真正调用前仍应先跑 dry-run。
## 本地模型怎么选
`--model auto` 使用可解释的保守策略:
| 模型 | 自动选择 | 实测缓存 | 适合 |
|---|---|---:|---|
| `small` | 低于 16 GiB,或内存未知 | 约 459 MB | 8 GB 级机器、速度与内存优先 |
| `large-v3` | 16 GiB 及以上 | 约 2.9 GB | 质量优先、技术词较多的内容 |
查看推荐项和缓存状态:
python3 "$SKILL_DIR/scripts/transcribe_router.py" --list-models
本地 dry-run 会检查平台、媒体、模型、音轨和输出位置,但不会下载模型、安装 MLX Python 依赖或执行识别:
python3 "$SKILL_DIR/scripts/transcribe_router.py" \
"/path/to/media.mp4" --backend local --profile timed \
--model auto --dry-run
第一次正式运行时不要设置 `HF_HUB_OFFLINE=1`,否则未缓存模型无法下载:
python3 "$SKILL_DIR/scripts/transcribe_router.py" \
"/path/to/media.mp4" --backend local --profile timed \
--model auto --language zh
模型已经缓存后,可以用该变量证明识别阶段不访问模型仓库:
HF_HUB_OFFLINE=1 python3 "$SKILL_DIR/scripts/transcribe_router.py" \
"/path/to/media.mp4" --backend local --profile timed \
--model auto --language zh
## 手动 CLI 示例
以下示例采用 macOS/Linux 变量;Windows PowerShell 使用前文的 `$SkillDir`,并把 `python3 "$SKILL_DIR/..."` 写成 `python (Join-Path $SkillDir "...")`。普通 Codex 用户无需手动执行这些命令。
StepFun 纯文本:
python3 "$SKILL_DIR/scripts/transcribe_router.py" \
"/path/to/media.mp3" --backend stepfun --profile text --dry-run
python3 "$SKILL_DIR/scripts/transcribe_router.py" \
"/path/to/media.mp3" --backend stepfun --profile text
豆包字幕:
python3 "$SKILL_DIR/scripts/transcribe_router.py" \
"/path/to/media.mp4" --backend volcengine --profile timed --dry-run
python3 "$SKILL_DIR/scripts/transcribe_router.py" \
"/path/to/media.mp4" --backend volcengine --profile timed
没有指定 `--output-dir` 时,产物写入调用者当前目录下的 `transcribe-output/`,不会写进只读的 Skill 安装目录。
## 热词是什么
热词是“本次音频里很可能出现、希望识别器重点留意的专有词”,例如人名、产品名和缩写。它不是强制替换,也不能证明某个词真的被说过。
默认术语表为空。为每个任务复制一份,只加入有上下文依据的词:
WorkBuddy
胡楚靖
FFmpeg = F F mpeg | Fmpeg
左侧是标准写法;右侧是经过观察确认的字面别名。云端只发送标准写法作为热词;别名修正会单独记录,不会改写原始响应。
## 产物与完成状态
output/
├── manifest.json # 输入指纹、能力要求、后端与公开路径信息
├── run.json # 执行、提交、恢复与计费状态
├── raw.json # 不可变的服务端/模型原始证据
├── transcript.plain.txt # 规范化纯文本
├── transcript.json # 结构化文本与时间信息
├── subtitles.srt # timed profile 才有
├── subtitles.vtt # timed profile 才有
├── review.md # 需要人工关注的具体问题
└── validation.json # 确定性校验结论
状态含义:
- `DONE`:产物通过校验,没有未解决的警告或错误。
- `DONE_WITH_CONCERNS`:产物通过校验,但 `review.md` 仍有明确关注项。
- `BLOCKED`:识别或校验失败,不宣称完成。
- `INCOMPATIBLE`:后端无法满足所需能力,并且在上传前停止。
独立复验:
python3 "$SKILL_DIR/scripts/validate_package.py" "/path/to/output"
## 测试证据与价格边界
两条脱敏中文/中英混合 canary 的本地模型对比:
| 模型 | 两条样本 CER | 峰值 MLX 内存 | 说明 |
|---|---:|---:|---|
| `small` | 1.32% / 2.86% | 约 1.36 GB | 更快、更省内存 |
| `large-v3` | 0 / 0 | 约 3.78 GB | 样本上质量更高 |
一条 16.9 秒干净 canary 上,本地 `large-v3`、StepFun 全球站和豆包 Seed ASR 2.0 均取得 CER 0,且所有产物包通过验证。它只证明这些样本与当时的运行路径,不代表普遍质量排名。完整数据与限制见 [`evidence/benchmark-summary.md`](evidence/benchmark-summary.md) 和 [`evidence/release-validation.md`](evidence/release-validation.md)。
| 后端 | 2026-08-01 公开标价 | 来源 |
|---|---:|---|
| StepFun 全球站 | 0.022 USD/小时 | [官方价格页](https://platform.stepfun.ai/docs/en/guides/pricing/details) |
| StepFun 中国站 | 0.15 CNY/小时 | [官方价格页](https://platform.stepfun.com/docs/zh/guides/pricing/details) |
| 豆包 Seed ASR 2.0 | 0.8 CNY/小时 | [官方产品价格页](https://www.volcengine.com/product/doubao) |
脚本只计算“媒体时长 × 记录的公开标价”。免费额度、套餐、计费取整、账户折扣和最新价格以实际账单及官方页面为准。
## 常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
| `doctor` 显示 FFmpeg 缺失 | `ffmpeg` 或 `ffprobe` 不在 PATH | 按 doctor 给出的系统命令安装,再打开新终端 |
| 本地正式运行提示需要 `uv` | 本地运行依赖尚未准备 | macOS 执行 `brew install uv`;dry-run 本身不需要 `uv` |
| StepFun 返回 401 | Key 错误或全球/中国区域不匹配 | 检查 Key 来源和 `STEPFUN_REGION`;脚本不会自动跨区重试 |
| 豆包提示 `grant not found` | 未开通 `volc.seedasr.auc`,或使用了错误凭据家族 | 在豆包语音控制台开通对应产品并创建 Speech Key |
| StepFun 请求字幕被拒绝 | StepFun 路径不返回原生时间轴 | 选择本地 timed 或豆包 timed;不会伪造 SRT |
| 不确定云端请求是否已提交 | 网络在提交后中断 | 查看 `run.json`;禁止盲目重试,避免重复计费 |
| 文件过大被阻止 | 内联上传设有 64 MiB 安全上限 | 在自然边界拆分;当前版本不宣称自动长音频分块 |
## 安全边界
- 云端只有在明确选择相应后端后上传,认证请求固定官方 HTTPS 主机并拒绝重定向。
- 默认清单只记录源文件名、SHA-256、大小和媒体信息,不记录本机绝对路径。
- 云端提交状态在请求前写入 `run.json`;不确定是否计费时不会自动重新提交。
- `raw.json` 保留原始证据;修正、恢复和人审状态分开记录。
- 不支持实时麦克风、说话人分离、OCR、字幕翻译或远程媒体下载。
安全问题请通过 GitHub Security Advisory 私密报告,详见 [`SECURITY.md`](SECURITY.md)。
## 开发与发布
python3 -m unittest discover -s tests -v
python3 tools/check_skill.py
python3 tools/privacy_lint.py
python3 tools/build_release.py
普通 CI 不调用付费 API。受保护的手动工作流只能通过仓库 Secrets 运行授权 canary。贡献约定见 [`CONTRIBUTING.md`](CONTRIBUTING.md)。
MIT License。仓库不分发模型权重、FFmpeg 或第三方 Python 包。标签:Codex插件, MLX Whisper, Python, 无后门, 本地优先, 语音识别, 逆向工具, 音视频转写