Skip to content

Latest commit

 

History

History
130 lines (97 loc) · 10.1 KB

File metadata and controls

130 lines (97 loc) · 10.1 KB

v0.7.6 — 笔记纯本地结构渲染层(章节入笔记 + 术语表入笔记)

状态: 已实施(REQ-177~181 全部落地,2026-08-20) 目标: 把 v0.7.5 裁决缓做的"结构组织"中纯本地可行的两项做掉——章节/TOC 入笔记(章节边界 → Markdown 标题层级)+ 术语表入笔记(词汇表块);不依赖云端 AI,与 v0.8.0 AI 精修(REQ-141)并存兼容。 关联: v0.7.5 版本文档(§六 缓做裁决)· REQ-044/064(章节检测已实施)· REQ-077(大纲标题检测已实施)· REQ-046/061(术语表已实施)· REQ-171(规则版本元数据)· REQ-172(黄金语料回归)· v0.8.0(AI 精修接管语义层,本版不做语义级结构)

一、范围裁决(2026-08-20 头脑风暴)

v0.7.5 §六 缓做六项逐一评估纯本地可行性:

缓做项 纯本地可行性 本版裁决
章节/TOC 入笔记 ✅ 完全可行(chapter_detect + outline 均已实施,缺"接进笔记") 做
术语表入笔记 ✅ 完全可行(glossary 已实施,缺"接进笔记") 做
讲述↔画面时间对齐内联 ⚠️ 部分可行(屏/段时间戳已有,交错呈现涉及前端布局重构) 不做(前端工作量独立)
要点/行动项 ⚠️ 部分可行(highlight_detect 已有——可做"重点段标记") 不做(下批候选)
摘要/结论 ❌ 语义层,必须 LLM v0.8.0 REQ-141
语义切段 ❌ 语义层,必须 LLM v0.8.0 REQ-141

用户裁决:章节/TOC + 术语表两项全收;章节标题复用 outline(OCR 大字块/屏标题);术语自动候选直接入笔记(可手动删,不做确认 UI);独立小版本 v0.7.6 发布(不与 v0.8.0 AI 合并)。

二、设计:独立结构渲染层(方案 B)

架构

filter_note(净化,零改动)          structure_note.rs(新增,纯函数)
segments/ocr_blocks ──► NoteFilterResult ──► render_note_structure ──► 带结构的 NoteFilterResult
                      ▲                         │
                      │                         ├─ chapters(章节边界,analyze_session_opt 已有)
                      │                         ├─ outline(章节标题,detect_outline_smart 复用)
                      │                         └─ glossary(术语候选,analyze_session_opt 已有)
  • note_filter.rs / concat.rs 零改动(零回归)
  • 新模块 structure_note.rs:纯函数、无 IO、单文件 ≤300 行、显式依赖注入
  • 与 v0.8.0 AI 精修兼容:AI 版将来以"结构块数组"重写本层输出,规则版=生成结构块,同一协议(精修=整理不创作原则不受影响)

核心纯函数

// structure_note.rs
pub struct NoteStructureConfig {
    pub chapter_headings: bool,    // 章节标题入笔记(默认 true)
    pub glossary_block: bool,      // 词汇表块(默认 true)
    pub glossary_max_terms: usize, // 词汇表条目上限(默认 20,防噪音)
}

pub fn render_note_structure(
    result: &mut NoteFilterResult,
    chapters: &[ChapterBoundary],
    outline: &[OutlineEntry],
    glossary: &[GlossaryCandidate],
    config: &NoteStructureConfig,
) -> StructureStats  // { chapters, titled_chapters, glossary_terms } 并入 purify_stats

章节 → 标题(## 章节 N [MM:SS]):

  • 章节边界 time_ms → 在 ## 讲述内容 内该时刻的段落前插入标题行(段落切分复用 concat::split_transcript_paragraphs_with 口径,与净化管线一致)
  • 章节名 = 本边界→下一边界窗口内第一个 outline 条目文本(OCR 大字块/屏标题,复用 outline::detect_outline_smart);无命中 → 占位"章节 N"
  • 边界落在段内 → 段首插(粗粒度边界,不切段——诚实标注不伪造粒度)

术语表 → 词汇表块(笔记尾部 ## 词汇表):

  • 每项 - 术语(画面 ×N / 语音 ×M),按 score 降序,上限 glossary_max_terms
  • 锚点:术语在 kept 段中首次出现处 → [MM:SS] 前缀(回跳语义,复用 REQ-165 锚点风格)

空输入降级(诚实降级):无章节(口播档案)→ 不插标题;无术语 → 不出词汇表;配置全关 → 原样返回。

接线(commands_session.rs,双出口同口径)

convert_to_note 与 preview_session_note 在 refresh_screen_points 之后、落库/返回之前调用:

  1. 装配 SessionDetail(load_note_material 已有 segments/ocr_blocks,补 events——章节真实信号)
  2. analyze_session_opt(detail, profile, ...) 取 chapters/glossary(profile 从 session.profile 解析,回退 Lecture)
  3. outline::detect_outline_smart(ocr_blocks, &result.ocr_screens, ...) 取章节标题
  4. render_note_structure(...) 重写 markdown + 更新 stats

结构渲染实现方式:章节标题行作为段落数组元素插入(kept → concat::split_transcript_paragraphs_with 复切段落 → 按章节边界在段落间插入 ## 章节 N 行 → concat::assemble_markdown(title, paragraphs, ocr_points) 复用现有组装 → 尾部追加 ## 词汇表 块)。与净化管线段落口径一致(同一阈值配置)。

预览与落库同一管线(REQ-081 契约),结构输出一致性由构造保证。

配置(REQ-179)

NoteStructureConfig(chapter_headings / glossary_block / glossary_max_terms)并入 PurifyConfig(嵌套结构字段):复用现有 JSON 校准与装配链(AppState.purify → PurifyEnv),零新装配点;structure_note.rs 消费独立类型,模块边界不破。全关 = v0.7.5 输出逐字节一致。

元数据

  • RULE_VERSION 递增:note-rules-0.7.5 → note-rules-0.7.6(REQ-171:产物可回答"用哪版规则生成")
  • StructureStats 并入 purify_stats JSON(前端预览统计卡可显示"章节 ×N / 术语 ×M";旧笔记 NULL 诚实降级)

三、范围(需求追溯)

REQ 内容 验收要点 规划状态
REQ-177 章节入笔记:章节边界 → ## 章节 N [MM:SS] 标题层级;章节名取窗口内 outline 标题(OCR 大字块/屏标题),无命中占位 网课档案转笔记带章节标题;边界位置正确(段前插入、段内不切段);口播档案无章节零变化;标题可手动删 已排期
REQ-178 术语表入笔记:glossary 候选 → 笔记尾部 ## 词汇表 块(- 术语(画面 ×N / 语音 ×M) + [MM:SS] 锚点);自动候选直接入笔记(不强制确认 UI);上限 20 防噪音 词汇表块生成正确、排序降序、上限生效、锚点回跳;无术语不出块;块可整体删除 已排期
REQ-179 结构渲染配置化:NoteStructureConfig(chapter_headings/glossary_block/glossary_max_terms)JSON 可校准(purify_config.json 先例) 配置全关 = v0.7.5 输出逐字节一致(零回归护栏);JSON 缺失/损坏回退内置默认不阻断 已排期
REQ-180 结构元数据:StructureStats 并入 purify_stats + RULE_VERSION 递增 note-rules-0.7.6 统计与落库一致;旧笔记 NULL 诚实降级 已排期
REQ-181 黄金语料回归扩展:会话31 夹具 → 期望带结构笔记断言(TDD,先写失败测试) 新增规则先失败测试再实现;全量回归一键跑;预览/落库双出口逐字节一致 已排期

四、测试与验证

  • Rust 单测(TDD,AAA 模式):
    • 章节插入位置:边界在段前 / 段中 / 无段区域 / 首个边界前(合成会话样本)
    • 章节命名:outline 命中取标题 / 未命中占位 / 窗口跨边界归属正确
    • 词汇表:排序降序 / 上限截断 / 锚点首现 / 空术语不出块
    • 配置:全关输出与 v0.7.5 完全一致(零回归护栏);partial JSON 覆盖语义
    • 黄金语料:会话31 样本 → 期望带章节标题 + 词汇表断言(REQ-181)
    • 双出口一致:preview_session_note / session_to_note 结构输出逐字节一致
  • 前端:## 标题与列表渲染已支持(Markdown 渲染器现有能力)——预计零改动或极小(统计卡加章节/术语计数)
  • 真机手动验证清单(实施完成后执行):
    1. 网课会话(会话31)重转笔记:章节标题层级正确、章节名来自画面标题、词汇表块带锚点
    2. 口播会话转笔记:无章节标题、无词汇表(零变化)
    3. 旧笔记(rule_version NULL):正常展示不报错
    4. 回归底线:现有 1053+ 单测全绿 + clippy 新代码零警告 + 前端构建通过

五、文件清单(实施完成,与实际一致)

Rust 新增:structure_note.rs(纯函数:章节标题插入 + 词汇表块 + 配置 + stats)· structure_note_tests.rs(16 个单测:插入位置/命名/词汇表/零回归/JSON 往返——审查补 max_terms=0 语义测试)

Rust 修改:commands_session.rs(apply_note_structure 接线函数——convert_to_note 与 preview_session_note 双出口同口径调用;失败不阻断主链路;v0.7.6 审查硬拆:笔记管线迁至新增 commands_session_note.rs,命令注册按定义模块)· commands_ai.rs(审查修复:AI 复核出口补结构渲染——三出口一致)· note_filter.rs(RULE_VERSION → note-rules-0.7.6;FilterStats 加 chapters/titled_chapters/glossary_terms)· purify_config.rs(嵌套 NoteStructureConfig——REQ-179)· note_filter_golden_tests.rs(REQ-181:会话31 结构黄金语料 2 例 + 审查补测"配置开无数据逐字节一致"共 3 例)· lib.rs(mod 注册)

前端:NotePreviewView.tsx(统计卡加章节/词汇表计数)· types.ts(FilterStats 三新字段)

六、本版不做(明确排除)

  • 摘要/结论、语义切段、要点/行动项、讲述↔画面时间对齐内联——语义层归 v0.8.0 REQ-141;其余为后续批次候选
  • TOC 折叠导航(V1.1 REQ-026 范畴)
  • 术语确认 UI(自动候选直入笔记,可手动删)
  • 章节速览/思维导图(V1.1 REQ-026)
  • 任何 AI 调用(本版纯本地,无密钥/授权/成本依赖)