edit | blame | history | raw

Round 3 PRD:Moonshine English 默认模型

状态:v0.1 启动稿
所属子项目:02-P-NBL
Round:Round 3
日期:2026-06-03
基线版本:v2.1.20-build20260603.1145
基线 commit:f66a79670c444010a59b8513c9f61257ebc7d9b6
关联文档:

1. 背景

Round 1 已完成模型 profile 基础设施,Round 2 已完成语言检测和语言版本设置。当前状态是:

  • 中文和 English UI 可以根据 effective language 切换。
  • LanguageProfile 已经有 zh-CNen
  • en 语言版本仍临时使用 sensevoice-zh
  • 引擎初始化仍只支持 sensevoice backend。
  • Onboarding 下载仍依赖 config 里的 SenseVoice URL。

Round 3 要把 English 语言版本接到真正的英文默认模型 Moonshine English。

2. 本轮目标

Round 3 完成后:

场景 effective language 默认模型 期望结果
中文系统新用户 zh-CN sensevoice-zh 继续中文 UI + SenseVoice
English 系统新用户 en moonshine-en English UI + Moonshine English
其他系统语言新用户 en moonshine-en English UI + Moonshine English
老中文用户升级 zh-CN sensevoice-zh 不重新下载、不丢数据
用户手动切到 English en moonshine-en 未安装则提示/下载 Moonshine
用户手动切回中文 zh-CN sensevoice-zh 使用已有 SenseVoice

核心目标:

  • 新增 moonshine-en model profile。
  • English 语言版本默认模型改为 moonshine-en
  • 新增 sherpa-onnx Moonshine backend builder。
  • Onboarding 按“当前应使用的模型 profile”下载模型,而不是写死 SenseVoice URL。
  • Moonshine 下载失败、初始化失败、缺文件时,不破坏 SenseVoice、用户词库、历史记录和配置。

3. 本轮非目标

明确不做:

  • 不接入 Parakeet。
  • 不接入 Qwen3-ASR。
  • 不接入 Moonshine Voice framework。
  • 不接 Moonshine v2 多语言模型。
  • 不做 realtime partial transcript。
  • 不做模型选择页。
  • 不做模型删除、清理和回滚 UI。
  • 不做 30+ 语言列表。
  • 不做粤语独立语言版本。
  • 不做欧洲语言第一优选模型决策。
  • 不改变用户词库、history、replacement 规则格式。
  • 不做正式签名和 notarization。

4. 模型选择决策

Round 3 选择:

model id: moonshine-en
actual package: sherpa-onnx-moonshine-base-en-int8
backend kind: moonshine
language: English only

选择 base-en-int8,不是 tiny-en-int8,原因:

  • GitHub release asset 显示 base-en-int8.tar.bz2250807309 bytes,约 239 MiB。
  • sherpa 官方文档列出的解压文件总量约 560448 blocks,仍在用户可接受的 300MB 级别附近。
  • 英文用户分支需要更稳的默认准确率,base 比 tiny 更适合作为第一默认模型。
  • tiny-en-int8 可作为工程备用候选,但本轮不暴露为独立 UI 选项。

资料依据:

5. Moonshine Profile

新增 profile:

ID: moonshine-en
DisplayName: Moonshine English
BackendKind: moonshine
Tier: default
SupportedLanguageIDs: en
RecommendedFor: en
Description: 轻量英文离线模型,适合英文听写和英文日常输入。
ApproxSize: 约 239 MiB 下载包,解压后约 270-280 MiB
InstallDirName: moonshine-en
ProviderOrder: cpu
NumThreads: 4

下载 URL:

primary:
https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-moonshine-base-en-int8.tar.bz2

fallback:
https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-moonshine-tiny-en-int8.tar.bz2

说明:

  • fallback URL 只用于下载源不可用时保证开发/QA 能继续验证,不表示最终产品会静默降级到 tiny。
  • 如果最终产品不接受 tiny 作为降级包,研发应把 fallback 留空或换成自维护 mirror。

Required files:

Role Required file
preprocessor preprocess.onnx
encoder encode.int8.onnx
uncached_decoder uncached_decode.int8.onnx
cached_decoder cached_decode.int8.onnx
tokens tokens.txt

6. sherpa-onnx 配置

当前项目锁定:

github.com/k2-fsa/sherpa-onnx-go v1.12.24
github.com/k2-fsa/sherpa-onnx-go-macos v1.12.24

该版本 Moonshine 是 v1 四文件配置:

config.ModelConfig.Moonshine.Preprocessor = resolved.Files["preprocessor"]
config.ModelConfig.Moonshine.Encoder = resolved.Files["encoder"]
config.ModelConfig.Moonshine.UncachedDecoder = resolved.Files["uncached_decoder"]
config.ModelConfig.Moonshine.CachedDecoder = resolved.Files["cached_decoder"]
config.ModelConfig.Tokens = resolved.Files["tokens"]
config.ModelConfig.NumThreads = resolved.Profile.NumThreads
config.ModelConfig.Provider = "cpu"
config.DecodingMethod = "greedy_search"

保留:

config.FeatConfig.SampleRate = 16000
config.FeatConfig.FeatureDim = 80

不要使用:

encoder_model.ort
decoder_model_merged.ort
MergedDecoder

这些不是当前项目依赖版本对应的 Moonshine v1 接入形态。

7. 默认模型解析规则

Round 3 必须修正“当前模型”的定义。

当前问题:

config.Default().SelectedModelID = sensevoice-zh
engine.New() 直接读取 SelectedModelID

这会导致 English 新用户即使 effective language 是 en,仍然被锁到 SenseVoice。

Round 3 目标规则:

CurrentModel = ResolveCurrentModel(Config, EffectiveLanguage)

建议引入:

ModelSelectionMode = auto | manual

默认:

ModelSelectionMode = auto

解析规则:

条件 当前模型
ModelSelectionMode=auto 且 effective language=zh-CN sensevoice-zh
ModelSelectionMode=auto 且 effective language=en moonshine-en
ModelSelectionMode=manualSelectedModelID 合法 SelectedModelID
ModelSelectionMode=manual 但模型非法 回退到 effective language 默认模型,并记录日志
旧配置缺少 ModelSelectionMode 视为 auto

说明:

  • Round 3 没有模型选择 UI,因此普通用户不会进入 manual
  • 老用户配置里已有的 SelectedModelID=sensevoice-zh 应视为历史默认值,不应阻止 English 默认 Moonshine 生效。
  • 后续 Round 4/5 做模型选择页时,再由 UI 把 ModelSelectionMode 设为 manual

8. 用户故事

8.1 English 新用户

作为 English macOS 用户,我第一次启动 App 时,应看到 English UI,并自动准备 Moonshine English。

验收点:

  • effective language=en
  • current model=moonshine-en
  • 如果 Moonshine 未安装,进入 onboarding 下载 Moonshine。
  • 下载完成后引擎显示 Moonshine English · CPU 或等价信息。
  • 按 R-Alt 说英文,可以离线识别并写入 history。

8.2 中文新用户

作为中文 macOS 用户,我第一次启动 App 时,应保持 Round 2 体验。

验收点:

  • effective language=zh-CN
  • current model=sensevoice-zh
  • 不下载 Moonshine。
  • SenseVoice 可正常离线识别。

8.3 老中文用户升级

作为已有中文用户,我升级到 Round 3 后,不应被要求下载 Moonshine。

验收点:

  • 旧 SenseVoice 目录可继续使用。
  • userdict.json 不变。
  • history.json 不变。
  • replacement 规则继续生效。
  • 热键和历史写入不退化。

8.4 用户手动切到 English

作为用户,我在设置页把语言版本切到 English 后,App 应切换到英文产品路径。

验收点:

  • UI 立即切到 English。
  • current model 解析为 moonshine-en
  • 如果 Moonshine 未安装,显示模型准备/下载状态。
  • 如果 Moonshine 已安装,重新初始化 Moonshine 引擎。
  • 切换失败时,不能删除或覆盖 SenseVoice。

8.5 用户手动切回中文

作为用户,我可以从 English 切回中文。

验收点:

  • UI 立即切回中文。
  • current model 解析为 sensevoice-zh
  • 若 SenseVoice 已安装,直接恢复中文识别。
  • Moonshine 模型保留,不自动删除。

9. Onboarding 与下载规则

Round 3 onboarding 不应再让前端从 Config.ModelDownloadUrlFallbackModelDownloadUrl 读取 SenseVoice URL。

目标:

frontend -> EngineService.DownloadCurrentModel()
backend -> ResolveCurrentModel()
backend -> profile.DownloadURLs
backend -> DownloadProfile(profile, urls, modelsRoot)

要求:

  • ModelExists() 检查 current model,不是固定 SenseVoice。
  • DownloadCurrentModel() 下载 current model。
  • 下载完成后重新初始化 current model。
  • 下载失败只影响目标模型,不删除已有模型。
  • 下载进度事件继续复用 model:download-progress

保留兼容:

  • 可以保留旧 DownloadModel(primaryURL, fallbackURL) API,但 Round 3 前端不应再调用它。
  • ModelDownloadUrl / FallbackModelDownloadUrl 可暂时留在 config 中,不在本轮强删。

10. 失败处理

10.1 下载失败

期望:

  • 显示下载失败。
  • 不删除 models/sensevoicemodels/sensevoice-zh
  • 不删除已有 models/moonshine-en 完整目录。
  • 不把 incomplete staging 目录作为可用模型。
  • 用户可重试。

10.2 缺文件

如果 moonshine-en 缺少任意 required file:

  • ValidateModelDir 返回 incomplete。
  • ModelExists() 返回 false。
  • engine.New() 不应崩溃。
  • UI 进入 need_model 或错误状态。

10.3 初始化失败

如果 Moonshine sherpa 初始化失败:

  • 状态为 errorneed_model,取决于模型是否完整存在。
  • 记录 backend、provider、model id、root dir。
  • 不修改用户词库、历史和 SenseVoice 目录。

11. 验收标准

Round 3 功能性验收 PASS 必须满足:

  • English fresh user 默认 Moonshine。
  • Chinese fresh user 默认 SenseVoice。
  • 老中文用户升级不触发 Moonshine 下载。
  • Moonshine 可下载、校验、加载。
  • 英文语音可离线识别,并写入 history.json
  • 中文 SenseVoice 回归通过。
  • 语言切换会同步 current model。
  • Moonshine 下载失败不破坏已有 SenseVoice。
  • Moonshine 缺文件不被判定为可用。
  • go test ./... 通过。
  • npm run build 通过。
  • QA 报告记录版本、build、commit、测试包、日志和关键证据。