前言

记录把一条美食教学视频整理成一篇可以阅读、复做、发布到博客的结构化文章项目的实现流程。

例如 YouTube 视频、本地视频、本地 rmvb/mp4/mkv 文件等。它会先把视频里的内容转成文字,再用大模型整理成菜谱文章,最后生成 AI 封面并上传到图床。最终产物可以直接复制到 Hexo博客里发布。

目前核心功能包括:

  • 处理单条 YouTube 视频。
  • 批量展开 YouTube 频道、播放列表、频道 videos 页面。
  • 处理单个本地视频或音频。
  • 批量扫描本地视频目录。
  • 优先读取 YouTube 字幕,没有字幕时自动下载音频并转写。
  • 支持 FunASR 和 Whisper 两种 ASR 路线。
  • 用提示词把转写稿整理成结构化文章。
  • 为文章生成 AI 封面图。
  • 上传封面到 EasyImage 图床,并回写文章 cover 字段。
  • 支持断点续跑、批量报告、局部问题提示。
  • 支持从已有 raw.md 补跑文章,或者只重生成封面。

它不是单纯的“视频摘要工具”,而是偏向“内容生产流水线”:输入视频,输出博客文章和配套静态资源。

它适合处理这类场景:

  • 视频内容有价值,但不方便反复看。
  • 视频步骤很多,需要整理成可查阅文档。
  • 视频标题和封面信息太杂,需要生成干净博客文章。
  • 想把公开视频、本地课程或资料视频批量整理成知识库。
  • 想把内容发布到静态博客,而不是只留在本地文件夹。

我现在把它用于“一览美食”博客:把美食教学视频整理成可复做菜谱,让读者不必在视频里来回拖进度条,也能快速看到食材、步骤和关键技巧。
演示地址:https://cook.yilanapp.com

用到的模型

项目里模型分三类:语音转文字、文章整理、封面生成。

语音转文字

默认使用 FunASR:

1
2
3
4
{
"asr_engine": "funasr",
"funasr_model": "sensevoice"
}

模型文件默认缓存到项目目录下:

1
2
3
4
5
6
models/
funasr/
models/
iic/
SenseVoiceSmall/
speech_fsmn_vad_zh-cn-16k-common-pytorch/

第一次使用 FunASR 转写时,如果本地没有模型,会通过 ModelScope 自动下载到这个目录。后续再次运行时,项目会优先使用本地已有模型目录,尽量避免因为 ModelScope 临时超时而影响转写。换电脑时也可以把 models\funasr 整个目录迁移过去,减少首次下载等待。

可替代方案:

  • paraformer:同样属于 FunASR 路线,可以作为中文 ASR 备选。
  • whisper:项目里支持 tiny/base/small,通过 faster-whisper 调用,更适合作为备选或对照。

如果主要处理中文教程视频,优先选 FunASR + SenseVoiceSmall;如果是多语言视频,或者 FunASR 对某些音频表现不稳定,再考虑 Whisper。

文章整理

文章整理使用大模型的 Chat Completions 接口。配置示例是 OpenAI 兼容接口:

1
2
3
4
5
{
"provider": "openai",
"base_url": "https://api.openai.com/v1",
"model": "gpt-4o-mini"
}

AI 封面生成

封面生成支持两条路线。

配置模板里默认是 ModelScope:

1
2
3
4
5
{
"provider": "modelscope",
"model": "Qwen/Qwen-Image",
"edit_model": "Qwen/Qwen-Image-Edit-2511"
}

也支持 OpenAI 兼容生图接口:

1
2
3
4
5
{
"provider": "openai",
"model": "你的图片生成模型",
"base_url": "你的 OpenAI 兼容生图接口"
}

封面生成的重点不是照搬视频封面,而是根据菜品主体重新生成一张干净的成品菜图。项目会尽量避免文字、水印、拼贴图、视频缩略图风格,目标是适配博客 16:9 封面。

如果原始缩略图本身比较干净,项目会把它作为菜品主体参考,在构图、光线、质感上重新生成。如果原图有大字、水印、拼贴或视频感很重,就只参考食物主体,不保留原封面上的文字元素。

生成后的图片会保存到本地,并可以上传到 EasyImage:

1
2
3
4
5
6
{
"image_host": {
"provider": "easyimage",
"api_url": "https://你的图床域名/api/index.php"
}
}

数据处理流程

整体流程可以理解成下面这条链路:

1
2
3
4
5
6
7
8
9
10
视频链接 / 本地视频
-> 字幕提取或音频提取
-> ASR 转写
-> raw.md 原始转写稿
-> 大模型整理
-> 结构化 Markdown 文章
-> AI 封面生成
-> 图床上传
-> 回写文章 cover
-> 批量报告和问题提示

输入

支持的输入包括:

  • YouTube 单条视频 URL。
  • YouTube 频道、播放列表、频道 videos 页面。
  • 本地视频文件,例如 mp4mkvmovwebmrmrmvb
  • 本地音频文件,例如 mp3wavm4a
  • 批量清单文件,每行一个视频路径或 URL。

中间产物

项目会把中间文件分类保存,避免根目录混乱。

运行数据在 data

1
2
3
4
5
6
7
8
9
10
11
12
data/
cookies/
youtube/
YouTube-频道名/
videos.txt
audio/
VIDEO_ID.mp3
local/
批次目录名/
videos.txt
audio/
菜品名.mp3

YouTube 音频如果已经下载过,后续重跑会优先复用本地 mp3,不必重新从 YouTube 下载。这样下载成功但 ASR、大模型或封面生成失败时,可以直接从中间产物继续补跑。

文章产物在 output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
output/
youtube/
频道名/
_batch_reports/
batch_report_YYYYMMDD-HHMMSS.json
视频标题_VIDEO_ID/
raw.md
文章标题.md
metadata.json
thumbnail.jpg
cover-prompt.txt
cover-ai.jpg
cover-ai.json

local/
批次目录名/
_batch_reports/
batch_report_YYYYMMDD-HHMMSS.json
菜品名/
raw.md
文章标题.md
cover-prompt.txt
cover-ai.jpg
cover-ai.json

也就是说,YouTube 单条视频会按“平台 / 频道 / 视频”保存,本地批量视频会按“平台 / 批次目录 / 菜品”保存。旧版本生成的平铺目录仍可读取,但新的输出会尽量按来源归档。

每个视频目录里常见文件包括:

1
2
3
4
5
6
7
8
视频目录/
raw.md
文章标题.md
cover-prompt.txt
cover-ai.jpg
cover-ai.json
metadata.json
thumbnail.jpg

其中:

  • raw.md 是原始转写稿,后续补跑文章时可以直接复用。
  • 文章标题.md 是最终可发布文章。
  • cover-ai.jpg 是本地 AI 封面图。
  • cover-ai.json 记录生图、上传、回写结果。
  • metadata.jsonthumbnail.jpg 主要出现在 YouTube 视频目录。
  • _batch_reports 保存每次批量处理报告,也会在文章被移动走时辅助判断是否曾经生成成功。

输出

最终最重要的输出是 Markdown 文章。以美食视频为例,文章会包含:

  • Hexo front-matter。
  • 分类、标签、菜系、菜品类型、烹饪方法。
  • 一句话摘要。
  • 做法速览。
  • 食材与配方表。
  • 制作流程 timeline。
  • 关键技巧。
  • 易错点与处理。
  • 营养与食用提醒。
  • 批量制作与出餐建议。
  • AI 封面图链接。

这类结构适合直接发布到 Hexo / 安知鱼主题,也方便后续搜索、分类和归档。

批量处理和断点续跑

常见命令类似:

1
python transcribe.py --batch "data\local\中国八大菜系之川菜-100道\videos.txt" --prompts snack_recipe --limit 10 --skip-existing

几个参数的作用:

  • --limit 10:本次只处理 10 个。
  • --skip-existing:跳过已经完整处理过的条目。
  • --dry-run:只预览,不实际处理。
  • --from-raw:已有 raw.md 时,只补跑大模型整理。
  • --regen-cover:只重新生成封面。

批量计划现在会把状态分得更细:

1
2
3
4
5
6
output 完整:raw.md 和正式文章都存在,文章结构校验通过
报告记录完成:raw.md 仍在,文章可能已被移动到博客目录,但同批次报告证明曾经成功生成
待补文章:已有 raw.md,但缺少正式文章
文章待重整:文章存在,但结构质检未通过
未处理:没有 raw.md
待确认标题:YouTube 标题预取失败,需要实际处理时再确认

这里的 _batch_reports 不会替代输出文件判断,也不会去扫描 Hexo 博客目录。它只在一个场景下辅助判断:raw.md 还在,但正式文章已经被移动到博客目录,报告能证明这个视频曾经生成过文章。这样批量续跑时不会反复把同一个视频当成未完成。

批量结束后会生成报告,记录成功、失败、局部问题和补救命令。局部问题包括封面生成失败、图床上传失败、文章缺 cover 等。

常见补救命令有两类。

如果 ASR 已完成,但大模型整理失败,可以从 raw.md 补跑:

1
python transcribe.py --from-raw "output\local\批次目录名\菜品名\raw.md" --prompts snack_recipe

如果文章已经生成,但 AI 封面或图床上传失败,可以只补封面:

1
python transcribe.py --regen-cover "output\local\批次目录名\菜品名\文章标题.md"

这两个命令都不会重新处理视频。前者复用原始转写稿,后者只处理封面生成、上传和文章 cover 回写。

提示词如何扩展

项目的提示词放在:

1
2
3
4
5
prompts/
format.md
summary.md
evaluation.md
snack_recipe.md

现在美食文章主要使用:

1
prompts/snack_recipe.md

如果要扩展到其他类型视频,不需要重写主程序,优先新增提示词即可。

例如:

1
2
3
4
prompts/tutorial_note.md       # 教程视频整理
prompts/course_summary.md # 课程总结
prompts/memory_archive.md # 家庭影像/回忆整理
prompts/tool_review.md # 工具测评整理

然后运行:

1
python transcribe.py --url "视频地址" --prompts tutorial_note

提示词里需要定义:

  • 输入转写稿如何理解。
  • 输出文章结构。
  • 是否需要 front-matter。
  • 是否需要表格、步骤、清单。
  • 哪些内容不能编造。
  • 哪些不确定内容要标注。

也就是说,项目底层是通用的视频转写和内容整理管线,美食只是当前最完整的一套提示词模板。

可以扩展到哪些方向

视频平台扩展

当前代码已经区分了:

  • YouTube
  • Bilibili
  • Local
  • Unknown

YouTube 已经支持字幕提取、频道/播放列表展开、cookies 登录态。B 站目前有搜索入口,后续可以继续补全单视频下载、合集展开等能力。

如果要加新平台,大致需要补:

  • 平台识别规则。
  • 元数据提取。
  • 音频下载或字幕提取。
  • 批量列表展开。
  • 失败诊断和 cookies 处理。

视频类型扩展

除了美食视频,还可以扩展到:

  • 编程教程。
  • 软件教学。
  • 课程视频。
  • 会议纪要。
  • 访谈整理。
  • 家庭影像回忆总结。
  • 产品测评。
  • 读书视频笔记。

扩展的关键不是改 ASR,而是改提示词和输出结构。

例如教程视频可以输出:

  • 学习目标。
  • 前置知识。
  • 操作步骤。
  • 命令清单。
  • 常见错误。
  • 复习提纲。

访谈视频可以输出:

  • 嘉宾观点。
  • 时间线。
  • 关键引用。
  • 主题归纳。
  • 延伸问题。