# Doco 子项目 · P1 完工快照 · 交接给 P2(OCR 阶段) > 起草:Opus 顾问(本对话) > 日期:2026-06-15 > 用户:制片人刘通(《军事科技》栏目 TPS 中台主理人) > 上一份:`doco_handoff_to_next_chat.md`(P1 调试中,bug 未解) > 状态:**P1 dry-run 已通过自检与人工验收,P1 完工** --- ## 一、一句话总结 P1(视频双路拆分预处理)的抽帧→空白过滤→去重→关键帧流水线已跑通并通过全部验收,可进入 OCR 阶段。OCR 选型方向已更正为**本地部署 DeepSeek-OCR(经 Ollama)**。 --- ## 二、P1 做了什么 - **输入**:一期节目视频(黑底白字字幕 + 干净人声)+ A 稿 - **本阶段产物**:`frames/`(308 张字幕关键帧)+ keyframes 数据;音轨/B 稿是后续阶段 - **流程**:ffmpeg 抽帧(1fps,crop 到下方 20% 全宽)→ 空白帧过滤 → dHash + IoU 去重 → 关键帧 - **demo 视频**:《现代防空反导大对决》(26 分钟) --- ## 三、本轮修复的 3 个 bug(都已修好、已验收) 交接前的核心卡点是「`is_blank_frame()` 读的图 ≠ frames/ 里的图」,自检反复中止。逐层挖下去,实际是三个独立 bug: ### bug 1 · off-by-one 索引错位(核心) - **根因**:`extract_frames()` 用 `enumerate()` 从 0 开始编号(frame_index 0-based),但下游清理逻辑和自检逻辑都从文件名提取 1-based 编号(`frame_0008.png` → 8),两套编号差 1。 - **后果**:空白帧因编号错位被错误保留;自检重读图片取到正确像素,却去查 CSV 错误的行 → 报告不一致、中止。 - **不是**"读了不同目录的图"——所有判断函数始终从同一个 frames/ 读图,是编号体系不一致。 - **修复**:改为直接从文件名提取 1-based 编号。commit `bc5a30e` ### bug 2 · 去重计数器恒为 0 - **根因**:`decision_stats[...] = decision_stats.get(..., 0)` 缺了 `+ 1`,每次迭代没递增。 - **后果**:统计永远显示"筛掉 0 张 IoU + 0 张哈希",看起来像去重没生效。**但去重逻辑本身一直是对的**,只是计数显示错。 - **修复**:加 `+ 1`。commit `d55f029` ### bug 3 · 2 个失败的单元测试(均与本次修改无关的旧断言问题) - `test_subtitle_frame`:切片比例写错(注释说 1% 实际取了 10%),修改前就在失败。改 `arr[:100,:10]` → `arr[:10,:10]`。 - `test_ratio_ok_but_max_brightness_too_low`:亮度阈值从 200→240 后,亮度 220 的像素不再算白像素,旧断言没同步。改断言为 `white_ratio == 0.0`。 - **修复**:commit `82973a7`,17/17 全过。 --- ## 四、验收数据(已核对,数字闭环) 本次 dry-run 全帧去向(1620 帧): | 类别 | 张数 | |---|---| | 空白帧(blank) | 227 | | IoU 重复(duplicate-iou) | 321 | | 哈希重复(duplicate-hash) | 764 | | 首帧保留(kept) | 1 | | 关键帧(keyframe-hash) | 307 | | **合计** | **1620** ✅ | - 最终关键帧 = 1 + 307 = **308 张**,与 `frames/` 实际文件数一致。 - 旁证:demo 这期约 300 条字幕,关键帧 308 ≈ 字幕数,基本一对一,说明去重准确(每条字幕保留一张、砍掉重复画面)。 - **人工验收**:制片人手动翻遍 frames/,确认无任何纯黑帧。 - **单元测试**:17/17 通过。 --- ## 五、遗留小尾巴(不影响完工,有空再收) - `test_ratio_ok_but_max_brightness_too_low` 这个测试名与它现在实际测的行为对不上了(白像素阈值提到 240 后,原本想测的"白像素够但亮度不够"场景已构造不出来,断言被改成了 white_ratio==0)。建议以后让 Cline 给这个测试改名或重构。纯属测试整洁度,不影响流水线正确性。 --- ## 六、重要更正 · OCR 选型(覆盖 PRD v2 的 Q1 表述) **PRD v2 写的"DeepSeek 有 OCR 模型 + Vision 识图模式(官方 API endpoint)"——这条事实有误,作废。** 查证结果(2026-06-15,DeepSeek 官方文档): - DeepSeek 官方 API 只有 `deepseek-v4-flash` / `deepseek-v4-pro` 两个模型,**纯文本,不收图像输入**(功能仅:文本对话 / Tool Calls / JSON 输出 / FIM)。Cline 里 DeepSeek 预设没有 image 选项是正常的,不是配置漏项。 - `DeepSeek-OCR`(3B,中文文档识别强)是**开源模型,只能本地部署**(vLLM 或 Ollama),**没有现成云端 API**,需自备 GPU。 - 因此制片人手上的 DeepSeek API key **调不了 OCR**。 **新方向(已与制片人确认)**:本地部署 DeepSeek-OCR,经 **Ollama** 运行。 - 理由:制片人有 RTX 4090D 24GB(跑 3B OCR 模型富余);零调用成本、不限量;栏目全年 52 期常态化使用,长期划算;**且制片人另有一个离线小机房,只能用本地方案,云端 API 调不通**。 - Windows 上优先 Ollama(原生支持、免 WSL),不碰 vLLM(Windows 上一般要 WSL,门槛高)。 > 候选备选(若本地部署受阻):MiniMax-VL 云端 API、讯飞 OCR。但离线小机房只能本地。 --- ## 七、下一步(P2 / OCR 阶段) 1. **本地部署 DeepSeek-OCR(Ollama)**:在制片人栏目主机上搭起来,确认能识别黑底白字字幕关键帧;之后同样流程部署到离线小机房。 2. **OCR 适配层 `ocr_adapter.py`**:把 308 张关键帧批量送入本地 OCR 服务,产出带 `[Nm Ns]` 时间戳的 **B 稿 txt**(格式必须与旧版完全一致,下游 P3 才零侵入)。 3. **去掉 `--dry-run`**,跑正式 OCR,产出 B 稿 + audio_16k.wav + keyframes.json,P1 整体产物齐活。 4. 之后才进 P2 的讯飞 ASR 适配、P3 的 Claude 融合层。 --- ## 八、关键决策(已锁,沿用) | 项 | 值 | |---|---| | 字幕裁切区域 | `crop=iw:ih*0.2:0:ih*0.8`(全宽 × 下方 20%),写死,全年 52 期一致 | | 抽帧密度 | 1fps | | 哈希算法 | dHash 阈值 5,pHash 阈值 2 | | IoU 保底阈值 | 0.95 | | 空白帧双条件 | `max_brightness >= 240` AND `white_pixel_ratio >= 0.005` | | 凭证管理 | doco 自管 `doco/.env`,主仓库根 `docs/api_credentials_inventory.md` 只记元信息 | | **OCR 提供方** | **本地 DeepSeek-OCR(经 Ollama)** ← 本次更正,原 PRD 的"DeepSeek 云端 Vision API"作废 | | ASR 提供方 | 讯飞录音文件转写标准版(P2 才用) | | AI 融合层 | Claude Sonnet 4.6(P3 才用) | | 抽帧/抽音轨 | subprocess 调系统 ffmpeg,不引入 ffmpeg-python | | Git workflow | 按宪法直接推 main,不开分支 | --- ## 九、环境信息 - Windows + Python 3.12.10 + `.venv`(主项目共享虚拟环境) - VS Code + Cline 插件(编程模型已从 Minimax M3 换为 **deepseek-v4-pro**,响应更快) - 仓库根:`E:\tps-dashboard\`(VS Code 必须打开仓库根,不能打开子目录) - 主仓库:`simonkoson/tps-dashboard`(自部署 git,localhost:3000) - ffmpeg:winget 安装,系统 PATH - GPU:**NVIDIA RTX 4090 D 24GB**(本地 OCR 部署用) - 另有一台**离线小机房**(无外网,本地部署的主要落地环境之一) - 正确 CLI:`doco split --episode-id XXX --input-video XXX --output-dir XXX [--dry-run]` --- ## 十、本轮 commit(按时间) | commit | 内容 | |---|---| | `bc5a30e` | extract_frames:frame_index 从 0-based enumerate 改为 1-based 文件名提取(核心 bug) | | `d55f029` | decision_stats 计数加 `+ 1`(去重计数器恒为 0) | | `82973a7` | 修复 2 个测试断言(切片比例 + 阈值适配),17/17 通过 | --- *P1 至此完工。下一轮从「Ollama 本地部署 DeepSeek-OCR」开始。*