来源:notes/projects/audio_transcription_workflow/01_长音频转写与博客同步流程.md

长音频转写与博客同步流程

背景

2026-06-10 收到音频附件:

/home/admin/code/cc-connect-work-space/.cc-connect/attachments/地平线机器人202606.10.mp3

目标是先分析音频,再生成带时间戳逐字稿,写入个人助理,并同步到 GitHub Pages 博客。

音频基本信息

检查命令:

file .cc-connect/attachments/地平线机器人202606.10.mp3
ffprobe -v error \
  -show_entries format=duration,bit_rate,size \
  -show_entries stream=codec_name,channels,sample_rate \
  -of default=noprint_wrappers=1 \
  .cc-connect/attachments/地平线机器人202606.10.mp3

结果:

  • 格式:MP3
  • 采样率:44.1 kHz
  • 声道:Stereo
  • 码率:128 kbps
  • 时长:约 3247.78 秒,约 54 分 08 秒
  • 文件大小:约 51.97 MB

环境检查

系统已有:

ffmpeg

系统没有现成语音识别库:

whisper
faster_whisper
whisperx
torch
torchaudio
transformers
speech_recognition
vosk
funasr

全局 Python 受 PEP 668 保护,不能直接 pip install --user。因此创建项目内临时虚拟环境:

python3 -m venv .venv-transcribe
.venv-transcribe/bin/pip install -U pip

Whisper 路线尝试

先安装 faster-whisper

.venv-transcribe/bin/pip install faster-whisper

安装成功,但模型下载走 Hugging Face,访问 huggingface.co 超时:

curl -I --max-time 10 https://huggingface.co/Systran/faster-whisper-small/resolve/main/config.json

结果是连接超时。因此放弃 Whisper 模型下载路线。

FunASR 路线

ModelScope 可访问:

curl -I --max-time 10 https://modelscope.cn/models/iic/SenseVoiceSmall/summary

安装 FunASR 和 ModelScope:

.venv-transcribe/bin/pip install funasr modelscope

FunASR 需要 PyTorch 和 torchaudio,安装 CPU 版:

.venv-transcribe/bin/pip install torch --index-url https://download.pytorch.org/whl/cpu
.venv-transcribe/bin/pip install torchaudio --index-url https://download.pytorch.org/whl/cpu

最终关键依赖:

  • funasr
  • modelscope
  • torch
  • torchaudio
  • ffmpeg

模型选择

使用模型:

iic/SenseVoiceSmall

原因:

  • 适合中文、英文混合音频。
  • 可从 ModelScope 下载,避开 Hugging Face 超时问题。
  • CPU 推理可接受,约 2 分钟音频片段推理 13-14 秒。

模型权重约 893 MB,首次运行会下载到:

/home/admin/.cache/modelscope/hub/models/iic/SenseVoiceSmall

样本验证

先截取前 60 秒验证模型可用:

mkdir -p .cc-connect/tmp
ffmpeg -y -v error \
  -i .cc-connect/attachments/地平线机器人202606.10.mp3 \
  -t 60 -ar 16000 -ac 1 \
  .cc-connect/tmp/horizon_sample60.wav

测试脚本:

from funasr import AutoModel

model = AutoModel(model="iic/SenseVoiceSmall", hub="ms", device="cpu")
res = model.generate(
    input=".cc-connect/tmp/horizon_sample60.wav",
    language="zh",
    use_itn=True,
    batch_size_s=60,
)
print(res)

样本识别成功,确认音频开头是地平线机器人 2026 年股东周年大会的英文开场。

完整转写策略

长音频直接转写不利于定位问题,因此先用 ffmpeg 切成 120 秒小片段:

ffmpeg -y -v error \
  -i .cc-connect/attachments/地平线机器人202606.10.mp3 \
  -ar 16000 -ac 1 \
  -f segment -segment_time 120 -reset_timestamps 1 \
  .cc-connect/tmp/horizon_chunks/chunk_%03d.wav

完整转写脚本逻辑:

  1. 加载 SenseVoiceSmall
  2. 逐个识别 120 秒音频片段。
  3. 去掉 FunASR 输出里的 <|...|> 标签。
  4. 给每个片段加粗略时间戳。
  5. 输出 TXT 和 JSONL。

关键输出:

.cc-connect/attachments/地平线机器人202606.10.funasr.transcript.txt
.cc-connect/attachments/地平线机器人202606.10.funasr.segments.jsonl

逐字稿写入个人助理

正式笔记位置:

codex_personal_assistant/notes/projects/地平线机器人20260610股东大会/01_逐字稿.md

源材料位置:

codex_personal_assistant/notes/projects/地平线机器人20260610股东大会/source_materials/

写入内容包括:

  • 音频来源
  • 音频时长
  • 转写方式
  • 校对状态
  • 内容概览
  • 分段摘要
  • 带时间戳逐字稿
  • 下一步动作

后续为了避免博客文章变成一大坨,又做了一次格式化:

  • 按时间段增加章节标题。
  • 每个章节增加“本段摘要”。
  • 每条 2 分钟转写段之间增加空行。
  • 校验所有时间戳逐字稿行与原 ASR 源文本完全一致,没有改动逐字稿原文。

校验脚本:

from pathlib import Path

note = Path("codex_personal_assistant/notes/projects/地平线机器人20260610股东大会/01_逐字稿.md")
src = Path("codex_personal_assistant/notes/projects/地平线机器人20260610股东大会/source_materials/地平线机器人202606.10.funasr.transcript.txt")

note_lines = [line for line in note.read_text(encoding="utf-8").splitlines() if line.startswith("[")]
src_lines = [line for line in src.read_text(encoding="utf-8").splitlines() if line.startswith("[")]

print(note_lines == src_lines)

飞书同步

创建飞书 Docs 文档:

lark-cli docs +create \
  --api-version v2 \
  --as user \
  --content @codex_personal_assistant/notes/projects/地平线机器人20260610股东大会/01_逐字稿.md \
  --doc-format markdown \
  --parent-position my_library \
  --format json

最终格式化版飞书文档:

https://my.feishu.cn/docx/JX27d4h99ojvvYxB3h5cmXmFnLe

回填到:

codex_personal_assistant/config/feishu_base.json

然后同步多维表格:

cd codex_personal_assistant
python3 scripts/sync_to_feishu_base.py

同步范围包括:

  • 待办事项
  • 每日记录
  • 文档资产
  • 知识索引
  • 阅读书籍

博客同步

博客仓库:

/home/admin/code/cc-connect-work-space/andywu1998.github.io

同步命令:

cd /home/admin/code/cc-connect-work-space/andywu1998.github.io
scripts/sync_personal_assistant_notes.sh

该脚本会:

  1. ../codex_personal_assistant/notes 导入 Markdown。
  2. 生成 Jekyll _posts
  3. 提交 _posts
  4. 推送到 GitHub Pages 仓库。

本次逐字稿博客文件:

andywu1998.github.io/_posts/2026-06-10-地平线机器人-2026-06-10-股东周年大会逐字稿.md

最终博客提交:

0b731c0 2026-06-10 sync

踩坑记录

1. 全局 pip 受保护

全局 Python 环境受 PEP 668 管理,直接安装失败。解决方式是创建 .venv-transcribe

2. Hugging Face 超时

faster-whisper 本身安装成功,但模型无法从 Hugging Face 下载。解决方式是改用 ModelScope 上的 FunASR/SenseVoiceSmall。

3. FunASR 没有自动安装 torch

安装 FunASR 后导入失败:

ModuleNotFoundError: No module named 'torch'

解决方式是安装 CPU 版 torchtorchaudio

4. 飞书 Docs 更新命令参数不稳定

lark-cli docs +update 的帮助与实际校验不一致,要求内部 --command 参数但帮助没有列出。最终处理方式是重新创建格式化版飞书文档,并把配置链接替换成新文档。

5. Markdown 只有单换行会在博客里显示成大段

原始逐字稿每条记录只有单换行,Jekyll 渲染后阅读体验差。解决方式是在每条时间戳片段之间增加空行,并按主题加入二级分段。

可复用 SOP

  1. 检查音频格式和时长。
  2. 如果本机没有 ASR 环境,创建 .venv-transcribe
  3. 优先尝试可访问的模型源;当前环境推荐 ModelScope + FunASR。
  4. 先截取 60 秒样本验证。
  5. 对长音频按 120 秒切片。
  6. 逐片识别并生成带时间戳 TXT/JSONL。
  7. 把正式逐字稿写入 codex_personal_assistant/notes/projects/<主题>/01_逐字稿.md
  8. 将原始 ASR 文件放入 source_materials/
  9. 增加分段标题、段落摘要和空行,但不要改逐字稿原文。
  10. 创建飞书 Docs 文档,回填 config/feishu_base.json
  11. 运行 python3 scripts/sync_to_feishu_base.py
  12. 运行博客同步脚本 scripts/sync_personal_assistant_notes.sh

下一步动作

  • 把完整转写脚本整理成个人助理或 cc-connect 的可复用脚本,减少下次手工命令。
  • 增加“逐字稿格式化器”:自动按时间段插入标题、摘要和空行,并校验原文未变。
  • 评估是否需要更高质量的二次校对流程,例如对关键问答片段单独复听修正。