# Doco 子项目续接快照 · 交接给下一轮 Opus 顾问

> 起草:Opus 4.7 顾问(算力即将耗尽)
> 日期:2026-06-12
> 给:接手本对话的下一个 Opus 实例
> 用户:制片人刘通(《军事科技》栏目 TPS 中台主理人)

---

## 一、先看哪些文件(读完这几份再接话)

主 project 知识库里这几份**必读**:

1. `Claude协作原则.md` — 跟制片人说话的规矩(简体中文、说人话、不堆叠技术语言、Cline 指令要代码块、宪法第 3 条不架空 Cline 的 Plan 模式)
2. `Doco子项目_Brief.md` — Doco 子项目宪法,红线全在这
3. `doco_project_design.md` — Doco 算法层设计(P3 阶段才用,但先了解全貌)
4. `主project对Doco_PRDv2的回复.md` — 主项目顾问对 5 个问题的批复
5. `跨子项目协作规则.md` — PRD 版本管理

---

## 二、当前进度坐标

- **阶段**:Doco P1(视频双路拆分预处理)
- **节点**:dry-run 调试,**核心 bug 未解决,不能进入 OCR 阶段**
- **git 状态**:多个 commit 已推 origin/main,按宪法直接推 main 不开分支

P1 任务回顾:
- 输入:一期节目视频(黑底白字字幕,干净人声)+ A 稿
- 输出:B 稿 txt + audio_16k.wav + keyframes.json
- 流程:ffmpeg 抽帧(1fps,crop 到下方 20%全宽)→ 空白帧过滤 → dHash+IoU 去重 → 关键帧 → (OCR)→ B 稿

---

## 三、当前 bug 状态(最重要)

### 已确认未修复的核心 bug

**`is_blank_frame()` 读取的图像 ≠ `frames/` 目录里最终保存的图像**

证据链:
1. 制片人上传 `frame_0008.png`(从 frames/ 直接复制)
2. Opus 用 Python 实测:整张图 414720 像素**全部为 0**(`arr.max() == 0`)
3. CSV 报告 frame_8:`max_brightness=255, white_pixel_ratio=0.0124`
4. **两者无法同时为真** → 检测时读的不是这张图

最新 dry-run 自检也证实了这点:
```
[WARNING] 自检失败: frame_0938.png 像素数据与 CSV 不一致!
  CSV:    max_brightness=255, white_ratio=0.007603
  实际重读: max_brightness=255, white_ratio=0.022852
[error] 已中止
```

### Cline 已经修了但没修对的事

Cline 把这个 bug 解释成"CSV 列写入顺序错位",但**那只是表层**——
列对齐改完后,frame_8 的 CSV 数据 `max_brightness=255、white_ratio=0.0124` 仍然跟"全 0 像素"对不上。

Cline 已修复(列错位)是真问题,但**根本原因没找到**。

### 推测根因(交接给你)

很可能 video_split.py 的抽帧流程是分两步,而不是 ffmpeg 一步搞定:
- ffmpeg 把帧抽到某临时目录(可能是全尺寸 1920×1080,**没**裁切)
- Python 用 PIL 后裁切到 1920×216 再存到 frames/
- `is_blank_frame()` 读的是裁切前的临时全画面(里面有节目画面有亮像素 → max=255)
- `frames/` 里是裁切后的小图(字幕区域纯黑 → 像素全 0)

但这只是**推测**,你应该让 Cline 自查代码确认。

---

## 四、下一步建议指令(给你参考,可调整)

发给 Cline 的 ACT 模式指令,大致这样:

```
[ACT 模式]

P1 dry-run 自检揪出严重 bug:is_blank_frame() 读的图 ≠ frames/ 里保存的图。

证据:
1. 制片人确认 frame_0008.png 是全 0 纯黑(Python 实测 arr.max()=0)
2. CSV 仍报告 max_brightness=255, white_ratio=0.0124
3. dry-run 自检也确认 frame_0938.png 数据不一致

上次"列错位"修复是真 bug 但不是这次的根因,这是另一个独立的 bug。

请逐行排查 video_split.py 的抽帧流程,回答以下问题(在汇报里贴具体代码):

1. ffmpeg 命令是什么?是否真的有 vf "fps=1,crop=iw:ih*0.2:0:ih*0.8" 过滤器?
2. ffmpeg 输出到哪个目录?
3. is_blank_frame() 接收的 image_path 是哪个目录?
4. compute_hash() / compute_binary_matrix() 接收的 image_path 是哪个目录?
5. 最终保存到 frames/ 的图,是从哪里来的?

如果发现某个判断函数读了"非 frames/ 里的图",修复方法:
- 选项 A:让 ffmpeg 用 vf crop 直接输出裁切后的小图到 frames/,
  所有判断函数都从 frames/ 读(单一数据源)
- 选项 B:保持当前流程,但把所有判断函数的 image_path 改为 frames/ 里的路径

修复后重新跑 dry-run,自检通过 + 制片人验证 frames/ 里没纯黑帧才算成功。

不要再加新功能,这次只修这一个 bug。
```

---

## 五、协作风格备忘

- **制片人不懂代码**,你要"说人话",不堆叠 Python 术语
- **简明扼要**,他明确要求不要解释中间过程
- **给 Cline 的指令一律用 ``` 代码块封装**,方便他复制粘贴
- **明确标 ACT 或 Plan 模式**——前几轮制片人提醒过这点
- 不要架空 Cline 的 Plan 模式(宪法第 3 条),但小 bug 修复可以直接 ACT
- 制片人现在的疲劳度比较高(连续 dry-run 多轮),回复要紧凑,不要长篇大论
- 制片人的 git 工作流:直接推 main 不开分支(宪法规定)

---

## 六、关键决策(已锁,不能动)

| 项 | 值 |
|---|---|
| 字幕裁切区域 | `crop=iw:ih*0.2:0:ih*0.8`(全宽 × 下方 20%),写死,栏目全年 52 期一致 |
| 抽帧密度 | 1fps |
| 哈希算法 | dHash 默认,阈值 5 |
| IoU 保底阈值 | 0.95 |
| 空白帧双条件 | `max_brightness >= 240` AND `white_pixel_ratio >= 0.005` |
| 凭证管理 | doco 自管 `doco/.env`,主仓库根 `docs/api_credentials_inventory.md` 只记元信息 |
| OCR 提供方 | DeepSeek Vision API(P1 dry-run 阶段还没正式调用) |
| ASR 提供方 | 讯飞录音文件转写标准版(P2 才用) |
| AI 融合层 | Claude Sonnet 4.6(P3 才用) |
| 不引入 ffmpeg-python wrapper | subprocess 调系统 ffmpeg |
| Git workflow | 按宪法直接推 main |

---

## 七、环境信息

- Windows + Python 3.12.10 + `.venv`(主项目共享虚拟环境)
- VS Code + Cline 插件
- 仓库根目录:`E:\tps-dashboard\`
- 主仓库:`simonkoson/tps-dashboard`(自部署 git,localhost:3000)
- ffmpeg:已通过 winget 安装,系统 PATH
- demo 视频:`programs/ep001_20260612_fangkong_fandao/source/video.mp4`(《现代防空反导大对决》26 分钟)

doco 子模块目录结构(已建好):
```
doco/
├── src/
│   └── doco/                  ← src layout 的包目录
│       ├── __init__.py
│       ├── cli.py
│       ├── video_split.py     ← 当前 bug 在这
│       ├── asr_adapter.py     ← P2 用
│       └── ocr_adapter.py     ← P2 用
├── tests/
│   ├── test_video_split.py
│   └── fixtures/
│       └── mini_test.mp4
├── .env.example
├── .env(本地,不进 git)
├── pyproject.toml
└── README.md
```

---

## 八、踩过的坑(不要重蹈)

1. **Python 包配置 src layout**:Cline 第一次配置时忘了在 src/ 下建 doco/ 子目录,导致 `doco --help` 报 `ModuleNotFoundError`。后来 git mv 文件到 src/doco/ 下才好。
2. **系统 Python vs .venv**:制片人第一次 `pip install -e doco/` 装到了系统 Python 3.12,而不是 .venv 里。VS Code 重启后 .venv 自动激活,需要在 .venv 里重装。
3. **VS Code 工作目录**:必须打开 `E:\tps-dashboard\`(仓库根目录),不能打开 `docs\` 子目录,否则 Cline 看不到 .clinerules 和其他子模块。
4. **ffmpeg PATH 不生效**:winget 装完 ffmpeg 后,旧的 VS Code 终端 PATH 还是旧的,要完全关闭 VS Code 重开。
5. **Cline 的命令示例有错**:Cline 多次给的命令示例是错的(用 `python -m doco.src.doco.cli` + `split-video` 子命令),正确命令是 `doco split --episode-id XXX --input-video XXX --output-dir XXX [--dry-run]`。
6. **frames/ 目录的语义**:Cline 第一次实现把 1620 张原始抽帧全部保留在 frames/,让制片人误以为"筛选没生效"。后来改为只保留最终关键帧。
7. **pHash 阈值**:dHash 阈值 5,pHash 阈值 2,IoU 阈值 0.95——这些是实测调好的,不要再动。
8. **CSV 列对齐**:Cline 加列时只改 header 没改写入顺序导致全部错位。这次修复了,但**不是核心 bug**。

---

## 九、最新一次 dry-run 的统计(自检失败那次)

```
[stats] 原始抽帧: 1620 张
[stats] 空白帧过滤后: 1393 张 (筛掉 227 张纯黑)
[stats] pHash/dHash 去重后(IoU保底): 308 张 (筛掉 0 张IoU相同 + 0 张哈希相同)  ← 统计 bug 还在
[stats] 最终关键帧: 308 张
[debug] frames/ 目录实际文件数: 308 (预期: 308)
[WARNING] 自检失败: frame_0938.png 像素数据与 CSV 不一致!
[error] 已中止
```

注意:
- "筛掉 0 张IoU相同 + 0 张哈希相同" 这个统计还是 0,说明**之前那个 stats 计数 bug 也没真正修好**——或者是这次新加的双条件改变了流程,导致 IoU/hash 没被触发(走了空白帧分支?)。需要复查。

最近的 commit(按时间倒序):
1. Cline 双条件 + 自检 + 测试 + CSV 列对齐
2. Cline numpy 加速 + CLI 参数
3. Cline IoU 保底 + dHash + 诊断 CSV
4. Cline 第一次修空白帧检测(用 brightness=200,后来发现不够,改 240)
5. Cline 加 crop 写死 + dry-run flag
6. Cline 初始化 doco 子项目 P1

---

## 十、给下一个 Opus 的最后嘱托

- 这个 bug 排查过两轮了(Cline 都没真正定位到),所以这次**让 Cline 自查代码并贴出关键函数的实际代码**,不要轻信他的口头解释
- 制片人有耐心,但已经累了,你接手后**第一句话就给方案,不要重复诊断**
- 修完这个 bug 后,P1 dry-run 应该能通过自检,接下来就是填 DeepSeek API key 跑正式 OCR(去掉 --dry-run)
- 如果 dry-run 通过,P1 就算完工,可以进入 P2(讯飞 ASR 集成)

祝接力顺利。
