|
| 1 | +# v0.7.6 — 笔记纯本地结构渲染层(章节入笔记 + 术语表入笔记) |
| 2 | + |
| 3 | +> **状态**: 规划中(2026-08-20 头脑风暴完成,设计已确认;待实施) |
| 4 | +> **目标**: 把 v0.7.5 裁决缓做的"结构组织"中**纯本地可行**的两项做掉——章节/TOC 入笔记(章节边界 → Markdown 标题层级)+ 术语表入笔记(词汇表块);不依赖云端 AI,与 v0.8.0 AI 精修(REQ-141)并存兼容。 |
| 5 | +> **关联**: [v0.7.5 版本文档](./v0.7.5.md)(§六 缓做裁决)· REQ-044/064(章节检测已实施)· REQ-077(大纲标题检测已实施)· REQ-046/061(术语表已实施)· REQ-171(规则版本元数据)· REQ-172(黄金语料回归)· v0.8.0(AI 精修接管语义层,本版不做语义级结构) |
| 6 | +
|
| 7 | +## 一、范围裁决(2026-08-20 头脑风暴) |
| 8 | + |
| 9 | +v0.7.5 §六 缓做六项逐一评估纯本地可行性: |
| 10 | + |
| 11 | +| 缓做项 | 纯本地可行性 | 本版裁决 | |
| 12 | +|--------|-------------|---------| |
| 13 | +| 章节/TOC 入笔记 | ✅ 完全可行(chapter_detect + outline 均已实施,缺"接进笔记") | **做** | |
| 14 | +| 术语表入笔记 | ✅ 完全可行(glossary 已实施,缺"接进笔记") | **做** | |
| 15 | +| 讲述↔画面时间对齐内联 | ⚠️ 部分可行(屏/段时间戳已有,交错呈现涉及前端布局重构) | 不做(前端工作量独立) | |
| 16 | +| 要点/行动项 | ⚠️ 部分可行(highlight_detect 已有——可做"重点段标记") | 不做(下批候选) | |
| 17 | +| 摘要/结论 | ❌ 语义层,必须 LLM | v0.8.0 REQ-141 | |
| 18 | +| 语义切段 | ❌ 语义层,必须 LLM | v0.8.0 REQ-141 | |
| 19 | + |
| 20 | +**用户裁决**:章节/TOC + 术语表两项全收;章节标题复用 outline(OCR 大字块/屏标题);术语自动候选直接入笔记(可手动删,不做确认 UI);独立小版本 **v0.7.6** 发布(不与 v0.8.0 AI 合并)。 |
| 21 | + |
| 22 | +## 二、设计:独立结构渲染层(方案 B) |
| 23 | + |
| 24 | +### 架构 |
| 25 | + |
| 26 | +``` |
| 27 | +filter_note(净化,零改动) structure_note.rs(新增,纯函数) |
| 28 | +segments/ocr_blocks ──► NoteFilterResult ──► render_note_structure ──► 带结构的 NoteFilterResult |
| 29 | + ▲ │ |
| 30 | + │ ├─ chapters(章节边界,analyze_session_opt 已有) |
| 31 | + │ ├─ outline(章节标题,detect_outline_smart 复用) |
| 32 | + │ └─ glossary(术语候选,analyze_session_opt 已有) |
| 33 | +``` |
| 34 | + |
| 35 | +- `note_filter.rs` / `concat.rs` **零改动**(零回归) |
| 36 | +- 新模块 `structure_note.rs`:纯函数、无 IO、单文件 ≤300 行、显式依赖注入 |
| 37 | +- 与 v0.8.0 AI 精修兼容:AI 版将来以"结构块数组"重写本层输出,规则版=生成结构块,同一协议(精修=整理不创作原则不受影响) |
| 38 | + |
| 39 | +### 核心纯函数 |
| 40 | + |
| 41 | +```rust |
| 42 | +// structure_note.rs |
| 43 | +pub struct NoteStructureConfig { |
| 44 | + pub chapter_headings: bool, // 章节标题入笔记(默认 true) |
| 45 | + pub glossary_block: bool, // 词汇表块(默认 true) |
| 46 | + pub glossary_max_terms: usize, // 词汇表条目上限(默认 20,防噪音) |
| 47 | +} |
| 48 | + |
| 49 | +pub fn render_note_structure( |
| 50 | + result: &mut NoteFilterResult, |
| 51 | + chapters: &[ChapterBoundary], |
| 52 | + outline: &[OutlineEntry], |
| 53 | + glossary: &[GlossaryCandidate], |
| 54 | + config: &NoteStructureConfig, |
| 55 | +) -> StructureStats // { chapters, titled_chapters, glossary_terms } 并入 purify_stats |
| 56 | +``` |
| 57 | + |
| 58 | +**章节 → 标题**(`## 章节 N [MM:SS]`): |
| 59 | +- 章节边界 `time_ms` → 在 `## 讲述内容` 内该时刻的段落前插入标题行(段落切分复用 `concat::split_transcript_paragraphs_with` 口径,与净化管线一致) |
| 60 | +- 章节名 = 本边界→下一边界窗口内**第一个 outline 条目文本**(OCR 大字块/屏标题,复用 `outline::detect_outline_smart`);无命中 → 占位"章节 N" |
| 61 | +- 边界落在段内 → 段首插(粗粒度边界,不切段——诚实标注不伪造粒度) |
| 62 | + |
| 63 | +**术语表 → 词汇表块**(笔记尾部 `## 词汇表`): |
| 64 | +- 每项 `- 术语(画面 ×N / 语音 ×M)`,按 score 降序,上限 `glossary_max_terms` |
| 65 | +- 锚点:术语在 kept 段中首次出现处 → `[MM:SS]` 前缀(回跳语义,复用 REQ-165 锚点风格) |
| 66 | + |
| 67 | +**空输入降级(诚实降级)**:无章节(口播档案)→ 不插标题;无术语 → 不出词汇表;配置全关 → 原样返回。 |
| 68 | + |
| 69 | +### 接线(commands_session.rs,双出口同口径) |
| 70 | + |
| 71 | +`convert_to_note` 与 `preview_session_note` 在 `refresh_screen_points` 之后、落库/返回之前调用: |
| 72 | +1. 装配 `SessionDetail`(load_note_material 已有 segments/ocr_blocks,补 events——章节真实信号) |
| 73 | +2. `analyze_session_opt(detail, profile, ...)` 取 chapters/glossary(profile 从 `session.profile` 解析,回退 Lecture) |
| 74 | +3. `outline::detect_outline_smart(ocr_blocks, &result.ocr_screens, ...)` 取章节标题 |
| 75 | +4. `render_note_structure(...)` 重写 markdown + 更新 stats |
| 76 | + |
| 77 | +**结构渲染实现方式**:章节标题行作为段落数组元素插入(`kept` → `concat::split_transcript_paragraphs_with` 复切段落 → 按章节边界在段落间插入 `## 章节 N` 行 → `concat::assemble_markdown(title, paragraphs, ocr_points)` 复用现有组装 → 尾部追加 `## 词汇表` 块)。与净化管线段落口径一致(同一阈值配置)。 |
| 78 | + |
| 79 | +> 预览与落库**同一管线**(REQ-081 契约),结构输出一致性由构造保证。 |
| 80 | + |
| 81 | +### 配置(REQ-179) |
| 82 | + |
| 83 | +`NoteStructureConfig`(chapter_headings / glossary_block / glossary_max_terms)**并入 `PurifyConfig`**(嵌套结构字段):复用现有 JSON 校准与装配链(AppState.purify → PurifyEnv),零新装配点;`structure_note.rs` 消费独立类型,模块边界不破。全关 = v0.7.5 输出逐字节一致。 |
| 84 | + |
| 85 | +### 元数据 |
| 86 | + |
| 87 | +- `RULE_VERSION` 递增:`note-rules-0.7.5` → `note-rules-0.7.6`(REQ-171:产物可回答"用哪版规则生成") |
| 88 | +- `StructureStats` 并入 `purify_stats` JSON(前端预览统计卡可显示"章节 ×N / 术语 ×M";旧笔记 NULL 诚实降级) |
| 89 | + |
| 90 | +## 三、范围(需求追溯) |
| 91 | + |
| 92 | +| REQ | 内容 | 验收要点 | 规划状态 | |
| 93 | +|-----|------|---------|---------| |
| 94 | +| REQ-177 | 章节入笔记:章节边界 → `## 章节 N [MM:SS]` 标题层级;章节名取窗口内 outline 标题(OCR 大字块/屏标题),无命中占位 | 网课档案转笔记带章节标题;边界位置正确(段前插入、段内不切段);口播档案无章节零变化;标题可手动删 | **已排期** | |
| 95 | +| REQ-178 | 术语表入笔记:glossary 候选 → 笔记尾部 `## 词汇表` 块(`- 术语(画面 ×N / 语音 ×M)` + [MM:SS] 锚点);自动候选直接入笔记(不强制确认 UI);上限 20 防噪音 | 词汇表块生成正确、排序降序、上限生效、锚点回跳;无术语不出块;块可整体删除 | **已排期** | |
| 96 | +| REQ-179 | 结构渲染配置化:NoteStructureConfig(chapter_headings/glossary_block/glossary_max_terms)JSON 可校准(purify_config.json 先例) | 配置全关 = v0.7.5 输出逐字节一致(零回归护栏);JSON 缺失/损坏回退内置默认不阻断 | **已排期** | |
| 97 | +| REQ-180 | 结构元数据:StructureStats 并入 purify_stats + RULE_VERSION 递增 note-rules-0.7.6 | 统计与落库一致;旧笔记 NULL 诚实降级 | **已排期** | |
| 98 | +| REQ-181 | 黄金语料回归扩展:会话31 夹具 → 期望带结构笔记断言(TDD,先写失败测试) | 新增规则先失败测试再实现;全量回归一键跑;预览/落库双出口逐字节一致 | **已排期** | |
| 99 | + |
| 100 | +## 四、测试与验证 |
| 101 | + |
| 102 | +- **Rust 单测**(TDD,AAA 模式): |
| 103 | + - 章节插入位置:边界在段前 / 段中 / 无段区域 / 首个边界前(合成会话样本) |
| 104 | + - 章节命名:outline 命中取标题 / 未命中占位 / 窗口跨边界归属正确 |
| 105 | + - 词汇表:排序降序 / 上限截断 / 锚点首现 / 空术语不出块 |
| 106 | + - 配置:全关输出与 v0.7.5 完全一致(零回归护栏);partial JSON 覆盖语义 |
| 107 | + - 黄金语料:会话31 样本 → 期望带章节标题 + 词汇表断言(REQ-181) |
| 108 | + - 双出口一致:preview_session_note / session_to_note 结构输出逐字节一致 |
| 109 | +- **前端**:`##` 标题与列表渲染已支持(Markdown 渲染器现有能力)——预计零改动或极小(统计卡加章节/术语计数) |
| 110 | +- **真机手动验证清单**(实施完成后执行): |
| 111 | + 1. 网课会话(会话31)重转笔记:章节标题层级正确、章节名来自画面标题、词汇表块带锚点 |
| 112 | + 2. 口播会话转笔记:无章节标题、无词汇表(零变化) |
| 113 | + 3. 旧笔记(rule_version NULL):正常展示不报错 |
| 114 | + 4. 回归底线:现有 1053+ 单测全绿 + clippy 新代码零警告 + 前端构建通过 |
| 115 | + |
| 116 | +## 五、文件清单(规划) |
| 117 | + |
| 118 | +**Rust 新增**:`structure_note.rs`(纯函数:章节标题插入 + 词汇表块 + 配置 + stats)· `structure_note_tests.rs`(单测独立文件) |
| 119 | + |
| 120 | +**Rust 修改**:`commands_session.rs`(convert_to_note / preview_session_note 接线:detail 装配 + analyze + outline + render)· `note_filter.rs`(RULE_VERSION 递增)· `purify_config.rs`(NoteStructureConfig 嵌套字段——REQ-179)· `types.rs`(StructureStats,如 purify_stats 需新字段——优先零迁移方案) |
| 121 | + |
| 122 | +**前端**:`NotePreviewView.tsx`(统计卡加章节/术语计数,可选)· `types.ts`(FilterStats/StructureStats 新字段) |
| 123 | + |
| 124 | +## 六、本版不做(明确排除) |
| 125 | + |
| 126 | +- 摘要/结论、语义切段、要点/行动项、讲述↔画面时间对齐内联——语义层归 v0.8.0 REQ-141;其余为后续批次候选 |
| 127 | +- TOC 折叠导航(V1.1 REQ-026 范畴) |
| 128 | +- 术语确认 UI(自动候选直入笔记,可手动删) |
| 129 | +- 章节速览/思维导图(V1.1 REQ-026) |
| 130 | +- 任何 AI 调用(本版纯本地,无密钥/授权/成本依赖) |
0 commit comments