# Round 1 研发任务拆解:模型 Profile 基础设施 状态:v0.1 研发拆解稿 所属子项目:`02-P-NBL` Round:Round 1 日期:2026-06-02 输入文档: - [`prd.md`](prd.md) - [`../engineering-plan.md`](../engineering-plan.md) - [`../plan.md`](../plan.md) ## 1. 研发目标 Round 1 的研发目标是: ```text 在不改变用户体验的前提下,把现有 SenseVoice 单模型实现改造成可扩展的 ModelProfile 架构。 ``` 本轮不接入 Moonshine、Parakeet、Qwen3-ASR,不做语言 UI,不做模型选择 UI。 ## 2. 交付边界 ### 2.1 必须交付 - `ModelProfile` / `ModelRegistry` - `LanguageProfile` / `LanguageRegistry` 最小实现 - `RequiredFileRule`,支持 `allOf` / `anyOf` - `ModelInstallState`,读写 `models/state.json` - `ModelResolver`,支持 state、新目录、旧目录 fallback - `ResolvedModel` - `sensevoice-zh` profile - `SelectedModelID` 隐藏配置,默认 `sensevoice-zh` - `EngineFactory` 初步实现 - SenseVoice 新旧路径兼容 - 下载器 staging + required files 校验 + 安全落盘 - Wails public API 兼容 - 自动化测试覆盖核心解析、校验、状态文件、下载失败保护 ### 2.2 明确不交付 - Moonshine 真实模型接入 - Parakeet 真实模型接入 - Qwen3-ASR 真实模型接入 - 语言设置 UI - 模型选择 UI - 模型删除 UI - 旧模型目录自动迁移 - 每个模型目录下的 `manifest.json` - checksum / 签名校验 - 远程模型 catalog ## 3. 推荐任务顺序 ```text T0 代码现状确认 T1 Profile / Registry 基础类型 T2 Required files 校验器 T3 Install state 读写 T4 ModelResolver T5 Config 兼容与 SelectedModelID T6 EngineFactory 改造 T7 下载器安全安装 T8 EngineService / Wails 兼容 T9 自动化测试 T10 开发自查与交付说明 ``` 建议按顺序推进。`T1-T5` 是地基,`T6-T8` 是业务接入,`T9-T10` 是进入 QA 前的门禁。 ## 4. 任务明细 ### T0:代码现状确认 负责人:后端 类型:准备任务 建议文件: - `privatevoice.src/internal/engine/engine.go` - `privatevoice.src/internal/engine/engine_darwin.go` - `privatevoice.src/internal/model/downloader.go` - `privatevoice.src/internal/paths/paths.go` - `privatevoice.src/internal/config/config.go` - `privatevoice.src/services/engine_service.go` - `privatevoice.src/frontend/src/App.svelte` - `privatevoice.src/frontend/src/components/onboarding/OnboardingView.svelte` 工作内容: - 标出当前写死 SenseVoice 的路径。 - 标出前端 Wails 调用链。 - 标出下载器中会删除旧目录的风险点。 - 确认当前测试命令和前端构建命令。 完成标准: - 形成代码改动前 checklist。 - 明确哪些 public API 不允许改签名。 ### T1:Profile / Registry 基础类型 负责人:后端 建议文件: - `privatevoice.src/internal/model/profile.go` - `privatevoice.src/internal/model/registry.go` 工作内容: - 新增 `ModelProfile`。 - 新增 `LanguageProfile`。 - 新增 `RequiredFileRule` 类型。 - 新增 `sensevoice-zh` profile。 - 新增 `zh-CN` language profile。 - 提供 `GetModelProfile(id)`、`DefaultModelProfile()`、`ListModelProfiles()` 等最小 registry 方法。 关键要求: - `ModelProfile` 使用 `SupportedLanguageIDs` 和 `RecommendedFor` 两个字段,不混用。 - `sensevoice-zh` 的 `InstallDirName` 为 `sensevoice-zh`。 - `BackendKind` 为 `sensevoice`。 完成标准: - 未知 model id 返回明确错误。 - 默认 profile 为 `sensevoice-zh`。 - 单元测试覆盖 registry 查询。 ### T2:Required files 校验器 负责人:后端 建议文件: - `privatevoice.src/internal/model/validator.go` 工作内容: - 实现 `RequiredFileRule` 的 `AllOf` / `AnyOf` 校验。 - 文件不存在视为失败。 - 文件为 0 字节视为失败。 - 对 SenseVoice 输出角色化文件路径:`model`、`tokens`。 - 同时存在 `model.int8.onnx` 和 `model.onnx` 时优先选择 `model.int8.onnx`。 完成标准: - 只有 `model.onnx` 时可通过。 - 只有 `model.int8.onnx` 时可通过。 - 两个模型文件都存在时选择 int8。 - 缺少 `tokens.txt` 时失败。 - 0 字节 required file 失败。 ### T3:Install state 读写 负责人:后端 建议文件: - `privatevoice.src/internal/model/install_state.go` - `privatevoice.src/internal/paths/paths.go` 工作内容: - 新增 `paths.ModelInstallDir(name string)`。 - 新增 `paths.ModelStatePath()`。 - 实现 `models/state.json` 最小 schema。 - `path` 字段存相对 `models` 根目录路径。 - 非法 JSON、空文件、未知 model id 都不能 panic。 完成标准: - state 不存在时返回空状态。 - state 非法 JSON 时返回可恢复错误,由 Resolver fallback。 - state 写入失败不阻塞旧模型加载。 ### T4:ModelResolver 负责人:后端 建议文件: - `privatevoice.src/internal/model/resolver.go` 工作内容: - 实现 `ResolvedModel`。 - 实现安装状态枚举。 - 路径候选顺序: 1. state 中 `sensevoice-zh` 记录路径 2. `models/sensevoice-zh` 3. `models/sensevoice` - 每个候选目录都执行 required files 校验。 - state 指向坏目录时继续 fallback。 - 新旧目录都完整且无 state 时使用新目录。 完成标准: - 旧目录完整时可解析。 - 新目录完整时可解析。 - state 损坏时可 fallback。 - 不完整目录不会被解析为可用。 - 返回 `ResolvedModel.Files["model"]` 和 `ResolvedModel.Files["tokens"]`。 ### T5:Config 兼容与 SelectedModelID 负责人:后端 建议文件: - `privatevoice.src/internal/config/config.go` 工作内容: - 新增隐藏字段 `SelectedModelID string`。 - 老配置缺失该字段时默认 `sensevoice-zh`。 - 空值或未知 model id 回退 `sensevoice-zh`。 - 保存配置时不得丢失旧字段。 - 保留 `ModelDownloadUrl` 和 `FallbackModelDownloadUrl`。 完成标准: - 老 `config.json` 可正常加载。 - `ConfigService.GetConfig()` 返回兼容旧前端的数据。 - 新字段不会要求 UI 改动。 ### T6:EngineFactory 改造 负责人:后端 建议文件: - `privatevoice.src/internal/engine/engine.go` - `privatevoice.src/internal/engine/factory.go` - `privatevoice.src/internal/engine/engine_darwin.go` - `privatevoice.src/internal/engine/engine_linux.go` - `privatevoice.src/internal/engine/engine_windows.go` 工作内容: - 保留 `engine.New()`。 - 新增内部入口 `NewWithModelID(modelID string)`。 - 新增内部入口 `NewWithResolvedModel(resolved model.ResolvedModel)`。 - 平台 `newPlatformEngine` 改为接收 `ResolvedModel`。 - SenseVoice config 使用 `resolved.Files["model"]` 和 `resolved.Files["tokens"]`。 - 用户可见 `HardwareInfo()` 保持 `SenseVoice · CoreML/CPU` 风格。 完成标准: - 调用方不用再直接拼 SenseVoice 路径。 - 不完整模型不会进入 sherpa 初始化。 - sherpa 初始化失败不导致 App 崩溃。 ### T7:下载器安全安装 负责人:后端 建议文件: - `privatevoice.src/internal/model/downloader.go` 工作内容: - 保留旧外部调用能力。 - 内部按默认 profile `sensevoice-zh` 安装。 - 下载到 `models/.downloads/sensevoice-zh/`。 - 解压到临时 extract 目录。 - 校验 staging 目录 required files。 - 校验通过后安装到 `models/sensevoice-zh`。 - 写入或更新 `models/state.json`。 - 下载失败、解压失败、校验失败不得破坏旧 `models/sensevoice`。 完成标准: - 不再直接 `RemoveAll(models/sensevoice)`。 - 半成品不会被 Resolver 误判为可用。 - 下载失败后可再次重试。 ### T8:EngineService / Wails 兼容 负责人:后端 + 前端确认 建议文件: - `privatevoice.src/services/engine_service.go` - `privatevoice.src/frontend/src/App.svelte` - `privatevoice.src/frontend/src/components/onboarding/OnboardingView.svelte` 工作内容: - 保持 `EngineService.ModelExists() bool` 签名。 - 保持 `EngineService.DownloadModel(primaryURL, fallbackURL) error` 签名。 - `ModelExists()` 返回当前 default/selected model 是否完整可用。 - 目录不完整时返回 false。 - 保持 `model:download-progress` payload。 - 保持 `engine:status` 事件语义。 完成标准: - 前端无需改调用即可运行。 - `ModelExists -> need_model -> OnboardingView -> DownloadModel -> ready` 链路正常。 - 不出现新模型 UI。 ### T9:自动化测试 负责人:后端 + QA 协作 建议文件: - `privatevoice.src/internal/model/*_test.go` - 必要时补充 engine 相关测试 最低测试集: - registry 默认模型。 - required files `allOf` / `anyOf`。 - int8 优先。 - state 缺失 fallback。 - state 非法 JSON fallback。 - state 指坏目录 fallback。 - 新旧目录优先级。 - 不完整目录不可用。 - `SelectedModelID` 默认和无效值回退。 - 下载失败不破坏已有目录。 完成标准: - Go 单元测试通过。 - 测试能在无真实大模型的 fixture 目录下运行。 ### T10:开发自查与交付说明 负责人:研发负责人 建议文件: - `02-P-NBL/round-1/dev-checklist.md` 工作内容: - 记录开发自查结果。 - 记录执行过的命令和结果。 - 记录手工 smoke 结果。 - 记录仍需 QA 覆盖的风险。 完成标准: - 开发自查完成后才能移交 QA。 - 交付说明包含变更范围、测试范围、已知风险。 ## 5. 依赖关系 | 任务 | 依赖 | |---|---| | T1 | T0 | | T2 | T1 | | T3 | T1 | | T4 | T1, T2, T3 | | T5 | T1 | | T6 | T4, T5 | | T7 | T2, T3, T4 | | T8 | T4, T6, T7 | | T9 | T1-T8 | | T10 | T9 | ## 6. 研发完成定义 Round 1 研发完成必须同时满足: - 所有必须交付项已实现。 - 旧 Wails public API 未破坏。 - 老用户旧目录场景可用。 - 新用户下载路径可用。 - 不完整模型不会进入 engine。 - 下载失败不会破坏已有完整模型。 - Go 单元测试通过。 - 前端构建或现有前端检查通过。 - 研发自查记录完成。 ## 7. 进入 QA 的交付包 研发移交 QA 时应提供: - 分支名 / commit id。 - 变更文件列表。 - 开发自查记录。 - 执行命令和结果。 - 测试 fixture 说明。 - 已知风险。 - 需要 QA 特别关注的路径: - 旧目录兼容。 - state 损坏 fallback。 - 下载失败保护。 - Wails API 兼容。 - 断网已有模型识别。