架构设计
整体流水线
altgo 采用线性流水线架构,由键盘事件驱动:
按键监听 → 状态机 → 录音 → ASR 转写 → LLM 润色 → 剪贴板 + 悬浮窗 + 通知 + 本地转写历史(纯文本 JSON)
转写历史:仅保存文本(原始转写 rawText 与当前展示 text),不保存录音;数据文件为 ~/.config/altgo/history.json。转写成功后(以 raw_text 非空为准)写入一条记录并广播 history-updated 事件,供主窗口历史页刷新。
各模块之间通过 tokio::sync::mpsc 异步通道解耦,每个处理阶段作为独立的 tokio::spawn 任务运行。
模块结构
以下为 Tauri 核心目录 src-tauri/src/(节选):
src-tauri/src/
├── main.rs # 薄入口,调用 `lib::run()`
├── lib.rs # Tauri 构建入口;AppState(含 history_path)
├── cmd.rs # IPC:配置、管道、模型、转写历史等
├── config.rs # TOML 配置加载(serde)
├── history.rs # 转写历史 persistence(history.json)
├── state_machine.rs # 按键状态机
├── audio.rs # WAV 编解码,线程安全 Buffer
├── transcriber.rs # Whisper API + 本地 whisper.cpp
├── polisher.rs # LLM 文本润色
├── pipeline.rs # 音频处理核心(转写 + 润色)
├── key_listener/ # 按键监听
│ ├── mod.rs # 公共接口 + 去抖逻辑
│ └── linux.rs # xinput test-xi2
├── recorder/ # 音频录制
│ ├── mod.rs # 公共接口
│ └── linux.rs # parecord
└── output/ # 剪贴板 + 通知
├── mod.rs # 公共接口
└── linux.rs # xclip / xsel / wl-copy + notify-send
按键状态机
状态机管理 5 个状态之间的转换:
按下
Idle ──────→ PotentialPress
↑ │
│ 长按超时 双击超时
│ ↓ ↓
│ Recording WaitSecondClick
│ │ │
│ 松开 再次按下
│ ↓ ↓
└──────── ContinuousRecording ←─┘
- 长按(> 200ms)→ 进入
Recording,松开停止 - 双击(< 300ms 间隔)→ 进入
ContinuousRecording,单击停止 - 使用
tokio::select!同时等待按键事件和超时
平台策略
所有平台交互通过 子进程调用 CLI 工具(如 parecord、xclip、xinput),而非 FFI,简化了构建和依赖管理。
转写引擎
通过 Transcriber 枚举分派:
WhisperApi— HTTP multipart 上传到 OpenAI 兼容端点LocalWhisper— 子进程调用whisper-cli二进制
润色引擎
- 支持 4 个级别:
none/light/medium/heavy - 使用 OpenAI 兼容 chat API
- 指数退避重试(最多 3 次)
历史页可对单条记录基于 rawText 再次调用当前润色配置(polish_history_entry)。
前端路由(主窗口)
- React Router Hash 模式:
/首页、/history历史、/settings设置。
测试策略
config.rs/audio.rs/history.rs— 全面的单元测试transcriber.rs/polisher.rs— 使用mockito进行 HTTP 级别 mock- 平台模块 — 仅构造/冒烟测试
- CI 在 Linux 上运行:
fmt、clippy、build --release、test