feat(multimodal): 完成阶段 F 运行管理与收尾验收 #22

Merged
Kronecker merged 2 commits from feat/multimodal-finalization-review into main 2026-09-05 02:13:21 +08:00
Owner

背景

阶段 F 已完成本地 Embedding、音频转写、片段级说话人聚类、声纹比对、API 优先与本地回退,以及媒体任务和知识库闭环。

本 PR 补齐阶段 F 的运行管理、CUDA 页面安装、可靠重试、诊断、用量统计、自定义请求 JSON 和最终验收,并修复多轮审阅发现的问题。

本 PR 必须在 fix/restore-main-review-flow 合并后再合并。

主要修改

本地模型与 CUDA

  • 默认继续使用 CPU。
  • 设置页增加“CUDA 运行组件(可选)”卡片。
  • 支持从前端触发 Windows CUDA 组件安装。
  • 显示环境检查、PyTorch CUDA 下载、依赖安装和运行验证阶段。
  • 使用独立的 .venv-models-cuda,不覆盖 CPU 环境。
  • 固定安装:
    • torch 2.9.1+cpu
    • torch 2.9.1+cu128
    • 对应版本的 torchaudio
  • 安装失败可以重试。
  • 重复安装请求复用当前任务。
  • 本地模型运行期间拒绝修改运行组件。
  • 后端关闭时回收安装进程树。
  • 显式设置的 APP_MODEL_PYTHON 保持最高优先级。

CUDA 失败回退

  • CUDA 初始化失败或 CUDA OOM 时,释放失败进程后使用 CPU 重试一次。
  • 普通推理错误、依赖缺失和用户取消不会错误触发设备重试。
  • CPU 重试失败后停止,不进入循环。
  • CUDA 重试期间保持原队列位置。
  • 转写重试前清除上一尝试产生的部分片段。
  • 每次 attempt 使用冻结的 RuntimeConfig 选择 Python 环境。
  • 排队期间修改设置不会改变已经提交任务的运行环境。
  • 每次 attempt 只解析一次可执行路径。

模型调度与诊断

  • 交互式向量查询优先级为 0。
  • 媒体任务优先级为 10。
  • 后台笔记索引优先级为 20。
  • 同优先级保持 FIFO。
  • 模型卡片显示权重目录的实际磁盘占用。
  • 下载字节数与实际磁盘占用分开显示。
  • 模型诊断持久化到 SQLite,保留最近 200 条。
  • 诊断覆盖:
    • 成功
    • 失败
    • 取消
    • 排队取消
    • API 调用
    • API 回退
    • CUDA → CPU 重试
  • 诊断不保存正文、音频、路径、密钥、声纹向量或异常全文。

媒体任务幂等

  • 前端在同一次提交中冻结文件、选项、上传键和任务键。
  • 上传响应丢失时复用原上传键。
  • 已获得附件 ID 后,只重试任务创建。
  • “重新处理为新任务”明确生成新的提交身份。
  • 后端持久保存:
    • Idempotency-Key
    • 文件名
    • attachment_id
    • 内容摘要
  • 同键同文件同内容返回原 attachment_id。
  • 同键更换文件名、扩展名或内容返回 IDEMPOTENCY_CONFLICT
  • 对应附件已经清理时返回 IDEMPOTENCY_EXPIRED,要求开始新提交。

转写笔记安全更新

  • 增加 TranscriptNoteRequest.update_existing
  • 新修订可以安全更新上次导出的笔记并保留 note_id。
  • 更新前在 Vault 写锁内检查导出基线摘要。
  • 用户手动修改过笔记时返回 NOTE_CONTENT_CONFLICT,不会覆盖正文。
  • 旧记录没有导出基线时返回 NOTE_UPDATE_BASELINE_MISSING
  • 用户可以关闭“更新上次导出”并创建新笔记。
  • 索引重建后仍保留媒体任务与导出笔记关联。
  • embedding_local_only: true 在更新后继续保留。

Token 与音频用量

  • 设置页增加 Token 消耗卡片。
  • 支持输入、输出、总量、缓存命中、缓存未命中、缓存写入和推理 Token。
  • 支持今日、7 天、30 天和自定义时间范围。
  • 支持提供商、模型和来源筛选。
  • 音频调用次数和时长单独统计,不换算成 Token。
  • 显示音频时长覆盖次数。
  • 重试按真实 attempt 分别计数。
  • 历史缺失值保持“未提供”,不使用字符数或估算值回填。
  • 明确统计是应用观测值,不是供应商账单。

自定义请求 JSON

  • 支持提供商、模型、能力及流式条件覆盖。
  • 支持格式化、校验、删除和恢复默认。
  • 支持 JSON 配置导入和导出。
  • 导入文件经过后端统一校验。
  • 禁止在 JSON 中注入:
    • API Key
    • Authorization
    • Header
    • URL
    • model
    • messages/input
    • tools
    • stream
    • 文件字段
  • 请求预览不联网,并隐藏正文和文件。
  • 聊天配置支持发送固定短消息进行真实推理验证。
  • 验证不读取知识库、工具或附件。
  • 验证调用计入真实用量。
  • 修改连接、模型、规则或 JSON 有效性后,旧验证结果失效。
  • 迟到的导入成功或失败响应不会覆盖、污染较新的草稿。

真实模型验收

在隔离的 Vault、SQLite 和附件目录中完成 CPU 与 CUDA 两套真实闭环:

  1. Qwen3-ASR 转写
  2. ERes2NetV2 片段级说话人聚类
  3. 生成 Markdown 笔记
  4. Bekko Embedding 索引
  5. 语义检索找回同一笔记
  6. 修改转写修订
  7. 安全更新原笔记并保留 note_id
  8. 保留 embedding_local_only: true

CUDA 环境:

  • Windows
  • Python 3.12
  • NVIDIA GeForce RTX 4060 Laptop GPU
  • PyTorch 2.9.1+cu128
  • torch.cuda.is_available() == true
  • ASR、片段声纹和 Embedding 的实际设备均为 cuda:0

Embedding 中文小样本对照:

模型 Hit@1 Recall@5 MRR
Bekko A8M 1.0 1.0 1.0
Granite 97M Multilingual r2 1.0 1.0 1.0

该结果只用于确认中文检索闭环可运行,不用于宣称整体模型质量。默认继续使用 Bekko,Granite 保持可选。

自动化验证

  • 后端全量:559 项通过。
  • 前端全量:29 个文件、103 项通过。
  • TypeScript 类型检查通过。
  • Vite 生产构建通过。
  • git diff --check 通过。
  • 仍有已有的 Starlette/httpx 弃用提示。
  • 仍有已有的大 bundle 构建提示。

验收边界

以下项目仍需后续专项验收:

  • 带参考文本的课程长音频 CER/WER。
  • 带说话人标注的 DER 和聚类阈值。
  • 多人重叠语音。
  • 逐字强制对齐。
  • 长音频吞吐和资源预算。
  • 使用目标账号验证供应商特殊 JSON 参数。

当前时间戳为片段级,声纹聚类不能描述为完整的说话人分离。

Tauri/Rust Host 和生产 MCP 沙箱仍属于后续阶段。本 PR 的持久化数据位于后端 SQLite 和 Vault,并保留桌面端集成所需的稳定接口。

合并说明

本分支建立在 fix/restore-main-review-flow 之上。

合并 fix/restore-main-review-flow 后,本 PR 可 Fast-forward 合并,不产生冲突。

## 背景 阶段 F 已完成本地 Embedding、音频转写、片段级说话人聚类、声纹比对、API 优先与本地回退,以及媒体任务和知识库闭环。 本 PR 补齐阶段 F 的运行管理、CUDA 页面安装、可靠重试、诊断、用量统计、自定义请求 JSON 和最终验收,并修复多轮审阅发现的问题。 本 PR 必须在 `fix/restore-main-review-flow` 合并后再合并。 ## 主要修改 ### 本地模型与 CUDA - 默认继续使用 CPU。 - 设置页增加“CUDA 运行组件(可选)”卡片。 - 支持从前端触发 Windows CUDA 组件安装。 - 显示环境检查、PyTorch CUDA 下载、依赖安装和运行验证阶段。 - 使用独立的 `.venv-models-cuda`,不覆盖 CPU 环境。 - 固定安装: - `torch 2.9.1+cpu` - `torch 2.9.1+cu128` - 对应版本的 `torchaudio` - 安装失败可以重试。 - 重复安装请求复用当前任务。 - 本地模型运行期间拒绝修改运行组件。 - 后端关闭时回收安装进程树。 - 显式设置的 `APP_MODEL_PYTHON` 保持最高优先级。 ### CUDA 失败回退 - CUDA 初始化失败或 CUDA OOM 时,释放失败进程后使用 CPU 重试一次。 - 普通推理错误、依赖缺失和用户取消不会错误触发设备重试。 - CPU 重试失败后停止,不进入循环。 - CUDA 重试期间保持原队列位置。 - 转写重试前清除上一尝试产生的部分片段。 - 每次 attempt 使用冻结的 RuntimeConfig 选择 Python 环境。 - 排队期间修改设置不会改变已经提交任务的运行环境。 - 每次 attempt 只解析一次可执行路径。 ### 模型调度与诊断 - 交互式向量查询优先级为 0。 - 媒体任务优先级为 10。 - 后台笔记索引优先级为 20。 - 同优先级保持 FIFO。 - 模型卡片显示权重目录的实际磁盘占用。 - 下载字节数与实际磁盘占用分开显示。 - 模型诊断持久化到 SQLite,保留最近 200 条。 - 诊断覆盖: - 成功 - 失败 - 取消 - 排队取消 - API 调用 - API 回退 - CUDA → CPU 重试 - 诊断不保存正文、音频、路径、密钥、声纹向量或异常全文。 ### 媒体任务幂等 - 前端在同一次提交中冻结文件、选项、上传键和任务键。 - 上传响应丢失时复用原上传键。 - 已获得附件 ID 后,只重试任务创建。 - “重新处理为新任务”明确生成新的提交身份。 - 后端持久保存: - Idempotency-Key - 文件名 - attachment_id - 内容摘要 - 同键同文件同内容返回原 attachment_id。 - 同键更换文件名、扩展名或内容返回 `IDEMPOTENCY_CONFLICT`。 - 对应附件已经清理时返回 `IDEMPOTENCY_EXPIRED`,要求开始新提交。 ### 转写笔记安全更新 - 增加 `TranscriptNoteRequest.update_existing`。 - 新修订可以安全更新上次导出的笔记并保留 note_id。 - 更新前在 Vault 写锁内检查导出基线摘要。 - 用户手动修改过笔记时返回 `NOTE_CONTENT_CONFLICT`,不会覆盖正文。 - 旧记录没有导出基线时返回 `NOTE_UPDATE_BASELINE_MISSING`。 - 用户可以关闭“更新上次导出”并创建新笔记。 - 索引重建后仍保留媒体任务与导出笔记关联。 - `embedding_local_only: true` 在更新后继续保留。 ### Token 与音频用量 - 设置页增加 Token 消耗卡片。 - 支持输入、输出、总量、缓存命中、缓存未命中、缓存写入和推理 Token。 - 支持今日、7 天、30 天和自定义时间范围。 - 支持提供商、模型和来源筛选。 - 音频调用次数和时长单独统计,不换算成 Token。 - 显示音频时长覆盖次数。 - 重试按真实 attempt 分别计数。 - 历史缺失值保持“未提供”,不使用字符数或估算值回填。 - 明确统计是应用观测值,不是供应商账单。 ### 自定义请求 JSON - 支持提供商、模型、能力及流式条件覆盖。 - 支持格式化、校验、删除和恢复默认。 - 支持 JSON 配置导入和导出。 - 导入文件经过后端统一校验。 - 禁止在 JSON 中注入: - API Key - Authorization - Header - URL - model - messages/input - tools - stream - 文件字段 - 请求预览不联网,并隐藏正文和文件。 - 聊天配置支持发送固定短消息进行真实推理验证。 - 验证不读取知识库、工具或附件。 - 验证调用计入真实用量。 - 修改连接、模型、规则或 JSON 有效性后,旧验证结果失效。 - 迟到的导入成功或失败响应不会覆盖、污染较新的草稿。 ## 真实模型验收 在隔离的 Vault、SQLite 和附件目录中完成 CPU 与 CUDA 两套真实闭环: 1. Qwen3-ASR 转写 2. ERes2NetV2 片段级说话人聚类 3. 生成 Markdown 笔记 4. Bekko Embedding 索引 5. 语义检索找回同一笔记 6. 修改转写修订 7. 安全更新原笔记并保留 note_id 8. 保留 `embedding_local_only: true` CUDA 环境: - Windows - Python 3.12 - NVIDIA GeForce RTX 4060 Laptop GPU - PyTorch `2.9.1+cu128` - `torch.cuda.is_available() == true` - ASR、片段声纹和 Embedding 的实际设备均为 `cuda:0` Embedding 中文小样本对照: | 模型 | Hit@1 | Recall@5 | MRR | | --- | ---: | ---: | ---: | | Bekko A8M | 1.0 | 1.0 | 1.0 | | Granite 97M Multilingual r2 | 1.0 | 1.0 | 1.0 | 该结果只用于确认中文检索闭环可运行,不用于宣称整体模型质量。默认继续使用 Bekko,Granite 保持可选。 ## 自动化验证 - 后端全量:559 项通过。 - 前端全量:29 个文件、103 项通过。 - TypeScript 类型检查通过。 - Vite 生产构建通过。 - `git diff --check` 通过。 - 仍有已有的 Starlette/httpx 弃用提示。 - 仍有已有的大 bundle 构建提示。 ## 验收边界 以下项目仍需后续专项验收: - 带参考文本的课程长音频 CER/WER。 - 带说话人标注的 DER 和聚类阈值。 - 多人重叠语音。 - 逐字强制对齐。 - 长音频吞吐和资源预算。 - 使用目标账号验证供应商特殊 JSON 参数。 当前时间戳为片段级,声纹聚类不能描述为完整的说话人分离。 Tauri/Rust Host 和生产 MCP 沙箱仍属于后续阶段。本 PR 的持久化数据位于后端 SQLite 和 Vault,并保留桌面端集成所需的稳定接口。 ## 合并说明 本分支建立在 `fix/restore-main-review-flow` 之上。 合并 `fix/restore-main-review-flow` 后,本 PR 可 Fast-forward 合并,不产生冲突。
Kronecker added 2 commits 2026-09-05 02:13:03 +08:00
Author
Owner

审阅通过,同意合并。

已确认:

  • CUDA 安装入口、独立环境和默认 CPU 行为符合阶段 F 规划。
  • CUDA 初始化失败及 OOM 的 CPU 回退不会影响普通错误和取消流程。
  • 推理使用冻结的 attempt 配置,排队期间修改设置不会改变运行环境。
  • 上传与任务重试保持幂等,跨文件名、扩展名和内容复用会被拒绝。
  • 跨修订更新笔记不会覆盖用户手动编辑。
  • 请求 JSON 的导入、导出、恢复默认、预览和实际推理验证边界清晰。
  • 迟到的导入成功及失败结果不会污染新草稿。
  • 诊断、Token 和音频用量不伪造缺失数据,也不记录敏感正文。
  • 后端 559 项、前端 103 项测试及生产构建通过。

课程长音频、逐字对齐、重叠语音和目标供应商兼容性已明确保留为专项验收项,不影响本次工程功能合并。

请确认 fix/restore-main-review-flow 已先合并,再合并本 PR。

审阅通过,同意合并。 已确认: - CUDA 安装入口、独立环境和默认 CPU 行为符合阶段 F 规划。 - CUDA 初始化失败及 OOM 的 CPU 回退不会影响普通错误和取消流程。 - 推理使用冻结的 attempt 配置,排队期间修改设置不会改变运行环境。 - 上传与任务重试保持幂等,跨文件名、扩展名和内容复用会被拒绝。 - 跨修订更新笔记不会覆盖用户手动编辑。 - 请求 JSON 的导入、导出、恢复默认、预览和实际推理验证边界清晰。 - 迟到的导入成功及失败结果不会污染新草稿。 - 诊断、Token 和音频用量不伪造缺失数据,也不记录敏感正文。 - 后端 559 项、前端 103 项测试及生产构建通过。 课程长音频、逐字对齐、重叠语音和目标供应商兼容性已明确保留为专项验收项,不影响本次工程功能合并。 请确认 `fix/restore-main-review-flow` 已先合并,再合并本 PR。
Kronecker merged commit d67199faad into main 2026-09-05 02:13:21 +08:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Kronecker/NotesAgentic#22