<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>谷雨的AI实验室</title>
    <link>https://guyuai.me/</link>
    <description>AI / 效率工具资源库：教程、工作流与可下载资源包。</description>
    <language>zh-CN</language>
    <atom:link href="https://guyuai.me/rss.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>把 B 站视频剪藏自动变成逐字稿和带时间戳可跳转的 AI 摘要（vault-ingest agent）</title>
      <link>https://guyuai.me/notes/bilibili-clip-digest-pipeline/</link>
      <guid isPermaLink="true">https://guyuai.me/notes/bilibili-clip-digest-pipeline/</guid>
      <pubDate>Wed, 16 Sep 2026 00:00:00 GMT</pubDate>
      <description>把 B 站视频/网页剪藏自动转成带时间戳的逐字稿和 AI 摘要；字幕优先、ASR 兜底，锚点校验杜绝 AI 编造</description>
      <content:encoded><![CDATA[<p>vault-ingest 是跑在 PARA 知识库里的「视频 / 文章网页剪藏」工作流：把 Obsidian Web Clipper 落在 <code>_Capture/</code> 根目录的 B 站视频与网页剪藏，批量转成「带时间戳逐字稿 + 基于逐字稿的 AI 总结摘要」，写入 <code>_Capture/_Clipper/</code> 文件夹，每周人工归类。确定性脚本（无 LLM）+ 摘要 agent + 手动命令三件套，用锚点强制校验杜绝 AI 编造。</p>
<p>一句话概括：三阶段工作流（prepare 抓取转录 → agent 写摘要 → finalize 校验记账），字幕优先、ASR 兜底，产物落进 git 忽略的 <code>_Clipper/</code>，源剪藏全程只读。</p>
<hr>
<h2 id="一它是什么">一、它是什么<a class="heading-link" aria-label="链接到本节" href="#一它是什么"><span class="icon icon-link"></span></a></h2>
<p>vault-ingest 解决的是「剪藏只进不出」问题：你在 B 站看到好视频、微信读到好文章，用 <strong>Obsidian Web Clipper</strong> 剪藏进 <code>_Capture/</code>，然后就没有然后了——视频舍不得花时间看、文章堆着不消化，<code>_Capture/</code> 慢慢变成信息垃圾场。</p>
<p>该工作流把这一步自动化：</p>
<ul>
<li><strong>输入</strong>：<code>_Capture/</code> 根目录下的视频/网页剪藏初始信息（frontmatter 含 <code>source</code> URL，在 Google 扩展程序中格式可配置）。自动区分两类——B 站视频链接（<code>bilibili-video</code>）与网页文章（<code>web-article</code>），跳过 <code>01-</code>/<code>02-</code>/<code>03-</code> 等人工构建笔记与所有子目录（即 <code>_Clipper</code> 文件夹）。</li>
<li><strong>处理</strong>：视频优先抓 B 站现成字幕（免费、快、准），无字幕才下载音频走云 ASR 兜底（未测试）；文章直接复用剪藏正文。</li>
<li><strong>产出</strong>：<code>_Capture/_Clipper/</code> 下每篇剪藏生成「摘要笔记（<code>&#x3C;缩写>-&#x3C;author>-&#x3C;title>.md</code>）+ 完整逐字稿（<code>transcripts/&#x3C;缩写>-&#x3C;author>-&#x3C;title>.md</code>，与摘要笔记同名）」。摘要笔记正文<strong>完全按剪藏模板组织</strong>（<code>**一句话总结**</code> + <code>#### 1. 要点</code> + <code>#### 2. 个人加工</code> + <code>#### 参考链接</code> + <code>#### 编辑历史记录</code>，段间以 <code>---</code> 分隔）；逐字稿 H1 与摘要笔记的来源链接文字统一用 <strong><code>&#x3C;缩写>-&#x3C;author>-&#x3C;title></code></strong> 格式（<code>bilibili-video</code>→<code>BV</code>、<code>web-article</code>→<code>WA</code>；<code>author</code>/<code>title</code> 按模板规则过滤：中文标点、空格、Windows 禁止字符一律删除）。另生成 <code>_本周回顾-&#x3C;日期>.md</code> 供每周归类。</li>
</ul>
<p>核心设计是<strong>摘要绝不脱离逐字稿</strong>：视频要点带<strong>可点击跳回视频的时间戳链接</strong>（<code>[MM:SS](视频URL?t=秒#t=MM:SS.ff)</code>，配合 media-extended 插件点击即跳转），文章要点带原文引句；<code>--finalize</code> 阶段脚本二次校验每个锚点确实存在于逐字稿，不通过就标记 <code>needs-review</code>，从机制上杜绝「AI 编造内容」。</p>
<p>适合场景：个人知识库的碎片剪藏定期消化、视频课/播客转文字归档、把「收藏夹」变成「可检索的知识」。</p>
<hr>
<h2 id="二复现章节照着做已拿到资源包">二、复现章节（照着做——已拿到资源包）<a class="heading-link" aria-label="链接到本节" href="#二复现章节照着做已拿到资源包"><span class="icon icon-link"></span></a></h2>
<blockquote>
<p>本节面向已拿到「vault-ingest 资源包」的读者。资源包包括下述 8 个文件。</p>
</blockquote>
<h3 id="一-资源包构成">(一) 资源包构成<a class="heading-link" aria-label="链接到本节" href="#一-资源包构成"><span class="icon icon-link"></span></a></h3>


















































<table><thead><tr><th>材料</th><th>路径</th><th>作用</th></tr></thead><tbody><tr><td>管道主脚本</td><td><code>.opencode/scripts/ingest.py</code></td><td>扫描/去重/抓取/转录/落盘/校验/报告（确定性、无 LLM）</td></tr><tr><td>依赖清单</td><td><code>.opencode/scripts/requirements.txt</code></td><td><code>yt-dlp</code>、<code>requests</code>、<code>PyYAML</code>、<code>secretstorage</code></td></tr><tr><td>入口 wrapper</td><td><code>.opencode/scripts/ingest.sh</code></td><td>固定走 venv 的 Python 调用 <code>ingest.py</code>（规避系统 Python 缺包）</td></tr><tr><td>cookie 助手</td><td><code>.opencode/scripts/bili-cookies.sh</code></td><td>从浏览器导出 B 站 cookie（Netscape 格式）</td></tr><tr><td>摘要 agent</td><td><code>.opencode/agents/vault-ingestor.md</code></td><td>编排管道 + 逐条写摘要（复用 opencode 模型）</td></tr><tr><td>触发命令</td><td><code>.opencode/commands/vault-ingest.md</code></td><td><code>/vault-ingest</code> 命令入口</td></tr><tr><td>git 忽略（库根）</td><td><code>.gitignore</code></td><td>追加 <code>_Capture/_Clipper/</code>（产物不进 git）</td></tr><tr><td>git 忽略（opencode）</td><td><code>.opencode/.gitignore</code></td><td>追加 <code>__pycache__/</code>、<code>*.pyc</code></td></tr></tbody></table>
<h3 id="二-前置条件">(二) 前置条件<a class="heading-link" aria-label="链接到本节" href="#二-前置条件"><span class="icon icon-link"></span></a></h3>
<ul>
<li>opencode 已安装，在 PARA 库根目录（<code>AGENTS.md</code> 生效的目录）操作</li>
<li>Python ≥ 3.10（<code>yt-dlp</code> 已提示弃用 3.10，建议 3.11+ 建 venv）</li>
<li><code>ffmpeg</code> 可用（音频时长探测与切分，ASR 接口对音频时长有限制（且长音频一次转写容易超时/截断），所以要<strong>先在静音处切段</strong>）</li>
<li>B 站账号（Chrome/Firefox 登录态，用于导出 SESSDATA cookie，让管道能免费、快速、准确地直抓 B 站现成字幕）</li>
<li>SiliconFlow 账号（可选——仅<strong>无字幕视频</strong>的 ASR 兜底需要；有字幕的视频用不到）</li>
<li>Obsidian（可选，用于查看产物与周回顾）</li>
</ul>
<h3 id="三-分步骤操作清单装配">(三) 分步骤操作清单（装配）<a class="heading-link" aria-label="链接到本节" href="#三-分步骤操作清单装配"><span class="icon icon-link"></span></a></h3>
<ol>
<li>放入资源包：把 8 个文件放到对应位置（<code>.opencode/scripts/</code>、<code>.opencode/agents/</code>、<code>.opencode/commands/</code>；<code>.gitignore</code> 两处按内容合并）
<ul>
<li>✅ 验证：<code>ls .opencode/scripts/</code> 显示 <code>ingest.py</code>、<code>ingest.sh</code>、<code>bili-cookies.sh</code>、<code>requirements.txt</code></li>
</ul>
</li>
<li>建 venv 并装依赖：
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">python3</span><span style="color:#79B8FF"> -m</span><span style="color:#9ECBFF"> venv</span><span style="color:#9ECBFF"> ~/.cache/para-ingest/venv</span></span>
<span class="line"><span style="color:#F97583">~</span><span style="color:#E1E4E8">/.cache/para-ingest/venv/bin/pip install -r .opencode/scripts/requirements.txt</span></span></code></pre>
<ul>
<li>✅ 验证：<code>~/.cache/para-ingest/venv/bin/python -c "import yt_dlp; print(yt_dlp.version.__version__)"</code> 输出 2026 版本号</li>
</ul>
</li>
<li>导出 B 站 cookie（先确认 Chrome 已登录 bilibili.com）：
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">bash</span><span style="color:#9ECBFF"> .opencode/scripts/bili-cookies.sh</span></span></code></pre>
<ul>
<li>✅ 验证：<code>~/.cache/para-ingest/cookies.txt</code> 存在、权限 600、含 <code>SESSDATA</code></li>
</ul>
</li>
<li>配置 SiliconFlow key（仅无字幕视频兜底需要，可后补）：
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#79B8FF">printf</span><span style="color:#9ECBFF"> '{\n  "siliconflow_api_key": "&#x3C;REDACTED>"\n}\n'</span><span style="color:#F97583"> ></span><span style="color:#9ECBFF"> ~/.cache/para-ingest/secrets.json</span></span>
<span class="line"><span style="color:#B392F0">chmod</span><span style="color:#79B8FF"> 600</span><span style="color:#9ECBFF"> ~/.cache/para-ingest/secrets.json</span></span></code></pre>
<ul>
<li>✅ 验证：<code>bash .opencode/scripts/ingest.sh --check</code> 显示 <code>SILICONFLOW_API_KEY：已设置</code></li>
</ul>
</li>
<li>Obsidian 排除逐字稿目录（避免全文污染搜索）：设置 → 文件与链接 → 忽略文件 → 添加 <code>_Capture/_Clipper/transcripts/</code>
<ul>
<li>✅ 验证：<code>_Capture/_Clipper/transcripts/</code> 下的文件不再出现在 Obsidian 搜索</li>
</ul>
</li>
<li>运行管道：
<ul>
<li>在 opencode 输入 <code>/vault-ingest</code>（agent 自动完成 prepare → 摘要 → finalize 三阶段）</li>
<li>✅ 验证：终端依次显示「prepare 完成 / 摘要写入 / finalize 完成」，<code>_Capture/_Clipper/</code> 出现笔记、逐字稿与 <code>_本周回顾-*.md</code></li>
</ul>
</li>
</ol>
<h3 id="四-验证--自测步骤">(四) 验证 / 自测步骤<a class="heading-link" aria-label="链接到本节" href="#四-验证--自测步骤"><span class="icon icon-link"></span></a></h3>
<ul>
<li><code>bash .opencode/scripts/ingest.sh --check</code>：打印配置路径、cookie 是否存在、API key 是否设置、Python/ffmpeg 版本</li>
<li><code>bash .opencode/scripts/ingest.sh --dry-run</code>：只扫描+分类+判重，<strong>不联网不写文件</strong>，确认 <code>bilibili-video</code> / <code>web-article</code> 识别正确、<code>01-/02-/03-</code> 被跳过</li>
<li>首跑 <code>/vault-ingest</code> 后抽查：视频笔记每个带链接的时间戳要点能在逐字稿对应行找到（且点击可跳回视频）；文章要点引句逐字出现在正文</li>
<li>打开 <code>_Capture/_Clipper/_本周回顾-*.md</code>：确认「新增 / 失败」两张表内容正确</li>
</ul>
<h3 id="五-坑与注意事项">(五) 坑与注意事项<a class="heading-link" aria-label="链接到本节" href="#五-坑与注意事项"><span class="icon icon-link"></span></a></h3>
<ol>
<li><strong>不要用系统 yt-dlp</strong>：系统自带的可能是 2022 年古董版，B 站接口早已变更。必须用 venv 内安装的新版——<code>ingest.sh</code> wrapper 强制走 venv，勿绕过。</li>
<li><strong>B 站字幕填充开关</strong>：<code>yt_dlp</code> 的 <code>extract_info(download=False)</code> 返回的 <code>info['subtitles']</code> 默认是<strong>空 dict</strong>（连 danmaku 都没有），必须在 YoutubeDL 选项里同时开 <code>writesubtitles: True</code> 和 <code>writeautomaticsub: True</code> 才触发 extractor 填充。</li>
<li><strong>字幕需要登录</strong>：不带 SESSDATA cookie 时 <code>--list-subs</code> 只显示 <code>danmaku</code>，<code>ai-zh</code> 等字幕不可见 → 视频会错误地落到 ASR。cookie 约每月过期，过期重跑 <code>bash .opencode/scripts/bili-cookies.sh</code>。</li>
<li><strong>Linux Chrome cookie 解密</strong>：Chrome cookie 用系统 keyring 加密，Python 侧需装 <code>secretstorage</code>（否则几百条 cookie 解不开）；且新版 yt-dlp 用 <code>--cookies</code> 落盘的是 JSON，读不回来——所以 <code>bili-cookies.sh</code> 用 <code>extract_cookies_from_browser</code> + <code>jar.save()</code> 直接写 Netscape 格式。</li>
<li><strong>相对路径</strong>：<code>.opencode/scripts/...</code> 只有在库根目录下才有效；在别的目录请用绝对路径或先 <code>cd</code> 到库根。</li>
<li><strong>opencode CLI 不在 PATH</strong>：<code>ingest.py</code> 刻意<strong>不</strong> shell 调 <code>opencode</code>（避免嵌套与路径依赖），摘要由 agent 直接编排完成。</li>
<li><strong>去重与续跑</strong>：已处理的源剪藏<strong>留在 <code>_Capture/</code> 根目录不动</strong>（管道只读源），靠 <code>_Clipper/.ingest-ledger.json</code> 判重；笔记骨架存在但 <code>ingest-status: new</code> 时重跑会「续跑」（不再抓取、不覆盖），<code>summarized</code> 才跳过。</li>
<li><strong>产物不进 git</strong>：<code>_Capture/_Clipper/</code> 整体被 <code>.gitignore</code> 忽略，靠坚果云等同步备份，避免每周提交噪音。</li>
</ol>
<hr>
<h2 id="三架构解析章节看懂">三、架构解析章节（看懂）<a class="heading-link" aria-label="链接到本节" href="#三架构解析章节看懂"><span class="icon icon-link"></span></a></h2>
<h3 id="一-文件职责地图">(一) 文件职责地图<a class="heading-link" aria-label="链接到本节" href="#一-文件职责地图"><span class="icon icon-link"></span></a></h3>





















































<table><thead><tr><th>文件</th><th>职责</th><th>关键操作</th><th>跨文件/模块交互</th></tr></thead><tbody><tr><td><code>.opencode/scripts/ingest.py</code></td><td>确定性管道主体</td><td>扫描 <code>_Capture/*.md</code> → 分类（重命名）/去重 → 抓取转录 → 写骨架+逐字稿+manifest → finalize 校验/记账/周回顾</td><td>调 <code>yt_dlp</code>、<code>ffmpeg</code>、SiliconFlow API；读写 <code>_Clipper/</code> 下笔记与两个 dotfile</td></tr><tr><td><code>.opencode/scripts/ingest.sh</code></td><td>venv 统一入口</td><td>解析 <code>~/.cache/para-ingest/venv</code> 的 Python 绝对路径后 <code>exec</code> <code>ingest.py</code></td><td>保证依赖在 venv 内，规避系统 Python 缺包与版本污染</td></tr><tr><td><code>.opencode/scripts/bili-cookies.sh</code></td><td>cookie 导出</td><td><code>extract_cookies_from_browser</code> + <code>jar.save()</code> 写 Netscape 文件；<code>chmod 600</code></td><td>产出 <code>~/.cache/para-ingest/cookies.txt</code>，供 <code>yt_dlp</code> 与 <code>requests</code> 取用</td></tr><tr><td><code>.opencode/agents/vault-ingestor.md</code></td><td>摘要 agent</td><td>跑 <code>ingest.sh --prepare</code> → 逐条写摘要 → <code>--finalize</code>；只改笔记「一句话+要点」两处</td><td>调 <code>ingest.sh</code>；读逐字稿写摘要；约束（不改源、不臆造）内嵌于提示词</td></tr><tr><td><code>.opencode/commands/vault-ingest.md</code></td><td>触发命令</td><td>声明 <code>agent: vault-ingestor</code> 与流程说明</td><td>在 opencode 输入 <code>/vault-ingest</code> 即进入 agent 流程</td></tr><tr><td><code>.gitignore</code>（库根）</td><td>忽略产物</td><td><code>_Capture/_Clipper/</code></td><td>管道产物不进 git 历史</td></tr><tr><td><code>.opencode/.gitignore</code></td><td>忽略 Python 缓存</td><td><code>__pycache__/</code>、<code>*.pyc</code></td><td>保持 opencode 工具目录干净</td></tr></tbody></table>
<p><strong>关键说明</strong>：工作流把「确定性」与「推理」物理分离——<code>ingest.py</code> 全程无 LLM，可幂等、可单测、失败可见；<code>vault-ingestor</code> agent 只做「读逐字稿 → 写摘要」这一件推理事，复用 opencode 当前配置的模型，不新增 API key。</p>
<h3 id="二-依赖--调用关系">(二) 依赖 / 调用关系<a class="heading-link" aria-label="链接到本节" href="#二-依赖--调用关系"><span class="icon icon-link"></span></a></h3>
<ul>
<li><strong>运行时依赖</strong>：<code>yt-dlp</code>（B 站元数据/字幕/音频）、<code>ffmpeg</code>（静音检测切段）、SiliconFlow <code>/v1/audio/transcriptions</code>（ASR 兜底）、<code>requests</code>（字幕与 ASR HTTP）、<code>PyYAML</code>（frontmatter 解析）、<code>secretstorage</code>（Linux Chrome cookie 解密，仅 cookie 导出用）</li>
<li><strong>调用链</strong>：<code>/vault-ingest</code> 命令 → <code>vault-ingestor</code> agent → <code>bash ingest.sh</code> → venv <code>python ingest.py</code> → <code>yt_dlp</code> / <code>ffmpeg</code> / SiliconFlow API；<code>bili-cookies.sh</code> → <code>yt_dlp.cookies.extract_cookies_from_browser</code></li>
<li><strong>运行时状态</strong>：<code>~/.cache/para-ingest/</code>（<code>config.json</code>、<code>cookies.txt</code>、<code>secrets.json</code>、<code>media/&#x3C;id>/</code> 音频缓存、<code>venv/</code>）+ <code>_Clipper/.ingest-ledger.json</code>（去重账本）+ <code>_Clipper/.ingest-manifest.json</code>（prepare → finalize 交接）</li>
<li><strong>被依赖方</strong>：产物笔记是用户周回顾与后续转正为原子笔记的素材，是知识库的「上游原料」</li>
</ul>
<h3 id="三-数据流--执行时序">(三) 数据流 / 执行时序<a class="heading-link" aria-label="链接到本节" href="#三-数据流--执行时序"><span class="icon icon-link"></span></a></h3>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="plaintext"><code><span class="line"><span>用户: /vault-ingest</span></span>
<span class="line"><span>   ↓</span></span>
<span class="line"><span>① prepare  ingest.py --prepare</span></span>
<span class="line"><span>   扫描 _Capture/*.md（跳过 01-/02-/03- 编号笔记与子目录）</span></span>
<span class="line"><span>   → 分类（bilibili-video / web-article）+ canonical id（BV 号 / 去 tracking 参数的 URL）</span></span>
<span class="line"><span>   → ledger 判重（status=done 跳过；骨架存在且未摘要 → 续跑）</span></span>
<span class="line"><span>   → 视频：yt_dlp 字幕优先（需 cookie）；无字幕 → 下载音频 → ASR 兜底（缺 key 报 asr_key_missing）</span></span>
<span class="line"><span>   → 文章：复用剪藏正文（正文 &#x3C;40 字符或含微信墙标记 → clipper_capture_incomplete 失败）</span></span>
<span class="line"><span>   → 写 _Clipper/&#x3C;base>.md 骨架 + transcripts/&#x3C;base>.md 逐字稿</span></span>
<span class="line"><span>   → 写 .ingest-manifest.json（prepared / failed 清单）</span></span>
<span class="line"><span>   ↓</span></span>
<span class="line"><span>② 摘要    vault-ingestor agent 读 manifest</span></span>
<span class="line"><span>   对每个 prepared 条目：读逐字稿 → 填「**一句话总结**」下的引用块与「#### 1. 要点」</span></span>
<span class="line"><span>   视频要点以带跳转链接的时间戳开头（直接从逐字稿复制 [MM:SS](视频URL?t=秒#t=NPT)，点击可跳回视频）；文章要点用「原句」引句锚点</span></span>
<span class="line"><span>   —— 只改这两处，不碰 frontmatter / #### 2. 个人加工 / #### 参考链接 / #### 编辑历史记录（正文骨架完全按剪藏模板）</span></span>
<span class="line"><span>   ↓</span></span>
<span class="line"><span>③ finalize  ingest.py --finalize</span></span>
<span class="line"><span>   校验每个锚点（时间戳/引句）确实在逐字稿中 → ingest-status: summarized 或 needs-review</span></span>
<span class="line"><span>   → 更新 ledger → 写 _本周回顾-YYYY.MM.DD.md（新增表 + 失败表）</span></span>
<span class="line"><span>   ↓</span></span>
<span class="line"><span>④ 用户周回顾 → 读 _本周回顾 与各笔记 → 人工 triage（转正原子笔记 / 丢弃 / 保留观望）</span></span></code></pre>









































































































































<table><thead><tr><th>文件/指令</th><th>子功能点的描述</th><th>[函数标注]</th><th>文字总结</th></tr></thead><tbody><tr><td>用户</td><td><code>/vault-ingest</code> 触发命令</td><td>—</td><td>入口</td></tr><tr><td>↓</td><td></td><td></td><td></td></tr><tr><td><strong>① prepare</strong>（脚本：写逐字稿 + 空骨架）</td><td></td><td></td><td></td></tr><tr><td><code>ingest.py --prepare</code></td><td>扫描 <code>_Capture/*.md</code>，跳过 <code>01-/02-/03-</code> 编号笔记与子目录</td><td><code>scan_capture</code></td><td>定型</td></tr><tr><td></td><td>分类 <code>bilibili-video</code> / <code>web-article</code> + canonical id（BV 号 / 去 tracking 参数 URL）</td><td><code>analyze_file</code></td><td>定身份</td></tr><tr><td></td><td>ledger 判重（<code>status=done</code> 跳过；骨架存在且未摘要 → 续跑），四态状态机判断后续进行的动作</td><td></td><td>定做不做</td></tr><tr><td></td><td>视频：yt_dlp 字幕优先（需 cookie）；无字幕 → 下载音频 → ASR 兜底（缺 key 报 <code>asr_key_missing</code>）</td><td><code>fetch_bilibili</code></td><td></td></tr><tr><td></td><td>文章：复用剪藏正文（正文 &#x3C;40 字符或含微信墙标记 → <code>clipper_capture_incomplete</code> 失败）</td><td><code>fetch_article</code></td><td>定内容</td></tr><tr><td></td><td>写 <code>_Clipper/&#x3C;base>.md</code> 骨架 + <code>transcripts/&#x3C;base>.md</code> 逐字稿</td><td><code>build_transcript_file</code> + <code>build_note_file</code></td><td>定产物</td></tr><tr><td></td><td>写 <code>.ingest-manifest.json</code>（prepared / failed 清单，输入给 finalize）</td><td><code>run_prepare</code></td><td>定清单/定账</td></tr><tr><td>↓</td><td></td><td></td><td></td></tr><tr><td><strong>② 摘要</strong>（agent：读 manifest → 写摘要）</td><td></td><td></td><td></td></tr><tr><td><code>vault-ingestor</code> agent</td><td>对每个 prepared 条目：读逐字稿 → 填「<strong>一句话总结</strong>」下的引用块与「#### 1. 要点」</td><td>—</td><td>写”一句话总结”和”要点”</td></tr><tr><td></td><td>视频要点以带跳转链接的时间戳开头（直接从逐字稿复制 <code>[MM:SS](视频URL?t=秒#t=NPT)</code>，点击可跳回视频）；文章要点用「原句」引句锚点</td><td></td><td>锚点可回跳/可查证</td></tr><tr><td></td><td>只改这两处，不碰 frontmatter / <code>#### 2. 个人加工</code> / <code>#### 参考链接</code> / <code>#### 编辑历史记录</code>（正文骨架完全按剪藏模板）</td><td></td><td>严守骨架</td></tr><tr><td>↓</td><td></td><td></td><td></td></tr><tr><td><strong>③ finalize</strong>（脚本：校验 + 写周回顾）</td><td></td><td></td><td></td></tr><tr><td><code>ingest.py --finalize</code></td><td>校验每个锚点（时间戳/引句）确实在逐字稿中 → <code>ingest-status: summarized</code> 或 <code>needs-review</code></td><td><code>validate_note</code></td><td>定真伪（校验）</td></tr><tr><td></td><td>更新 ledger → 写 <code>_本周回顾-YYYY.MM.DD.md</code>（新增表 + 失败表）</td><td><code>write_weekly_review</code></td><td>定账（周回顾）</td></tr><tr><td>↓</td><td></td><td></td><td></td></tr><tr><td><strong>④ 用户周回顾</strong></td><td>读 <code>_本周回顾</code> 与各笔记 → 人工 triage（转正原子笔记 / 丢弃 / 保留观望）</td><td>—</td><td>定去留</td></tr></tbody></table>
<h3 id="四-设计意图为什么这么设计">(四) 设计意图（为什么这么设计）<a class="heading-link" aria-label="链接到本节" href="#四-设计意图为什么这么设计"><span class="icon icon-link"></span></a></h3>
<ul>
<li><strong>脚本不做 LLM、agent 不做抓取</strong>：抓取/转录是确定性 I/O 活，放脚本里可幂等、可测试、单条失败不拖垮整批；摘要是推理活，交给 agent 复用 opencode 模型。脚本不 shell 调 opencode（CLI 不在 PATH + 会话嵌套有风险），由 agent 编排最稳。</li>
<li><strong>字幕优先、ASR 兜底</strong>：B 站大部分视频有 CC/AI 字幕（<code>ai-zh</code> 等），直抓字幕免费、快、准确率高；无字幕才下音频转写。云 ASR 选 SiliconFlow <code>SenseVoiceSmall</code>（免费档、OpenAI 兼容、中文效果好）。</li>
<li><strong>锚点强制防捏造</strong>：视频摘要的时间戳锚点直接复用逐字稿里的<strong>跳转链接</strong>（点击可跳回 B 站对应位置），<code>--finalize</code> 再机械校验一遍（时间戳在逐字稿中真实存在、引句逐字可查），不过则标 <code>needs-review</code>。这是「AI 总结不编造」的<strong>机制保障</strong>而非提示词愿望。</li>
<li><strong><code>_Clipper/</code> git 忽略 + 同步备份</strong>：管道产物是中间态，进 git 会造成每周噪音；靠坚果云备份，源剪藏保持只读，<code>_Capture/</code> 收件箱语义不破。</li>
<li><strong>去重靠 ledger、续跑靠 ingest-status</strong>：源文件不移动（尊重收件箱），用 canonical id（BV 号 / 去 tracking 参数的 URL）判重；笔记骨架存在但未摘要时续跑，避免重抓和覆盖已写内容。</li>
</ul>
<h3 id="五-二次开发入口">(五) 二次开发入口<a class="heading-link" aria-label="链接到本节" href="#五-二次开发入口"><span class="icon icon-link"></span></a></h3>

































<table><thead><tr><th>想做的修改</th><th>改哪里</th></tr></thead><tbody><tr><td>新增输入源（YouTube / 本地视频 / 图片 OCR）</td><td><code>ingest.py</code> 的 <code>classify</code> + 新增 <code>fetch_*</code> 函数 + 输出命名扩展</td></tr><tr><td>换 ASR 引擎（本地 SenseVoice/Paraformer 等）</td><td><code>run_asr</code>（保持 <code>(音频) -> [(ts, text)]</code> 接口，只改这一个函数）</td></tr><tr><td>换摘要模型</td><td><code>vault-ingestor.md</code>（agent 用 opencode 当前模型即可）；或改为脚本直调 API</td></tr><tr><td>加定时触发</td><td>命令外另配 cron / systemd timer：prepare → 摘要 → finalize 三段脚本化</td></tr><tr><td>调整摘要锚点规则</td><td><code>vault-ingestor.md</code> 摘要硬规则 + <code>ingest.py</code> 的 <code>validate_note</code></td></tr><tr><td>改产物笔记 schema（框架、模板）</td><td><code>build_note_file</code> / <code>build_transcript_file</code></td></tr></tbody></table>
<hr>
<h2 id="四二次开发指南">四、二次开发指南<a class="heading-link" aria-label="链接到本节" href="#四二次开发指南"><span class="icon icon-link"></span></a></h2>
<blockquote>
<p>把「二次开发入口」具体化为可操作指引，含资源包重新打包/构建说明。</p>
</blockquote>
<h3 id="一-核心改动点">(一) 核心改动点<a class="heading-link" aria-label="链接到本节" href="#一-核心改动点"><span class="icon icon-link"></span></a></h3>
<p><strong>示例：新增 YouTube 输入</strong></p>
<ol>
<li><code>classify</code> 增加 <code>youtube.com</code> 分支 → kind <code>youtube-video</code>，canonical id 用 <code>youtube:&#x3C;videoId></code></li>
<li>新增 <code>fetch_youtube()</code>：yt_dlp 对 YouTube 字幕同样走 <code>writesubtitles</code> 开关；无字幕复用 <code>run_asr</code> 兜底</li>
<li>输出命名按 kind 扩展（如 <code>yt-&#x3C;videoId>.md</code>），<code>validate_note</code> 的时间戳校验规则可复用</li>
<li>验证：<code>--dry-run</code> 确认分类正确 → 首跑确认字幕/兜底两条路径 → 抽查周回顾</li>
</ol>
<p><strong>示例：ASR 从云端换本地</strong></p>
<ol>
<li>在 <code>run_asr</code> 内把 SiliconFlow POST 替换为本地 <code>funasr</code>/<code>faster-whisper</code> 调用，保持返回 <code>[(时间戳, 文本)]</code></li>
<li><code>--check</code> 增加本地模型/环境的可用性检查</li>
<li>验证：用一个无字幕视频走通，确认时间戳与文本正确</li>
</ol>
<p><strong>示例：改摘要锚点规则</strong></p>
<ol>
<li><code>vault-ingestor.md</code>「摘要硬规则」改要求（如视频要点必须同时带时间戳与引句）</li>
<li><code>ingest.py</code> 的 <code>validate_note</code> 同步改校验逻辑</li>
<li>验证：写一条不合规摘要跑 <code>--finalize</code>，应被标 <code>needs-review</code></li>
</ol>
<h3 id="二-资源包如何打包与构建">(二) 资源包如何打包与构建<a class="heading-link" aria-label="链接到本节" href="#二-资源包如何打包与构建"><span class="icon icon-link"></span></a></h3>
<blockquote>
<p>让别人在相同环境里复现你改过的管道，需要把改动重新打成资源包。</p>
</blockquote>
<p><strong>资源包所需材料</strong>：</p>



































<table><thead><tr><th>材料</th><th>来源</th><th>是否必选</th></tr></thead><tbody><tr><td><code>.opencode/scripts/</code>（4 文件）</td><td>本管道</td><td>✅ 必选</td></tr><tr><td><code>.opencode/agents/vault-ingestor.md</code></td><td>本管道</td><td>✅ 必选</td></tr><tr><td><code>.opencode/commands/vault-ingest.md</code></td><td>本管道</td><td>✅ 必选</td></tr><tr><td><code>.gitignore</code>、<code>.opencode/.gitignore</code> 追加行</td><td>本管道</td><td>✅ 必选</td></tr><tr><td><code>~/.cache/para-ingest/venv</code></td><td>本机创建</td><td>环境依赖（不随包分发）</td></tr></tbody></table>
<p><strong>打包/构建步骤</strong>：</p>
<ol>
<li>复制上述 6 个文件 + 2 处 <code>.gitignore</code> 追加行到资源包目录</li>
<li>随包附 <code>README</code>：前置条件（Python ≥3.10 + ffmpeg + B 站登录态 + SiliconFlow 账号）、venv 创建命令、Obsidian 排除目录设置、cookie/key 配置命令</li>
<li>校验：干净库放资源包 → 建 venv 装依赖 → <code>--check</code> → <code>--dry-run</code> → 首跑 <code>/vault-ingest</code> → 核对 <code>_本周回顾-*.md</code></li>
<li>交付时注明：产物笔记的格式约定（原子笔记模板、库整理规范）与 opencode 版本</li>
</ol>
<p><strong>验证包可复现</strong>：</p>
<ul>
<li>在无本管道的干净 opencode 库放入资源包 → 跑 <code>/vault-ingest</code> → 应能走通 prepare → 摘要 → finalize</li>
<li>若失败，回查「前置条件」清单：venv 依赖是否装全、cookie 是否含 SESSDATA、是否在库根目录操作</li>
</ul>
<hr>
<h2 id="参考资料">参考资料<a class="heading-link" aria-label="链接到本节" href="#参考资料"><span class="icon icon-link"></span></a></h2>
<ol>
<li><a href="https://github.com/yt-dlp/yt-dlp">yt-dlp 文档</a>：yt-dlp 是管道里唯一的外部视频/字幕抓取器。</li>
<li><a href="https://docs.siliconflow.cn/">SiliconFlow 文档</a></li>
</ol>]]></content:encoded>
    </item>
  </channel>
</rss>
