Commit Graph
384 Commits
Author SHA1 Message Date
TRIP 0ddd04fafb Merge pull request #248 from appergb/fix/overview-no-scroll-243
fix(ui): 概览页整屏不滚 + 其他页 scrollbar 变细 (#243)
2026-05-04 18:44:45 +08:00
baiqing fd0b2fdf02 fix(overview): Codex P1 + P2 — 保留 fallback scroll + 嵌套 scroller 同步细化
Codex P1:之前 displayTab==='overview' 时 wrapper 用 overflow:hidden,
窗口被压缩或文案变长(i18n / 字体放大)后底部 Recent Card 整片不可达,
没有 scroll 兜底路径。

修法:所有 tab 一律 overflow:auto。Overview.tsx 内部已经用 flex 把底部
行 grow 到撑满 → 正常尺寸下内容刚好占满,浏览器不显示 scrollbar;真挤
不下了 fallback 出细 scrollbar。"整屏不滚"的视觉效果保留,但有 scroll
保险。

Codex P2:::-webkit-scrollbar 不级联到子节点,所以 .ol-thinscroll 加
在 wrapper 上对 History / SettingsModal 等内层 overflow:auto 容器无效。
把 className 显式补到这些嵌套 scroller:
- History 左侧列表 + 右侧详情 Card(Card 组件加 className prop 透传)
- Settings.tsx 内嵌模式右栏
- SettingsModal personalize/about 块
QaPanel 是独立窗口,不在主壳 thinscroll 范围内,保留默认。
2026-05-04 18:26:34 +08:00
baiqing 8b435b4844 fix(overview): 底部行 flex:1 + 仅最近识别区域滚动
#243 第一版给外层 wrapper 加了 overflow:hidden 让概览不滚,但底部「近 7 天 +
最近识别」grid 仍按自然高度展开 → 内容超出 wrapper 时被硬裁,看不到底部
圆角;最近识别第 5 行只露半截。

修法(Overview.tsx 底部 grid):
- grid 自身 flex:1, minHeight:0,撑满父 flex:column 的剩余高度
- 两张 Card 都加 display:flex/column + minHeight:0;最近识别 Card 还加
  overflow:hidden,让内层行严格剪裁到 Card 的圆角
- 最近识别的 list <div> 加 .ol-thinscroll + flex:1 + overflow:auto,自己
  独立滚动;其他区域按需求保持不滚

视觉效果:底部圆角现在完整显示并与上方 metrics / providers 对齐;只有最
近识别区域出现细滚动条,整体仍是 dashboard「一眼看完」节奏。
2026-05-04 18:19:22 +08:00
baiqing b41c904104 fix(ui): 概览页整屏不滚 + 其他页 scrollbar 变细 (#243)
FloatingShell.tsx 的 page wrapper:
- displayTab === 'overview' 时 overflow:hidden,让 Overview 真"一眼看完"
- 其他 tab 维持 overflow:auto,加上 .ol-thinscroll 让 scrollbar 细而可见

tokens.css 新增 .ol-thinscroll —— 与既有 .ol-noscrollbar 同位置;区别是
"细而仍可见",保留可滚动的视觉 affordance(不像 noscrollbar 完全隐藏)。

Closes #243
2026-05-04 18:02:25 +08:00
Chris233 f87e598044 Merge pull request #240 from H-Chris233/main
fix(windows): make QA panel close button clickable
2026-05-04 17:12:15 +08:00
H-Chris233 337eaeb7ef Restore Windows QA no-activate contract without breaking close interaction
Issue #239 required the close button to be clickable, but a plain window.show() regression can steal focus and break selection capture assumptions in QA flow. Keep an explicit no-activate show on Windows while simplifying the native call path to only SW_SHOWNOACTIVATE.

Constraint: QA panel must not steal foreground focus when opening

Rejected: Keep plain window.show() | violates non-activation contract and risks wrong selection source

Confidence: medium

Scope-risk: narrow

Directive: If Windows QA show logic changes again, verify both close-button clickability and front-app selection capture

Tested: cargo check -q (openless-all/app/src-tauri)

Not-tested: Manual Windows interaction on physical device
2026-05-04 17:09:58 +08:00
Chris233 d81bbc4261 Merge pull request #233 from H-Chris233/main
feat(vocab): 增加词汇表场景预设
2026-05-04 16:45:34 +08:00
H-Chris233 647fc2ded0 Fix autostart runtime loading and preset apply disabled-term behavior
Address review feedback by removing fragile runtime import of the autostart
plugin package and invoking plugin commands via Tauri core bridge, so production
bundles no longer depend on unresolved bare imports.

Also update preset batch apply to re-enable existing disabled terms and continue
processing remaining terms/presets when one add operation fails.

Constraint: Minimal changes limited to existing Settings/Vocab flows
Rejected: New backend batch endpoint for preset apply | broader cross-layer change
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Preset apply should be idempotent and restore disabled matching terms
Tested: npm run build
Not-tested: Manual autostart toggle check on packaged desktop build
2026-05-04 16:33:50 +08:00
H-Chris233 47069cea4a Harden preset save/apply against partial failures
Preset edits were applied to local UI state before persistence finished, so
storage failures could show a misleading saved state and then lose changes on
reload. Also, batch apply aborted on first add_vocab error and skipped later
selected presets.

Make preset save await persistence before mutating UI/closing editor, and make
batch apply continue across per-term failures while reporting aggregated errors.

Constraint: Minimal behavior fix within existing Vocab page flow
Rejected: Add transactional backend endpoint for batch apply | larger cross-layer change
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep UI success states aligned with durable persistence completion
Tested: npm run build
Not-tested: Manual readonly-disk simulation for persist failure
2026-05-04 16:25:03 +08:00
H-Chris233 f2122dc4f9 Persist only user preset deltas to keep builtin updates receivable
Saving presets previously wrote the merged list (including built-ins) into user
storage, which froze old builtin copies and shadowed future app updates with the
same preset ids. Switch preset persistence to a delta store: custom presets,
overrides for edited built-ins, and disabled builtin ids.

Constraint: Keep current preset UI and command names unchanged
Rejected: Force builtin presets to always overwrite user file | would discard intentional user edits
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Never persist untouched builtin presets into user store
Tested: cargo test vocab_presets_roundtrip_json_file -q; npm run build
Not-tested: Manual end-to-end UX for builtin delete/restore (no delete UI yet)
2026-05-04 16:10:39 +08:00
H-Chris233 d1b4adbff8 Keep built-in vocab presets available after user saves custom presets
Loading presets from app-data JSON previously replaced bundled defaults entirely,
so adding any custom preset made shipped scenarios disappear on the next load.
Merge user presets onto bundled defaults by id so built-ins always remain
available while still allowing user overrides.

Constraint: Minimal change in preset loading path without altering storage schema
Rejected: Persist defaults into user file on first run | unnecessary write churn and migration complexity
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Preserve default+user merge behavior when adding future preset sources
Tested: npm run build
Not-tested: Manual Tauri UI check for merged list ordering
2026-05-04 16:09:45 +08:00
H-Chris233 91dd39932d Prevent unsaved preset drafts from polluting persisted storage
New preset previously persisted an empty entry immediately on click, so cancel
or navigation left permanent junk rows without any delete path. Keep new preset
as in-memory draft and persist only after explicit save.

Also add a regression test for vocab preset JSON persistence roundtrip to cover
the new preset storage workflow with automated verification.

Constraint: Minimal UI change without introducing preset delete UX in this patch
Rejected: Auto-delete blank presets on load | implicit cleanup can remove user-intended drafts
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep create flow non-persistent until user confirms save
Tested: cargo test vocab_presets_roundtrip_json_file -- --nocapture; npm run build
Not-tested: Manual UX walkthrough for preset draft cancel across app restart
2026-05-04 16:09:45 +08:00
H-Chris233 21da4f912d Unblock web build by lazy-loading autostart plugin in Settings
The frontend build failed because the autostart plugin import could not be
resolved in the browser-targeted Vite bundle, and strict TS also flagged
implicit any in the same flow. Switch the autostart integration to runtime
lazy-loading behind the Tauri guard and type the callback parameters explicitly.

Constraint: Keep autostart UX behavior unchanged on Tauri runtime
Rejected: Add Vite external alias for plugin package | hides integration mismatch in app code
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Tauri-only plugin modules should stay runtime-gated to keep web build healthy
Tested: npm run build (openless-all/app) passed
Not-tested: End-to-end autostart toggle interaction on all desktop platforms
2026-05-04 16:09:45 +08:00
H-Chris233 9f8e9650e0 Add vocabulary presets with JSON-based repo and user storage
Issue #224 requires scenario presets with multi-select apply and editable custom
presets, while preparing for import/export. This revision moves built-in presets
into a repository JSON file and stores user presets in the app data directory as
JSON via Tauri commands, so preset persistence uses one JSON shape both in repo
and user space.

Constraint: Keep vocabulary entry backend and UI interaction model unchanged
Rejected: Keep presets in localStorage/TS constants | does not satisfy unified JSON storage requirement
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Preserve vocab-presets JSON schema compatibility for future import/export
Tested: cargo check (src-tauri) passed
Not-tested: npm build currently fails on pre-existing Settings.tsx typing issues unrelated to this change
2026-05-04 16:09:09 +08:00
Chris233 4b53310f75 Merge pull request #210 from millionart/main
[codex] Add Windows TSF IME insertion backend
2026-05-04 13:37:00 +08:00
millionart ec16958d4d fix: restore IME before abort idle 2026-05-04 13:15:49 +08:00
millionart 9e2c79598a fix: classify Windows IME focus failures 2026-05-04 12:37:56 +08:00
millionart 1de10d32ae fix: skip stale Windows IME session restores 2026-05-04 11:58:18 +08:00
millionart 77eb569468 fix: restore IME profile after activation failure 2026-05-04 11:11:21 +08:00
millionart e040caebf9 fix: extend Windows IME submit timeout 2026-05-04 10:48:23 +08:00
millionart 104793cf18 merge upstream main into Windows IME PR 2026-05-04 10:23:42 +08:00
millionart 2554259d80 fix: harden Windows IME review edge cases 2026-05-04 10:17:56 +08:00
Chris233 1a8f4aac2c Merge pull request #220 from appergb/fix/preset-switch-race-219
fix(settings): 切换 LLM/ASR preset UI 不刷新 (#219)
2026-05-04 09:21:40 +08:00
baiqing 1eec2fa21c fix(settings): 拆 committed*Provider 让受控 <select> 立即响应 (#220 P2)
Codex P2: 上一版把 setLlmProvider/setAsrProvider 挪到所有 await 之后,
受控 <select> 的 value 现在依赖 IPC 完成顺序——用户连点两次时,先发的
请求晚到会用旧 id 覆盖最新的 setProvider,UI 卡在错误选项上。

修法(state 二分):
- *Provider:立即跟随用户输入,驱动 <select>
- committed*Provider:仅在所有 await 完成后才 commit,驱动 CredentialField
  的 key 与 placeholder/preset 的渲染
- *SwitchSeqRef:每次进入 handler 自增,每段 await 后比对,发现已有更新的
  switch 在飞就 abort 当前 commit,stale write 保护

效果:
- 用户切换 <select> 立刻看到新选项(受控反馈正确)
- CredentialField 等到后端 active 真切完才 remount 读 entry(issue #219 修复保留)
- 100ms 内连点两次:只有最后那次的 commit 落地,UI 不会被旧请求覆盖
2026-05-04 09:04:41 +08:00
baiqing 1accecbd57 fix(settings): 切换 LLM/ASR preset 顺序错导致 UI 显示旧 active 凭据
底层 providers HashMap 已是 per-provider,bug 完全在前端两个 onChange:

1) Race
setLlmProvider(id) / setAsrProvider(id) 是同步 React state 改动,
CredentialField 用 `key={`${provider}:api_key`}` 强制重挂载、读后端
ark.api_key —— 但此时 await setActive*Provider 还没跑,root.active.llm
还是旧值,lookup_account 落到旧 entry。把 await setActive 移到
setLlm/AsrProvider 之前修。

2) 覆盖
旧实现无条件 setCredential('ark.endpoint', preset.baseUrl),把用户在
该 provider 上之前自定义的 baseUrl 覆盖掉。改成「仅在 entry 该字段
为空」才填默认值,保留用户自定义。ASR 端的 endpoint + model 同款修。

不动 persistence schema、不动 IPC、不动 coordinator。

Closes #219
2026-05-04 08:44:37 +08:00
Chris233 bdd4cb1c7d Merge pull request #217 from appergb/feat/autostart-194
feat(autostart): macOS / Linux / Windows 三平台开机自启
2026-05-04 08:09:13 +08:00
TRIP e4f6f2eb43 Merge pull request #206 from appergb/fix/windows-qa-panel-205
fix(qa,windows): 划词追问浮窗读用户当前录音键 + Windows 加 toolbar 拖拽 (#205)
2026-05-04 07:33:28 +08:00
baiqing 07c083d9a1 fix(autostart): toggle 失败给用户看错误,不再吞到 console (#194)
原版 AutostartRow 的 onToggle catch 只 console.error + 回滚,
失败完全不在 UI 上反馈:Windows 写 HKCU\Run 被组策略拦、
macOS LaunchAgent plist 写入失败 这些真实场景下,用户只看到
toggle 弹回去,根本不知道为什么。

补一个 error state:
- onToggle 进入清 null,catch 里 setError(message)。
- SettingRow children 改成 flex column:toggle 上面、错误小字下面。
- 配色 var(--ol-err) 跟 about 卡片的 update error 同款。
- i18n 加 settings.recording.startupAtBootError,{{message}} 插
  入插件抛的具体错。

不动 isEnabled 失败路径(#194 验收没列);不动 prefs 持久化
策略(仍由 OS 持有真相)。
2026-05-04 07:33:00 +08:00
TRIP 98488cd136 Merge pull request #213 from appergb/feat/asr-providers-presets
feat(asr): 接入 Qwen3-ASR / SiliconFlow / GLM-ASR / Groq 作为可选服务商
2026-05-04 07:11:11 +08:00
baiqing e5608db21e feat(autostart): macOS / Linux / Windows 三平台开机自启
接入官方 tauri-plugin-autostart:
- macOS:~/Library/LaunchAgents/com.openless.app.plist (LaunchAgent)
- Linux:~/.config/autostart/openless.desktop (XDG)
- Windows:HKCU\Software\Microsoft\Windows\CurrentVersion\Run (per-user,
  不需要 admin)

设置页 → 录制 区追加「开机自启」Toggle;状态以 OS 为唯一真相,
直接调插件 isEnabled / enable / disable,不进 prefs,避免缓存
与系统设置不一致。

Closes #194
2026-05-04 07:07:55 +08:00
baiqing 17bb078f19 fix(qa): 录音键改了立刻刷新浮窗文案,不用等重开 (#205 review)
PR #206 review 反馈:QaPanel 的 recordHotkeyLabel 只在 mount / 语言切换时
重读 prefs;用户在主窗口改了录音键,浮窗如果还开着就一直停留在旧值
("按 右 Option 提问" 之类),误导用户按错键。

修法是补一条事件通路,不动现有的初始读取:
- commands.rs::set_settings 持久化后 `app.emit("prefs:changed", &prefs)`,
  广播给所有 webview。沿用 vocab:updated 同款跨窗口通知模式。
- QaPanel.tsx 在原有 qa:state / qa:dismiss / qa:level 订阅旁边加一条
  prefs:changed listener,收到后用 getHotkeyTriggerLabel 重算 label。
  cleanup 一并处理。

QaPanel 跑在独立 webview(label="qa"),没有 HotkeySettingsContext 注入,
所以必须走 IPC 事件而不是 React context;这也是为什么不能复用 Settings
页面的本地 state 更新。
2026-05-04 06:58:13 +08:00
baiqing d048107abb fix(asr): 把 Qwen3-ASR-Flash 从 V1 拿掉,需独立客户端留给 V2
reviewer 指出 DashScope 的 Qwen3-ASR-Flash 不走 OpenAI Whisper 的
multipart `/audio/transcriptions`,而是 MultiModalConversation 协议
(messages=[{content:[{audio:...}]}])。核实两个独立公开实现
(xinnan-tech/xiaozhi-esp32-server、jianchang512/pyvideotrans)确认
属实——把 qwen 强行塞进 WhisperBatchASR 必然 transcription 失败。

按 PR 描述里"待复核风险 → 不通则降级到 V2"的预案:
- 从 ASR_PRESETS 删除 qwen 项
- 从 is_whisper_compatible_provider 拿掉 "qwen"
- i18n 删掉 asrQwen 文案
- 注释里点名 Qwen 留给 V2 的原因

剩下 SiliconFlow / GLM-ASR / Groq / OpenAI Whisper 四家都有公开
OpenAI 兼容 /audio/transcriptions 端点,继续走原通道。
2026-05-04 06:53:40 +08:00
Chris233 a176f25529 Merge pull request #215 from H-Chris233/main
Add Intel macOS artifacts to Tauri release matrix
2026-05-04 06:44:45 +08:00
baiqing 9809b19eab revert(asr): 移除 endpoint/model 前置硬错校验
PR-Agent 在 commit 3416919 后改口反对前置校验("breaks silent-fallback
contract, removes the previous backend defaulting behavior")。维护者
@H-Chris233 同样要求处理。

回滚到 0a4d33c 状态:兼容分支只校验 api_key(与 main 上既有 whisper
分支一致),endpoint/model 缺失走 read_whisper_credentials 的既有
fallback(base_url 空字符串、model 兜底 "whisper-1"),让 runtime
失败信号在 coordinator 既有错误胶囊路径里出。

api_key 校验保留,因为这段不是本 PR 引入——main 上既有,超出 V1 范围。
2026-05-04 05:52:51 +08:00
H-Chris233 c8ccff0669 Avoid macOS updater asset collisions across architectures
Intel and Apple Silicon macOS jobs produced the same updater bundle filename,
which let one matrix job overwrite the other release asset and could point
both architecture manifests to a single binary. Rename macOS updater bundles
per architecture before release upload and prefer arch-specific artifact lookup
when generating updater manifests.

Constraint: Keep existing updater manifest format and release action usage
Rejected: Split macOS uploads into separate release jobs | larger workflow churn
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Any new macOS updater lane must keep unique asset names to preserve manifest correctness
Tested: release-tauri.yml YAML parse; diff audit for rename+manifest path alignment
Not-tested: End-to-end tagged GitHub Actions release run
2026-05-04 01:02:44 +08:00
H-Chris233 fbcddc40db Add Intel macOS artifacts to Tauri release matrix
The release workflow only produced Apple Silicon macOS packages, so Intel
users had no official GitHub Release artifact. Extend the matrix with an
x86_64 macOS lane and align artifact naming and updater-manifest paths
with per-arch outputs.

Constraint: Keep existing release pipeline shape and signing flow unchanged
Rejected: Split Intel build into separate workflow file | higher maintenance and duplicated logic
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep macOS conditions architecture-agnostic so new mac runners are not skipped accidentally
Tested: YAML syntax parse via python yaml.safe_load; workflow diff reviewed for mac gating/artifact paths
Not-tested: Full GitHub Actions matrix run on tag push
2026-05-04 00:27:02 +08:00
millionart 31045f7871 fix: preserve IME snapshot on activation failure 2026-05-04 00:18:26 +08:00
millionart f533f6ea05 fix: address Windows IME review cleanup 2026-05-04 00:14:56 +08:00
millionart 8cb289ea8c fix: move Word caret after IME commit 2026-05-03 23:53:29 +08:00
millionart 152e38c843 fix: support async Word IME commits 2026-05-03 23:38:35 +08:00
millionart cb10e0d39c fix: register 32-bit Windows IME 2026-05-03 22:59:38 +08:00
baiqing 3416919da6 fix(asr): OpenAI 兼容 preset 也前置校验 endpoint 与 model
PR-Agent #213 reviewer guide: 切到新 preset 后用户若手动清空
asr.endpoint,read_whisper_credentials 会返回空字符串,
WhisperBatchASR 拼出相对路径 `/audio/transcriptions`,要等用户录完
才以 reqwest 错误失败。model 同理(兜底成 "whisper-1" 对 SiliconFlow
等是无效模型名,runtime 才 400)。

在 ensure_asr_credentials 的兼容分支里加前置校验,把错误时机提前到
按下热键的瞬间,复用与 api_key 同款 hard-error 语义。
2026-05-03 22:18:45 +08:00
baiqing 0a4d33c755 fix(asr): QA 凭据校验改用专用 Volcengine 检查,避免被 active_asr 误导
Codex P1 (PR #213): 主听写路径分支化 `ensure_asr_credentials` 后,QA 路径
仍然复用同一函数,导致两类用户可见 bug:

1. 用户选了 qwen/siliconflow/zhipu/groq 但没填 `asr.api_key` → QA 报
   "请先填写 ASR 服务商 API Key",可火山凭据明明是齐的。
2. 反之 `asr.api_key` 已填、火山凭据为空 → QA 通过 ensure,进 open_session
   再以 Volcengine 凭据错误失败,更难诊断。

修法是给 QA 加专用 `ensure_qa_volcengine_credentials()`,只看 Volcengine 字段;
dictation 路径继续走 `ensure_asr_credentials` 不变。
2026-05-03 22:01:34 +08:00
baiqing 94d6a7199c feat(asr): 接入 Qwen3-ASR / SiliconFlow / GLM-ASR / Groq 作为可选服务商
复用现有 OpenAI 兼容 `/audio/transcriptions` 通道(WhisperBatchASR),无需
新增 Rust 客户端。把 `coordinator.rs` 中的 whisper 分支条件改为
`is_whisper_compatible_provider(id)`,新增厂商时一处即可扩展。

设置页 ASR 下拉新增 4 项预设,切换时自动预填 baseUrl 与 model,避免用户
忘填模型 ID 必然踩坑。

Closes #212
2026-05-03 21:54:34 +08:00
millionart ab7d1bc7b5 fix: restore IME profile after skipped insertion 2026-05-03 20:40:51 +08:00
millionart 4e4f3d12e8 merge upstream main before TSF PR 2026-05-03 20:02:28 +08:00
millionart f497cd4eb5 merge Windows TSF IME support 2026-05-03 19:24:21 +08:00
millionart 865e432fb7 fix: package and register Windows TSF IME 2026-05-03 19:03:43 +08:00
Chris233 6062516dba Merge pull request #209 from H-Chris233/main
docs(readme): add Chris233 to Developers section
2026-05-03 18:00:23 +08:00
Chris233 d08f649f15 docs(readme): add Chris233 to Developers section 2026-05-03 17:55:00 +08:00