Skip to content

Latest commit

 

History

History
248 lines (185 loc) · 21.4 KB

File metadata and controls

248 lines (185 loc) · 21.4 KB

v0.12.0:图文与窗口捕获重塑——正文源多态 + WGC 抗遮挡 + 系统级截屏覆盖层 + DeepSeek 默认化 + vision 精修

状态:规划定稿(2026-08-23,设计完成待实施) 依据:用户对话 2026-08-23(图文笔记空内容修正需求 · WGC 稳定性评估 · 截屏 UX 对比调研 · DeepSeek 默认化裁决 · 视频 OCR 质量裁决 · 图片精修可选性与 AI 链条开关裁决) 前置:v0.11.7(图文会话)交付后开工

一句话

七项改进修正五个断裂:图文会话转笔记空内容的设计债(filter_note 正文源多态重构)、视频采集窗口遮挡的能力债(WGC 窗口级捕获 + 三级降级链)、图文截屏看不全的交互债(系统级覆盖层截图替代 letterbox 框选)、AI 默认链路过时的配置债(默认 Provider 切 DeepSeek + 默认模型 deepseek-v4-flash-vision-exp,旧 key 废除)、视频画面 OCR 质量差的质量债(本地 OCR 下线 + AI 精修图片理解可选增强)+ 全屏采集体验的体验债(浮窗化)。

范围

# 项目 类型 落点
1 笔记正文源多态(长期重构) P0 设计债 detect_body_source 抽象层 + filter_note_from_ocr 精简净化链——图文会话 OCR 文本直接进入笔记 markdown
2 WGC 窗口级捕获 P1 能力债 新增 capture/wgc_capture.rs,WGC 为主路径,DXGI 为降级 1,GDI 为兜底——三级自愈链
3 系统级覆盖层截图 P2 交互债 Tauri 独立全屏透明窗口替代应用内 letterbox 框选,1:1 原始像素显示,全局快捷键触发
4 DeepSeek 默认化 P1 配置债 默认 Provider 切 DeepSeek + 默认模型 deepseek-v4-flash-vision-exp;设置页预设/文案/价格表同步;旧 key 环境变量废除
5 视频会话画面要点降级 + vision-exp 视觉提取 P1 质量债 本地 OCR 下线(仅保留字幕/图文采集);关键帧纯图;用户授权后 deepseek-v4-flash-vision-exp 视觉提取进笔记正文;vision 块回补章节/术语/大纲
6 采集浮窗化 P1 体验债 采集中全屏看视频时悬浮小窗(状态/转写/控制),Tauri 子窗口 alwaysOnTop
7 文档与治理 伴随 ADR-021(正文源多态)+ ADR-022(WGC 窗口级捕获)+ ADR-023(视频 OCR 下线 + vision 提取)+ 本版本文档

设计背景

1. 正文源多态(笔记正文源重构)

问题:filter_note 硬编码 segments(转写段)为唯一正文源,ocr_blocks(OCR 块)始终为辅助画面要点不入 markdown。对视频会话这是正确设计(关键帧信息密度低),但对图文会话(kind=photo)——用户手动框选、OCR 文本即意图——导致笔记 markdown 只有标题,正文空。

根因:数据层的语义抽象不足——(segments, ocr_blocks) 二元组缺乏"哪个是正文"的表达层。

方案:引入 BodySource 枚举(Transcript / OcrDirect / Empty),detect_body_source 纯函数根据输入智能判断,filter_note 内部按来源分叉到不同过滤链:

  segments ──┐
               ├→ detect_body_source ─→ Transcript ─→ 既有口语过滤链(视频,不变)
  ocr_blocks ─┘                       ─→ OcrDirect ─→ 精简 OCR 过滤链(图文,新增)
                                       ─→ Empty     ─→ 标题仅

OCR 精简过滤链:排序 → 置信度过滤(0.5) → 符号归一(跳过口语净化——OCR 文本无结巴/口头禅) → 相邻去重 → markdown 组装。利用已有 region=="full" 标记为判断依据(photo_capture 写入的图文会话 OCR 块特征)。

与既有设计的冲突:无。Transcript 路径不做任何改动,OcrDirect 是纯新增分支——零回归风险。

2. WGC 窗口级捕获(抗遮挡)

问题:当前 DXGI Desktop Duplication 是显示器级捕获,窗口上方覆盖的 UI(弹窗/任务栏/通知)会入镜。GDI BitBlt 降级更差,遮挡完全无法避免。

方案:新增 WGC (Windows.Graphics.Capture) 后端,构建三级降级自愈链:

WGC(主,窗口级,Win 10 1903+)
  ↓ AcquireNextFrame 失败 / 安全桌面 / 窗口最小化
DXGI Desktop Duplication(降级 1,屏幕级+窗口裁剪,当前主路径)
  ↓ 远程桌面 / 锁屏 / 设备丢失
GDI BitBlt(兜底,全场景可用)

WGC 不稳定的场景及处理:

场景 表现 处理
安全桌面(UAC) API 不可用 降级 DXGI
全屏独占 DX 游戏 窗口脱离 DWM 降级 DXGI(与当前行为一致)
窗口最小化 丢帧 / 最后一帧 降级 DXGI+GDI,回退屏幕级捕获
Win 10 1903 以下 API 不存在 编译期 gate(#[cfg]),回退 DXGI
无 DWM(Server Core) API 不可用 降级 GDI

ScreenCaptureSampler 扩展为三级链:新增 capture/wgc_capture.rs 模块(WinRT 异步帧回调 → 通道同步化),dxgi_capture.rs 的 ScreenCaptureSampler 增加 WGC 状态机,try_create_dxgi 语义泛化为 try_create_backend(WGC → DXGI → GDI 逐级尝试)。

3. 系统级覆盖层截图(替代 letterbox 框选)

问题:当前 ScreenSelectOverlay 在应用窗口内用 letterbox 缩略显示全屏截图——4K 屏在 1200px 窗口内缩到 73%,文字细节丢失。且需三步操作(开始采集 → 点击截屏 → 框选),vs 微信截图 Alt+A 一步触发。

市场调研:

方案 承载层 像素比例 触发方式
当前(ScreenSelectOverlay) 应用内 letterbox 缩放 50-80% 应用内按钮三步
Windows Snipping Tool 独立全屏窗口 1:1 原始 全局 Win+Shift+S
微信截图 全屏透明 WS_EX_LAYERED 窗口 1:1 原始 全局 Alt+A

方案:Tauri 创建独立透明全屏窗口作为覆盖层,1:1 显示捕获帧,用户在原分辨率下框选:

全局快捷键 Ctrl+Shift+Q(或应用内按钮)
  → Tauri 创建全屏透明窗口(decorations:false, transparent:true, fullscreen:true)
  → 窗口内 1:1 像素显示当前帧(不缩略,超大屏幕可滚动手势缩放)
  → 用户拖拽框选(自动边缘检测候选)
  → 框选确认 → 窗口关闭 → PNG 回传主窗口 → 存图+OCR
  → Esc 取消 → 窗口关闭,无副作用

DPI 换算简化为零——覆盖层窗口以物理像素显示,鼠标坐标直接对应图像坐标。交互流从当前三步缩减为一步(快捷键→框选→确认,快捷键→框选→Esc)。

跨窗口通信:主窗口等待覆盖层结果(通道 / event bus);覆盖层不持久,截完即销毁。

4. DeepSeek 默认化(配置债)

问题:当前预设模板首选项为 SiliconFlow(legacy 迁移默认);旧 key 已废除,默认链路应切到 DeepSeek 官方端点 + deepseek-v4-flash-vision-exp(视觉多模态,图文会话精修/OCR 增强的未来主力)。

方案:

  • preset_templates() 将 DeepSeek 提到首位(effective_default_id 取第一个 enabled → DeepSeek 生效);DeepSeek 预设 models 添加 deepseek-v4-flash-vision-exp,default_model 改为该模型
  • legacy 迁移(migrate_from_legacy)目标从 SiliconFlow 改为 DeepSeek(旧 key 废除后迁移到新默认链)
  • ai_cost.rs builtin_prices 登记 deepseek-v4-flash-vision-exp 价格(官方 2026-08:输入缓存未命中 1.5-3.0 元/百万,输出 4.5-9.0 元/百万——取保守上界 9.0 登记,注释标注分段价)
  • 前端 AiProviderSettings PRESET_OPTIONS 同步(I-3 双源:后端优先,前端兜底)
  • 文案统一:AiRefineCard/EnrichPanel/NotePreviewView 的 SiliconFlow 硬编码文案 → DeepSeek(或通用 Provider 表述)
  • 旧 key 废除:SILICONFLOW_API_KEY 环境变量读取路径移除/改为 DEEPSEEK_API_KEY;401 错误文案同步

与既有设计的冲突:无。Provider 机制不变(BYOK 多端点),仅默认指向与预设内容更新。

5. 视频会话画面要点降级 + vision-exp 视觉提取(质量债)

问题:本地 PaddleOCR 对视频全帧画面要点提取质量差(动态模糊/复杂版面/小字/干扰物)——同一引擎在字幕/图文场景效果好。

决策(用户 2026-08-23 裁决):

  • 本地 OCR 只做字幕(视频)+ 图文采集(photo 会话)——视频会话不再做全帧 OCR
  • 关键帧纯图(存图不识别);存图触发从「OCR 文本非空」解耦为「grid diff 变化 + 时间间隔」
  • vision-exp 图片理解(可选增强,仅视频会话,并入 AI 精修):不做独立提取命令——精修时若 vision_refine_enabled 开启,屏卡图随转写文本一并送 vision-exp(content 数组多模态),精修输出直接含画面要点;屏卡缩略图走现有 attach_images
  • 图文会话 OCR 已足够,不启用 vision(用户决策:仅视频会话使用)
  • 图片精修可选性:vision_refine_enabled 开关(默认关)——图片上传最敏感,独立闸门,关闭则精修纯文本(现有行为零变化)
  • AI 强化链条总开关:复用现有 AiSettings.enabled(全局闸门,默认关)——关闭则采集期领域识别/AI 复核/精修/补充全部拒绝(已有 content_gate 门控)
  • 图片缩略图走现有机制(attach_images / convertFileSrc,屏卡配图不新建通道)

隐私红线:图片上传默认关(vision_refine_enabled 默认 false + 全局 enabled 默认关);关闭时精修走纯文本(零变化);图片仅随精修切片请求上传,不作独立提取(ADR-010 扩展)。

交付内容

M1 · 笔记正文源重构(P0,预估 1 天)

  • 新增 note_body_source.rs:BodySource 枚举 + detect_body_source 纯函数 + 独立单测
  • 新增 note_filter_ocr.rs:filter_note_from_ocr 精简净化链(排序 → 置信过滤 → 符号归一 → 相邻去重 → markdown)
  • 修改 note_filter.rs:filter_note 入口增加 BodySource 分派(use note_body_source + use note_filter_ocr),三路 match
  • 修改 lib.rs:注册 note_body_source + note_filter_ocr 模块
  • 更新 note_filter_tests.rs:适配 filter_note_with_empty_segments 测试新语义(OCR 文本进入 markdown,ocr_points 空)
  • 验收:纯图文会话转笔记 → markdown 含 OCR 识别文字;视频会话转笔记 → 零变化(回归验证)

M2 · WGC 窗口级捕获(P1,预估 2-3 天)

  • 新增 capture/wgc_capture.rs:
    • WgcState(WinRT GraphicsCaptureItem + Direct3D11CaptureFramePool + 通道发送端)
    • WgcState::create(hwnd) → 按窗口句柄创建捕获目标 + 帧池 + 捕获会话
    • 异步帧回调 → 通道同步化(帧到达推入 crossbeam_channel / std::sync::mpsc)
    • capture() → 从通道取最新帧(non-blocking try_recv)
  • 修改 capture/dxgi_capture.rs:ScreenCaptureSampler 扩展为三级链
    • 新增 backend: enum CaptureBackend { Wgc, Dxgi, Gdi }
    • try_create_backend() 逐级尝试(WGC → DXGI → GDI)
    • capture() 按当前后端路由,失败自动降级下一级
  • DxgiState try_create_dxgi 旧逻辑保留,作为三级链中段
  • 验收:窗口被遮挡时捕获内容不受影响;远程桌面/锁屏自动降级;窗口关闭后兜底正常

M3 · 系统级覆盖层截图(P2,预估 2 天)

  • 主进程:Tauri::Builder 注册覆盖层窗口工厂(create_overlay_window / close_overlay_window)
  • 渲染进程(覆盖层窗口):
    • 全屏透明窗口显示捕获帧(1:1 像素,超大屏幕加平移/捏合缩放)
    • 框选组件(仿微信截图 + 自动边缘检测)
    • 确认后通过 IPC 回传裁剪 PNG base64
  • 渲染进程(主窗口):
    • PhotoCapturePanel 适配两触发器(应用内按钮 / 全局快捷键)
    • 等待覆盖层结果 → save_photo_capture 存图+OCR
  • 验收:图文采集一步触发框选;4K 屏不再缩略;框选精度提升

M4 · DeepSeek 默认化(P1,预估 0.5 天)

  • ai_provider.rs:preset_templates() DeepSeek 提首位 + models 加 deepseek-v4-flash-vision-exp + default_model 切换;migrate_from_legacy 目标改 DeepSeek
  • ai_cost.rs:builtin_prices 登记 deepseek-v4-flash-vision-exp(保守上界 9.0,注释标注分段价待实测校准)
  • AiProviderSettings.tsx:PRESET_OPTIONS DeepSeek 行同步
  • 文案:AiRefineCard/EnrichPanel/NotePreviewView 硬编码 SiliconFlow → DeepSeek;commands_ai_providers.rs env 读取 SILICONFLOW_API_KEY → DEEPSEEK_API_KEY
  • 测试:ai_provider_tests 断言适配(DeepSeek 首位/迁移目标);ai_cost_tests 价格断言
  • 验收:新装/迁移用户默认 Provider=DeepSeek、默认模型=deepseek-v4-flash-vision-exp;设置页预设与文案一致;成本估算显示正确单价

M5 · 视频会话画面要点降级 + AI 精修图片理解(P1,预估 2 天)

  • live_keyframes.rs:handle_full_frame 拆分——存图触发解耦(grid diff + 2s 防抖,不再依赖 OCR 文本);OCR 落库分支退役(视频会话)
  • live_frame_process.rs:全帧分支跳过 recognize_image_timeout(保留 is_subtitle 路径不动);screen_tracker.assign_screen 输入从 texts 改为 layout_changed + grid diff
  • ai_client.rs:新增 chat_vision(system, user, images)——OpenAI 兼容 content 数组(text + image_url data URI);现有 chat_text/chat_json 9 处调用零改动
  • ai_note_refine.rs:refine() 增加多模态分支——vision_refine_enabled 开启时组装屏卡图为 image_url 随切片请求(屏卡图来自 session_images_dir 归档,缩放 ≤1280px 控 token);关闭时纯文本(现有行为零变化)
  • ai_settings.rs:新增 vision_refine_enabled: bool(默认关)
  • AiServicePanel.tsx:新增「精修时启用画面理解」复选框(复用现有开关模式)
  • 触发:仅 AI 精修时生效(不新增独立命令/自动触发)
  • 验收:视频会话关键帧纯图默认态;开启图片开关后精修请求含屏卡图、输出含画面要点;关闭开关精修纯文本零变化;图文会话不受影响;enabled=false 时精修命令拒绝

M6 · 采集浮窗化(P1,预估 1-2 天)

  • commands_window.rs(新增):open_capture_float() / close_capture_float()——WebviewWindowBuilder 创建 "capture-float" 子窗口(alwaysOnTop/decorations:false/transparent/skipTaskbar/360×240),加载 index.html?float=1
  • capabilities/default.json:windows 列表加 "capture-float"
  • CaptureFloatPanel.tsx(新增):顶部状态(录制/暂停/时长/电平)· 中部最近转写 2-3 条 · 底部最近画面缩略图 · 操作按钮(暂停/继续/标记/停止/回主窗)
  • useLiveSessionEvents.ts(新增 hook):从 LiveActivityPanel 抽取事件监听逻辑(partial/final/subtitle/status)——主面板与浮窗共用
  • App.tsx 入口:URL 带 ?float=1 → 渲染 CaptureFloatPanel(不渲染主导航壳)
  • ClassroomPage.tsx:采集中按钮组加「🗕 浮窗化」+ 快捷键 Ctrl+Shift+F;停止后自动关闭浮窗
  • 验收:全屏视频上浮窗置顶可见;暂停/标记/停止可操作;停止后浮窗自动关闭

M7 · 文档(伴随)

  • ADR-021:笔记正文源多态——detect_body_source 架构决策
  • ADR-022:WGC 窗口级捕获——三级降级链决策
  • ADR-023:视频会话 OCR 下线 + vision-exp 视觉提取(含隐私授权契约)
  • 本版本文档

关键决策与纪律

  1. 正文源多态是长期重构:不是打补丁——note_body_source.rs 作为独立抽象层,detect_body_source 可扩展(未来导入 PDF/网页截图等新正文源只需加变体,不改过滤链核)
  2. OCR 不走口语净化链:OCR 文本是视觉识别产物,无 ASR 的结巴/填充词/重复。引用 photo_capture 已有规则:用户框选即意图,不过 UI 垃圾黑名单
  3. WGC 异步转同步:WinRT 异步帧回调通道化——采集线程仍保持 capture() 同步接口,上层 Worker 零改动(变化检测/双速率调度/OCR 编排全部复用)
  4. 三级链不引入新不确定性:WGC 初版编译期 #[cfg(windows)] gate,Win 10 1903 以下回退 DXGI/GDI——旧系统行为零变化
  5. 覆盖层窗口不持久:截完即销毁,不常驻内存。跨窗口通信不走 DB/文件,IPC event 直传
  6. YAGNI:覆盖层不引入截图编辑(标注/马赛克/文字)——仅框选;WGC 最小化场景不回退到 DXGI 后不尝试自动切回——沿用 DXGI 已有 30s 周期重建(TD-033 快速节流同理)
  7. 版本号策略:七项跨模块不关联——M1 可独立发 patch(v0.11.8);M4 可独立发(v0.11.9,配置债零风险);M2+M3+M5+M6 合入 v0.12.0;M5 依赖 M4(vision-exp 默认链),M6 独立

验收标准

  1. M1:纯图文会话(kind=photo,无 segments)→ session_to_note 产出 markdown 含 OCR 识别文本,且标注"图文提取"段;视频会话转笔记 → 零变化(回归);cargo test note_filter 全通过
  2. M2:目标窗口被遮挡时捕获内容为窗口实际内容(非遮挡物);远程桌面会话下自动降级 DXGI/GDI 且不 panic;窗口关闭/最小化时捕获按现有 DXGI/GDI 逻辑兜底;cargo build 通过
  3. M3:图文采集快捷键触发全屏覆盖层 → 1:1 像素显示 → 框选确认 → 截图落库;当前 letterbox 路径保留为降级(覆盖层窗口创建失败时回退)
  4. M4:新装/迁移用户默认 Provider=DeepSeek、默认模型=deepseek-v4-flash-vision-exp;设置页预设与文案一致;成本估算显示正确单价
  5. M5:视频会话关键帧纯图(无 OCR 文字);开启图片开关后精修请求含屏卡图、输出含画面要点;关闭开关精修纯文本零变化;图文会话不受影响;enabled=false 时精修命令拒绝
  6. M6:全屏视频上浮窗置顶可见;暂停/标记/停止可操作;停止后浮窗自动关闭
  7. 全量回归:cargo test / cargo clippy --all-targets / tsc / vitest

测试策略

层 M1 笔记正文源 M2 WGC 捕获 M3 覆盖层截图 M4 DeepSeek M5 vision 提取 M6 浮窗
纯函数 detect_body_source 黄金用例(5 场景)、filter_note_from_ocr 过滤链(空/重复/低分) D3D11 设备管理可测(mock),变化检测复用现有 frame_diff_tests.rs 坐标换算复用 photoCrop.test.ts,增加全屏覆盖层场景 ai_provider_tests 顺序/迁移断言 build_chat_payload 多模态分支、vision 开关门控 useLiveSessionEvents hook 事件合并
数据层 内存库 create_session(kind=photo) + add_ocr_block + session_to_note 验证 markdown 不涉及 不涉及 不涉及 vision_refine_enabled 持久化 不涉及
集成 图文会话全链路(capture → save → finish → to_note) 暂不 mock DXGI/WGC,真机验收 暂不 mock 多窗口 IPC,真机验收 不涉及 开关开/关两种精修请求形态 多窗口创建/关闭真机验收
前端 不涉及(纯 Rust 改动) 不涉及 ScreenSelectOverlay.spec.tsx 的 ESC/鼠标事件覆盖新窗口模式 AiProviderSettings 预设渲染 AiServicePanel 新复选框 CaptureFloatPanel 状态/按钮

后续门控

  • 覆盖层截图的标注/编辑/OCR 实时预览功能以用户反馈为门控,不预排
  • WGC 全路径达到生产级后,ScreenCaptureSampler 可移除 CaptureBackend 枚举的 DXGI 前两位保留为仅降级
  • 正文源多态为未来"导入 PDF/网页截图直接转笔记"提供架构地基(仅需新增 BodySource::PdfDirect + 对应过滤链)
  • PPT 语义提取(通义听悟对标):M5 的 AI 精修图片理解是地基(屏卡图随精修上云),未来可升级为独立多屏卡批量提取 + 图文总结 + PPT 导出——以用户反馈为门控
  • 双声源分离(Granola Me/Them):WASAPI 环回 + 麦克风双流融合,speaker 影子列(types.rs)已留桩——需独立 ADR,记 TD
  • 转录面板片段操作(复制/删除/搜索,Granola 转录面板对标):依赖 live:asr-final 段 id 回传协议扩展,记需求池
  • 问题回顾展示(通义听悟对标):复用修辞问句检测逻辑改为双向输出,记需求池
  • 热词建议(Granola Internal Jargon 对标):会话后低置信段+高频专名 → 候选词一键采纳,记需求池
  • 自动结束与 Resume:15min 无音频自动停(idle_governor 扩展)+ 已结束会话恢复转录(生命周期语义变更)——需独立 ADR,记 TD

关联

  • 设计文档:2026-08-23-v0.12.0-body-source-wgc-overlay-design(待写,未落档)
  • 依赖/复用:capture/frame_diff.rs(变化检测纯函数)· capture/dxgi_capture.rs(降级 1 层)· capture/gdi_capture.rs(兜底层)· photo_capture.rs(OCR 块 region=full 写入)· note_filter.rs(既有 Transcript 路径完全不变)· ai_client.rs(chat_vision 多模态扩展点)· live_keyframes.rs(存图触发解耦)
  • 市场对标:Granola(转录面板/自动停止/Me-Them 双声源/浮窗指示器)· 通义听悟(PPT 提取/问题回顾/值得关注)· Notion AI(结构化上下文)
  • ADR-002(DXGI 窗口裁剪)· ADR-010(AI gap-filling 隐私契约——M5 授权扩展)· ADR-018(FSRS)· ADR-020(图文会话 kind=photo)