视频教程转 Markdown 文本教程工具。专为 Apple Silicon Mac 优化,利用 mlx-whisper GPU 加速转录 + macOS 原生 Vision OCR 提取屏幕内容。
- 语音转录 — mlx-whisper 在 Apple Silicon 上 GPU 加速,支持 tiny/base/small/medium/large-v3 模型
- 屏幕 OCR — Apple Vision Framework(Live Text 同款引擎),无需额外依赖
- 六策略智能抽帧:
- 终端输出稳定点检测(快速滚动结束后抓帧)
- 语音停顿期密采 + OCR diff 去重
- 键盘敲击结束检测(打字完成 = 命令输入完毕)
- 窗口切换检测(标题栏变化 = 切换应用)
- 两遍法(粗采感知哈希 → 变化密集区精采)
- LLM 智能命令提取(ollama 可选,回退正则)
- 三层 OCR 过滤管道:
- UI 噪声剥离(任务栏时间/天气/搜索框/菜单栏)
- 质量门控(二进制装饰、OCR 乱码、过短帧丢弃)
- 滚动感知去重(同一页面不同滚动位置合并为最清晰帧)
- 课程标题帧检测 — 自动识别课程标题页(OSCP/WEB-300/EXP-312 等)
- 终端命令提取 — 正则 + LLM 双引擎,从 OCR 文本中提取可执行命令
安全/编程课程视频(OSCP、WEB-300、EXP-312 等)知识密度极高,但视频格式不便检索和复习。v2t 自动提取三类核心信息:语音讲解 → 理解思路,屏幕内容 → 查看输出,终端命令 → 可直接复制执行。
| 决策 | 选择 | 原因 |
|---|---|---|
| 转录引擎 | mlx-whisper | Apple Silicon Metal 加速,比 PyTorch Whisper 快 3-5x |
| OCR 引擎 | Apple Vision | 零额外依赖、Live Text 同款、系统内置 |
| 管线模式 | Phase 串行 + 纯函数 | 可独立测试/替换每个 Phase,数据流清晰 |
| 命令提取 | LLM + regex 双引擎 | LLM 处理复杂交互工具 prompt,regex 高速兜底 |
| 数据格式 | list/dict,无自定义类 | 最大互操作性,任何工具可读写中间结果 |
| 降级策略 | 每 Phase 自行降级 | 单点失败不中断管线(ollama 挂→用 regex) |
| 依赖 | 说明 | 安装方式 |
|---|---|---|
| macOS | 需要 Apple Vision Framework | 系统自带 |
| Apple Silicon | M1/M2/M3/M4,mlx-whisper 依赖 Metal GPU | 硬件要求 |
| Python >= 3.11 | 运行时 | brew install python@3.11 |
| uv | Python 包管理与脚本运行器 | curl -LsSf https://astral.sh/uv/install.sh | sh |
| ffmpeg / ffprobe | 音视频处理(抽帧、提取音频) | brew install ffmpeg |
| ollama(可选) | 本地 LLM 命令提取 | brew install ollama + ollama pull qwen2.5:7b |
在 pyproject.toml 中声明,uv 自动管理:
| 包名 | 用途 |
|---|---|
mlx-whisper |
Apple Silicon GPU 加速的 Whisper 语音转录 |
pyobjc-framework-Vision |
Python 绑定 macOS Vision Framework(OCR) |
Pillow |
图像处理(感知哈希计算) |
# 1. 安装 uv(如果还没有)
curl -LsSf https://astral.sh/uv/install.sh | sh
# 2. 安装 ffmpeg
brew install ffmpeg
# 3. 克隆仓库
git clone <repo-url> && cd video-extractor
# 4. 安装 Python 依赖(uv 自动解析 pyproject.toml,创建虚拟环境)
uv sync
# 5.(可选)安装 ollama 用于 LLM 命令提取
brew install ollama
ollama pull qwen2.5:7b# 处理单个视频(输出同名 .md)
uv run video-extractor input.mp4
# 指定输出路径
uv run video-extractor input.mp4 -o output.md
# 也可以直接运行脚本
uv run scripts/extract.py input.mp4 -o output.md# 使用更大的模型获得更好的转录质量
uv run video-extractor input.mp4 -m large-v3
# 指定语言(中文)
uv run video-extractor input.mp4 -l zh
# 调整场景检测灵敏度(0-1,越高越敏感,抽帧越多)
uv run video-extractor input.mp4 -s 0.5
# 批量处理目录下所有 MP4
uv run video-extractor ./videos/ -o ./output/| 参数 | 说明 | 默认值 |
|---|---|---|
input |
MP4 文件或包含 MP4 的目录 | (必填) |
-o, --output |
输出 Markdown 文件路径 | 与输入同名 .md |
-m, --model |
Whisper 模型大小 | small |
-l, --language |
语言代码 | en |
-s, --scene |
场景检测灵敏度 0-1 | 0.3 |
| 模型 | 速度 | 质量 | VRAM | 适用场景 |
|---|---|---|---|---|
tiny |
~30x 实时 | 一般 | ~1GB | 快速预览、确认管线正常 |
base |
~20x 实时 | 尚可 | ~1GB | 简单英文内容 |
small |
~10x 实时 | 好 | ~2GB | 默认推荐,平衡速度与质量 |
medium |
~5x 实时 | 很好 | ~5GB | 口音重或专业术语多 |
large-v3 |
~2x 实时 | 最佳 | ~10GB | 最高精度需求 |
MP4 输入
│
├─ Phase 1: 音频提取 + mlx-whisper 转录
│ ├─ ffmpeg 提取 16kHz 单声道 WAV
│ ├─ mlx-whisper GPU 转录(含词级时间戳)
│ └─ 输出: [{start, end, text}, ...] 带时间戳的文本段落
│
├─ Phase 2: 六策略智能抽帧
│ ├─ 策略 A: 场景变化检测(ffmpeg scene filter)
│ ├─ 策略 B: 语音停顿点(transcript gap > 1.5s)
│ ├─ 策略 C: 键盘敲击结束(音频波形分析)
│ ├─ 策略 D: 窗口切换(标题栏 OCR diff)
│ ├─ 策略 E: 两遍法(粗采哈希→密集区精采)
│ ├─ 策略 F: 停顿区均匀密采
│ ├─ 合并: ±1s 内去重取中点
│ └─ 输出: [{file, timestamp, path}, ...] 关键帧列表
│
├─ Phase 3: Apple Vision OCR + 三层过滤
│ ├─ Vision OCR: 每帧图片 → 文本
│ ├─ Stage 1: UI 噪声剥离(正则全行匹配删除)
│ ├─ Stage 2: 质量门控(乱码/过短/装饰帧丢弃)
│ ├─ Stage 3: 滚动感知去重(相似帧分组→选最优)
│ └─ 输出: [{file, timestamp, path, ocr_text}, ...]
│
├─ Phase 4: 终端命令提取
│ ├─ 首选: ollama LLM 提取(JSON 格式返回)
│ ├─ 回退: 正则引擎(shell prompt 模式匹配)
│ ├─ 后处理: 清洗 + 可信度过滤
│ └─ 输出: [{timestamp, command}, ...]
│
├─ Phase 4.5: 课程标题帧检测
│ ├─ 匹配已知课程关键词(WEB-300、PEN-200 等)
│ └─ 输出: {course, topic}
│
└─ Phase 5: 组装输出 Markdown
├─ 所有事件按时间轴排序
├─ Whisper 幻觉去重(连续相同 speech 合并)
├─ 命令汇总 Cheatsheet
└─ 时间轴: 转录 + OCR 折叠块 + 命令代码块
生成的 Markdown 包含:
# 视频标题
**Course:** 课程系列名
**Topic:** 课程主题
## Commands Cheatsheet
(提取的终端命令汇总,去重后)
## Full Timeline
### [00:00:00]
**[00:00:05]** 语音转录文本...
<details><summary>[00:01:23] Screen Content</summary>
(OCR 提取的屏幕内容,已去噪去重)
</details>
```bash
# [00:01:25]
nmap -sV 192.168.1.1
## 外部 CLI 工具依赖说明
| 工具 | 用途 | 调用场景 |
|------|------|----------|
| `ffprobe` | 获取视频时长和元信息 | Phase 1/2 |
| `ffmpeg` | 提取音频 WAV、关键帧截图 | Phase 1/2 |
| `ollama` | 本地 LLM 推理(命令提取) | Phase 4(可选,不安装自动回退 regex) |
### ffmpeg 使用详情
```bash
# Phase 1: 提取音频为 WAV(16kHz 单声道,Whisper 要求)
ffmpeg -i input.mp4 -vn -acodec pcm_s16le -ar 16000 -ac 1 audio.wav
# Phase 2: 粗采帧(每2秒一帧,用于感知哈希)
ffmpeg -i input.mp4 -vf "fps=0.5" -q:v 2 frame_%04d.png
# Phase 2: 精确时间戳抽帧(关键帧)
ffmpeg -ss <timestamp> -i input.mp4 -frames:v 1 -q:v 2 output.png
video-extractor/
├── pyproject.toml # 项目配置 & Python 依赖声明
├── uv.lock # uv 锁定依赖版本
├── CLAUDE.md # AI 助手项目指南(代码风格/约束/命令)
├── README.md # 本文件
├── scripts/
│ ├── extract.py # CLI 入口脚本
│ └── v2t/ # 核心处理包
│ ├── __init__.py # 公开 API: process_video, main
│ ├── pipeline.py # Phase 编排 + argparse
│ ├── utils.py # 共享常量 + 工具函数
│ ├── transcribe.py # Phase 1: 转录
│ ├── keyframes.py # Phase 2: 抽帧
│ ├── ocr.py # Phase 3: OCR + 过滤
│ ├── commands/ # Phase 4: 命令提取
│ ├── title.py # Phase 4.5: 标题检测
│ └── markdown.py # Phase 5: 输出组装
├── skills/ # Claude Code / Ducc 技能定义
│ └── v2t/
│ ├── SKILL.md # v2t 技能描述
│ └── references/
│ └── code-modification-guide.md # 代码修改指南
└── commands/ # Claude Code / Ducc 自定义命令
# 克隆并安装
git clone <repo-url> && cd video-extractor
uv sync
# 验证环境
uv run scripts/extract.py --help# 运行处理(始终用 uv run)
uv run scripts/extract.py input.mp4 -o output.md
# 语法检查
uv run python -c "import ast; ast.parse(open('scripts/v2t/ocr.py').read()); print('OK')"
# 模块导入验证
uv run python -c "from scripts.v2t import process_video; print('import OK')"
# 测试 OCR 过滤逻辑
uv run python -c "
from scripts.v2t.ocr import _strip_ui_noise, _passes_quality_gate
text = '5:24 PM\n75°F\nCloudy\nroot@kali:~# whoami'
cleaned = _strip_ui_noise(text)
print(cleaned)
print('Pass:', _passes_quality_gate(cleaned))
"详细的代码修改指南见 skills/v2t/references/code-modification-guide.md。
核心约束:
- 不加新依赖 — 仅
mlx-whisper、pyobjc-framework-Vision、Pillow - 不改数据结构 — Phase 间 dict key 是隐式 API
- 不改 CLI 接口 — 保持向后兼容
- 用
uv run— 所有 Python 执行通过 uv,避免环境问题
MIT