Skip to content

Fix/sherpa local asr state sync v2#526

Closed
weikeyi wants to merge 21 commits into
Open-Less:mainfrom
weikeyi:fix/sherpa-local-asr-state-sync-v2
Closed

Fix/sherpa local asr state sync v2#526
weikeyi wants to merge 21 commits into
Open-Less:mainfrom
weikeyi:fix/sherpa-local-asr-state-sync-v2

Conversation

@weikeyi
Copy link
Copy Markdown
Contributor

@weikeyi weikeyi commented May 24, 2026

User description

概要

  • 放宽 Sherpa Qwen3-ASR 模型的 tokenizer 目录校验,支持两种布局:
    • tokenizer.json
    • vocab.json + merges.txt
  • 修复 Sherpa 本地 ASR 的部分下载状态展示:
    • 页面刷新后可从 catalog 的 downloadedBytes 恢复 partial 状态
    • 继续下载、删除按钮、进度显示能正确反映本地残留/部分下载文件
  • 放宽 Sherpa “准备”按钮逻辑,不再强制要求 cached === true,允许在本地文件存在但缓存状态未完整识别时尝试准备模型

背景

此前 Qwen3-ASR 的 tokenizer 校验只接受 tokenizer.json,但实际模型资产可能使用 vocab.json + merges.txt 的布局,导致本地文件已经存在时仍被判定为无效。

同时,Sherpa 的前端状态逻辑主要依赖实时下载事件中的 progress。页面刷新后,如果本地已有部分下载文件,但当前没有实时 progress,UI 可能无法正确显示继续下载/删除/进度状态。

说明

已同步检查 Foundry Local Whisper 的同类情况。当前 Foundry 模型资产仍是固定文件布局,没有发现类似 Qwen3 tokenizer 这种目录型资产多布局校验需求,因此本次不扩展 Foundry 后端校验逻辑。

验证

  • cmd /c node_modules\.bin\tsc.cmd --noEmit --pretty false
  • cargo test qwen3_tokenizer_accepts_supported_layouts --lib

PR Type

Enhancement, Bug fix, Tests, Documentation


Description

  • Add sherpa-onnx runtime and downloads

  • Sync active ASR provider during saves

  • Refresh network, marketplace, and update flows

  • Refactor settings UI for local ASR


Diagram Walkthrough

flowchart LR
  UI["Settings / Local ASR UI"] -- "invoke Tauri commands" --> CMD["commands.rs"]
  CMD -- "prepare / download / switch" --> SRV["sherpa_runtime.rs"]
  CMD -- "fetch / verify model files" --> DL["sherpa_download.rs"]
  CMD -- "retry HTTP requests" --> NET["net.rs"]
  SRV -- "persist preferences" --> CFG["types.rs"]
Loading

File Walkthrough

Relevant files
Enhancement
17 files
commands.rs
Wire sherpa commands and retries                                                 
+836/-182
sherpa_download.rs
Implement sherpa model download verification                         
+906/-0 
sherpa_runtime.rs
Add sherpa runtime lifecycle handling                                       
+517/-0 
sherpa.rs
Define sherpa models and layouts                                                 
+415/-0 
sherpa_provider.rs
Register sherpa provider entrypoints                                         
+182/-0 
mod.rs
Export sherpa local ASR modules                                                   
+12/-2   
net.rs
Add shared HTTP retry helper                                                         
+72/-0   
types.rs
Persist sherpa ASR preferences                                                     
+34/-1   
persistence.rs
Serialize new preferences safely                                                 
+7/-0     
lib.rs
Register sherpa state and commands                                             
+38/-1   
LocalAsr.tsx
Add sherpa local ASR screen                                                           
+2927/-1136
localAsr.ts
Extend local ASR client bindings                                                 
+493/-224
ipc.ts
Expose sherpa IPC contracts                                                           
+1020/-784
SettingsModal.tsx
Route settings into new sections                                                 
+119/-495
ProvidersSection.tsx
Add provider settings section                                                       
+791/-0 
MarketplaceSection.tsx
Refresh marketplace management controls                                   
+108/-0 
CheckUpdateButton.tsx
Add channel-aware update button                                                   
+80/-0   
Bug fix
1 files
coordinator.rs
Sync active provider into vault                                                   
+99/-3   
Configuration changes
1 files
build.rs
Adjust Windows build configuration                                             
+22/-0   
Tests
1 files
backend_rust.rs
Stub sherpa provider in tests                                                       
+9/-0     
Documentation
1 files
windows-sherpa-onnx-asr-plan.md
Document sherpa rollout plan                                                         
+421/-0 
Additional files
43 files
Cargo.toml +4/-0     
download.rs +5/-2     
foundry_native.rs +2/-2     
combo_hotkey.rs +3/-0     
dictation.rs +74/-0   
resources.rs +2/-0     
polish.rs +5/-4     
qa_hotkey.rs +3/-0     
App.tsx +5/-4     
AutoUpdate.tsx +6/-4     
FloatingShell.tsx +3/-3     
GithubLoginModal.tsx +218/-0 
Icon.tsx +1/-0     
MarketplaceModal.tsx +2/-2     
Modal.tsx +51/-0   
SelectLite.tsx +9/-0     
en.ts +54/-27 
ja.ts +54/-27 
ko.ts +54/-27 
zh-CN.ts +55/-28 
zh-TW.ts +55/-28 
stylePrefs.test.ts +3/-0     
types.ts +6/-0     
main.tsx +4/-1     
Marketplace.tsx +20/-261
Overview.tsx +17/-3   
QaPanel.tsx +2/-2     
Settings.tsx +0/-2213
AboutSection.tsx +151/-0 
AboutUpdateControl.tsx +0/-53   
BetaChannelSection.tsx +51/-0   
DataStorageSection.tsx +84/-0   
DebugToolsSection.tsx +110/-0 
LanguageSection.tsx +2/-6     
LocalModelSection.tsx +54/-96 
MicrophoneSelect.tsx +152/-0 
PermissionsSection.tsx +7/-28   
RecordingInputSection.tsx +336/-0 
ShortcutsSection.tsx +1/-5     
shared.tsx +168/-60
tabs.tsx +78/-0   
HotkeySettingsContext.tsx +212/-161
global.css +23/-4   

weikeyi and others added 21 commits May 21, 2026 09:46
…-onnx-local-asr

# Conflicts:
#	openless-all/app/src/i18n/en.ts
#	openless-all/app/src/i18n/ja.ts
#	openless-all/app/src/i18n/ko.ts
#	openless-all/app/src/i18n/zh-CN.ts
#	openless-all/app/src/i18n/zh-TW.ts
…x-local-asr

feat(windows): add sherpa-onnx local ASR
将 2200 行的 Settings.tsx 单体拆为 pages/settings/ 下的按节文件(通用 / 服务 /
隐私 / 高级 / 关于),并对设置界面做整体精简与功能调整。

界面精简
- 移除各设置项冗长 / 多行描述(在 180px 标签列普遍折成多行),只留标签与控件
- 删除「个性化」独立 tab —— 仅剩字体大小一项、整页太空,并入「关于」
- 移除失效的「毛玻璃强度」滑块(其 CSS 变量无可见元素消费)

关于 / 更新
- 版本卡片图标右上方放「检查更新」按钮,固定查正式版(channel='stable')
- 「加入 Beta 渠道」迁到「高级」页底部、单独成节;开启后出现查测试版的检查按钮
- 检查中按钮内转圈;结果(已是最新 / 失败)只在按钮内呈现,卡片高度恒定,
  不再因状态文字 reflow 抽搐
- Rust app_check_update_with_channel 新增可选 channel 参数,两个按钮各查各渠道;
  后台 AutoUpdateGate 仍按 prefs.update_channel 走

麦克风选择
- 由全屏弹窗改为 SelectLite 下拉(与语言选择一致的「官方框」)
- SelectLite 增加 trailing / onOpenChange;新增 MicrophoneSelect —— 选中项右侧
  打勾、勾左侧实时音量条

市场登录
- 抽出共用 GithubLoginModal 与 ui/Modal,扩展市场与风格市场登录统一走弹窗
- 修复风格市场登录弹窗「先小后大」尺寸跳动(各阶段固定 minHeight)

弹窗动画
- 去掉开启动画里的 blur 滤镜(卡顿 / 闪烁),改纯 opacity + transform
- 设置弹窗切 tab 内容轻微淡入;各处弹窗动画时长 / 缓动统一到 global.css

网络
- 新增 net.rs:进程级共享 reqwest 客户端(连接池复用)+ 传输层失败指数退避重试
- ProvidersSection: 验证失败时显示 validateFailed 文案,不再对 result.ok=false
  误报「连接检查通过」
- ProvidersSection: LLM/ASR 切换失败时下拉框回滚到 committed provider,避免 UI
  停在新选项而后端仍是旧 provider;去掉 handler 末尾的 rethrow —— 作为 SelectLite
  onChange 是即发即忘调用,rethrow 会变成未处理的 promise rejection
- CheckUpdateButton: 自动收起计时器只依赖 status,不再因 useAutoUpdate 每次渲染
  返回新 updater 对象而被反复 clear/reset
- 新增 i18n key settings.providers.validateFailed(zh-CN/zh-TW/en/ja/ko)
- send_with_retry 不再重试 is_timeout():reqwest 的 is_timeout 也涵盖「请求已发出、
  等响应时超时」,此时服务端可能已收到并在处理,重试 POST/DELETE(marketplace
  点赞 / 删除等)会重复执行。只保留 is_connect / is_request 两类「请求未送达服务端」
  的重试;net.rs 文档原本宣称超时重试幂等安全 —— 该说法对超时不成立,一并订正
- check_network 改单发、不走 send_with_retry:每 30s 的状态探针走 10 次退避会在
  被过滤 / 黑洞网络下把探测拖到近一分钟、状态灯像卡死;瞬时误判由下个 30s 周期
  自动纠正。仍用 net::http() 共享连接池
解决 LocalModelSection.tsx 冲突:beta 的 PR Open-Less#504(Windows sherpa-onnx 本地 ASR)
改的是 AdvancedSection.tsx,而本分支已把它拆分重命名为 LocalModelSection.tsx。
合并保留本分支的拆分 + 文案精简,并并入 Open-Less#504 的 sherpa-onnx-local 引擎行、
isOnSherpaOnnx / pendingNameKey / 禁用逻辑。其余文件由 git 自动合并。
types.rs 的 STRUCTURED_BUILTIN_PROMPT「事项数 → 输出形态」规则已重写(原「≤ 2 条」
拆成「仅 1 条 / = 2 条」两档),但 polish.rs 的两个 structured_prompt 测试仍断言旧
文案,CI 的 macOS / Linux cargo test 因此变红(Windows 偶然未跑到同批次)。
同步订正断言:
- 「事项 ≤ 2 条」→「事项仅 1 条」+「事项 = 2 条」
- 「不硬塞层级」→「输出连贯段落」(仅 1 条事项 → 连贯段落,语义等价)
本地 cargo test --lib:306 passed / 0 failed。
重构 OAuth 登录为 GithubLoginModal 后,onLoginSuccess / MarketplaceSection
onSuccess 用裸 void updatePrefs(...) 写 marketplaceDevLogin,丢掉了重构前
try/catch 里的失败日志 —— prefs 写入失败会冒成未处理的 promise rejection。
补回 .catch + console.warn,与重构前行为一致。
上一轮加的回滚无条件把下拉退回 committed provider。但 provider 切换是多步非原子
操作:若 setActiveLlmProvider 已成功、后续 updatePrefs / setCredential 才失败,
后端 active 已是新 provider,回滚下拉到旧的反而让「下拉显示旧 / 后端用新」。
改为记 backendSwitched 标志:仅当后端切换本身没成时才回滚下拉框,让下拉始终与
后端 active 一致。ASR 同理。
LocalModelSection.performSwitch 是 async、try/finally 无 catch,而调用方
(Qwen3 / Foundry / sherpa Toggle、禁用按钮)都是 void performSwitch(...)
即发即忘。setActiveAsrProvider / updatePrefs 失败会冒成未处理的 promise
rejection。补 catch + console.error 吞掉。
合并 beta 的 Open-Less#504 引入了第三个本地 ASR 引擎 sherpa-onnx-local,但本分支的
ProvidersSection(早于 Open-Less#504 拆出)只认 local-qwen3 / foundry-local-whisper。
sherpa-onnx-local 激活时 knownAsr 查不到 → 主 Card 回落显示 volcengine、
凭据字段也错。补齐 5 处:ASR_PRESETS 条目、visibleAsrPresets 过滤、isLocked、
anomalousNameKey、本地引擎不渲染云端凭据字段的分支判断。
处理 PR-Agent 第 8 轮:
- ProvidersSection.onAsrProviderChange: asr.endpoint / asr.model 是所有 ASR 厂商
  共用的凭据槽,原「仅槽空时填」逻辑使跨厂商切换不生效(dropdown 切了、实际仍
  打旧厂商地址)。改为强制覆盖预设默认值,与 onLlmProviderChange 一致。
- net.rs send_with_retry: 重试范围从 is_connect() || is_request() 收窄到只剩
  is_connect()。is_request() 多为确定性失败(endpoint 配置错误等),重试 10 次
  只是徒增数秒延迟才暴露错误;连接层失败才是真正瞬时、值得重试的一类。
feat(settings): 设置界面重构 — 分节化 / 精简 / Beta 渠道 / 麦克风 / 市场登录
@github-actions
Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Cancel handling

The archive extraction step runs to completion even if cancel is set, because the spawn_blocking unpack/move work does not check the flag. If the user cancels after the release archive finishes downloading but before extraction ends, the model files can still be installed on disk while the UI reports the download as cancelled.

let extract_result = tauri::async_runtime::spawn_blocking(move || {
    extract_release_archive(
        &archive_path_for_extract,
        &dir_for_extract,
        archive,
        &model_alias_for_extract,
    )
})
.await
.map_err(|error| anyhow::anyhow!("extract join failed: {error:#}"))
.and_then(|result| result);
if let Err(error) = extract_result {
    emit_failed(app, model_alias, file_count, total_bytes, &error);
    return Err(error);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants