extract_audio and transcribe_audio scripts

This commit is contained in:
2026-08-23 22:12:51 +08:00
parent 86c0dd1c53
commit 02e655ddf4
4 changed files with 1568 additions and 171 deletions

631
synthmind/README.md Normal file
View File

@@ -0,0 +1,631 @@
# SynthMind - 视频音频提取与转录工具
将视频文件转换为文字稿的自动化工具链,为后续 AI 内容分析与总结提供数据基础。
**流水线**:视频文件 → MP3 音频 → TXT 文字稿 → *(后续 AI 分析)*
---
## 目录
- [功能特性](#功能特性)
- [环境要求](#环境要求)
- [安装](#安装)
- [快速开始](#快速开始)
- [脚本一:extract_audio.py](#脚本一extract_audiopy)
- [脚本二:transcribe_audio.py](#脚本二transcribe_audiopy)
- [多模型精度对比](#多模型精度对比)
- [Manifest 文件说明](#manifest-文件说明)
- [高级用法](#高级用法)
- [故障排查](#故障排查)
- [测试报告](#测试报告)
---
## 功能特性
### 通用特性
- ✅ 支持单文件或递归扫描目录
- ✅ 完善的**断点续传**:中断后重新运行自动跳过已完成项
- ✅ **JSON manifest** 进度追踪,两个脚本共享同一文件
- ✅ **失败自动记录 + 重试机制**(`--retry-failed`)
- ✅ **状态查询**(`--status`)实时查看进度
- ✅ 完全支持**含空格、中文的文件名**
- ✅ 详细的时间戳日志
### extract_audio.py 特性
- 使用 FFmpeg 提取音频:**MP3 / 64kbps / 22050Hz / 单声道**(语音场景优化,体积小)
- 支持视频**切分模式**:超大视频按时长切分为多段分别处理
- 支持多种输入格式:`.mp4/.mkv/.avi/.mov/.flv/.wmv/.webm/.m4v`
### transcribe_audio.py 特性
- 基于 **openai-whisper** 命令行工具
- 支持 4 种模型:**`tiny / base / small / medium`**(详见 [Whisper 模型选择](#whisper-模型选择))
- **多模型批量转录(`--all-models`)**:一次运行对每个音频用 4 个模型分别转录,输出 `<stem>.<model>.txt` 便于精度对比
- **模型预下载(`--preload-models`)**:一次性下载全部支持的模型到本地缓存
- **自定义输出后缀(`--output-suffix`)**:便于同一模型多次转录(不同参数)不覆盖
- 支持指定语言(`--language zh/en/...`)或自动检测
- 支持音频**切分转录**:超长音频切分后逐段转录再合并
- 支持多种音频格式:`.mp3/.m4a/.wav/.flac/.ogg/.aac`
- **Manifest key 含模型维度**:多模型多参数结果共存,互不覆盖
---
## 环境要求
| 依赖 | 版本 | 用途 |
|------|------|------|
| Python | 3.8+ | 脚本运行 |
| FFmpeg | 4.0+ | 音视频处理(含 `ffprobe`)|
| openai-whisper | 最新 | 音频转录 |
**当前实测环境**:Ubuntu 22.04 (WSL2) + Python 3.13 + FFmpeg 6.0 + Whisper 20250625
---
## 安装
### 1. 安装 FFmpeg
```bash
sudo apt update
sudo apt install -y ffmpeg
ffmpeg -version # 验证
```
### 2. 安装 Whisper
```bash
pip install openai-whisper
whisper --help # 验证
```
### 3. 预下载所有 Whisper 模型(推荐)
首次运行前,建议一次性下载所需的 4 个模型(共约 2.1GB):
```bash
python3 transcribe_audio.py --preload-models
```
**下载耗时参考**(本机测试):
```
tiny (~75MB) → 数秒
base (~140MB) → 数秒
small (~460MB) → 数十秒
medium (~1.5GB) → 75s
```
模型会缓存到 `~/.cache/whisper/`。
### 4. 下载脚本
将 `extract_audio.py` 和 `transcribe_audio.py` 放到同一目录即可,无需额外配置。
---
## 快速开始
### 场景 1:处理某目录下所有视频(简单流水线)
```bash
# Step 1: 提取音频(生成 .mp3)
python3 extract_audio.py /path/to/videos/
# Step 2: 转录文字(生成 .txt,默认 base 模型)
python3 transcribe_audio.py /path/to/videos/ --language zh
```
### 场景 2:对比 4 个模型的精度
```bash
# 一次运行,每个音频用 4 个模型都跑一遍
python3 transcribe_audio.py /path/to/audio/ --all-models --language zh
```
输出(每个 mp3 生成 4 个 txt):
```
audio1.mp3
audio1.tiny.txt
audio1.base.txt
audio1.small.txt
audio1.medium.txt
```
### 场景 3:高精度转录(推荐配置)
```bash
python3 transcribe_audio.py /path/to/audio/ --model medium --language zh
```
---
## 脚本一:extract_audio.py
### 用法
```bash
python3 extract_audio.py <source> [选项]
```
### 参数说明
| 参数 | 简写 | 默认 | 说明 |
|------|------|------|------|
| `source` | - | 必填 | 视频文件路径 或 包含视频的目录 |
| `--output` | `-o` | 与源同目录 | MP3 输出目录 |
| `--manifest` | `-m` | source 目录下 | manifest.json 路径 |
| `--split-size` | - | 不切分 | 视频时长超过此秒数则切分(单位:秒) |
| `--split-segment` | - | 600 | 每个切分片段时长(单位:秒) |
| `--retry-failed` | - | false | 重新处理上次失败的文件 |
| `--status` | - | false | 仅查看进度状态,不执行提取 |
### 使用示例
**1. 处理目录下所有视频**
```bash
python3 extract_audio.py /home/user/videos/
```
**2. 处理单个视频**
```bash
python3 extract_audio.py /home/user/videos/lesson1.mp4
```
**3. 指定 MP3 输出目录**
```bash
python3 extract_audio.py /home/user/videos/ -o /home/user/audio/
```
**4. 超过 1 小时的视频自动切分为 10 分钟片段**
```bash
python3 extract_audio.py /home/user/videos/ --split-size 3600 --split-segment 600
```
**5. 查看进度**
```bash
python3 extract_audio.py /home/user/videos/ --status
```
**6. 重试失败的文件**
```bash
python3 extract_audio.py /home/user/videos/ --retry-failed
```
### 输出规格(FFmpeg 参数)
```
-vn 去除视频轨道
-acodec libmp3lame MP3 编码
-ab 64k 比特率 64kbps
-ar 22050 采样率 22050Hz
-ac 1 单声道
```
> **场景优化**:这套参数针对语音课程/讲座优化,体积约为原视频的 **20%**,同时保留清晰的人声。
---
## 脚本二:transcribe_audio.py
### 用法
```bash
python3 transcribe_audio.py <source> [选项]
python3 transcribe_audio.py --preload-models # 仅下载模型(source 可省略)
```
### 参数说明
| 参数 | 简写 | 默认 | 说明 |
|------|------|------|------|
| `source` | - | 见备注 | MP3 文件路径 或 包含音频的目录 |
| `--output` | `-o` | 与源同目录 | TXT 输出目录 |
| `--manifest` | `-m` | source 目录下 | manifest.json 路径 |
| `--model` | - | `base` | Whisper 模型:`tiny/base/small/medium`(4 选一) |
| `--language` | - | 自动检测 | 语言代码。推荐 **`zh`**(中文)或 **`en`**(英文) |
| `--all-models` | - | false | 每个音频用**全部 4 个模型**转录,输出 `<stem>.<model>.txt` |
| `--output-suffix` | - | 空 | 输出 txt 附加后缀:`<stem><suffix>.txt` |
| `--split-size` | - | 不切分 | 音频超过此秒数则切分(需要 ffmpeg) |
| `--split-segment` | - | 1800 | 每个切分片段时长(单位:秒) |
| `--retry-failed` | - | false | 重新处理上次失败的文件 |
| `--status` | - | false | 仅查看进度状态 |
| `--preload-models` | - | false | 预下载全部支持模型,无需 source |
> **备注**:`--preload-models` 或 `--status` 模式下可省略 `source`。
### Whisper 模型选择
| 模型 | 参数量 | 磁盘 | 显存 | CPU 转录 890s 音频 | 中文精度 | 语言输出 |
|------|--------|------|------|------|------|------|
| `tiny` | 39M | ~75MB | ~1GB | **47s** | ⭐⭐ | 繁体 |
| `base` | 74M | ~140MB | ~1GB | **58s** | ⭐⭐⭐ | 简体 |
| `small` | 244M | ~460MB | ~2GB | **93s** | ⭐⭐⭐⭐ | 简体 |
| `medium` | 769M | ~1.5GB | ~5GB | **170s** | ⭐⭐⭐⭐⭐ | 简体 + 标点 |
> **实测数据来源**:本项目 [测试报告](#测试报告)(14 分 50 秒中文课程视频)
> **推荐**:日常速稿用 `base`,重要内容用 `medium`。
### 使用示例
**1. 转录目录下所有 MP3(默认 base 模型)**
```bash
python3 transcribe_audio.py /home/user/audio/
```
**2. 中文课程使用 medium 模型(高精度)**
```bash
python3 transcribe_audio.py /home/user/audio/ --model medium --language zh
```
**3. 一次跑 4 个模型对比精度**
```bash
python3 transcribe_audio.py /home/user/audio/ --all-models --language zh
```
**4. 预下载模型(首次安装后一次性下载全部)**
```bash
python3 transcribe_audio.py --preload-models
```
**5. 自定义输出后缀(避免覆盖)**
```bash
# 用 base 模型转录,输出为 <stem>_v1.txt
python3 transcribe_audio.py /home/user/audio/ --model base --output-suffix _v1
# 稍后再用 base + 不同参数转录,输出为 <stem>_v2.txt(不覆盖 v1)
python3 transcribe_audio.py /home/user/audio/ --model base --output-suffix _v2
```
**6. 超长音频(>30 分钟)切分转录**
```bash
python3 transcribe_audio.py /home/user/audio/ \
--model medium --language zh \
--split-size 1800 --split-segment 600
```
**7. 查看进度(含每个模型的记录)**
```bash
python3 transcribe_audio.py /home/user/audio/ --status
```
**8. 重试失败的文件**
```bash
python3 transcribe_audio.py /home/user/audio/ --retry-failed
```
---
## 多模型精度对比
### 实测样本
- **音频**:SketchUp 软件优化设置课程(14 分 50 秒,中文普通话)
- **命令**:`python3 transcribe_audio.py <mp3> --all-models --language zh`
### 精度对比(关键词识别)
| 关键词 | 原意 | tiny | base | small | medium |
|--------|------|------|------|-------|--------|
| SketchUp 中文名 | 草图大师 | 草毒大師 ❌ | 吵毒大师 ❌ | 草读大师 ❌ | 草毒大师 ❌ |
| 出厂设置 | 常规的设置 | 殘酷 ❌ | 残酷 ❌ | 常规 ✅ | 常规 ✅ |
| 行业 | 行业 | 含業 ❌ | 行业 ✅ | 行业 ✅ | 行业 ✅ |
| 轮廓线 | 轮廓线 | 能夠像 ❌ | 能扩限 ❌ | 轮廓线 ✅ | 轮廓线 ✅ |
| 场景 | 场景 | 殘景 ❌ | 场景 ✅ | 场景 ✅ | 场景 ✅ |
| 输出语言 | 简体中文 | **繁体** ⚠️ | 简体 ✅ | 简体 ✅ | 简体 ✅ |
| 标点符号 | 有 | 无 ❌ | 无 ❌ | 少量 ⚠️ | 有 ✅ |
### 各模型样例输出(首行)
**原音频**:"大家好,这一节我们对**草图大师**来进行一个软件的一些优化设置方面的一些操作"
| 模型 | 输出 | 备注 |
|------|------|------|
| tiny | 大家好,這一節我們對**草毒大師**來進行一個軟件的一些優化設置方面的一些操作 | 繁体,专有名词错 |
| base | 大家好,这一节我们对**吵毒大师**来进行一个软件的一些优化设置方面的一些操作 | 简体,专有名词错 |
| small | 大家好,这一节我们对**草读大师**来进行一个软件的一些优化设置方面的一些操作 | 简体,专有名词接近 |
| medium | 大家好,这一节我们对**草毒大师**来进行一个软件的一些优化设置方面的一些操作 | 简体,专有名词接近,有逗号 |
### 结论
| 场景 | 推荐模型 |
|------|----------|
| 快速内容概览、草稿 | **tiny** 或 **base**(快,可接受) |
| 日常转录、笔记 | **base** 或 **small**(平衡) |
| 正式转录、发布 | **medium**(最好精度) |
| 专有名词很多的领域 | 结合 `--initial_prompt` 或人工校对 |
> **提示**:所有 whisper 模型对**专有名词**(品牌名、人名、技术术语)识别都容易出错。生产环境建议:
> 1. 使用 medium 模型
> 2. 通过 `whisper --initial_prompt "本视频讨论 SketchUp / 草图大师"` 提示 whisper(本脚本暂未透传此参数,可直接调 whisper CLI)
> 3. 人工二次校对
---
## Manifest 文件说明
两个脚本**共享同一个 `manifest.json`**,通过 key 前缀区分:
- **视频提取记录**:key = 视频绝对路径
- **音频转录记录**:key = `transcribe:<model>[:<suffix>]:<音频绝对路径>`
### key 结构详解
| Key 格式 | 场景 |
|---------|------|
| `/path/to/x.mp4` | 视频提取记录 |
| `transcribe:tiny:/path/to/x.mp3` | tiny 模型转录(无 suffix) |
| `transcribe:medium:/path/to/x.mp3` | medium 模型转录(无 suffix) |
| `transcribe:base:_v1:/path/to/x.mp3` | base 模型 + `_v1` 后缀 |
| `transcribe:base:_v2:/path/to/x.mp3` | base 模型 + `_v2` 后缀 |
多个 key 可并存于同一 manifest,互不覆盖。
### manifest.json 完整示例(含多模型对比)
```json
{
"version": 1,
"files": {
"/path/to/lesson1.mp4": {
"audio_extracted": true,
"audio_path": "/path/to/lesson1.mp3",
"split_segments": [],
"error": null,
"updated_at": "2026-08-23T10:30:00"
},
"transcribe:tiny:/path/to/lesson1.mp3": {
"transcribed": true,
"txt_path": "/path/to/lesson1.tiny.txt",
"split_segments": [],
"model": "tiny",
"language": "zh",
"output_suffix": null,
"error": null,
"updated_at": "2026-08-23T10:35:00"
},
"transcribe:medium:/path/to/lesson1.mp3": {
"transcribed": true,
"txt_path": "/path/to/lesson1.medium.txt",
"split_segments": [],
"model": "medium",
"language": "zh",
"output_suffix": null,
"error": null,
"updated_at": "2026-08-23T10:50:00"
}
}
}
```
### 字段说明
**视频提取记录字段**
- `audio_extracted` - 是否已提取音频(布尔)
- `audio_path` - 生成的 MP3 路径(切分模式下为第一个片段)
- `split_segments` - 切分片段列表(非切分模式为空)
- `error` - 失败时的错误信息,成功为 `null`
- `updated_at` - 最后更新时间(ISO 8601)
**音频转录记录字段**
- `transcribed` - 是否已转录(布尔)
- `txt_path` - 生成的 TXT 路径
- `split_segments` - 切分片段列表
- `model` - 使用的 whisper 模型(`tiny/base/small/medium`)
- `language` - 使用的语言代码(`zh/en/...`)或 `null`(自动检测)
- `output_suffix` - 输出后缀(默认 `null`)
- `error` - 失败错误信息
- `updated_at` - 最后更新时间
### 断点续传逻辑
脚本判断是否需要处理某文件时,**同时校验**:
1. manifest 中标记为已完成
2. 目标文件实际存在且非空
**任一条件不满足则重新处理**(例如手动删除了 mp3 后重跑,会重新提取)。
**多模型模式**:每个 (音频 × 模型 × 后缀) 组合独立跟踪。已完成的组合被跳过,未完成的继续。
---
## 高级用法
### 1. 完整流水线脚本
```bash
#!/bin/bash
VIDEO_DIR="/path/to/videos"
echo "=== Step 0: 预下载模型(仅首次)==="
python3 transcribe_audio.py --preload-models
echo "=== Step 1: 提取音频 ==="
python3 extract_audio.py "$VIDEO_DIR" --split-size 3600 --split-segment 600
echo "=== Step 2: 转录文字(medium 模型高精度)==="
python3 transcribe_audio.py "$VIDEO_DIR" \
--model medium --language zh \
--split-size 1800 --split-segment 600
echo "=== Step 3: 查看最终状态 ==="
python3 extract_audio.py "$VIDEO_DIR" --status
python3 transcribe_audio.py "$VIDEO_DIR" --status
```
### 2. 多模型对比工作流
```bash
# 1) 提取音频
python3 extract_audio.py /videos/
# 2) 一次跑 4 个模型(此步骤会跑 4x 时长,请预留时间)
python3 transcribe_audio.py /videos/ --all-models --language zh
# 3) 查看所有结果
python3 transcribe_audio.py /videos/ --status
# 4) 对比不同模型输出(例如用 diff)
diff /videos/lesson1.base.txt /videos/lesson1.medium.txt
```
### 3. 独立分离 MP3 与 TXT 输出
```bash
python3 extract_audio.py /videos/ -o /audios/
python3 transcribe_audio.py /audios/ -o /transcripts/ --model medium
```
### 4. 自定义 manifest 位置(多套并行)
```bash
python3 extract_audio.py /videos/ -m /var/run/task1_manifest.json
python3 extract_audio.py /videos2/ -m /var/run/task2_manifest.json
```
### 5. 同一模型不同参数的多轮转录
```bash
# 第一版:自动检测语言
python3 transcribe_audio.py audio.mp3 --model base --output-suffix _auto
# 第二版:强制中文
python3 transcribe_audio.py audio.mp3 --model base --language zh --output-suffix _zh
# 两个 txt 独立保存,manifest 各自记录
ls audio_*.txt
# audio_auto.txt audio_zh.txt
```
---
## 故障排查
### FFmpeg 相关
| 症状 | 原因 | 解决 |
|------|------|------|
| 未找到 ffmpeg 命令 | 未安装 | `sudo apt install ffmpeg` |
| 视频时长为 0 | ffprobe 无法解析 | 检查视频是否损坏 `ffprobe <file>` |
| 切分片段为空 | 编码不兼容 codec copy | 手动尝试 `ffmpeg -i in.mp4 -c copy out.mp4` |
### Whisper 相关
| 症状 | 原因 | 解决 |
|------|------|------|
| 未找到 whisper 命令 | 未安装 | `pip install openai-whisper` |
| 首次转录卡住 | 正在下载模型 | 提前用 `--preload-models` 一次下完 |
| CUDA out of memory | 显存不足 | 使用更小模型;whisper 自动 fallback 到 CPU |
| 转录内容为繁体 | tiny 模型对中文倾向输出繁体 | 使用 `base` 及以上模型 |
| 专有名词识别错 | 模型未训练过 | 使用 `medium`;未来可支持 `--initial-prompt` |
### Manifest 相关
| 症状 | 解决 |
|------|------|
| 想强制重跑所有文件 | 删除 `manifest.json` |
| 想强制重跑某个文件 | 编辑 manifest 或删除对应 `.mp3/.txt` 文件 |
| 想重跑失败的文件 | 加 `--retry-failed` 参数 |
| 想同一音频用同模型换参数再跑一次 | 用 `--output-suffix` 区分 |
### 文件名相关
- 中文文件名:完全支持
- 空格文件名:完全支持(内部用 subprocess 参数列表,非 shell 拼接)
- 特殊字符(如 `&`、`|`):应可正常处理,遇到问题请提 issue
---
## 测试报告
### 测试环境
- OS: Ubuntu 22.04 (WSL2 on Windows)
- Python: 3.13
- FFmpeg: 6.0
- Whisper: 20250625 (全部 4 个模型)
### 测试用例
**测试视频**:`03-SU软件的优化设置.mp4`
- 时长:890 秒(14 分 50 秒)
- 大小:37 MB
- 视频:H.264 1280x720
- 音频:AAC 44.1kHz 立体声
- 语言:中文(普通话)
- 内容:SketchUp 软件优化设置教学
### 提取音频 & 通用功能测试
| # | 测试项 | 结果 | 耗时 | 备注 |
|---|--------|------|------|------|
| 1 | 基本音频提取 | ✅ | 4s | 输出 6.9MB MP3 (22050Hz mono 64kbps) |
| 2 | 断点续传(重跑跳过) | ✅ | <1s | manifest 校验通过 |
| 3 | `--status` 状态查看 | ✅ | <1s | 正确显示 1/1 完成 |
| 4 | 视频切分模式(500s 阈值) | ✅ | 4s | 3 片段完美衔接(修复 pipe:0 bug) |
| 5 | 失败重试 + 含空格文件名 | ✅ | - | 失败记录、跳过、`--retry-failed` 均正常 |
| 6 | 端到端流水线(视频→MP3→TXT) | ✅ | 54s | 从零开始生成完整产物 |
### 转录 & 多模型功能测试
| # | 测试项 | 结果 | 耗时 | 备注 |
|---|--------|------|------|------|
| 7 | `--preload-models` 预下载 4 模型 | ✅ | ~120s | 共 2.1GB,缓存到 `~/.cache/whisper/` |
| 8 | 单模型转录(tiny + zh) | ✅ | 47s | 输出 9KB TXT |
| 9 | 单模型转录(base + zh) | ✅ | 58s | 输出 9KB TXT |
| 10 | 单模型转录(small + zh) | ✅ | 93s | 输出 9KB TXT |
| 11 | 单模型转录(medium + zh) | ✅ | 170s | 输出 9KB TXT,有标点符号 |
| 12 | `--all-models` 4 模型一次跑 | ✅ | 368s | 生成 4 个独立 txt |
| 13 | 多模型 manifest 记录 | ✅ | - | 4 条独立 key,互不覆盖 |
| 14 | 多模型 `--status` 展示 | ✅ | <1s | 每个模型独立行显示 |
| 15 | 断点续传(重跑跳过) | ✅ | <1s | 4/4 全部跳过 |
| 16 | `--output-suffix` 自定义后缀 | ✅ | 46s | `_custom` 生成独立 key + 独立 txt |
| 17 | 音频切分转录 | ✅ | 59s | 3 片段并转录后合并成完整 TXT |
| 18 | manifest 共享验证 | ✅ | - | 提取+转录记录并存互不干扰 |
### 已修复 Bug
**BUG-01**:切分模式下 MP3 为空文件(148 字节)
- **原因**:使用 `cat <file> | ffmpeg -i pipe:0` 时,MP4 的 `moov` atom 位于文件末尾需要 seek,pipe 不支持 seek 导致 ffmpeg 静默失败
- **修复**:改用 `ffmpeg -i <file>` 直接读取本地文件,同时增加输出文件非空校验(> 1KB)
- **验证**:切分后 3 个片段合计 890.4s ≈ 原视频 890.2s
**BUG-02**:`--output-suffix` 被 manifest 误跳过
- **原因**:初版 manifest key 只含 `model + path`,未含 `output_suffix`,导致同一模型换 suffix 后被判定为已完成
- **修复**:key 结构改为 `transcribe:<model>[:<suffix>]:<path>`,suffix 参与 key 判定
- **验证**:同一 tiny 模型,无 suffix 和 `_custom` suffix 生成独立 manifest 条目和独立 txt
### 性能参考(本次测试环境,CPU 转录)
| 阶段 | 输入 | 输出 | 耗时 | 吞吐 |
|------|------|------|------|------|
| 音频提取 | 37MB / 890s 视频 | 6.9MB MP3 | 4s | 223x realtime |
| 转录(tiny) | 6.9MB / 890s 音频 | 9KB TXT | 47s | 19x realtime |
| 转录(base) | 6.9MB / 890s 音频 | 9KB TXT | 58s | 15x realtime |
| 转录(small) | 6.9MB / 890s 音频 | 9KB TXT | 93s | 9.6x realtime |
| 转录(medium) | 6.9MB / 890s 音频 | 9KB TXT | 170s | 5.2x realtime |
| **多模型一次跑(4 model)** | 6.9MB / 890s 音频 | 4 个 9KB TXT | 368s | - |
> 上述数据为 CPU 转录性能。GPU 转录速度可提升 5-10x。
---
## 项目路线图
- [x] Phase 1: 音频提取(extract_audio.py)
- [x] Phase 2: 音频转录(transcribe_audio.py)
- [x] 单模型转录
- [x] 多模型批量对比(`--all-models`)
- [x] 模型预下载(`--preload-models`)
- [x] 输出后缀自定义(`--output-suffix`)
- [x] 语言指定(`--language zh/en`)
- [ ] Phase 3: 内容归纳整理(summarize.py)- 待定
- AI 分析文字内容 + 视频内容
- 生成脑图、结构化文档
---
## 相关脚本
- `nas_audio_extract_v3.py` - 针对 NAS 场景的原始脚本(通过 SSH 直接处理群晖 NAS 上的视频)
- `extract_audio.py` - 本地通用视频音频提取(本项目 Phase 1)
- `transcribe_audio.py` - 本地音频转录(本项目 Phase 2)