baiqing
81fa80da69
fix(windows): NSIS x64 dll 用 Sysnative 绕过 WOW64 重定向
...
NSIS installer 是 32-bit 进程,进程内的 $SYSDIR / $WINDIR\System32 都因
WOW64 文件系统重定向变成 $WINDIR\SysWOW64,跑的是 32-bit regsvr32 → x64 dll
被注册到 HKLM\Software\Wow6432Node\Classes\CLSID(KEY_WOW64_32KEY 视图)。
但 windows_ime_profile.rs 用 KEY_WOW64_64KEY 校验时只看 HKLM\Software\Classes
\CLSID,永远查不到 → 仍判 RegistrationBroken("OpenLess COM registration is
missing")。
修复:x64 改用 $WINDIR\Sysnative\regsvr32.exe — 这是 32-bit 进程访问真
64-bit System32 的专用 alias,写入会落在 KEY_WOW64_64KEY 视图。x86 保持
SysWOW64 不变(确实需要 32-bit regsvr32 写 Wow6432Node)。
2026-05-06 10:52:12 +08:00
baiqing
c52658b08b
fix(windows): NSIS 也注册 32-bit TSF DLL — 修 P1 review
...
Codex review 发现:windows_ime_profile.rs::inspect_windows_ime_registration() 同时
用 KEY_WOW64_64KEY 和 KEY_WOW64_32KEY 两次检查 HKLM\Software\Classes\CLSID\{...}\
InprocServer32,少了任一边就返回 RegistrationBroken("OpenLess 32-bit COM
registration is missing")。MSI 流程通过 wxs 同时跑了 64-bit 和 SysWOW64\regsvr32
注册两份;之前的 NSIS hook 只注册了 x64,所以 NSIS / updater 用户依然在 Settings
页看到「不可用」。
修复:
- bundle.resources 拆出 x64 / x86 两份 dll target;x64 → tsf-ime\x64,x86 → tsf-ime\x86
- installer.nsh PostInstall/PreUninstall 增加 x86 分支,
x86 用 $WINDIR\SysWOW64\regsvr32.exe(写 KEY_WOW64_32KEY 必需)
- CI Build Windows IME native DLLs 步骤把复制 dll 移到循环里,x64 + x86 都覆盖
仓库占位
- 仓库新增 0 字节 x86 占位 dll,让本地 mac/linux 构建也能 resolve resources
2026-05-06 10:47:03 +08:00
baiqing
5aec74653b
fix(windows): NSIS 安装包注册 OpenLess TSF DLL — 修"输入法后端:不可用"
...
## 现象
1.2.15 起在 Settings 页"Windows 输入法后端"出现 Pill「不可用」。`get_windows_ime_status()`
查 HKLM 注册表四件套(COM CLSID + TSF LanguageProfile + 三个 Category),缺一即报 NotInstalled。
## 根因
- MSI 通过 wix/openless-ime.wxs 的 RegisterOpenLessIme* CustomAction 跑 regsvr32 → 注册齐全。
- NSIS 包既没把 OpenLessIme.dll 打进去(wxs.componentRefs 是 MSI-only),也没 hook 跑
regsvr32 → 用 setup.exe 安装的用户、走 updater 自动升级的存量用户全部命中"不可用"。
- 由于 updater latest-windows-x86_64.json 是 NSIS pass 写的,老 MSI 用户每次更新后也
会被替换为没 TSF 的 NSIS 版本。
## 修复
- 加 src-tauri/installer.nsh:NSIS_HOOK_POSTINSTALL/PREUNINSTALL 跑 regsvr32 注册/反注册。
- bundle.resources map 把 OpenLessIme.dll 拷贝到 $INSTDIR\tsf-ime\OpenLessIme.dll
(target 路径避开 wxs File 已声明的 windows-ime\x64\,避免 MSI component 路径冲突)。
- bundle.windows.nsis.installMode = "perMachine",让 NSIS 以管理员身份运行(写 HKLM 必需)。
- CI 在 build native dll 后把真 dll 复制到 src-tauri/openless-ime-payload/x64/OpenLessIme.dll;
仓库 commit 0 字节占位文件,让本地 mac 端 tauri build 也能 resolve resources 路径。
- build-mac.sh 与 Linux build 步骤加 --config '{"bundle":{"resources":{}}}' 跳过 Windows-only
的 dll 占位,避免污染 mac .app / Linux .deb/.rpm/.AppImage。
## Trade-off
- NSIS perMachine 升级需要 UAC,老 currentUser 用户首次升级时多一次 UAC 提示。
- MSI 包里 dll 会有两份(wxs File + bundle.resources),磁盘冗余 ~几百 KB,无功能影响。
2026-05-06 10:41:07 +08:00
baiqing
463a6d9716
fix(local-asr): 切走/删模型/手动释放时真正归还 RAM
...
三个问题合修:
1. 用户点"释放"按钮后活动监视器看 RSS 不下降。原因:encoder f32 weights
是 malloc 出来的几百 MB,free 后 macOS libmalloc 不会立即把页归还内核。
修:drop QwenAsrEngine 后调 malloc_zone_pressure_relief(NULL, 0),主动
归还。decoder bf16 走 mmap 不依赖这个。
2. 切回云端 ASR 后本地引擎仍驻留。set_active_asr_provider 切到非 local
时未释放,1.2GB+ RAM 一直留到进程退出。
3. 删除已下载的模型时未释放内存里加载的同 id 引擎,留下 mmap 指向已
unlink 文件 + RAM 不归还的双重问题。
Windows 端本期不上线(cache.rs macOS cfg 块包住改动)。
2026-05-05 20:20:46 +08:00
TRIP
c85b1bd4c6
Merge pull request #263 from appergb/fix/local-asr-pr-review-fixes
...
fix(local-asr): 修 PR #262 review 提的两个 bug
2026-05-05 13:36:55 +08:00
baiqing
cd00ebc584
fix(local-asr): 修 PR #262 review 提的两个 bug
...
(1) 小文件路径 try_download_range_append 的 retry 污染:
原实现用 append 模式打开 .partial。若上一次 attempt 已写了部分字节后失败,
retry 拿到的还是完整 chunk → append → 文件比应有大小多 N 字节,永久损坏。
改成 truncate(effective_start) + seek 写入,每次 attempt 从干净起点重写。
小文件(≤ 32MB)每个 chunk 是整个文件,重写无成本。
(2) 多文件并发一个失败不 abort 其它 worker:
原代码只 log "signaling others to stop",没真 set cancel flag。剩下的
workers 会继续吃带宽直到全部完成才把错误冒上来。
现在错误时主动 cancel.store(true),再用 self_aborted 标记区分这是"我们
因错误 abort"还是"用户主动 cancel"——前者 emit Failed,后者 emit Cancelled,
避免错误被误报成用户取消。
跟踪 PR: #262 review by github-actions PR Reviewer Guide
2026-05-05 12:59:01 +08:00
TRIP
438fce26ab
Merge pull request #262 from appergb/feat/local-asr-qwen3
...
feat(local-asr): 加本地 Qwen3-ASR 引擎(macOS 优先)
2026-05-05 12:53:35 +08:00
baiqing
8c3e4aca0d
Merge remote-tracking branch 'origin/main' into feat/local-asr-qwen3
...
# Conflicts:
# openless-all/app/src-tauri/src/coordinator.rs
2026-05-05 12:48:13 +08:00
Chris233
a0cc88d2ac
Merge pull request #260 from weikeyi/capsule-confirm-overflow
...
fix(capsule): keep confirm icon inside pill on done/error states
2026-05-05 12:46:39 +08:00
Chris233
f984dec84b
Merge pull request #261 from sora520/fix/windows-hotkey-trigger-leak
...
fix(windows): suppress consumed hotkey trigger events
2026-05-05 12:42:27 +08:00
Chris233
3e1ba69bfc
Merge pull request #252 from Cooper-X-Oak/fix/recorder-timeout-238
...
fix(recorder): 添加 liveness watchdog 和全局超时保护以修复 #238
2026-05-05 12:32:37 +08:00
kaku.ki
9c0ae1495a
fix(windows): suppress consumed hotkey trigger events
2026-05-05 13:17:50 +09:00
baiqing
520787b0f7
feat(local-asr): 引擎内存常驻 + 切到本地时预加载 + 释放时机可配
...
用户痛点:之前每次按 hotkey 都重加载 1.2GB 模型 → 首句词延迟 3-5s。
新流程:
- 新 LocalAsrCache:模型一次 load 后驻留内存,跨多次会话复用
- LocalQwenAsr::new 改成接受 Arc<QwenAsrEngine>(引擎所有权挪到 cache)
- build_local_qwen3 改成 async + spawn_blocking 走 cache.get_or_load()
- 切换 active model 时自动 drop 旧引擎再加载新的
- end_session 后调 cache.touch() + schedule_local_asr_release
- keep_loaded_secs == 0 → 立即释放
- keep_loaded_secs > 0 → spawn 一个 sleep+check 任务,到点查 last_used,
若中间又被使用过则跳过释放
预加载:
- commands::set_active_asr_provider("local-qwen3") 触发 preload_in_background
- 用户在「模型设置」页可手动「立即加载」/「立即释放」
- 实时显示「内存中的引擎: <model id>(约占 1.2-3.4 GB 内存)」
- 5 秒轮询刷新状态
新设置项:
- prefs.local_asr_keep_loaded_secs (u32,默认 300)
- UI 选项:说完话立即释放 / 1 min / 5 min(默认)/ 30 min / 始终保留
- 4 个新 IPC:local_asr_engine_status / release_engine / preload /
set_keep_loaded_secs
2026-05-05 12:09:55 +08:00
baiqing
8ed674ecaf
fix(local-asr): 多文件并发 + 8MB 小块 + aria2 UA — 对齐 hfd/hf_xet 实测
...
参考 hf-mirror 官方推荐工具 hfd(aria2 包装)+ hf_xet 默认 16 并发:
- PARALLEL_FILES = 3:原本顺序下文件,大 .safetensors 在跑时 6 个小文件
全在排队;改成最多 3 个文件并发,让小文件不阻塞、大文件 throttle
时剩余带宽喂别的文件
- PARALLEL chunks per file = 4 → 8:贴 hf_xet 默认 (16) 的折中
- CHUNK_SIZE = 32MB → 8MB:单连接寿命缩到 5-20s(CDN throttle 临界点之下),
失败重做成本降 4 倍
- User-Agent: openless/x → aria2/1.36.0:实测 aria2 UA 在 HF / hf-mirror
反滥用规则里走白名单;自定义 UA 在 sustained 传输后会被切流
(日志里大量 "end of file before message length reached" 就是这个)
进度计算改成多文件汇总:每个文件 in_flight bytes 用 AtomicU64,全模型
总进度 = sum(in_flight) + already_done。失败时 cancel 标志传播给其它
spawn task 早退。
2026-05-05 11:33:46 +08:00
weikeyi
dab04fc345
fix(capsule): keep confirm icon inside pill on done/error states
2026-05-05 11:17:49 +08:00
baiqing
209dc9fece
fix(local-asr): 4 并发分块下载 + 取消正确传播 + 残留进度可见可删
...
四个用户报的问题,逐个修:
(1) 慢——单连接顺序拉,HF CDN 单连接限速明显
→ 4 并发 chunk + sparse 文件 seek+write,每完成一块原子追加 .partial.idx;
与 huggingface_hub / aria2 / hf_transfer 同款思路;下次启动只下未完成块
→ 走严格 206 协议(并发 seek 模式不能容忍服务端忽略 Range 返 200,否则会
把整个文件写到 chunk 偏移导致灾难);非 206 直接 fail 让 retry 接手
(2) 取消按钮没反应
→ 原因:旧 download_one 的 chunk loop 在 chunk Err 后 "若有进度就 continue";
用户取消时也属于"有进度"路径 → cancel 标志被吞
→ 新版每次 spawn task 都拿 Arc<AtomicBool>,每个 chunk + 每个流块都查
cancel;run_download 主线在 download_one 返回后立刻再查 cancel emit
Cancelled 事件
→ DownloadManager::cancel 加日志方便诊断
(3) 继续下载丢进度条
→ showProgress 原来只在有 progress 事件时为 true → 重启 app 后看不到 partial
→ 加 hasPartial 判断:downloadedBytes>0 && !isDownloaded 也算 showProgress
→ 按钮文案对应改 "继续下载" / "Resume"
(4) 残留无法删
→ 原本只有 isDownloaded 状态才出 删除按钮
→ 加 hasPartial 状态显示 [继续下载] [删除] 两个按钮
2026-05-05 11:13:41 +08:00
Chris233
c5aa3fef4a
Merge pull request #259 from H-Chris233/main
...
feat(i18n): add full Traditional Chinese (zh-TW) UI support
2026-05-05 11:07:37 +08:00
Chris233
2a472edc59
Merge pull request #253 from sora520/fix/windows-capsule-visuals
...
fix(windows): stabilize capsule visuals and audio meter
2026-05-05 11:06:09 +08:00
kaku.ki
23d7f44a96
fix(windows): stabilize capsule visuals and audio meter
2026-05-05 11:51:57 +09:00
H-Chris233
e50bc17a15
Add complete Traditional Chinese UI locale support
...
Add zh-TW locale resources and wire it through language selection,
persistence, and system-locale detection. Also add static shape typing
for zh-TW to prevent future key drift from zh-CN.
Constraint: Keep changes minimal and localized to i18n + language pickers
Rejected: Partial zh-TW translation only for language section | fails full locale support goal
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep zh-TW key shape locked to zh-CN when adding new translation keys
Tested: npm run -s build (openless-all/app)
Not-tested: Manual runtime walkthrough on all platform shells
2026-05-05 10:51:46 +08:00
baiqing
4a3531083b
feat(local-asr): HTTP Range 分块下载 + 加载测试按钮
...
下载彻底重写 (huggingface_hub / aria2 同款思路):
- 之前是"整文件 GET,失败重试整文件"——HF CDN 对长连接不友好,到某个固定时间
点会强制断流,导致看到"卡 5% 就死"。用户对比别家工具发现这点,确实如此。
- 现在 download_one 内按 32MB chunk 跑 Range,每块 4 次指数退避 retry,每次都
从 .partial 真实长度续传;CDN 中途断流只丢一个 chunk
- 防御服务端忽略 Range 返回 200 + 全文件:检测到就 truncate .partial 重头来,
避免 append 污染
- client 加 User-Agent (HF 把 no-UA 流量算异常 → 限速)
- pool_idle_timeout 缩短,避免复用已被 CDN 关掉的连接
加载测试按钮(用户:「做好加载模型和测试按钮」):
- 内嵌 antirez 自带的 samples/test_speech.wav(120KB,"Hello. This is a test
of the Voxtrail speech-to-text system.")
- 严格按 RIFF chunk 链解析(fmt 后面带 LIST/INFO,不能 +44 硬偏移)
- 新 IPC local_asr_test_model:spawn_blocking 跑 qwen_load + transcribe_audio
分别计时;返回 backend / 原文 / 识别 / load_ms / transcribe_ms
- LocalAsr 页每个已下载模型行加「加载并测试」按钮 + 结果卡片
Backend 标识改为 "Apple Accelerate (AMX/NEON, CPU)"——antirez 引擎不走 Metal
GPU(作者明确选择跳过 MPS),Apple Silicon 上靠 AMX 矩阵协处理器 + NEON 加速。
不撒谎说支持 Metal。
2026-05-05 10:27:48 +08:00
baiqing
25d9e9f3da
fix(local-asr): 下载 retry 升级 4 次指数退避 + 已下载列表/删除/性能警告
...
下载失败修:
- HF 大文件被 CDN 中途断流(end of file before message length reached);
原 1 次 retry 不够 + 间隔太短两次都失败
- 升到 4 次:1s → 4s → 16s 指数退避;每次都从 .partial 当前长度断点续传
- reqwest client 加 connect_timeout(30s) + pool_idle_timeout(20s) 避免
连接被复用到已被 CDN 关掉的 socket
- 不设整体 timeout(1GB 文件没意义),只防卡死
UI 补「已下载管理 + 性能预期警告」(用户两条新需求):
- Settings 的 LocalAsrProviderHint 现在列出所有已下载模型 + 每行删除按钮
(原来只显示当前激活模型 ready/not 状态,没看到其它模型也没法删)
- Settings 与 LocalAsr 页顶部都加 ⚠️ 性能警告卡片:明确"比云端慢/中文准确率
通常不如火山+turbo/适用于离线/隐私场景",避免用户误判
- i18n 新增 zh+en:localAsrPerformanceWarning / localAsrDownloadedTitle /
localAsrDelete + LocalAsr.performanceWarning
2026-05-05 10:03:26 +08:00
baiqing
5a58f74c4a
fix(local-asr): HF 下载 TLS unexpected_eof + Settings 引导改下载入口
...
下载层修两件事:
1. 改用 native-tls (macOS = SecureTransport) 而非 rustls:
HF LFS CDN 经常不发 TLS close_notify 直接关 TCP,rustls 0.22+ 把这当
致命 unexpected_eof,实测多个 .safetensors 失败。SecureTransport 容错。
Volcengine WebSocket 不动,继续走 rustls。
2. 单文件失败自动 retry 1 次(带 1s 退避,且尊重 cancel)。
HF 大文件偶发瞬断很常见,不让用户手点重试。
Settings 引导(按用户反馈):
- ASR 选 'local-qwen3' 时**不**渲染 API key / Base URL / Model 三个填空
- 改为 LocalAsrProviderHint 卡片:
* 文案"本地 Qwen3-ASR 在本机运行,无需 API Key"
* 已下载/未下载 Pill 显示当前激活模型状态
* 一键按钮 → 派发 NAVIGATE_LOCAL_ASR_EVENT
- FloatingShell 监听同事件,关 Settings modal + 切到 'localAsr' tab
- i18n 同步 zh + en
2026-05-05 09:56:54 +08:00
baiqing
839ad76c5b
fix(local-asr): 用 tauri::async_runtime 取代 tokio::spawn — 修点击下载即崩
...
崩溃栈:local_asr_download_model → DownloadManager::start → tokio::spawn
→ panic("there is no reactor running")。
根因:Tauri 同步 command 在 main thread 上下文跑,没进 tokio runtime;
tokio::spawn 直接 panic。换 tauri::async_runtime::spawn —— 它走 Tauri
持有的 runtime handle,不依赖调用方上下文。
同步把 local_provider.rs 的 spawn_blocking 也换成 tauri::async_runtime
版本(虽然现在在 async 路径上调没事,保持一致防回归)。
附带把 qwen_ffi.rs 的 `unsafe extern "C"` block 改回经典 extern block,
匹配 CLAUDE.md 声明的 rust-version = "1.77"(前者要 1.82+)。
2026-05-05 09:49:33 +08:00
baiqing
dd43a7801d
feat(local-asr): 前端「模型设置」页 + Settings 预设 + 反硬编码重构 — P5
...
后端反硬编码(按用户反馈):
- models.rs 删 files()/approx_bytes(),改用哨兵文件 .openless-asr-ready
判 is_downloaded、walk_dir 求和算 downloaded_bytes
- download.rs 加 fetch_remote_info(repo, mirror):实时 GET HF
/api/models/<repo>/tree/main 拿真实文件清单 + 尺寸;过滤 .md/.png/.git*
等非权重文件(白名单:json/safetensors/txt/bin/model/tiktoken)
- 新 IPC: local_asr_fetch_remote_info(modelId, mirror)
→ RemoteInfo { files: [{path,size}], totalBytes }
前端:
- LocalAsr.tsx 新页:状态卡 / 镜像源切换 / 模型列表 (下载/取消/删除/设为默认)
+ 进度条订阅 local-asr-download-progress 事件实时刷新
+ 真实尺寸通过 fetchLocalAsrRemoteInfo 拉取,**不硬编码**
- localAsr.ts: 全套 IPC 包装 + dev mock 分支
- FloatingShell.tsx + useAppState.ts: 加 'localAsr' tab,icon=archive
- Settings.tsx ASR_PRESETS 加 { id: 'local-qwen3', nameKey: 'asrLocalQwen3' }
- i18n zh+en 同步:nav.localAsr / asrLocalQwen3 / 整块 localAsr.* 文案
- types.ts UserPreferences 加 localAsrActiveModel + localAsrMirror
2026-05-05 09:39:26 +08:00
baiqing
4656ecc7c7
feat(local-asr): coordinator 接 ActiveAsr::Local 第三分支 — P4
...
- local_provider.rs (LocalQwenAsr):实现 AudioConsumer 缓 i16 PCM →
stop 时转 f32 → 跑 qwen_transcribe_stream,token 经
`local-asr-token` 事件实时推到前端胶囊;spawn_blocking 防止占住 tokio runtime
- coordinator.rs:
* ActiveAsr::Local(Arc<LocalQwenAsr>) cfg(macos)
* start_dictation_for_session 优先走 local 分支再回落 whisper/volc
* end_session 加 Local arm,失败静默回退(CLAUDE.md 不变量)
* cancel_active_asr / ensure_asr_credentials 都补 Local 分支
* build_local_qwen3 helper:从 prefs 拿 model id → models::model_dir → 加载
* ensure_local_qwen3_model_ready:模型未下载时友好提示用户去模型设置页
- 非 macOS 选择 local-qwen3 时 ensure_asr_credentials 直接返回错误
2026-05-05 09:29:12 +08:00
baiqing
51b638a52e
feat(local-asr): IPC commands + 偏好持久化 — P3
...
- types.rs UserPreferences 加 local_asr_active_model + local_asr_mirror,
serde 默认值保证向后兼容(老 prefs.json 不需手工迁移)
- commands.rs 加 7 个 local_asr_* IPC:
get_settings / set_active_model / set_mirror /
list_models / download_model / cancel_download / delete_model
- lib.rs .manage(Arc<DownloadManager>) + invoke_handler 注册全部新命令
- 引擎可用性通过 cfg!(target_os = "macos") 暴露给前端,Win UI 据此灰按钮
2026-05-05 09:26:46 +08:00
baiqing
7b38e26473
feat(local-asr): 加模型注册表 + HF/HF-Mirror 下载管理 — P2
...
- models.rs: ModelId (0.6B / 1.7B) + 文件清单复刻 antirez download_model.sh
+ is_downloaded / downloaded_bytes / list_status / delete_model
- download.rs: DownloadManager (per-model AtomicBool 取消) + reqwest stream
写 .partial 然后原子 rename;支持 Range 续传;Tauri 事件
`local-asr-download-progress` 上报五种 phase
- Mirror enum:Huggingface(默认)/ HfMirror(hf-mirror.com 国内镜像)
- persistence.rs 加 pub fn local_models_root() —— 路径
~/Library/Application Support/OpenLess/models/qwen3-asr/<id>/
2026-05-05 09:24:27 +08:00
baiqing
bd3bac3ca6
feat(local-asr): 接入 antirez/qwen-asr 编译链路 — 阶段 1 脚手架
...
- vendor antirez/qwen-asr 作为 git submodule (commit b00b789)
- build.rs 用 cc 编 10 个 C 源 + 链 Accelerate (仅 macOS)
- src/asr/local/{mod,qwen_ffi,qwen_engine}.rs 包装最小 FFI 面:
load / transcribe_audio / transcribe_stream + token 回调蹦床
- libqwen_asr.a (~434KB) 已链通,nm 验证 qwen_* 符号齐全
- Windows 端不编入,路径见 issue #256
下一阶段:模型下载管理 + IPC commands + 新页 LocalAsr.tsx + coordinator 路由
2026-05-05 09:17:32 +08:00
baiqing
003b713d52
docs(agents): 写入 Windows CI 红线,避免下一个 agent 重复踩四颗雷
...
修复迭代里翻过四个不可合并的雷:
1. light.exe 调用要 -sice:ICE80(IME wxs 的 32-bit Component 落 64-bit Directory)
2. tauri build 必须拆 NSIS+MSI 两轮(Tauri 签名是 post-bundle 钩子)
3. Build (Windows) shell 必须 bash 不是 pwsh(pwsh 吃 JSON 引号)
4. Repair 假设 candle 已跑出 wixobj
把每条的 ✗ 反例写出来,附上 'CI 失败先看历史日志' 的固定动作和
'保持 bump+tag 流程' 的偏好声明,下一个 agent 就不需要从头复盘。
2026-05-05 07:25:03 +08:00
cooper and Claude Sonnet 4.6
27451298da
audit(system): 完成系统级多尺度审计 - 发现 3 大架构风险和 13 项技术债务
...
建立多尺度审计框架(4 个尺度):
- 尺度 1: 系统级(架构、安全、扩展性)
- 尺度 2: 模块级(设计、接口、依赖)
- 尺度 3: 功能级(实现、体验、边界)
- 尺度 4: 代码级(bug、风格、性能)
**系统级审计关键发现**:
架构风险(3 项):
- 🔴 Coordinator 过于庞大(3462 行)
- 🔴 缺少统一的 ASR Provider trait
- 🔴 测试基础设施缺失(覆盖率接近 0%)
技术债务(13 项):
- P0: 2 项(测试相关)
- P1: 5 项(架构 + 测试 + 代码)
- P2: 4 项(架构 + 文档 + 代码)
- P3: 2 项(文档)
- 预计偿还成本: 14 周(3.5 个月)
**关键决策**:
1. ✅ 需要架构重构
2. ⏸️ 暂停低尺度审计(先解决高尺度问题)
**下一步行动**:
1. 编写测试策略文档
2. 编写 Coordinator 拆分设计文档
3. 编写 ASR Provider trait 设计文档
**审计产出**:
- 多尺度审计框架文档
- 架构风险地图
- 技术债务矩阵
- 系统级审计总结
- 系统级审计脚本
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-04 23:16:12 +08:00
baiqing
149a6b8eca
chore(release): 1.2.19 — Windows updater 修 NSIS+MSI 拆两轮跑
2026-05-04 23:12:55 +08:00
baiqing
0bd338a94c
ci(release): split Windows tauri build into NSIS + MSI passes
...
Tauri 的签名 / updater artifact 是 post-bundle 钩子,单次 tauri build 内
任意 bundler 失败都会跳过 .sig 生成。MSI 必踩 ICE80,所以单 pass 永远
拿不到 NSIS 的 .exe.sig(v1.2.18 build 验证)。
拆两轮:
- Pass 1: --bundles nsis 单独跑,必须成功,产出 .exe + .exe.sig
- Pass 2: --bundles msi 单独跑,允许 ICE80 失败,Repair 用 light 重链兜底
不 bump 版本号——下一次 release 之前用 workflow_dispatch 验证 CI 全绿。
2026-05-04 23:11:41 +08:00
cooper and Claude Sonnet 4.6
7e7b200198
docs(epic): 建立 Cooper 贡献体系 - 两大 EPIC 母体与 Finding 流程
...
建立完整的贡献规划体系:
**两大 EPIC 母体**:
- EPIC-001: 测试基础设施建设 (41 tasks, 6 weeks)
- 目标:测试覆盖率 0% → 60%+
- Phase 1: 核心模块单元测试
- Phase 2: 集成测试
- Phase 3: CI 自动化
- EPIC-002: ASR 功能扩展与优化 (71 tasks, 6 weeks)
- Phase 1: 混淆词纠错层 (对应 #89 )
- Phase 2: 本地 ASR 支持 (对应 #211 )
- Phase 3: ASR 架构优化
**Finding 基础设施**:
- finding-helper.sh: 自动化分析脚本
- 生成 4 份 finding 报告:
- 测试覆盖率分析
- ASR 模块分析
- 依赖关系分析
- Finding 总结
**工作流程文档**:
- COOPER_README.md: 快速开始指南
- COOPER_WORKFLOW.md: 详细工作流程
- COOPER_CONTRIBUTION_STRATEGY.md: 贡献策略分析
**关键指标**:
- 包含测试的文件数: 15
- 测试函数数: 76
- ASR 模块代码量: 1164 行
下一步:开始实现混淆词纠错层(EPIC-002 Phase 1)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-04 23:00:25 +08:00
baiqing
429780b5e4
chore(release): 1.2.18 — Windows bundle 顺序锁 nsis,msi 让 updater 资产先落盘
...
历史链:
1.2.13 ✓ 无 IME wxs,MSI+NSIS 全过
1.2.15 ✗ 加 IME wxs;CI pwsh 把 JSON 引号吃掉,tauri 连 candle 都没跑
1.2.16 ✗ shell 切 bash 后到 light 阶段,但 ICE80 触发,Repair 没 -sice
1.2.17 ✗ Repair 加了 -sice:ICE80 修了 MSI;但 Tauri 字母序 msi→nsis 让
MSI 先挂掉,NSIS 永远没机会跑,updater .exe(.sig) 缺失
1.2.18 显式 --bundles nsis,msi:NSIS 先写盘产 updater 资产,MSI 再失败
由 Repair 兜底 light.exe 重链
唯一改动:Build (Windows) 步骤两个分支都加 --bundles nsis,msi。
预留:NSIS 不读 wix.fragmentPaths,所以 .exe 暂不带 IME DLL;MSI 仍带,
后续单独 issue 跟进 NSIS IME 集成,不挂当前发版。
2026-05-04 22:56:33 +08:00
cooper
84e1649681
docs: 添加 Watchdog 线程影响分析与风险评估
...
- 分析了 5 个潜在风险点
- 验证了 ASR 资源清理逻辑
- 结论:当前实现完全安全,可以合并
2026-05-04 22:31:08 +08:00
baiqing
a5f1a8f16d
chore(release): 1.2.17 — Windows MSI 修 light.exe ICE80 报错
...
x86/x64 IME DLL 都装进 INSTALLDIR\windows-ime\,32-bit 组件落在 64-bit
Directory 是 ICE80 的硬性报错。本场景路径绝对指向、不依赖 SysWOW64
重定向,按 Microsoft 文档是合法用法,给手动 light.exe 重链加 -sice:ICE80
即可放行。改动同步覆盖 CI workflow 和本地打包脚本。
2026-05-04 22:21:50 +08:00
cooper
d1c68f0f30
test: 添加实机测试报告(仅保留在 fork)
...
- BUILD_TEST_REPORT.md: 构建和启动测试
- P1_TEST_REPORT.md: 麦克风异常恢复测试
- TEST_VERIFICATION.md: 代码审查验证
这些文档仅用于 fork 仓库的测试记录,不提交到上游 PR
2026-05-04 22:21:14 +08:00
cooper
4e66c91e07
docs: 添加 Issue #238 修复的代码审查验证报告
2026-05-04 21:54:35 +08:00
baiqing
49210363d6
chore(release): 1.2.16 — Windows MSI 修 PowerShell 引号吞双引号 bug
...
1.2.15 第 4 轮 Windows job 在 wix 阶段之前就 exit 2,根因是上一版我把
Build (Windows) 整步切成 shell:pwsh 后,& npm run tauri --- build --config
'{"bundle":{"createUpdaterArtifacts":true}}' 这条命令 PowerShell 调外部
进程时把 JSON 内的双引号剥光,tauri 收到 {bundle:{createUpdaterArtifacts:true}}
直接拒绝。log 第 586 行能看到剥过引号的 commandline。
修法:
- Build (Windows) 切回 shell:bash(单引号能保留内部双引号)。set +e 抓
exit code 写到 GITHUB_ENV,让本步不直接失败,把判断权交给下一步。
- 新增独立 step "Repair Windows MSI if Tauri failed at WiX link"(pwsh),
仅在 tauri 非零退出且 MSI 不存在时手动从 appRoot 跑 light.exe 重链。
本地 windows-package-msvc.ps1::Repair-TauriMsiBundle 同款手术。
2026-05-04 21:53:23 +08:00
cooper
a8741dd568
fix(recorder): watchdog 从播放开始时计时,避免慢启动误报
...
- 移除 StreamState::stream_start_time 字段
- 在 watchdog 线程内部记录启动时间
- 确保首次回调截止时间从 stream.play() 成功后开始计时
- 修复慢速后端可能导致的过早超时问题
2026-05-04 21:46:07 +08:00
Chris233
88452cb2ca
Merge pull request #251 from H-Chris233/feat/asr-e2e-validation
...
feat(settings): add end-to-end ASR provider validation
2026-05-04 21:45:45 +08:00
cooper and Claude Sonnet 4.6
87838617f8
fix(recorder): 添加首次回调截止时间检测
...
根据 code review 反馈,修复 watchdog 的行为缺口:
## 问题
修复 Finding 3 后,虽然避免了误报慢启动设备,但也失去了对
"第一个回调永远不到达"这种失效模式的检测能力。
如果 stream.play() 成功但 CPAL 从未发送任何回调,watchdog
的 `if let Some(last_time)` 分支永远不会执行,session 仍然
可能无限期挂起。
## 修复方案
添加"首次回调截止时间"机制,watchdog 现在检查两种情况:
1. **首次回调未到达**(last_callback_time = None)
- 检查是否超过 FIRST_CALLBACK_DEADLINE_SECS (5秒)
- 如果超过,报错:"录音启动后 X 秒内未收到回调"
2. **回调中途停止**(last_callback_time = Some)
- 检查是否超过 CALLBACK_TIMEOUT_SECS (3秒)
- 如果超过,报错:"录音回调静默停止 X 秒"
## 技术细节
- 在 StreamState 中添加 stream_start_time 字段
- 在 watchdog 中使用 match 语句区分两种情况
- 5 秒首次回调截止时间足够慢启动设备,但能捕获永不回调的失败
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-04 21:39:52 +08:00
H-Chris233
cb2eb8e9ce
Preserve query parameters when building ASR transcription validation URL
...
ASR validation URL normalization now edits the parsed URL path instead of string-appending to the raw endpoint, so endpoints with query parameters (e.g. api-version) remain valid after adding /audio/transcriptions.
Constraint: Keep endpoint normalization minimal and avoid changing query/fragment semantics
Rejected: Drop query parameters during validation | would break Azure-style OpenAI-compatible deployments
Confidence: high
Scope-risk: narrow
Tested: cargo test -q
2026-05-04 21:35:14 +08:00
H-Chris233
df2d51e014
Normalize ASR transcription endpoint and enforce streaming response cap
...
Addresses review feedback: ASR validation now recognizes OpenAI-style /chat/completions endpoints when building the /audio/transcriptions URL, and response-size protection is enforced while streaming the body instead of after buffering it all.
Constraint: Keep ASR validation behavior provider-agnostic and minimal in scope
Rejected: Heuristic URL rewrites beyond known suffixes | risk of breaking custom reverse proxies
Confidence: high
Scope-risk: narrow
Directive: If changing reqwest features, keep Cargo.lock in sync and re-run tests
Tested: cargo test -q
2026-05-04 21:16:46 +08:00
H-Chris233
fd60f815c0
Accept /audio base URLs when validating ASR transcription endpoint
...
Some OpenAI-compatible deployments expose ASR under a base URL that already ends with /audio. ASR validation now treats that as a valid prefix and appends only /transcriptions to avoid generating /audio/audio/transcriptions.
Constraint: Keep ASR validation URL normalization conservative and backwards-compatible
Rejected: Full URL path rewrite heuristics | risk of breaking custom reverse-proxy layouts
Confidence: high
Scope-risk: narrow
Tested: cargo test -q
2026-05-04 20:51:40 +08:00
baiqing
dcfeb405bf
chore(release): 1.2.15 — Windows MSI 修复 IME bundle 集成
...
1.2.14 三轮 release pipeline Windows job 全挂在 WiX 集成上:
1. 没构建 IME DLL → light.exe 找不到文件
2. 加了 build 步骤后用相对路径 src-tauri\target\... → Tauri wix bundler
cwd 和本地脚本不同,相对路径 resolve 错位
3. 改 $(env.OPENLESS_IME_DLL_X64) 想用绝对路径 → candle 处理 env var
substitution 时 abort(具体原因被 Tauri 吞掉)
1.2.15 切换到本地 windows-package-msvc.ps1 已经验证可行的 Repair 思路:
- wxs 维持字面相对路径 src-tauri\target\... (让 candle 正常吃过)
- workflow 接住 tauri build 失败:从 appRoot (openless-all/app/) 手动跑
light.exe 重链 main.wixobj + openless-ime.wixobj。这是 light 唯一能
resolve 该相对路径的 cwd。
2026-05-04 20:39:22 +08:00
Chris233
9c3ab9b100
Merge pull request #250 from H-Chris233/chore/readme-update
...
docs: add final acknowledgements for sponsors, developers, and LinuxDo community
2026-05-04 20:28:10 +08:00
H-Chris233
73dbd4cef7
Harden ASR validation path against endpoint and response regressions
...
Follow-up fixes from dual review keep the new end-to-end ASR check while removing compatibility and robustness regressions: normalize transcription endpoint URL, enforce HTTPS except localhost, cap response size, and switch to stable backend error codes mapped in i18n.
Constraint: Preserve issue #242 full-chain validation behavior with minimal surface change
Rejected: Revert to model-list-only validation | no longer verifies real transcription route
Confidence: high
Scope-risk: narrow
Directive: Keep providerHttpStatus:* and stable error-code contract synchronized with Settings error mapping
Tested: npm run build; cargo check -q
Not-tested: Manual validation against all third-party ASR endpoints
2026-05-04 20:27:08 +08:00
H-Chris233
2ae3bdf68a
Use real transcription call for ASR connection validation
...
ASR validation now runs one end-to-end /audio/transcriptions request with the currently selected model and a tiny bundled silence WAV payload. This verifies endpoint, auth, model routing, and response schema in one pass instead of model-list reachability only.
Constraint: Keep UI/API contract unchanged and avoid touching recording pipeline
Rejected: Reuse live microphone capture in settings validation | invasive and non-deterministic for quick checks
Confidence: high
Scope-risk: narrow
Directive: Preserve providerHttpStatus:* error marker so frontend can keep status-specific guidance
Tested: npm run build; cargo check -q
Not-tested: Live validation against every third-party ASR provider implementation
2026-05-04 20:27:08 +08:00