diff --git a/CLAUDE.md b/CLAUDE.md index add8a32a..ccbbf0d7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -33,6 +33,19 @@ INSTALL=0 ./scripts/build-mac.sh # build only # Frontend-only TS check npm run build # = tsc && vite build + +# Rust type-check without full compile +cargo check --manifest-path src-tauri/Cargo.toml +``` + +### Windows (cross-check only — no macOS runner in CI) + +```powershell +# Preflight: verify toolchain +.\scripts\windows-preflight.ps1 + +# Build (requires Windows host or cross-compile target) +.\scripts\windows-build-gnu.ps1 ``` Generated artifacts: @@ -67,7 +80,7 @@ Swift (Sources/OpenLess*) Rust (openless -all/app/src-tauri/src) P OpenLessCore types.rs Pure value types: DictationSession, PolishMode, HotkeyBinding, errors OpenLessHotkey hotkey.rs Global hotkey monitor (modifier-key edges) OpenLessRecorder recorder.rs Mic → 16 kHz mono Int16 PCM, RMS callback -OpenLessASR asr/{mod,frame,volcengine}.rs Volcengine streaming ASR over WebSocket +OpenLessASR asr/{mod,frame,volcengine,whisper}.rs ASR providers: Volcengine streaming WebSocket + Whisper HTTP OpenLessPolish polish.rs OpenAI-compatible chat completions (Ark / DeepSeek / etc.) OpenLessInsertion insertion.rs AX focused-element write → clipboard + Cmd+V → copy-only fallback OpenLessPersistence persistence.rs History/preferences/vocab JSON + Keychain credentials @@ -75,6 +88,8 @@ OpenLessUI src/components/Capsule.tsx C OpenLessApp / DictationCoord. coordinator.rs + commands.rs + lib.rs State machine, IPC surface, tray icon, window plumbing permissions.rs TCC checks (Accessibility / Microphone) src/ (React) Main window UI: Overview / History / Vocab / Style / Settings + src/pages/_atoms.tsx Recoil atoms — global frontend state + src/state/HotkeySettingsContext.tsx HotkeySettings React context (capability + binding from backend) ``` ### Dictation pipeline diff --git a/README.md b/README.md index 12e7c889..39438392 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@
- Open-source macOS voice input for the AI era.
- Press a hotkey, speak, get a usable AI prompt at your cursor.
+ Open-source voice input for macOS & Windows.
+ Press a hotkey, speak, get AI-polished text at your cursor.
@@ -16,14 +16,20 @@
++ Join our QQ Group: 1078960553 +
+ --- -OpenLess is a native macOS voice-input app — a **fully open-source** alternative to commercial tools like [Typeless](https://www.typeless.com/), [Wispr Flow](https://wisprflow.ai), [Lazy](https://heylazy.com), and Superwhisper. +OpenLess is a cross-platform (macOS & Windows) voice-input app — a **fully open-source** alternative to commercial tools like [Typeless](https://www.typeless.com/), [Wispr Flow](https://wisprflow.ai), [Lazy](https://heylazy.com), and Superwhisper. Put your cursor in any text field — ChatGPT, Claude, Cursor, Notion, an email draft, a chat box — press one global hotkey and talk. OpenLess records, transcribes, polishes the text in the mode you picked, and inserts the result at the cursor. If insertion is blocked it copies to the clipboard, so the words you spoke don't get lost. @@ -84,60 +90,68 @@ OpenLess does one thing: **turn speech into usable written text (especially AI p | [Lazy](https://heylazy.com) | Closed-source notes / capture tool | Not a notes container — inserts straight into any input field | | [Superwhisper](https://superwhisper.com) | Closed-source macOS, subscription | Open source; cloud ASR today, local ASR on the roadmap | -## Status (v1.0) +## Status (v1.1) -- Native Swift / SwiftUI / AppKit, SwiftPM project; macOS 15+. -- macOS 26+ uses Liquid Glass; older systems fall back to system materials. +- Tauri 2 + Rust backend + React/TS frontend. macOS 12+, Windows 10+. - Toggle-style recording: press to start, press again to stop. `Esc` cancels. - Volcengine streaming ASR + Ark / DeepSeek-compatible chat-completions for polish. - 4 output modes: raw, light polish, structured (**AI prompt mode**), formal. -- Main window: Home / History / Dictionary / Settings. Persistent menu bar. Mini status capsule at the bottom of the screen. -- Dictionary entries are injected as Volcengine ASR `context.hotwords` and as semantic hints during polish. +- Main window: Overview / History / Vocab / Style / Settings. Persistent tray icon. Mini status capsule floating on screen. +- Dictionary entries injected as Volcengine ASR `context.hotwords` and as semantic hints during polish. +- Platform-native global hotkey: CGEventTap on macOS, low-level keyboard hook (`WH_KEYBOARD_LL`) on Windows. ## Download & install (end users) -Grab `OpenLess-1.0.0.zip` from [Releases](../../releases), unzip to get `OpenLess.app`, drag to `/Applications`. +Go to [Releases](../../releases) and download: +- **macOS**: `OpenLess_
- 面向 AI 时代的开源 macOS 语音输入。
- 按一次快捷键说话,自动整理成可直接用的 AI prompt,落到当前光标。
+ 开源语音输入,支持 macOS 和 Windows。
+ 按一次快捷键说话,AI 润色后的文字直接落到当前光标。
@@ -16,14 +16,20 @@
++ 加入 QQ 群:1078960553 +
+ --- -OpenLess 是一个原生 macOS 语音输入应用,对标 [Typeless](https://www.typeless.com/)、[Wispr Flow](https://wisprflow.ai)、[Lazy](https://heylazy.com)、Superwhisper 等商业语音输入工具的 **完全开源** 替代品。 +OpenLess 是一个跨平台(macOS & Windows)语音输入应用,对标 [Typeless](https://www.typeless.com/)、[Wispr Flow](https://wisprflow.ai)、[Lazy](https://heylazy.com)、Superwhisper 等商业语音输入工具的 **完全开源** 替代品。 把光标放在 ChatGPT、Claude、Cursor、Notion、邮件、聊天框任意输入框里,按一次全局快捷键说话——OpenLess 会录音、转写、按你选的模式润色,把结果直接插入光标位置。插入失败时会自动复制到剪贴板,尽量保证「你说过的话不丢」。 @@ -84,60 +90,68 @@ OpenLess 只做一件事:**把语音变成可用的书面文字(尤其是 AI | [Lazy](https://heylazy.com) | 闭源笔记/捕获工具 | 不做笔记容器,专做「插入到任意输入框」 | | [Superwhisper](https://superwhisper.com) | 闭源 macOS,订阅制 | 开源;目前云端 ASR 优先,本地 ASR 在 roadmap | -## 当前状态(v1.0) +## 当前状态(v1.1) -- 原生 Swift / SwiftUI / AppKit,SwiftPM 项目;macOS 15+。 -- macOS 26+ 使用 Liquid Glass 效果,旧系统回退到系统 material。 -- 默认是切换式录音:按一次开始,再按一次结束;录音中按 `Esc` 取消。 +- Tauri 2 + Rust 后端 + React/TS 前端;macOS 12+,Windows 10+。 +- 切换式录音:按一次开始,再按一次结束;录音中按 `Esc` 取消。 - 接入火山引擎流式 ASR 和 Ark / DeepSeek 兼容 Chat Completions 进行润色。 - 4 种输出模式:原文、轻度润色、清晰结构(**AI prompt 模式**)、正式表达。 -- 主窗口按「首页 / 历史记录 / 词典 / 设置」组织;菜单栏常驻;底部有微型状态胶囊。 -- 词典支持作为 ASR 热词注入和润色阶段的语义判断。 +- 主窗口按「概览 / 历史 / 词典 / 风格 / 设置」组织;托盘图标常驻;浮动状态胶囊。 +- 词典条目注入 ASR 热词和润色语义提示。 +- 平台原生全局快捷键:macOS 使用 CGEventTap,Windows 使用低层键盘钩子(`WH_KEYBOARD_LL`)。 ## 下载与安装(普通用户) -到 [Releases](../../releases) 下载 `OpenLess-1.0.0.zip`,解压得到 `OpenLess.app`,拖到 `应用程序`。 +到 [Releases](../../releases) 下载对应平台的安装包: +- **macOS**:`OpenLess_<版本>_aarch64.dmg` — 打开后拖入「应用程序」 +- **Windows**:`OpenLess_<版本>_x64-setup.exe` — 运行安装程序 -**重要:** 1.0 是开发期 ad-hoc 签名构建(未做 Apple Developer ID 签名和 notarization)。直接打开会被 Gatekeeper 拦下提示“无法验证开发者”。需要在终端中移除隔离属性: +首次启动需要授予权限: -```bash -xattr -dr com.apple.quarantine /Applications/OpenLess.app -``` +**macOS:** +1. 授予麦克风权限。 +2. 授予辅助功能权限。 +3. **退出 OpenLess 并重新打开**(辅助功能授权需要重启才对全局快捷键生效)。 +4. 打开「设置」,填入火山引擎 ASR 和 Ark 凭据。 -之后就可以双击启动。首次启动需要在 `系统设置 → 隐私与安全`: +**Windows:** +1. 按提示授予麦克风权限。 +2. 打开「设置 → 权限」确认全局快捷键监听器已启动。 +3. 在「设置」中填入火山引擎 ASR 和 Ark 凭据。 -1. 授予 OpenLess 麦克风权限。 -2. 授予 OpenLess 辅助功能权限。 -3. **退出 OpenLess 并重新打开**(辅助功能授权对全局快捷键生效需要重启进程)。 -4. 从 Dock 打开 OpenLess 首页 → 「设置」 → 填入火山引擎 ASR 和 Ark 凭据。 - -完整的端用户使用步骤见 [USAGE.md](USAGE.md)。 +完整使用步骤见 [USAGE.md](USAGE.md)。 ## 从源码构建(开发者) +当前活跃代码库在 `openless -all/app/`(Tauri 2 + Rust + React/TS)。 + ```bash -# 库 / 测试构建 -swift build -swift test +cd "openless -all/app" +npm ci -# 完整 .app 构建(release,ad-hoc 签名,默认重置 TCC) -./scripts/build-app.sh +# 开发模式:Vite at :1420 + Tauri shell +npm run tauri dev -# 保留已授予的 TCC 权限 -RESET_TCC=0 ./scripts/build-app.sh +# macOS release 构建(签名、安装、重置 TCC) +./scripts/build-mac.sh +INSTALL=0 ./scripts/build-mac.sh # 只构建,不安装 -# 启动 -open build/OpenLess.app +# Rust 类型检查(不做完整编译) +cargo check --manifest-path src-tauri/Cargo.toml -# 实时日志 -tail -f ~/Library/Logs/OpenLess/OpenLess.log +# 前端 TS 检查 +npm run build ``` -启动参数(在 `AppDelegate.runLaunchActions` 处理): +日志路径:`~/Library/Logs/OpenLess/openless.log`(macOS)/ `%LOCALAPPDATA%\OpenLess\Logs\openless.log`(Windows)。 + +**Windows 构建** — MSVC 和 GNU/MinGW 两种路线详见 [`openless -all/README.md`](openless%20-all/README.md)。 + +**Swift(仅用于 Sparkle 遗留版本发布):** ```bash -open build/OpenLess.app --args --open-settings -open build/OpenLess.app --args --start-recording +swift build && swift test +./scripts/build-app.sh ``` ## 凭据 @@ -187,43 +201,46 @@ OpenLess 的润色模型只做文本整理,不做问答、不做任务执行 ## 架构概览 -SwiftPM 工作区,1 个可执行 + 8 个库。库与库之间无相互依赖,全部只依赖 `OpenLessCore`,由 `OpenLessApp` 统一在 `DictationCoordinator` 里编排。 +当前活跃实现是 Tauri 2(`openless -all/app/`)。`Sources/` 下的 Swift/SwiftPM 代码是遗留版本,仍为老用户提供 Sparkle 自动更新。 + +**Tauri 后端(Rust)** — 各模块只依赖 `types.rs`: ``` -OpenLessCore // Pure value types: DictationSession, PolishMode, HotkeyBinding, - // AudioConsumer protocol, RawTranscript/FinalText, errors. -OpenLessHotkey // CGEventTap-based modifier-key monitor. Requires Accessibility. -OpenLessRecorder // AVAudioEngine → 16 kHz mono Int16 PCM, 推送到 AudioConsumer. -OpenLessASR // 火山引擎 streaming ASR over WebSocket. -OpenLessPolish // Ark / Doubao chat-completions 客户端 + 模式驱动 prompts。 -OpenLessInsertion // AX focused-element 优先;剪贴板 + Cmd+V 兜底;最后 copy-only。 -OpenLessPersistence // CredentialsVault (Keychain), HistoryStore, DictionaryStore, - // UserPreferences。 -OpenLessUI // SwiftUI 胶囊视图 + 状态枚举(不接窗口)。 -OpenLessApp // AppDelegate, 菜单栏, 设置窗口, 胶囊窗口, DictationCoordinator。 +types.rs 纯值类型:DictationSession, PolishMode, HotkeyBinding, 错误类型 +hotkey.rs 全局快捷键(macOS: CGEventTap,Windows: WH_KEYBOARD_LL,Linux: rdev) +recorder.rs 麦克风 → 16 kHz 单声道 Int16 PCM,RMS 回调 +asr/ 火山引擎流式 ASR(WebSocket)+ Whisper HTTP +polish.rs OpenAI 兼容 chat-completions(Ark / DeepSeek 等) +insertion.rs AX focused-element → 剪贴板 + Cmd+V → 仅复制兜底 +persistence.rs 历史记录 / 偏好设置 / 词典 JSON + Keychain 凭据 +permissions.rs TCC 权限检查(辅助功能 / 麦克风) +coordinator.rs 状态机:Idle → Starting → Listening → Processing +commands.rs Tauri IPC 接口 ``` -录音 → 转写 → 润色 → 插入的状态机由 `Sources/OpenLessApp/DictationCoordinator.swift` 单一拥有,详见 [CLAUDE.md](CLAUDE.md)。 +**React 前端(`src/`)** — 状态通过 Recoil atoms(`pages/_atoms.tsx`)管理;快捷键能力和绑定通过 `HotkeySettingsContext` 获取;所有后端调用走 `lib/ipc.ts`。 -## 1.0 之后的规划 +录音 → 转写 → 润色 → 插入流水线:`快捷键触发 → Recorder.start + ASR.openSession → [音频帧] → 再次触发 → Recorder.stop + ASR.sendLastFrame → Polish → Insert → History.save`。 -下面这些功能在需求文档里有规划,但 1.0 没有发布: +详细的不变量和模块接线规则见 [CLAUDE.md](CLAUDE.md)。 -- 本地 ASR:当前仅接入火山引擎云端 ASR。 +## 规划中 + +尚未发布的功能: + +- 本地 ASR(Whisper 接入进行中;当前仅支持火山引擎云端)。 - 常用片段 Snippets:尚无 UI 和触发逻辑。 - 历史增强:复制按钮、搜索、重新润色、重新插入。 -- 粘贴上一条快捷键。 -- 多屏定位:胶囊按当前焦点所在屏幕显示。 -- Developer ID 签名 + Notarization + Sparkle 自动更新。 +- 粘贴上一条结果快捷键。 +- 多屏定位:胶囊跟随焦点所在屏幕显示。 -## 维护者:发布前检查 +## 维护者:发布检查 -- 确认没有提交 `.build/`、`build/`、`.DS_Store`、`~/.openless/credentials.json` 或临时截图。 -- 保留 `Resources/Brand/openless-app-icon-source.jpg`、`Resources/AppIcon.png`、`Resources/AppIcon.icns`。 -- 运行 `./scripts/build-app.sh`,确认 `build/OpenLess.app` 可启动。 -- 在一台干净 macOS 机器上验证权限引导、快捷键、录音、ASR、润色、插入和剪贴板兜底。 -- 用 `ditto -c -k --keepParent build/OpenLess.app build/OpenLess-