|
| 1 | +# v0.14 子项目 D:采集质量攻坚设计规格(结构 / 质量 / 算法 / 平台 四层) |
| 2 | + |
| 3 | +> 状态:✅ 已批准(2026-08-28,逐节确认) |
| 4 | +> 所属版本:v0.14 |
| 5 | +> 范围:子项目 D——章节级混合形态笔记 / 双维决策质量门控 / 版面重建+行合并+跨帧增量+行级重识别 / 平台模板适配 |
| 6 | +
|
| 7 | +## 1. 背景与目标 |
| 8 | + |
| 9 | +### 1.1 痛点(用户反馈,2026-08-27~28) |
| 10 | + |
| 11 | +| # | 痛点 | 现状根因 | |
| 12 | +|---|------|----------| |
| 13 | +| D1 | PPT 型视频知识内容可视但笔记仍口语化 | v0.11.5 决策:`assemble_markdown` 将 OCR 画面要点移出笔记正文(笔记只剩口语转写);"转文字+手动梳理"优于"采集-转化" | |
| 14 | +| D2 | OCR 产物质量偏低,喂 AI 只增 token 消耗 | 净化链是"字幕思维"(按时间戳线性拼接),对 PPT 版面结构性错误;bbox 已落库(v0.5.0)但从未使用;无质量评估,低质量 OCR 照样进正文/喂 AI | |
| 15 | + |
| 16 | +### 1.2 用户关键纠正 |
| 17 | + |
| 18 | +> "问题在于不是所有的视频都有 ppt,而且一个视频内也可能存在两个部分。" |
| 19 | +
|
| 20 | +**不能做视频级二分法**——形态决策必须下沉到**章节级**。 |
| 21 | + |
| 22 | +### 1.3 目标 |
| 23 | + |
| 24 | +1. **章节级混合形态**:整篇笔记 = 图文章节 / 口语章节混编,每章独立决策 |
| 25 | +2. **质量门控**:低质量 OCR 不进正文、不喂 AI(省 token);质量分诚实呈现 |
| 26 | +3. **算法提质**:屏内版面重建(bbox 空间排序)+ 行合并评分器 + 跨帧增量合并 + 行级重识别(官方 adapter 编排自研) |
| 27 | +4. **平台适配**:B站/抖音/Edge 视频区 ROI + 字幕带先验 + 噪音区掩码(噪音从源头消失) |
| 28 | +5. **全链路零新增 token 成本**:规则方案,可单测,有降级 |
| 29 | + |
| 30 | +## 2. 方案选型记录 |
| 31 | + |
| 32 | +### 2.1 结构层:章节级混合形态(已裁决) |
| 33 | + |
| 34 | +| 变体 | 结论 | |
| 35 | +|---|---| |
| 36 | +| A. 大纲骨架+屏幕内容为主体(视频级)| 否决——无 PPT 视频被误伤 | |
| 37 | +| B. 双轨笔记(视频级二分)| 否决——一个视频内两个部分无法处理 | |
| 38 | +| C. 最小改动(仅口语净化)| 否决——不解决"内容可视不可得" | |
| 39 | +| **章节级混合形态** | ✅ 采纳——章节边界检测(已有)→ 每章独立决策 → 图文/口语混编 | |
| 40 | + |
| 41 | +### 2.2 质量层:双维决策 + 质量门控(已裁决) |
| 42 | + |
| 43 | +| 维度 | 信号 | 决策 | |
| 44 | +|---|---|---| |
| 45 | +| OCR 密度(已有信号下沉)| 章节窗口内 OCR 文本量 / 屏卡数 | 密度高 → 候选图文章节 | |
| 46 | +| **OCR 质量分(新增)** | 置信度 + 碎片率 + 连贯性 + 噪音比 | 质量高 → 图文章节;**质量低 → 退回口语章节(OCR 弃用)** | |
| 47 | + |
| 48 | +门控双出口:**笔记出口**(低质量不沉淀)+ **AI 精修出口**(低质量不喂 AI)。 |
| 49 | + |
| 50 | +### 2.3 算法层:三层叠加(已裁决,经 API 查证) |
| 51 | + |
| 52 | +| 层 | 方案 | 状态 | |
| 53 | +|---|---|---| |
| 54 | +| 行合并评分器(B)| 识别后文本级合并(几何+文本信号)| ✅ 主链路 | |
| 55 | +| 跨帧增量合并(C)| PPT 动画逐行出现的增量拼接 | ✅ 主链路 | |
| 56 | +| 行级重识别(A)| 官方 `TextRecognitionAdapter` 编排自研 | ✅ 已确认 API(见 2.4)| |
| 57 | + |
| 58 | +### 2.4 引擎 API 查证裁决(2026-08-28 源码验证) |
| 59 | + |
| 60 | +| 结论 | 证据 | |
| 61 | +|---|---| |
| 62 | +| oar-ocr 0.9.2 **无 rec-only API** | `OAROCR.predict` 为 det+rec 一体(源码 oarocr/ocr.rs) | |
| 63 | +| **`TextRecognitionAdapter` 是公共 API** | `oar_ocr::domain::adapters::TextRecognitionAdapter` + Builder(CRNN + 预处理 + CTC 解码全封装,`supports_batching()=true`)| |
| 64 | +| 结构引擎已接入 | `OARStructure.predict_image`(structure_engine.rs,表格/公式在用)——作精修链路增强,不作实时主链路(模型 129MB+231MB)| |
| 65 | + |
| 66 | +### 2.5 平台层:平台模板 + 通用几何兜底(已裁决) |
| 67 | + |
| 68 | +| 变体 | 结论 | |
| 69 | +|---|---| |
| 70 | +| A. 平台硬编码模板 | 否决——网页改版即失效 | |
| 71 | +| B. 纯通用视频区检测 | 中间态——实现复杂 | |
| 72 | +| **C. 平台先验 + 通用兜底** | ✅ 采纳——模板是 JSON 数据不是代码;未命中走几何兜底;全失败走现状 | |
| 73 | + |
| 74 | +## 3. 架构设计 |
| 75 | + |
| 76 | +### 3.1 四层数据流 |
| 77 | + |
| 78 | +``` |
| 79 | +采集(关键帧 + bbox + 时间戳) |
| 80 | + │ |
| 81 | + ├─ D4 平台层:视频区 ROI 裁剪 / 字幕带先验 / 噪音区掩码(OCR 前) |
| 82 | + ▼ |
| 83 | +OCR 净化链(D3,重构 note_filter_ocr.rs): |
| 84 | + 排序 → ① 行合并评分器 → ② 行级重识别(疑碎行)→ ③ 跨帧增量合并 → 净化 → 去重 |
| 85 | + │ |
| 86 | + ├─ D1 结构层:章节边界检测 → 每章形态决策(图文/口语) |
| 87 | + ▼ |
| 88 | +D2 质量层:ocr_quality_score 门控 → 图文章节(达标)/ 口语章节(弃用/退回) |
| 89 | + │ |
| 90 | + ├─ 笔记出口:图文章节 OCR 主体 + 口语引用块 / 口语章节现状形态 |
| 91 | + └─ AI 出口:仅达标图文章节 OCR 进精修输入(提示词标注修正错字) |
| 92 | +``` |
| 93 | + |
| 94 | +### 3.2 新增/修改文件清单 |
| 95 | + |
| 96 | +| 文件 | 职责 | 行数预算 | |
| 97 | +|---|---|---| |
| 98 | +| `chapter_morph.rs`(新)| 章节形态决策纯函数(密度×质量 → 图文/口语)| ≤150 | |
| 99 | +| `ocr_quality.rs`(新)| `ocr_quality_score` 计算(四信号加权)| ≤150 | |
| 100 | +| `layout_reorder.rs`(新)| 屏内版面重建:行聚类/栏检测/块排序(简化 XY-Cut)| ≤250 | |
| 101 | +| `line_merge.rs`(新)| 行合并评分器(几何+文本信号 + 护栏)| ≤150 | |
| 102 | +| `incremental_merge.rs`(新)| 跨帧增量合并(包含关系 + bbox 锚定)| ≤120 | |
| 103 | +| `line_rec_engine.rs`(新)| 行级重识别编排(行聚类→裁剪→官方 adapter→替换)| ≤200 | |
| 104 | +| `platform_layout.rs`(新)| 平台识别 + 模板加载 + 几何兜底(三层降级)| ≤200 | |
| 105 | +| `platform_templates.json`(新)| B站/抖音/Edge 平台模板数据(videoRoi/subtitleBand/noiseMasks)| ≤80 | |
| 106 | +| `note_filter_ocr.rs`(改)| 净化链插入 ① ② ③ 三步 | ≤40 增量 | |
| 107 | +| `note_filter.rs` / `concat.rs`(改)| 图文章节组装(OCR 主体 + 口语引用块)| ≤60 增量 | |
| 108 | +| `group_route.rs`(改)| ocr_text_density 信号下沉到章节级复用 | ≤30 增量 | |
| 109 | + |
| 110 | +## 4. 详细设计 |
| 111 | + |
| 112 | +### 4.1 D1 章节级混合形态 |
| 113 | + |
| 114 | +**章节形态决策**(`chapter_morph.rs` 纯函数): |
| 115 | + |
| 116 | +``` |
| 117 | +输入:章节内屏卡集合(含 OCR 密度)+ ocr_quality_score |
| 118 | +决策:密度 ≥ DENSITY_TH && 质量 ≥ QUALITY_TH → 图文 |
| 119 | + 密度 ≥ DENSITY_TH && 质量 < QUALITY_TH → 口语(OCR 弃用,原料视图可查) |
| 120 | + 密度 < DENSITY_TH → 口语(现状形态) |
| 121 | +边界:无章节边界 → 全篇退化现状;全高密度 → 整篇图文;空章节跳过 |
| 122 | +``` |
| 123 | + |
| 124 | +**图文章节组装**(concat.rs 扩展): |
| 125 | +- 主体:OCR 屏卡要点(版面重建后的段落) |
| 126 | +- 口语降级为引用块(`> 讲者:...`,保留时间戳锚点) |
| 127 | +- 章节标题复用 `detect_outline_smart` 屏标题资产 |
| 128 | + |
| 129 | +### 4.2 D2 质量分与门控 |
| 130 | + |
| 131 | +**`ocr_quality_score`**(章节窗口内,四信号加权): |
| 132 | + |
| 133 | +| 信号 | 计算 | 权重 | |
| 134 | +|---|---|---| |
| 135 | +| 置信度 | OcrBlock.score 加权均值 | 0.4 | |
| 136 | +| 碎片率 | ≤4 字块占比(越低越好)| 0.2 | |
| 137 | +| 连贯性 | 行合并后句长分布(可成句 → 高)| 0.2 | |
| 138 | +| 噪音比 | UiJunkList 命中率(越低越好)| 0.2 | |
| 139 | + |
| 140 | +- **阈值**:`QUALITY_TH = 0.6`(可配置,初值经 golden 用例校准) |
| 141 | +- **AI 出口门控**:精修输入组装时过滤低质量章节 OCR(省 token);达标章节提示词标注"以下为屏幕 OCR 内容,请优先修正错字后使用" |
| 142 | +- **质量报告**:会话详情显示"本章节 OCR 质量 72 分,已采用/已弃用"(quality_report.rs 哲学延续:"指标从恒 ≈0 变真实") |
| 143 | + |
| 144 | +### 4.3 D3 算法层 |
| 145 | + |
| 146 | +**屏内版面重建**(`layout_reorder.rs`,简化 XY-Cut): |
| 147 | +1. 行聚类:y 坐标容差(±8px)内归行 |
| 148 | +2. 行内排序:x 升序 |
| 149 | +3. 栏检测:相邻行稳定列间隙 → 多栏分组(栏内 y 序、栏间左→右) |
| 150 | +4. 标题识别:最大字号/最短文本行 → 标题(复用屏标题资产) |
| 151 | +5. 段落拼接:行间隙小的块合并为段落 |
| 152 | + |
| 153 | +**行合并评分器**(`line_merge.rs`): |
| 154 | + |
| 155 | +``` |
| 156 | +几何信号:垂直重叠 > 50%(同行)/ 水平间隙 < 半字宽 / 行高一致 |
| 157 | +文本信号:A 尾虚词(的/了/是/在/与…)→ 续接;A 尾句号/问号 → 断开; |
| 158 | + B 首项目符号(•/-/1.)→ 新要点 |
| 159 | +护栏:合并超长回退;字体差 > 30% 不合并(标题+正文) |
| 160 | +反误合并原则:宁可少合并(损失完整性)不可错合并(制造幻觉句子) |
| 161 | +``` |
| 162 | + |
| 163 | +**跨帧增量合并**(`incremental_merge.rs`): |
| 164 | +``` |
| 165 | +帧2 文本 ⊇ 帧1 文本 && bbox 位置稳定 → 同屏增量合并(动画逐行出现) |
| 166 | +bbox 整体位移 → 翻页 → 新屏 |
| 167 | +``` |
| 168 | + |
| 169 | +**行级重识别**(`line_rec_engine.rs`): |
| 170 | +``` |
| 171 | +疑碎行判定:碎片率高(≤4 字块占比 > 阈值)或 置信度 < 阈值 |
| 172 | +流程:行聚类 → 行图裁剪(bbox 并集 + padding)→ TextRecognitionAdapter::execute(批量) |
| 173 | + → 行级文本替换碎片文本(行级得分取均值) |
| 174 | +降级:adapter 构建失败 → 保留碎片结果(能力降级不失效) |
| 175 | +挂载:engine.rs 常驻引擎池(OCR worker 线程) |
| 176 | +``` |
| 177 | + |
| 178 | +### 4.4 D4 平台模板 |
| 179 | + |
| 180 | +**平台识别**:窗口标题/URL → `platform_layout.rs`(bilibili/douyin/youtube/edge-local/unknown) |
| 181 | + |
| 182 | +**模板数据**(`platform_templates.json`,数据非代码): |
| 183 | + |
| 184 | +```json |
| 185 | +{ |
| 186 | + "bilibili": { |
| 187 | + "videoRoi": [0.15, 0.08, 0.62, 0.72], |
| 188 | + "subtitleBand": { "y": 0.82, "h": 0.10 }, |
| 189 | + "noiseMasks": ["danmaku_band", "right_recommend"] |
| 190 | + }, |
| 191 | + "douyin": { |
| 192 | + "videoRoi": [0.0, 0.12, 1.0, 0.8], |
| 193 | + "subtitleBand": { "y": 0.60, "h": 0.15 }, |
| 194 | + "noiseMasks": ["right_comments", "left_likes"] |
| 195 | + } |
| 196 | +} |
| 197 | +``` |
| 198 | + |
| 199 | +**三层降级**:命中模板 → 用模板;未命中 → 几何兜底(黑边检测/动态区域/宽高比);全失败 → 现状全窗口 OCR。 |
| 200 | + |
| 201 | +**收益**:OCR 只在视频区 ROI 内跑 → 弹幕/推荐流/评论区噪音从源头消失;字幕带先验让 `subtitle_detect` 从"盲找"变"带先验找"。 |
| 202 | + |
| 203 | +## 5. 错误处理 |
| 204 | + |
| 205 | +- **adapter 构建失败**:行级重识别跳过,保留碎片结果(净化链照常) |
| 206 | +- **模板 JSON 解析失败**:跳过模板层,走几何兜底 |
| 207 | +- **章节边界缺失**:全篇退化现状(无回归风险) |
| 208 | +- **质量分计算异常**(空章节):按最低分处理(OCR 弃用,宁缺毋滥) |
| 209 | + |
| 210 | +## 6. 测试计划 |
| 211 | + |
| 212 | +| 层 | 用例 | |
| 213 | +|---|---| |
| 214 | +| 纯函数 | `chapter_morph` 四象限决策(密度×质量);`ocr_quality_score` 四信号加权;`layout_reorder` 单栏/多栏/标题识别;`line_merge` 合并/断开/护栏;`incremental_merge` 增量/翻页 | |
| 215 | +| 引擎 | `line_rec_engine` 疑碎行判定 + 批量识别替换(集成测试标注:需模型文件)| |
| 216 | +| 平台 | 平台识别(标题/URL);模板加载;几何兜底(黑边/动态区域)| |
| 217 | +| 组装 | 图文章节(OCR 主体 + 口语引用块)golden 用例;混合形态整篇 | |
| 218 | +| 门控 | 低质量章节不进正文/不喂 AI(精修输入组装过滤)| |
| 219 | +| 回归 | 无 OCR 会话 → 全口语(现状形态零变化)| |
| 220 | + |
| 221 | +## 7. 范围外 |
| 222 | + |
| 223 | +- 视频解析下载(B站/抖音内容源接入——非采集适配) |
| 224 | +- AI 版面理解(token 成本,用户反对;规则方案已覆盖) |
| 225 | +- 表格/公式 OCR 结构化(结构引擎精修增强,另行立项) |
| 226 | + |
| 227 | +## 8. 决策记录 |
| 228 | + |
| 229 | +| 决策 | 结论 | 理由 | |
| 230 | +|---|---|---| |
| 231 | +| 形态粒度 | 章节级(非视频级)| 用户纠正:无 PPT 视频 + 一视频双部分 | |
| 232 | +| 质量门控 | 密度 × 质量双维 | 低质量不沉淀、不喂 AI(省 token)| |
| 233 | +| 行合并 | 几何+文本信号评分器 | 零 token、可单测;宁可少合并 | |
| 234 | +| 行级重识别 | 官方 TextRecognitionAdapter 编排自研 | rec-only API 不存在;adapter 公共 API 已源码验证 | |
| 235 | +| 跨帧增量 | 包含关系 + bbox 锚定 | 解决 PPT 动画逐行出现(现有去重失效场景)| |
| 236 | +| 平台适配 | 模板 JSON + 几何兜底三层 | 改版只改数据;能力降级不失效 | |
| 237 | +| 精修链路 | 结构引擎(A')作增强 | 模型重(129MB+231MB),不进实时链路 | |
0 commit comments