Files
atlas/synthmind/README.md

632 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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)