Generated from repository Markdown docs on 2026-05-09. Self-contained HTML, CSS only.
P0 决议汇总

Red Blue CP 文档总览

本页汇总 README / PRD / SPEC / PLAN / CLAUDE / LOG / REFERENCES / CEO Plan 的完整内容,并把 P0 范围、架构约束、红蓝平台差异放在同一处审阅。

共享

P0 交付边界

  • ModelProvider Protocol + DashscopeProvider 是 P0 范围内的唯一模型实现边界。
  • P0 任务调度使用 asyncio.create_task,不引入 Queue、worker 重建或 step 进度。
  • P0 交付 rbcp run、rbcp serve、URL 自动检测、pyproject entry point、启动检查。
  • WebUI 无认证、SSRF 不处理被显式记录为 P0 局域网部署下的已知限制。
  • uvicorn 绑定 0.0.0.0,输出路径默认 ~/transcript/ 且允许 RBCP_OUTPUT_DIR 覆盖。
B 站 #00A1D6

B 站主路径

视频优先使用平台字幕;无字幕自动 ASR。P1 再提供手动“重抽 ASR”,不在 P0 自动判断字幕质量。

小红书 #FF6B6B

小红书主路径

视频走流式音频到云 ASR;图文走图片 URL 优先喂 VLM,失败后 tempfile 下载并保留 referer headers。

CEO Plan Scope Decisions

CEO plan 范围决议

提案决议理由摘要
模型接口抽象P0 ACCEPTEDModelProvider + DashscopeProvider;从零写时是自然边界。
asyncio.Queue 任务队列P1P0 用 create_task 先跑通;Queue 复杂度推后。
任务进度跟踪 step 字段P1与 Queue 配合更有意义。
pyproject.toml + entry pointP0 ACCEPTED从零建项目的必须步骤。
首次使用引导P0 ACCEPTED检查 DASHSCOPE_API_KEY + ffmpeg,降低启动失败成本。
CLI rbcp statusP1P0 只保留 rbcp run + rbcp serve。
URL 自动检测平台P0 ACCEPTED粘链接即识别 B 站 / 小红书。
WebUI basic authP1P0 局域网部署,认证延后。
PLAN.md · Eng Review 决议

Eng Review 决议

PLAN.md 底部列出 11 条工程决议;这里全部纳入,避免遗漏第 9 条“输出路径可配”等实现前置约束。

  1. extractor.py 拆分service/extractor.py 负责编排和模型调用,service/fetcher.py 负责 HTTP 爬取和解析。
  2. 新增 model.pyservice/model.py 放 ModelProvider Protocol 与 DashscopeProvider。
  3. 目录与配置SPEC §2 删除 config/,改为根目录 .env + .env.example。
  4. B 站无字幕处理无字幕时自动走 ASR,frontmatter status 标为 asr。
  5. DB driverP0 使用 sqlite3 标准库,不用 aiosqlite。
  6. event loop 保护阻塞操作用 asyncio.create_task(asyncio.to_thread(sync_fn)) 包装。
  7. 后台任务异常捕获try/except + mark_failed,避免任务静默停在 running。
  8. 进程重启清理启动时把 status=running 的任务改为 failed。
  9. 输出路径可配RBCP_OUTPUT_DIR 可配置,默认 ~/transcript/。
  10. 配置发现顺序环境变量 > ~/.config/rbcp/.env > 当前目录 .env。
  11. 分发方式继续 if/elif 分发,遵循反过度抽象原则。
Table of Contents

目录

README.md

README

项目入口与总体说明

源文件

Red Blue CP · 红蓝CP

自古红蓝出 CP —— B 站小红书 Content Pipeline

把 B 站和小红书的视频/图文内容转成纯文本,沉淀成本地 Markdown 知识库。

状态

P0 实施中。参考 JNHFlow21/social-post-extractor-mcp 逻辑,自主架构实现。

仓库名:red-blue-cp | PyPI 包名:red-blue-cp | CLI 命令:rbcp | 内部代号:rbcp

文档导航

文档 用途
PRD.md 产品需求:项目定位、五层功能架构、优先级排期
SPEC.md 技术规格:架构、API、数据模型、决策记录
PLAN.md 开发计划:里程碑、P0 Checklist、风险
CLAUDE.md Claude Code 工作规则、项目不变量、红线
REFERENCES.md 外部仓库选型记录
LOG.md 项目演进日志:决策纲要 + 开发纲要 + 经验沉淀(详情在 logs/

形态

  • WebUI:手机 + 电脑浏览器
  • CLI:AI Agent + 脚本调用

两者共享同一组业务函数。

目录结构(预期)

.
├── app/
│   ├── service/
│   │   ├── model.py            # ModelProvider Protocol + DashscopeProvider
│   │   ├── extractor.py        # 自实现内容提取(参考上游逻辑)
│   │   ├── markdown.py         # frontmatter + sanitize + 原子写入
│   │   └── storage.py          # SQLite jobs CRUD
│   ├── web/
│   │   └── routes.py           # WebUI + REST API
│   └── cli.py                  # rbcp 命令
├── .env                        # 百炼 API Key + 小红书 cookie(gitignored)
├── PRD.md
├── SPEC.md
├── PLAN.md
├── CLAUDE.md
├── REFERENCES.md
├── LOG.md
├── logs/
│   ├── TEMPLATE.md
│   └── YYYY-MM-DD-{slug}.md     # 决策/里程碑/经验详情
└── README.md

知识库默认输出位置:~/transcript/

快速开始(占位,P0 完成后填)

# 1. 克隆
git clone <repo-url>
cd red-blue-cp

# 2. 装依赖
uv sync

# 3. 配 API Key
cp .env.example .env
# 编辑填入 DASHSCOPE_API_KEY

# 4. 启 WebUI
rbcp serve

# 或 CLI
rbcp run <url>

技术栈

FastAPI + Jinja2 + HTMX + typer + SQLite + asyncio + dashscope SDK

部署位置

自部署工具。推荐部署在国内 IP 机器(避免小红书海外风控)。支持 WSL2 mirrored networking。手机访问走 tailscale 私有网络或 frp 中转。

范围外

  • 抖音平台
  • MCP server(P0 不含,P2 按需新建)
  • Get 笔记历史数据迁移(独立项目)
  • 远期 LLM Wiki 主题索引(本项目只产 Markdown 原料)

License

MIT 或 Apache-2.0(待定)。

PRD.md

PRD

产品需求与范围

源文件

PRD · Red Blue CP

自古红蓝出 CP —— B 站小红书 Content Pipeline

项目定位

把 B 站和小红书的视频/图文内容转成纯文本,沉淀成本地 Markdown 知识库。模型默认百炼,开源后期可换。


功能架构(五层)

第一层 · 形态

  • WebUI:手机 + 电脑浏览器
  • CLI:AI Agent 接入 + 脚本调用

两个入口共享同一组业务函数。

第二层 · 核心流水线

平台 内容类型 主路径 兜底
B 站 视频 平台字幕 UI 手动按钮切 ASR
小红书 视频 流式音频 → 云 ASR
小红书 图文 图片 URL 优先喂 VLM;失败回退 tempfile 下载(保留 referer headers)→ VLM 后期可加 PaddleOCR 备选

每条流水线最终持久化的产物只有 Markdown、纯文本和元数据。媒体文件(音频流、图片)允许存在于 tempfile 临时目录,任务结束后自动清理,不进入 ~/transcript/

B 站不自动判断字幕质量,由用户在 UI 手动触发"重抽 ASR"。

第三层 · 任务调度

  1. 单链接:即时处理
  2. 批量链接:粘贴一批 URL,串行 + 限流
  3. 博主全量:拉取 → 过滤 → 勾选 → 入队
    • 拉取实现:bili user-videos / xhs user-posts
    • 过滤维度:时长 / 发布日期 / 关键词
    • 勾选交互:单选 + 全选

第四层 · 辅助功能(独立模块)

小红书评论提取

  • 独立入口,输入笔记链接
  • 输出:JSON / Markdown
  • 实现:subprocess 调 xhs comments --all --json
  • 不做可视化树形 UI

第五层 · 出口

5.1 本地 Markdown 落盘(主存储)

~/transcript/
├── bili/{YYYY-MM-DD}-{up_name}-{title}-{BV_id}.md
├── xhs/{YYYY-MM-DD}-{author}-{title}-{note_id}.md
├── xhs/{YYYY-MM-DD}-{author}-{title}-{note_id}.comments.md
└── _index.sqlite

frontmatter 字段:

---
platform: bilibili | xiaohongshu
type: video | image_note
url: <原链接>
author: <作者名>
author_id: <作者 ID>
title: <原标题>
published_at: 2025-MM-DD
fetched_at: 2026-MM-DD
duration_sec: 600          # 视频特有
image_count: 9             # 图文特有
asr_model: paraformer-v2
vision_model: qwen3-vl-flash
status: subtitle | asr | vision | asr_force
tags: []                   # 远期手动/自动加
---

5.2 WebUI 出口

能力 形态
渲染 服务端 Jinja2 + 前端 markdown 库实时渲染
复制 三种粒度:全文 / 仅正文 / 仅 frontmatter
下载 .md 下载、批量打包 zip
手机分享 Web Share API

5.3 飞书多维表格同步

放在 P2,本阶段不做。

第六层 · 基础设施

关注点 MVP 后期
模型 ModelProvider Protocol + DashscopeProvider(百炼 paraformer-v2 / qwen3-vl-flash / qwen-flash) OpenAI 兼容适配层
内容存储 本地 Markdown + frontmatter
索引存储 SQLite(任务状态) + FTS5 全文
中间媒体 tempfile 临时目录,跑完即删
部署位置 本地服务器(国内 IP,避免小红书海外风控)
远程访问 tailscale 私有网络(首选)或 frp 中转阿里云日本
失败任务持久化 url / platform / error_type / error_message / log_excerpt / created_at / updated_at / retry_count

范围外

  • 抖音平台
  • MCP server(P0 参考移植不 fork,无 MCP 入口;P2 按需新建)
  • Get 笔记历史数据迁移(独立项目)
  • DreameClaw skill 形态
  • 复杂字幕时间戳 / 视频播放器嵌入
  • 评论可视化树形 UI
  • MVP 阶段的主题索引知识库(远期愿景)

实施优先级

P0 · 跑通 URL → MD(核心闭环)

目标:从前端粘一个链接,几分钟后桌面多一个 Markdown 文件。

模块 内容
流水线 B 站视频 / 小红书视频 / 小红书图文,三条全跑通
模型 ModelProvider Protocol + DashscopeProvider(唯一实现)
存储 本地 Markdown 落盘 + frontmatter,目录结构定死
索引 SQLite jobs 表(schema 见 SPEC)
WebUI 单页:输入框 + 任务列表 + 详情查看 + 下载(轮询,无 SSE)
CLI rbcp run <url> 同步阻塞,吐 MD 路径
部署 本地服务器本地访问,不上公网

P0 不包含:批量、博主全量、评论、手动 ASR 切换、模型抽象、远程访问、飞书、SSE、FTS5、Pipeline 类抽象、外部 CLI 依赖。

P1 · 能用 → 好用

按子优先级串行进行(不并行):

P1a · 批量 + 限流              (1 天)
P1b · 博主全量(装 bili/xhs cli)(1.5 天)
P1c · 评论提取                  (0.5 天)
P1d · B 站手动 ASR 切换         (0.5 天)
P1e · 模型抽象层(最后做)       (1.5 天)
P1f · 远程访问 tailscale         (0.5 天)

模型抽象(P1e)单独排足时间,不要与 P1a-d 并行——dashscope SDK 不是 OpenAI 兼容,三种调用形态(ASR/VLM/LLM)差异大,会拆乱代码。

P2 · 完善(按需)

模块 触发条件
飞书多维表格同步 多端同步真实痛了再做
移动端响应式深度适配 手机用得多了
图片 OCR 备选(PaddleOCR) VLM 出问题或成本太高
SQLite FTS5 全文检索 文档量过百再做
任务失败重试 / 断点续抓 / 自动 cooldown 风控经常踩坑了再做

关键决策回顾

  • 形态从三入口(WebUI + CLI + MCP)砍到双入口;MCP fork 后保留入口不维护
  • 小红书图文 MVP 走 VLM,OCR 是 P2 备选不是 P0 必需
  • 远期 LLM Wiki 不进需求文档,本项目交付 Markdown 文件库即可
  • 飞书移到 P2
  • P0 原则:"产物正确",不要"架构优雅"
SPEC.md

SPEC

技术规格与约束

源文件

SPEC · Red Blue CP

自古红蓝出 CP —— B 站小红书 Content Pipeline

1. 模块分层(运行时架构)

┌─ 入口层 ──────────────────────────────────────────┐
│  WebUI (FastAPI + Jinja2 + HTMX)                 │
│  CLI  (typer)                                     │
│  ↓ 共享同一组业务函数                             │
├─ 业务层 (P0) ─────────────────────────────────────┤
│  service/extractor.py    自实现内容提取(参考上游)│
│  service/markdown.py     frontmatter + 模板 + 写入 │
│  service/storage.py      SQLite jobs CRUD         │
├─ 适配层 (P1 引入) ────────────────────────────────┤
│  PlatformAdapter   ModelAdapter   CliSubprocess  │
├─ 存储层 ──────────────────────────────────────────┤
│  Filesystem      (~/transcript/)                 │
│  SQLite Index    (jobs / 后续 fts5)              │
└──────────────────────────────────────────────────┘

P0 阶段不引入:PlatformAdapter / ModelAdapter / CliSubprocess / Pipeline 类体系 / asyncio.Queue / SSE / FTS5。


2. P0 代码组织

app/
  service/
    extractor.py        # 自实现内容提取逻辑(参考上游 social-post-extractor-mcp)
                        # 输入 URL,输出 ExtractResult
    markdown.py         # frontmatter + 正文模板 + sanitize + 原子写入
    storage.py          # SQLite jobs CRUD
  web/
    routes.py           # 输入页 + 任务列表 + 详情 + 下载
    templates/          # Jinja2 模板
  cli.py                # rbcp run <url>
config/
  social-post-extractor.env  # 百炼 API Key(gitignored,继承上游)

P0 走捷径:

  • 提交 URL → asyncio.create_task(extract_and_save(url)) 后台跑
  • CLI 同步阻塞,跑完返回路径
  • WebUI 任务列表用轮询(2s 拉一次 /api/jobs
  • 不抽 Pipeline 接口,三种内容类型在 extractor.py 内部用 if/elif 分发

3. 数据流

URL ──→ Job (status=pending)
     ↓
service.extractor.extract_url(url)
     ├─ 自实现内容提取,直接调用 dashscope SDK + requests 爬取
     ├─ 通过 ModelProvider 接口调 ASR/VLM/LLM
     └─ 转换成 ExtractResult dataclass
     ↓
service.markdown.render_and_write(result)
     ├─ sanitize 文件名
     ├─ Jinja2 渲染 frontmatter + 正文
     ├─ 写 .tmp 文件
     └─ os.replace 原子替换
     ↓
service.storage.mark_done(job_id, md_path)
     ↓
WebUI / CLI 读 SQLite + 文件返回给用户

4. 接口约定

4.1 REST API(WebUI ↔︎ Backend)

P0 必备:

POST /api/jobs                      # 提交单条 URL,返回 job_id
GET  /api/jobs?limit=20&offset=0    # 任务列表,前端轮询
GET  /api/jobs/{id}                 # 任务详情
GET  /api/jobs/{id}/markdown        # 渲染 MD 内容(用于详情页展示)
GET  /api/jobs/{id}/download        # 下载 .md(带 Content-Disposition)

P1 增加:

POST /api/jobs/batch                # 批量提交
POST /api/jobs/{id}/rerun           # 强制重抽(B 站手动 ASR)
POST /api/uploaders/{platform}/{uid}/posts  # 拉博主作品列表
POST /api/comments                  # 评论提取
GET  /api/jobs/zip?ids=1,2,3        # 批量打包下载(按 id,不暴露 path)

安全约束:所有文件接口必须通过 job_id 反查 md_path不允许用户传任意 path(防路径穿越)。

4.2 CLI 命令

P0 必备:

rbcp run <url>                  # 单条,同步阻塞,输出 md_path
rbcp serve                      # 启 WebUI

P1 增加:

rbcp batch <file>               # 批量,每行一个 URL
rbcp uploader <platform> <uid>  # 拉博主作品列表(不自动跑)
rbcp comments <url>             # 评论提取

CLI 内部直接 from app.service import extractor不走 HTTP


5. SQLite Schema

5.1 jobs 表(P0 完整版)

CREATE TABLE jobs (
  id            INTEGER PRIMARY KEY,
  url           TEXT NOT NULL,
  platform      TEXT,           -- bilibili | xiaohongshu
  content_type  TEXT,           -- video | image_note
  status        TEXT NOT NULL,  -- pending | running | done | failed
  md_path       TEXT,
  title         TEXT,
  author        TEXT,
  error_message TEXT,
  log_excerpt   TEXT,
  retry_count   INTEGER DEFAULT 0,
  created_at    TEXT NOT NULL,
  updated_at    TEXT NOT NULL,
  started_at    TEXT,
  finished_at   TEXT
);

CREATE INDEX idx_jobs_status ON jobs(status);
CREATE INDEX idx_jobs_created_at ON jobs(created_at DESC);

5.2 P1 加字段

ALTER TABLE jobs ADD COLUMN source_uid    TEXT;   -- 博主 uid(来自博主全量任务)
ALTER TABLE jobs ADD COLUMN published_at  TEXT;
ALTER TABLE jobs ADD COLUMN duration_sec  INTEGER;
ALTER TABLE jobs ADD COLUMN image_count   INTEGER;
ALTER TABLE jobs ADD COLUMN asr_model     TEXT;
ALTER TABLE jobs ADD COLUMN vision_model  TEXT;

5.3 P2 加 FTS5

CREATE VIRTUAL TABLE jobs_fts USING fts5(title, author, content='jobs');
-- 触发器同步,省略

6. Markdown 文件规范

6.1 命名

~/transcript/
├── bili/{YYYY-MM-DD}-{up_name}-{safe_title}-{BV_id}.md
├── xhs/{YYYY-MM-DD}-{author}-{safe_title}-{note_id}.md
└── xhs/{YYYY-MM-DD}-{author}-{safe_title}-{note_id}.comments.md

6.2 文件名 sanitize 规则

safe_title  = 去除 / \ : * ? " < > | + 控制字符 + emoji
            + 压缩连续空白
            + 中英文空格统一
            + 截断到 60 字符
safe_author = 缺失 → "unknown_author"
date        = published_at 缺失 → fetched_at
suffix      = 始终拼 BV_id / note_id 防冲突

6.3 原子写入

1. 写入 {final_path}.tmp
2. os.replace({tmp_path}, {final_path})
3. 失败时清理 tmp

6.4 frontmatter 模板

---
platform: bilibili | xiaohongshu
type: video | image_note
url: <原链接>
author: <作者名>
author_id: <作者 ID>
title: <原标题>
published_at: 2025-MM-DD
fetched_at: 2026-MM-DD
duration_sec: 600          # 视频特有
image_count: 9             # 图文特有
asr_model: paraformer-v2
vision_model: qwen3-vl-flash
status: subtitle | asr | vision | asr_force
tags: []
---

# {title}

> [{author}]({author_url}) · {published_at} · [原链接]({url})

## 转录文本 / 图文 OCR

{text}

7. 部署约束(必须执行)

MVP 仅支持单进程:
  uvicorn app.web.routes:app --host 0.0.0.0    (不用 --workers)

绑定 0.0.0.0 而非 127.0.0.1,兼容 WSL2 mirrored networking + tailscale 等外部访问场景。

任务队列是进程内:P0 用 asyncio.create_task,P1 引入 asyncio.Queue + N worker。
P0 阶段没有真队列,重启即丢失运行中任务。

P0 安全已知限制(局域网/tailscale 部署下可接受):
- WebUI 无认证(P1 加 basic auth)
- 无 SSRF 防护(用户提交 URL 后端直接抓取)

P1 引入持久化前不要做多进程部署。

8. 媒体文件处理

8.1 原则

  • 持久化产物只有:Markdown / 纯文本 / 元数据
  • 允许临时存在:tempfile.TemporaryDirectory 内的音频流、图片
  • 任务结束后自动清理:通过 context manager 保证

8.2 小红书图片 VLM 调用

1. 优先:把图片 URL 直接喂给 qwen3-vl-flash
2. 失败回退:
   - 用 requests.get 下载到 tempfile
   - 必须保留 referer / user-agent headers(小红书图片有防盗链)
   - 喂给 VLM 后立即删除

不要把"URL 直接喂模型"当作稳定主路径,必须做双轨。

8.3 视频音频流抽取

ffmpeg -i <m3u8|mp4_url> -vn -c:a copy <tempfile.m4a>
→ 喂给 paraformer-v2 ASR
→ 用完即删

9. 失败任务持久化

每条失败任务必须在 SQLite 留下:

url
platform
content_type           可选
status = failed
error_message          单行错误摘要
log_excerpt            最后 50 行日志或异常 traceback
retry_count
created_at
updated_at

WebUI 任务列表必须能区分 donefailed,并展示 error_message 让用户知道为什么失败(小红书风控场景下尤其重要)。


10. 关键决策记录

决策 不选 理由
队列 asyncio.Queue (P1) / create_task (P0) celery / rq 单机、单进程、零依赖
前端 HTMX + Jinja2 服务端渲染 React 无 build step
索引 SQLite Postgres 单文件、无运维
中间媒体 tempfile,跑完即删 落盘缓存 需求明确"无中间媒体进知识库"
图片 VLM URL 优先 + tempfile 兜底 单一路径 防盗链、签名过期
远程访问 tailscale 公网 frp 私有网络更安全、零配置
部署 单进程 uvicorn,禁 --workers 多 worker asyncio.Queue 不跨进程
MCP 入口 保留不动 不存在(参考移植) fork 上游 从零写无 MCP 入口,P2 按需新建
Pipeline 抽象 P0 不做 一开始就分层 过度抽象,先验证可行性
模型抽象 P1e 最后做 早期抽象 dashscope 不是 OpenAI 兼容,工作量大
文件下载 经 job_id 反查 直接传 path 防路径穿越

11. 修订记录

版本 改动
v1 初稿:CLI + skill 范式
v2 改 WebUI + CLI 双入口;明确本地 Markdown 主存储;加飞书同步、远程访问
v3 砍 MCP 入口;模型抽象推到 P1;图文笔记走 VLM;分 P0/P1/P2
v3.1 接受外部审阅:P0 砍到极简 / 不删 MCP / 安全 API / 单进程约束 / 失败持久化 / 文件名 sanitize
v3.2(当前) 项目命名为 Red Blue CP(红蓝CP);CLI 命令 spx → rbcp;包名 red-blue-cp
PLAN.md

PLAN

开发计划与 Review 决议

源文件

PLAN · Red Blue CP

自古红蓝出 CP —— B 站小红书 Content Pipeline

里程碑总览

阶段 天数 目标
M0 0.5-1 研读上游 + 评估复杂度(参考移植)
M1a 1 CLI 极简闭环 + ModelProvider
M1b 0.5 WebUI 最小页
M2 3-5 P1 规模化(按子优先级串行)
M3 按需 P2 完善

P0 = M0 + M1a + M1b ≈ 2-2.5 天(CC 辅助开发) P1 = M2 ≈ 3-5 天 P2 = M3,按需


M0 · 研读上游 + 评估复杂度(0.5-1 天)

参考移植:研读上游 social-post-extractor-mcp 的代码,理解 SDK 调用和爬取逻辑,评估自实现复杂度。

任务清单

    • 某单项预估超过 2 天 → 退回方案 A(fork + 旁路包装)
    • 可控 → 继续参考移植

不做的事

出口

理解上游核心逻辑,确认自实现可行性。决定是继续参考移植还是退回 fork。


M1a · CLI 极简闭环(1 天)

目标:终端跑 rbcp run <url>,桌面多一个 Markdown 文件。

任务清单

验收


M1b · WebUI 最小页(0.5 天)

目标:浏览器粘 URL,看到结果。

任务清单

验收

不做的事


M2 · P1 规模化(3-5 天,子任务串行不并行)

M2a · 批量 + 限流(1 天)

    • 小红书 worker = 1,间隔 ≥ 2s
    • B 站 worker = 2-4

M2b · 博主全量(1.5 天)

M2c · 评论提取(0.5 天)

M2d · B 站手动 ASR 切换(0.5 天)

M2e · 模型抽象层(1.5 天,单独排足时间)

  • asr(audio) -> text
    vlm(images) -> text
    llm_clean(text) -> text

重点:不要与 M2a-d 并行。三种调用形态差异大,会拆乱代码。

M2f · 远程访问(0.5 天,运维任务)


M3 · P2 完善(按需)

子任务 触发条件
飞书多维表格同步 手机查看真实痛了
移动端响应式深度适配 + Web Share API 手机用得多了
PaddleOCR 备选通路 VLM 出问题或成本太高
SQLite FTS5 全文检索 + WebUI 搜索框 文档量过百
任务失败重试 / 断点续抓 / cooldown 自动调整 风控经常踩坑了

不进时间盘。


风险与缓解

风险 概率 缓解
小红书风控触发(即使国内 IP) 保留 cookie 配置;串行限流强制;UA 伪装
B 站字幕质量参差 不自动判断;M2d 提供手动"重抽 ASR"按钮
VLM 图片 token 成本失控(10+ 图笔记) max_images 软限制(默认 9),超限拒绝
dashscope 不是 OpenAI 兼容,模型抽象工作量低估 M2e 单独排足 1.5 天,不与 M2a-d 并行
小红书爬取自实现复杂度超预期 M0 研读上游逻辑,超 2 天预估则退回 fork
asyncio.Queue 在多 worker 部署下状态混乱 SPEC 强制单进程 uvicorn,禁用 --workers
文件下载接口路径穿越 所有文件接口走 job_id 反查,不接受用户 path
MCP 入口删除带坏业务函数 参考移植,无 MCP 入口,风险不存在
上游图片防盗链 VLM 调用走"URL 优先 + tempfile 兜底"双轨

时间盘建议

项目阶段顺序:

阶段 建议时间窗
M0 + M1a + M1b 5 月内(一个完整周末,CC 辅助)
M2 下阶段后再做
M3 长期可选

P0(M0 + M1a + M1b)应当在近期完成,让本地 Markdown 知识库的核心闭环可用。 P1 P0 稳定运行后启动,避开关键期。


Eng Review 决议(2026-05-09)

/plan-eng-review 产出的 P0 架构补充决议,需要在写代码前同步到 SPEC.md:

  1. extractor.py 拆分service/extractor.py(编排 + 调 model)+ service/fetcher.py(HTTP 爬取 + 解析)
  2. 新增 model.pyservice/model.py 包含 ModelProvider Protocol + DashscopeProvider
  3. SPEC §2 目录更新:删除 config/ 目录,改为根目录 .env + .env.example
  4. B 站无字幕处理:API 返回无字幕时自动走 ASR,frontmatter status 标 asr(不违反红线 #10)
  5. DB driver:sqlite3 标准库(不用 aiosqlite),P0 单进程阻塞影响可忽略
  6. event loop 保护asyncio.create_task(asyncio.to_thread(sync_fn)) 包装阻塞操作
  7. 后台任务异常捕获:try/except 包装 + mark_failed,防止任务静默卡在 running
  8. 进程重启清理:启动时把所有 status=running 的任务改为 failed
  9. 输出路径可配:环境变量 RBCP_OUTPUT_DIR,默认 ~/transcript/
  10. 配置发现顺序:环境变量 > ~/.config/rbcp/.env > 当前目录 .env
  11. 分发方式(dispatch):if/elif 分发,遵循 CLAUDE.md 反过度抽象原则

GSTACK REVIEW REPORT

Review Trigger Why Runs Status Findings
CEO Review /plan-ceo-review Scope & strategy 1 CLEAR 8 proposals, 4 accepted, 4 deferred
Outside Voice codex Independent 2nd opinion 1 issues_found 4 findings adopted (event loop, restart, config)
Eng Review /plan-eng-review Architecture & tests (required) 1 CLEAR 6 issues, 0 critical gaps
Design Review /plan-design-review UI/UX gaps 0
DX Review /plan-devex-review Developer experience gaps 0
  • CODEX: event loop 阻塞、restart 清理、输出路径可配、配置发现顺序 — 全部采纳
  • CROSS-MODEL: 无重大分歧。Codex 认为 P0 范围仍然太大(建议砍到单平台),review 保持三平台(核心竞争力)
  • UNRESOLVED: 0
  • VERDICT: CEO + ENG CLEARED — ready to implement
CLAUDE.md

CLAUDE

工程规则与红线

源文件

CLAUDE.md · Red Blue CP

这个文件是 Claude Code 在本仓库工作时的规则书。每次对话开始时自动读。 修改前先看 PRD.md / SPEC.md,理解上下文。

项目目标(一句话)

Red Blue CP(红蓝CP)—— 自古红蓝出 CP,B 站小红书 Content Pipeline。

把 B 站和小红书的视频/图文内容转成纯文本,沉淀成本地 Markdown 知识库。

当前阶段

P0(M0 + M1a + M1b)。目标:URL → Markdown 文件闭环。 不要做 P1/P2 范围内的事,即便代码看起来该重构。

不变量(红线,违反就是 bug)

安全

  1. 文件下载/读取接口必须走 job_id,不允许用户传任意 file path。任何 GET /api/files/{path} 这类设计都是路径穿越漏洞,禁止。
  2. 敏感配置不进 Git。百炼 API Key 和小红书 cookie 存放在 .env 文件中,必须在 .gitignore 里。

部署

  1. MVP 仅支持单进程 uvicorn。启动命令禁止 --workers > 1。asyncio.Queue / create_task 是进程内的,多 worker 会让任务状态混乱。
  2. 不允许把数据库或日志写到 ~/transcript/。知识库目录只放 Markdown 文件。SQLite 索引文件 _index.sqlite 是唯一例外。

持久化

  1. 媒体文件不进知识库。音频流、图片必须只存在于 tempfile.TemporaryDirectory,任务结束自动清理。用 with 块保证。
  2. 失败任务必须留痕。SQLite 里有 status=failed + error_message + log_excerpt。WebUI 必须能展示。
  3. Markdown 写入必须原子。先写 {path}.tmp,再 os.replace 替换。中途崩溃不能留半个文件。

业务

  1. 不删 MCP 入口已废除)。P0 采用参考移植方案,不 fork 上游,无 MCP 入口。如未来需要 MCP 能力,作为 P2 新建。
  2. 不引入 bilibili-cli / xiaohongshu-cli 到 P0。这两个 CLI 是 P1 博主全量和评论用的,P0 不依赖。
  3. 不自动判断 B 站字幕质量。字幕优先是默认行为,"切 ASR" 是 P1 的手动按钮。不要写"如果字幕长度小于 X 就走 ASR"这种启发式。
  4. 小红书图文图片处理走双轨:URL 优先喂 VLM,失败回退到 tempfile 下载(保留 referer 等 headers),喂完即删。不要把 URL 当唯一稳定路径。

范围

  1. 不做抖音。即便上游仓库支持,本项目范围明确不包含。
  2. 不做飞书集成、不做 PaddleOCR、不做 FTS5、不做 SSE。这些是 P2,P0 一律不写代码也不留半成品入口。

工程纪律

P0 阶段反过度抽象

P0 阶段只用三个文件夹service/ web/ cli.py不要引入以下抽象(即使你觉得"以后会用到"):

  • PlatformAdapter / BiliAdapter / XhsAdapter
  • Pipeline 接口和 BiliVideoPipeline 等实现
  • JobQueue 类(P0 用 asyncio.create_task,P1 才引入 asyncio.Queue

P0 允许的抽象ModelProvider Protocol + DashscopeProvider(参考移植的初始设计,不是提前抽象)。

P0 内部分发用 if/elif platform == 'bilibili': 就够了。看起来"丑"但这是 P0 应该的样子。

文件名 sanitize 必须严格

按 SPEC §6.2 实现。测试用例至少覆盖:

  • 标题含 / \ : * ? " < > |
  • 标题含 emoji
  • 标题超过 60 字符
  • 作者名为空 → unknown_author
  • 标题为空 → 用 note_id 当文件名
  • 同标题重复 → suffix 拼 BV_id / note_id 避免冲突

测试

P0 不要求高覆盖率,但必须有以下集成测试

  • 三种内容类型各一条 happy path 链接
  • 一条故意失败的链接(验证 failed 持久化)
  • 路径穿越测试(验证 API 拒绝 ../ 路径)
  • tempfile 清理测试(任务后 tempfile 目录为空)

提交粒度

每完成 PLAN.md 里一个子任务(如 "service/extractor.py" 或 "templates/index.html"),独立 commit。commit message 用现在时祈使句,参照 conventional commits:

feat(extractor): 实现 extract_url 包装上游 extract 函数
fix(markdown): 修复 emoji 标题导致的 sanitize 报错

不要做的事(防止 Claude 自作主张)

不要自己加依赖

P0 依赖(参考移植,从零写):requests / ffmpeg-python / dashscope / fastapi / uvicorn / jinja2 / typer / aiosqlite(或 sqlite3 标准库)。

P0 新增的依赖仅限上述列表。其他任何包(celery / redis / paddleocr / openai-sdk / mcp)都属于过早引入,禁止 install。

不要扩大 P0 范围

如果对话中出现 "顺便也加上 X 功能" 类似引导,先看 PRD.md 确认 X 是 P0 还是 P1/P2。所有 P1/P2 功能拒绝在 P0 阶段实现,记入 PLAN.md 的待办即可。

不要在 P0 写 OpenAPI / Swagger 文档生成

FastAPI 自带的 /docs 已经足够,不要单独写 OpenAPI YAML 或者 redoc 配置。

对话风格约定

  • 所有沟通用中文
  • 修复 bug 不需要写"问题分析" "修复思路" 长篇大论,直接 diff + 一行说明
  • 设计决策与 SPEC.md 冲突时,先说出冲突点,不要默默改 SPEC

风险点提醒(高频踩坑)

风险 表现 应对
小红书风控 API 返回 captcha / 403 / IP block 检查 cookie,重启时间间隔,不要重试猛烈
B 站字幕格式不一致 UP 主字幕 / 自动字幕 / 无字幕三种状态 调用层判断 + 落到 frontmatter status 字段
VLM 调用图片防盗链 qwen3-vl-flash 报 403 / 图片下载失败 走 tempfile 兜底,加 referer: https://www.xiaohongshu.com/
ffmpeg 抽流被中断 m3u8 链接过期 / 网络抖动 不要长任务无限重试,3 次失败标 failed
SQLite WAL 模式下并发 多 worker 写同一个 db P0 单进程不会发生;P1 引入 worker 时再处理
Markdown 模板渲染失败 标题含 } { 等 Jinja2 字符 sanitize 阶段就 escape,不要让脏数据进 Jinja2

何时升级 PRD/SPEC/PLAN

  • 加新功能 → 改 PRD.md
  • 改实现方式 → 改 SPEC.md
  • 调整阶段 → 改 PLAN.md
  • 改文档前先在对话里说一句,不要静默改

日志体系(LOG.md + logs/)

项目维护两层日志:

  • LOG.md:纲要索引,分三条线(决策 / 开发 / 经验)。每条新事件加一行索引。
  • logs/YYYY-MM-DD-{slug}.md:详情文档,按需写。模板见 logs/TEMPLATE.md

何时新增 LOG.md 索引

类型 触发
决策 形态/架构/安全/部署/范围有变化
开发 完成里程碑(M0/M1a/M1b/...)或阶段切换
经验 踩坑后总结、工具非显然行为、值得复用的 lesson

何时新增 logs/ 详情文档

不强制。判断标准:

  • 🔴 高优先级决策:建议写详情
  • 🟡 中优先级:可写可不写
  • 🟢 低优先级:通常只在 LOG.md 留索引

写新 logs/ 文档的流程

  1. 复制 logs/TEMPLATE.mdlogs/YYYY-MM-DD-{slug}.md(slug 用小写连字符)
  2. 填 frontmatter(type / priority / related / status)
  3. 写正文
  4. 回到 LOG.md 对应纲要表格加一行索引
  5. 如果新决策推翻了旧决策,把旧 logs 文件的 status 改为 superseded,加链接指向新文件

最后:写代码前先 grep 一下相关代码看是否已有实现,避免重复。完成后跑一下 python -m compileall app/ 确保至少能编译。

Skill routing

When the user's request matches an available skill, ALWAYS invoke it using the Skill tool as your FIRST action. Do NOT answer directly, do NOT use other tools first. The skill has specialized workflows that produce better results than ad-hoc answers.

Key routing rules:

  • Product ideas, "is this worth building", brainstorming → invoke office-hours
  • Bugs, errors, "why is this broken", 500 errors → invoke investigate
  • Ship, deploy, push, create PR → invoke ship
  • QA, test the site, find bugs → invoke qa
  • Code review, check my diff → invoke review
  • Update docs after shipping → invoke document-release
  • Weekly retro → invoke retro
  • Design system, brand → invoke design-consultation
  • Visual audit, design polish → invoke design-review
  • Architecture review → invoke plan-eng-review
  • Save progress, checkpoint, resume → invoke checkpoint
  • Code quality, health check → invoke health
LOG.md

LOG

项目演进日志

源文件

LOG · Red Blue CP · 项目演进日志

自古红蓝出 CP —— B 站小红书 Content Pipeline

本文档分三条线:决策纲要 / 开发纲要 / 经验沉淀。 每行是索引,详情文档放在 logs/ 目录下,按 YYYY-MM-DD-{slug}.md 命名。 模板见 logs/TEMPLATE.md


设计源对话

日期 阶段 渠道 链接
2026-05-08 早期需求探索 ChatGPT 私有对话,未公开
2026-05-09 需求收敛 + 文档冻结 v3.1 Claude.ai 私有对话,未公开
2026-05-09 CEO review + 文档同步 Claude Code /plan-ceo-review

决策纲要

倒序排列(最新在上)。优先级:🔴 高 / 🟡 中 / 🟢 低。

类别:架构 / 安全 / 业务 / 部署 / 工程 / 范围

日期 优先级 类别 决策 详情
2026-05-09 🔴 高 架构 CEO review:参考移植取代 fork,P0 加 ModelProvider,Queue/status/auth 推 P1 CEO plan
2026-05-09 🔴 高 架构 目录结构 ~/knowledge-vault/ → ~/transcript/ 扁平结构
2026-05-09 🔴 高 部署 uvicorn 绑定 0.0.0.0,兼容 WSL2 mirrored networking
2026-05-09 🔴 高 安全 cookie 与 API Key 同存 .env,.gitignore 保护;P0 WebUI 无认证(已知限制)
2026-05-09 🔴 高 命名 项目命名为 Red Blue CP(红蓝CP),CLI 命令 rbcp 详情
2026-05-09 🔴 高 架构 P0 只允许 ModelProvider 抽象,其余(Pipeline/Queue/Adapter)P1 再引入 详情
2026-05-09 🔴 高 架构 不删 MCP 入口(已废除:参考移植无 MCP 入口)
2026-05-09 🔴 高 安全 文件接口走 job_id 不暴露 path
2026-05-09 🔴 高 部署 MVP 强制单进程 uvicorn,禁 --workers
2026-05-09 🔴 高 业务 小红书图文走 VLM,不依赖 desc 字段
2026-05-09 🔴 高 工程 失败任务必须持久化(含 error_message + log_excerpt)
2026-05-09 🔴 高 范围 形态从 CLI+skill 演变到 WebUI+CLI 双入口;MCP 砍掉
2026-05-09 🟡 中 架构 模型抽象推到 P1e,与 P1a-d 串行不并行
2026-05-09 🟡 中 业务 VLM 图片走 URL 优先 + tempfile 兜底双轨(防盗链)
2026-05-09 🟡 中 范围 bilibili-cli / xiaohongshu-cli 推到 P1,不阻塞 P0
2026-05-09 🟡 中 工程 文件名 sanitize 规则严格定义(emoji/特殊字符/超长)
2026-05-09 🟡 中 工程 tempfile 跑完即删,不进 ~/transcript/
2026-05-09 🟡 中 架构 选 HTMX + Jinja2 服务端渲染,不上 React
2026-05-09 🟡 中 架构 asyncio.Queue 进程内队列,不上 celery/redis
2026-05-09 🟢 低 部署 部署到本地服务器(国内 IP,避免小红书海外风控)
2026-05-09 🟢 低 部署 远程访问首选 tailscale,frp 备选
2026-05-09 🟢 低 工程 文档命名约定:PRD/SPEC/PLAN/CLAUDE/REFERENCES/LOG

开发纲要

按时间正序(最新在下)。

日期 阶段 状态 备注
2026-05-08 早期需求探索 done ChatGPT 多轮,得出"开源工具链 vs Get 笔记"的对比
2026-05-09 仓库选型完成 done 主体确定 social-post-extractor-mcp,P1 接 bilibili-cli/xiaohongshu-cli
2026-05-09 文档冻结 v3.1 done PRD / SPEC / PLAN / CLAUDE / REFERENCES / LOG 创建
2026-05-09 项目命名 v3.2 done 定名 Red Blue CP(红蓝CP),CLI 命令 rbcp,文档批量更新
2026-05-09 CEO review 完成 done 参考移植方案确定,P0 scope 精简(+ModelProvider -Queue/status/auth),文档同步 22 处
待定 M0 启动 pending 研读上游代码 + 评估 SDK/爬取复杂度
待定 M1a 完成 pending CLI 极简闭环:rbcp run <url> 出 MD
待定 M1b 完成 pending WebUI 最小页
待定 P0 收尾 pending 三类链接均能稳定出 Markdown
待定 P1 启动(M2) pending P0 稳定后启动

经验沉淀

值得复用的工程经验。开发过程中遇到值得复用的 lesson 时在这里加索引。

日期 优先级 主题 详情
(空)

维护规则

何时新增决策行

  • 形态/架构变化(影响多个文件)
  • 安全约束新增或修订
  • 上游依赖切换
  • 时间盘 / 优先级调整
  • 范围变化(加新功能 / 砍功能)

何时新增详情文档

不是所有决策都需要写详情。判断标准:

  • 高优先级决策:建议写详情,未来回看时省时间
  • 中优先级决策:值得写但不强求
  • 低优先级决策:通常只在 LOG.md 留索引

何时新增经验沉淀

实际开发遇到这些情况时:

  • 踩了一个意料之外的坑(如小红书风控触发条件)
  • 某个工具/库的非显然行为(如 dashscope SDK 的某个怪癖)
  • 验证了某个怀疑(如"VLM 直接吃 URL 失败率多高")
  • 完成一个里程碑后值得复盘的事

链接源对话

每次产品/需求级别的网页讨论(Claude.ai / ChatGPT)后,在"设计源对话"表格里新增一行。这样未来排查"这个决定是怎么来的"时可以追溯。

REFERENCES.md

REFERENCES

外部仓库选型

源文件

REFERENCES · Red Blue CP

自古红蓝出 CP —— B 站小红书 Content Pipeline

外部仓库选型。

仓库映射表

仓库 能干什么 不能/不适合干什么 项目里的定位
JNHFlow21/social-post-extractor-mcp 直接把 B 站/小红书链接转成文本;支持视频转写、小红书图文图片理解、输出 script.md / info.json 原本是 MCP,不是 WebUI/CLI 产品;项目较新(5⭐ 21 commits Alpha) P0 参考源,研读其 SDK 调用和爬取逻辑,自主架构实现
runesleo/x-reader 覆盖 7+ 平台的通用内容读取器 无法提取小红书内容 竞品参考,Red Blue CP 是唯一覆盖 B站+小红书的开源项目
public-clis/bilibili-cli B 站字幕、音频提取、评论、UP 主视频列表、JSON 输出 不负责整体知识库入库;不是 WebUI P1 接入,用于 B 站博主全量、字幕兜底、强制 ASR
jackwener/xiaohongshu-cli 小红书读笔记、搜索、评论、用户主页、博主笔记列表 不能下载图片/视频,所以不能直接做小红书视频转写/图文 OCR P1 接入,用于小红书博主全量和评论提取
jackwener/xhs-cli 浏览器自动化版小红书 CLI,可能更抗风控 更重、更慢,需要浏览器环境 P2 备胎,API 版失效时再用
jackwener/opencli 把网站变成 CLI,复用浏览器登录态 太泛化;本项目已有更直接工具 不进 MVP,未来登录态兜底
epiral/bb-browser "浏览器就是 API",给 Agent 复用已登录浏览器 工程复杂,不适合 P0/P1 主链路 P2 兜底,适合自己账号复盘/后台页面
Panniantong/Agent-Reach 帮你安装和配置一堆工具 它是工具集合 / installer,不是核心能力本身 不采用,只做参考
HKUDS/CLI-Anything 把复杂软件包装成 agent-native CLI 本项目 CLI 简单,typer 手写够了 不采用

一句话决策

  • P0 参考 social-post-extractor-mcp 逻辑,自主实现(不 fork)
  • P1 再接 bilibili-clixiaohongshu-cli
  • 其他仓库都是兜底、参考或过度工程化,先不要引入

引入时机

P0:
  social-post-extractor-mcp
    → 参考其逻辑(不 fork)
    → 自主实现 WebUI + CLI + Markdown exporter + SQLite + ModelProvider

P1:
  bilibili-cli
    → uv tool install bilibili-cli[audio]
    → subprocess 调 user-videos / video --subtitle / audio
    → 用于 B 站博主全量、字幕拉取(备用)、强制 ASR 时音频抽取

  xiaohongshu-cli
    → uv tool install xiaohongshu-cli
    → subprocess 调 user-posts / comments --all
    → 用于小红书博主全量、评论提取

P2:
  xhs-cli                 # API 版风控失效时
  opencli                 # 浏览器登录态兜底
  bb-browser              # 自己账号复盘 / 后台页面访问

不采用:
  Agent-Reach             # 工具集合,不是核心能力
  CLI-Anything            # 项目体量不需要这套 harness

关键能力对比(P1 接入时参考)

B 站

能力 bilibili-cli social-post-extractor-mcp
视频字幕(CC + 自动) bili video BV... --subtitle-timeline --json ✅ 自带
视频转写(ASR) ❌ 需自接 ASR ✅ 自带(paraformer-v2)
音频抽取 bili audio BV... --segment 25 出 16kHz WAV ⚠️ 内部走 ffmpeg-python
UP 主视频列表 bili user-videos UID --max 200 ❌ 不支持
评论 bili video BV... --comments ❌ 不支持
AI 总结(B 站官方) bili video BV... --ai ❌ 不支持

P1 分工:博主全量用 bilibili-cli;单条转写继续用 social-post-extractor-mcp 的整合链路。

小红书

能力 xiaohongshu-cli social-post-extractor-mcp
笔记正文(desc 字段) xhs read URL --json ✅ 自带
视频转写(ASR) ❌ 不下载视频 ✅ 自带
图文图片视觉理解 ✅ 自带(qwen3-vl-flash)
博主笔记列表 xhs user-posts <user_id> ❌ 不支持
评论(含子评论) xhs comments URL --all --json ❌ 不支持
限流策略 内置 1-1.5s 抖动,禁止并行 自实现

P1 分工:博主全量和评论用 xiaohongshu-cli;单条转写/视觉用 social-post-extractor-mcp。


social-post-extractor-mcp 内部依赖(pyproject.toml)

mcp >= 1.0.0       # MCP 协议层(fork 后保留入口不动)
requests           # HTTP 抓取
ffmpeg-python      # 音视频处理
tqdm               # 进度条
dashscope          # 阿里云百炼 SDK(ASR + 视觉 + 清理 LLM 都靠它)
fastapi            # HTTP 服务器(本项目继承复用)
uvicorn            # ASGI 服务器(本项目继承复用)
jinja2             # 模板引擎(本项目继承复用)
websockets         # WebSocket
python-socks       # SOCKS 代理

关键事实

  1. 不依赖 bilibili-cli / xiaohongshu-cli,是用 requests 自己实现的抓取
  2. 唯一对外 CLI 依赖在 README 写明:social_analyze_owner_posts(自己账号复盘)需要 opencli/bb-browser
  3. 模型层硬绑 dashscope SDK;不是 OpenAI 兼容,要换模型必须重写适配(P1e 任务)
  4. 没有传统 OCR 库,"OCR" 实际是 qwen3-vl-flash 视觉模型

风险与备选

主路径失效场景 备选
小红书 API 风控(xiaohongshu-cli 失效) xhs-cli(浏览器自动化版)
小红书需要登录态访问后台数据 opencli / bb-browser
dashscope 不可用或成本飙升 P1e 完成后切 OpenAI 兼容服务(Groq / 火山 / 自建 vllm)
qwen3-vl-flash 视觉效果不达标 P2 加 PaddleOCR 备选通路
上游 social-post-extractor-mcp 长期不维护 fork 自己维护,依赖少(10 个包)

与上游同步策略

  • 不主动从上游 git pull,避免破坏改造
  • 重大上游修复(小红书签名更新等)按需 cherry-pick
  • 自己的改动只放在 app/ 目录下,不混入 social_post_extractor_mcp/,方便上游同步
docs/gstack/ceo-plans/2026-05-09-p0-from-scratch.md

CEO Plan

P0 从零参考移植决策

源文件

CEO Plan: Red Blue CP P0 — From Scratch

Generated by /plan-ceo-review on 2026-05-09 Branch: main | Mode: SCOPE EXPANSION Repo: red-blue-cp

Vision

10x Check

不只是 "粘链接出 Markdown"。10 倍版本是你的个人内容情报系统。每条你看过的B站视频、每篇你收藏的小红书笔记,自动变成本地知识节点。节点之间有关联(同一个博主、同一个话题)。你可以问 "某UP主在过去三个月里提到了几次 X 话题?" 然后从自己的知识库里得到答案。

P0 是地基层:一条链接 → 一个结构化的 Markdown 文件。地基打对了,后面的每一层都是自然生长。

Platonic Ideal

你在手机上看到一个B站视频,复制链接,粘到浏览器里。30 秒后,一个干净的 Markdown 文件出现在你的 Obsidian vault 里。frontmatter 完美。视频内容被精确转录。图文笔记的每张图都有文字描述。标签自动生成。相关的历史内容自动链接。知识图谱有机生长。

用起来的感觉是:每消费一条内容,你的知识库就多一个节点,而你什么都不用做。

Implementation Decision

Approach C: 参考移植(Reference Migration)(原 PLAN.md 方案 A "旁路包装" 被替换)

含义:读懂上游 social-post-extractor-mcp 的逻辑(爬取、SDK 调用、防封号策略),用自己的架构重写。代码 100% 自己的,但不踩重复的坑。不是"完全不看上游代码",而是"看懂再用自己的方式写"。

理由:

  • 开源叙事更干净 — "参考了上游逻辑" 比 "fork 了上游" 好,不带包袱
  • 地基更深 — 代码 100% 自己写,架构完全可控
  • 上游 social-post-extractor-mcp 只作为参考,不再 fork
  • M0 的核心任务是研读上游代码,理解三件事:dashscope SDK 调用方式、小红书爬取签名逻辑、防封号策略

逃生路线:如果 M0 评估发现 dashscope SDK 调用或小红书爬取逻辑比预期复杂太多(标准:某单项预估超过 2 天),退回方案 A。具体步骤:fork social-post-extractor-mcp → uv sync → 在 app/ 旁路调用上游业务函数。退回后 ModelProvider 接口仍保留,但 DashscopeProvider 内部改为调用上游函数。

MCP 入口处理

从零写意味着没有上游 MCP 入口。CLAUDE.md 红线 #8("不删 MCP 入口")基于 fork 上游的前提,从零写后该红线废除。如果未来需要 MCP 能力,作为 P2 新建,不是保留。

Scope Decisions

# Proposal Effort Decision Reasoning
1 模型接口抽象 (ModelProvider + DashscopeProvider) S (~2-3h) P0 ACCEPTED 从零写的核心价值就是架构自由度,画插座的边际成本极低
2 asyncio.Queue 任务队列 S (~80-120 行) → P1 Codex 审查后重新评估:P0 用 create_task 先跑通,Queue 复杂度被低估
3 任务进度跟踪 (step 字段) S (~1h) → P1 跟 Queue 配合更有意义,一起推到 P1
4 pyproject.toml + entry point S (~30min) P0 ACCEPTED 从零建项目的必须步骤
5 首次使用引导 (API Key + ffmpeg 检测) S (~10-20 行) P0 ACCEPTED 新用户不会在第一步就放弃
6 CLI rbcp status S (~1h) → P1 P0 只需 rbcp run + rbcp serve
7 URL 自动检测平台 S (~10 行) P0 ACCEPTED "粘链接就行"体验的基础
8 WebUI basic auth S (~2h) → P1 P0 局域网部署,auth 不紧急

Document Conflicts — Must Sync Before Coding

本 CEO plan 接受的扩展与现有文档体系有以下冲突,开始写代码前必须同步修改

文件 冲突点 修改方式
CLAUDE.md §反过度抽象 禁止 P0 引入 IModelProvider 接口 移除该禁令,改为"P0 定义 ModelProvider Protocol + DashscopeProvider"
CLAUDE.md §反过度抽象 禁止 P0 引入 JobQueue 保留该禁令(Queue 已推到 P1)
CLAUDE.md 红线 #8 "不删 MCP 入口" 废除该红线(从零写,无上游 MCP 入口)
CLAUDE.md 红线 #4 引用 ~/knowledge-vault/ 改为 ~/transcript/
SPEC.md §1 "P0 阶段不引入 asyncio.Queue" 保留(Queue 已推到 P1),但需更新模块分层图去掉上游引用
SPEC.md §2 extractor.py "包装上游 extract 函数" 改为"自实现内容提取逻辑(参考上游)"
SPEC.md §3 数据流 "调上游业务函数" 改为"直接调用 dashscope SDK"
SPEC.md §6.1 目录结构 ~/knowledge-vault/ 改为 ~/transcript/ 扁平结构
PRD.md §5.1 目录结构 ~/knowledge-vault/ 同上
PLAN.md M0 "fork 上游" 改为"研读上游 + 理解 SDK + 评估复杂度"
PLAN.md M1a "调用上游业务函数" 改为"自实现"
PLAN.md M1a CLI 输出 ~/knowledge-vault/... 改为 ~/transcript/...
PLAN.md M2a asyncio.Queue 在 P1 保留在 P1(不再移动)
README.md ~/knowledge-vault/ 改为 ~/transcript/
README.md "快速开始" 引用 cd social-post-extractor 改为项目自身的安装方式
REFERENCES.md "fork social-post-extractor-mcp" 改为"参考其逻辑,自实现"
REFERENCES.md 无 x-reader 竞品记录 加入 x-reader 条目(无小红书能力)
design doc Approach A "严格按现有 SPEC 执行" 标记为 superseded by CEO plan Approach C
pyproject.toml 依赖 mcp >= 1.0.0 从零写不需要 mcp 依赖,移除
SPEC.md §7 无 WebUI 认证说明 加 basic auth 说明(RBCP_PASSWORD env)
SPEC.md / CLAUDE.md 无 cookie 存储方案 明确 cookie 存 env 文件,.gitignore 保护
PRD.md §P0 "模型:百炼硬编码,不抽象" 改为"P0 定义 ModelProvider Protocol,DashscopeProvider 为唯一实现"
SPEC.md §4.2 P0 CLI 只有 rbcp run + serve 保留(rbcp status 已推到 P1)
SPEC.md §7 uvicorn 启动命令无 host 参数 改为 --host 0.0.0.0,兼容 WSL2/tailscale 外部访问

为什么 ModelProvider 不算过度抽象: CLAUDE.md 的反过度抽象原则基于 "fork 上游、旁路包装" 的前提——那时候加接口是提前抽象。参考移植从零写的情况下,ModelProvider 是自然的代码组织方式(不是提前抽象,而是初始设计),边际成本极低。asyncio.Queue 经 Codex 审查后保留在 P1。

P0 Accepted Scope

  • ModelProvider Protocol class (asr/vlm/llm_clean) + DashscopeProvider 实现
  • pyproject.toml 带 [project.scripts] entry point,uv pip install .rbcp 可用
  • 启动时检测 DASHSCOPE_API_KEY + ffmpeg,缺失给清晰提示
  • URL 自动检测平台(bilibili.com/b23.tv/xiaohongshu.com/xhslink.com 正则匹配)
  • 小红书 cookie 存储方案:与 API Key 同一个 env 文件,受 .gitignore 保护
  • P0 任务调度用 asyncio.create_task(不用 Queue)
  • 安全已知限制显式记录:SSRF 风险(P0 不处理,局域网部署)、WebUI 无认证
  • 部署约束:uvicorn 绑定 0.0.0.0(非 127.0.0.1),兼容 WSL2 mirrored networking + tailscale 等外部访问场景

Moved to P1 (from original expansion)

  • asyncio.Queue + worker 数 + 启动重建(P1a)
  • SQLite jobs 表 step 字段 + 进度跟踪(P1b,与 Queue 配合)
  • CLI rbcp status(P1c)
  • WebUI basic auth(P1c)
  • 批量 + 限流(P1d)
  • 博主全量(P1e)
  • 评论提取(P1f)
  • B站手动 ASR(P1g)
  • 模型抽象层 OpenAI compat(P1h,最后做)
  • 远程访问 tailscale(P1i)

Test Plan Additions (CEO Review)

CLAUDE.md 已列 4 类集成测试(happy path × 3 + failure + 路径穿越 + tempfile 清理)。参考移植后新增:

  • ModelProvider 单元测试:DashscopeProvider 的 asr/vlm/llm_clean 三种调用分别 mock 验证
  • Queue 恢复测试:杀进程后重启,SQLite 里 running 状态的任务应回到 pending
  • basic auth 测试:设置 RBCP_PASSWORD 后未认证请求返回 401

Deferred to TODOS.md

  • WebUI 品牌色区分 B站/小红书(UI polish,M1b 或 P1)
  • Obsidian URI scheme 按钮(P2 集成层)
  • 键盘快捷键粘贴即提交(UI polish)
  • Dark mode(UI polish)

Landscape Update

x-reader (runesleo/x-reader) 是新出现的竞品:覆盖 7+ 平台的通用内容读取器。但经确认,x-reader 无法提取小红书内容。Red Blue CP 是目前唯一能实现以下四项的开源项目:

  1. B站视频提取文字稿
  2. 小红书视频提取文字稿
  3. 小红书图片提取文字稿
  4. 小红书提取评论(P1, not in this plan)

Key Changes from Original PLAN.md

  1. 实现方案: fork 上游 → 参考移植(读懂上游逻辑,用自己架构重写)
  2. M0 内容: "fork + verify" → "研读上游 + 理解 SDK + 评估复杂度"
  3. P0 新增: ModelProvider + pyproject.toml + 首次引导 + URL 检测(4 项,其余推 P1)
  4. P0 移出: asyncio.Queue、进度跟踪、rbcp status、basic auth → P1(Codex 审查后决定)
  5. 文档同步: ~/knowledge-vault/ → ~/transcript/(见 Document Conflicts 表)
  6. REFERENCES.md: 需加入 x-reader 作为竞品/参考
  7. 时间: 4 天 → 2-2.5 天(CC 辅助开发 + 砍 scope)

Codex Independent Review Summary

Codex 独立审查结论:

  • 原 P0 范围膨胀风险高(7 项扩展 + auth),建议回归精简
  • 最可能卡死的点:小红书爬取 + dashscope SDK 自实现
  • 时间估计被调整为更现实的 2-2.5 天(CC 辅助)
  • 两个被遗漏的文档矛盾已补入 Document Conflicts 表(PRD 模型抽象、SPEC CLI scope)

Time Estimate (from-scratch)

原 PLAN 预估 P0 = 4 天(基于 fork 上游 + 手写)。参考移植 + CC 辅助开发后的估计:

阶段 原估计 新估计 变化原因
M0 研读+评估 1 天 0.5-1 天 CC 辅助分析上游代码,但人要亲自读核心逻辑
M1a 核心+CLI 1.5 天 1 天 CC 写 extractor+markdown+storage+CLI+ModelProvider
M1b WebUI 1.5 天 0.5 天 CC 写 HTMX+Jinja2 模板很快
P0 总计 4 天 2-2.5 天 CC 辅助 + 砍掉 Queue/status/auth 到 P1

M0 完成后再精确修正 M1a 时间。如果 dashscope SDK 比预期简单,M1a 可能不到半天。

Open Questions

  1. dashscope SDK 的 ASR/VLM/LLM 三种调用形态复杂度如何?M0 评估后才知道
  2. 短链接(b23.tv / xhslink.com)需要 HTTP 请求解析跳转,可能触发反爬。P0 建议只支持完整链接,短链接支持推到 P1
  3. rbcp status 验收标准:默认 table 格式输出最近 20 条任务,--json 参数输出 JSON 格式,--limit N 控制条数
  4. B站视频无字幕时 P0 是否自动走 ASR?("无字幕→ASR"是必须行为,不同于"字幕质量差→ASR"的 P1 手动切换)
  5. 小红书图文 desc 字段(文字正文)+ VLM 图片理解如何合并到最终 Markdown?M0 研读上游时确认
  6. 并发提交同一 URL:P0 允许重复处理(不做去重),P1 可加 URL 查重提示