# digest-video **Repository Path**: Humoonruc/digest-video ## Basic Information - **Project Name**: digest-video - **Description**: B站视频AI字幕提取 + LLM摘要生成 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-06 - **Last Updated**: 2026-07-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # digest-video — B 站视频 AI 字幕提取 + LLM 自动总结 输入 B 站视频链接,自动提取 AI 字幕,调用大模型生成结构化总结,输出 Markdown 并支持 SQLite 归档。 ## 解决的问题 深度评论分析类视频越来越多,但看视频太费时间。本工具自动化"字幕提取 → LLM 总结 → 结构化输出"全流程,帮你快速获取核心观点。 ## 工作流程 ``` 添加 URL → prefetch 获取元信息 → run 批量处理 → normalize 格式修正 → archive 归档 SQLite B站链接 → 提取 BV 号 → API/Playwright 获取 AI 字幕 → LLM 单次调用 → normalize 自动修正格式 → video_news.md → 周末 archive 入库 ``` ## 项目结构 ``` digest-video/ ├── cli.py # 命令行入口(run / prefetch / archive / list) ├── config.toml # LLM、B站、输出路径配置 ├── .env # API Key(不入 git) ├── pyproject.toml # 项目元数据 + pip install -e . ├── run.bat # Windows 日常脚本:prefetch → run ├── weekend.bat # Windows 周末脚本:archive 归档 ├── input/ │ ├── urls.txt # 待添加的 URL 列表(prefetch 后清空) │ └── videos.json # 视频元信息缓存 + processed 标记 ├── prompt/ │ └── prompt_combined.md # LLM 提示词模板(组合式:总结+精简+元数据) ├── src/ │ ├── main.py # 流水线编排器(单视频/批量统一入口) │ ├── context.py # AppContext 数据类 + PROJECT_ROOT │ ├── archive.py # video_news.md → SQLite 归档(UPSERT) │ ├── crawler/ # B 站字幕提取 │ │ ├── bilibili.py # API 方式(httpx,主方案) │ │ └── bilibili_playwright.py # Playwright 浏览器(登录/降级方案) │ ├── pipeline/ # 流水线各阶段 │ │ ├── config.py # 参数解析 + 配置加载 + 路径准备 │ │ ├── prefetch.py # Phase 0:增量预取视频元信息 │ │ ├── subtitle.py # 字幕提取(API → Playwright 自动降级) │ │ ├── summarize.py # LLM 总结调用 │ │ ├── report.py # 输出文件 + 字幕清理 │ │ ├── writer.py # video_news.md 追加 + 排序去重 │ │ ├── normalize.py # LLM 输出格式规范化(自动修正字段漂移) │ │ └── batch.py # 批量处理编排 + profile 缓存清理 │ ├── summarizer/ │ │ └── llm.py # LLM API 调用(流式+心跳、组合输出、分段安全阀) │ └── utils/ │ └── log.py # 终端日志(缩进层级、进度提示、批量汇总) ├── data/ │ ├── subtitles/ # 临时字幕文件(处理后自动清理) │ ├── bilibili_profile/ # Playwright 浏览器持久化登录态 │ └── video_news.db # SQLite 归档数据库 └── output/ └── video_news.md # LLM 总结输出(追加模式,按时间排序去重) ``` ## 快速开始 ### 1. 安装依赖 ```bash pip install -e . playwright install chromium ``` ### 2. 配置 API Key 复制模板并填入你的 LLM API Key: ```bash cp .env.example .env # 编辑 .env:LLM_API_KEY=sk-xxxxxxxxxxxxxxxx ``` 其余配置(api_base、model 等)在 `config.toml` 中,默认已配好 DeepSeek,切换到其他 OpenAI 兼容接口只需修改 `[llm]` 段。 ### 3. 首次登录 B 站(需要获取 AI 字幕时) 部分视频的 AI 字幕需要登录才能获取,首次使用时运行: ```bash python cli.py run --login ``` 会打开有头浏览器,手动登录 B 站后 cookie 持久化到 `data/bilibili_profile/`。**登录态缓存后,后续批量处理自动使用无头模式,浏览器窗口不会弹到屏幕中央遮挡其他程序。** ### 4. 典型使用流程 ```bash # Step 1:把视频链接贴到 input/urls.txt(一行一个) # Step 2:预取视频元信息(增量追加到 input/videos.json) python cli.py prefetch # Step 3:批量处理所有未处理视频 python cli.py run # Step 4(周末执行):归档到 SQLite python cli.py archive ``` ### 5. 命令参考 ```bash # 处理单个视频 python cli.py run BV1xx411c7mD python cli.py run https://www.bilibili.com/video/BV1xx411c7mD # 批量处理 videos.json 中所有未处理视频(默认) python cli.py run # 仅提取字幕,不调用 LLM python cli.py run --no-summary # 强制使用 Playwright 提取 python cli.py run --use-playwright # 自定义配置文件 python cli.py run --config my_config.toml # 自定义输出目录 python cli.py run --output-dir my_output # 预取视频信息(强制刷新全部) python cli.py prefetch --force # 预取但保留 urls.txt 内容 python cli.py prefetch --no-clear # 归档到指定数据库 python cli.py archive --input output/video_news.md --db data/my_archive.db # 归档后不清空源文件 python cli.py archive --no-clear # 查看所有可用命令 python cli.py list ``` ### 6. 重新处理某个视频 只需在 `input/videos.json` 中把对应条目的 `"processed": true` 改为 `false`,然后: ```bash python cli.py run # 重新处理(video_news.md 按链接去重,新覆盖旧) python cli.py archive # 重新归档(SQLite ON CONFLICT DO UPDATE,自动覆盖旧记录) ``` 不需要手动清 `.md` 或 `.db`。 ### 7. Windows 用户 - **日常**:双击 `run.bat`,自动执行 prefetch → run 全流程 - **周末归档**:双击 `weekend.bat`,将本周 `video_news.md` 内容写入 SQLite 数据库并清空 ## 输出说明 ### video_news.md(`output/`) LLM 每次总结以追加方式写入,按视频发布时间降序排列,同链接自动去重。条目以 `## ` 二级标题为边界,之间以空行分隔。写入后自动触发 `normalize.py` 格式规范化(修正 LLM 输出漂移)。每条目包含: - LLM 拟定的精炼标题(`##` 开头) - 12 个元数据字段(`>> 发布时间 / 信源 / 链接 / 领域 / 二级领域 / 三级领域 / 地区 / 摘要 / 关键词 / 文本性质 / 重要性 / 信源倾向`) - 结构化总结(`### 总结`) - 去口水词精简版(`### 正文`) ### SQLite 数据库(`data/video_news.db`) 通过 `python cli.py archive` 将 video_news.md 解析并写入数据库,链接重复时 UPSERT 覆盖。表 `video_entries` 包含 15 个字段——12 个元数据字段 + `总结` + `正文` + `id`。 ## 工作原理 ### 字幕提取(双方案自动降级) **方案 A(API,主路径)**: 1. 从链接提取 BV 号 2. 调用 B 站 API 获取视频信息与字幕列表 3. 下载字幕 JSON,转换为 SRT 和纯文本 4. 内容验证:检查字幕是否与视频标题匹配,防 API 返回错误 CDN URL **方案 B(Playwright 拦截,降级路径)**: 方案 A 失败或 NeedLogin 时自动触发: 1. 复用持久化登录态(`data/bilibili_profile/`)打开视频页,首次有头登录后自动切无头 2. 从 `__INITIAL_STATE__` 提取 aid/cid 3. 通过 `page.request`(共享浏览器 Cookie)调用 player/v2 API 获取字幕 CDN URL 4. 若 CDN URL 返回音乐字幕或质量差,自动触发方案B:悬停 CC 按钮 → 选择「中文 AI 字幕」→ 播放视频 → 拦截 `aisubtitle` 网络请求 批量处理时 Playwright 浏览器窗口通过 `--window-position=-32000,-32000` 移到屏幕外,不遮挡其他程序。处理完成后自动清理 `Cache`、`Code Cache`、`GPUCache` 等缓存目录,仅保留登录态 Cookie。 ### LLM 处理(一次调用完成) - **组合调用**:一次 API 请求同时输出标题、元数据(12字段)、摘要、总结、精简文本 - **Prompt 模板**:`prompt/prompt_combined.md` 包含完整指令和「格式铁律」(输出恰好 12 个 `>>` 字段、字段名不带括号选项、所有字段必有值、以 `## ` 标题开头、不用代码块包裹),末尾附自检清单。`{pubdate}`/`{uploader}`/`{url}` 占位符自动替换 - **流式生成**:终端实时显示心跳 spinner(等待)→ 打点进度(生成中),避免"卡死"错觉 - **长文本安全阀**:>200K 字符的字幕自动分段处理,最后汇总(正常视频几乎不触发此路径) - **字幕质量预检**:自动检测乱码/歌词噪音,异常时标记警告但仍尝试处理 - **配置驱动**:`config.toml [llm]` 段的 `max_tokens` / `temperature` / `timeout` 可灵活调整 ### 输出规范化(自动修正 LLM 格式漂移) LLM 输出偶尔会出现格式偏差,`normalize.py` 在写入 `video_news.md` 后自动执行 5 项修正: 1. **字段名去括号**:`>> 地区(非洲/美洲/...):中国` → `>> 地区:中国` 2. **旧标题统一**:`## 去口水词后的高信息密度文本` → `### 正文` 3. **重复正文合并**:同一条目多个 `### 正文` 节自动合并 4. **缺失字段补全**:缺少 `>> 重要性` 时自动插入 5. **残留分隔线清理**:清除旧的 `---` 分隔线 ### 批量处理流程 ``` input/videos.json(processed: false) ↓ 逐视频处理:API提取字幕 → Playwright降级(如需要)→ LLM组合总结 → 输出 → 标记 processed: true ↓ video_news.md 按发布时间排序去重 ↓ normalize.py 自动修正格式(字段去括号、补全缺失字段等) ↓ 清理 Playwright profile 缓存(保留登录 Cookie) ``` 跳过逻辑:已处理的视频(`"processed": true`)和预取失败的视频(含 `"error"` 字段)自动跳过。 ## 扩展计划 - [ ] 定期自动抓取关注 UP 主的新视频