出口成章 · 说话即成文的桌面语音输入工具
全局快捷键触发,边说话文字边实时上屏;说完一键复制到任意应用,或展开成主应用做润色、调整场景与语气。
当前状态:桌面端(Windows)主链路与主应用已可用,正朝公司内部 50+ 人试用推进。macOS 已能打包运行(托盘图标 / 不抢焦点 / 公司内网证书三个打包后才暴露的问题已修并复验);2026-09-15 在 Mac 真机上按
docs/macos-test-runbook.md跑过一轮(控制台启动,非 Finder 启动打包.app),除采纳写回的两个问题(已修,待复验)外其余用例通过。剩:焦点类用例按打包.app从 Finder 复跑、辅助功能授权复验、签名公证;内部试用基建仍在路上。 产品权威文档见docs/plans/2026-09-05-voicepilot-prd.md。
一个常驻托盘的桌面语音输入工具,有两个形态:
| 悬浮条(Mini) | 主应用(Studio) | |
|---|---|---|
| 触发 | 主快捷键(听写)/ 第二个快捷键(常用语) | 悬浮条点「打开应用」 |
| 位置 | 桌面右下角,半透明,置顶,聆听期不抢焦点。macOS 上空闲时窗口直接隐藏(只留托盘),Windows 上常驻可见但鼠标穿透 | 普通应用窗口 |
| 职责 | 实时听写 + 编辑 + 复制 / 采纳 + 条内润色 + 常用语选择器 | 润色、场景×语气、历史回看、设置、常用语管理 |
核心流程:快捷键 → 说话(灰字实时跟随,停顿定稿转白字)→ 停止 → 复制 / 润色 / 采纳。
常用语:第二个快捷键 → 搜索 / ↑ / ↓ / Enter 挑一条 → 落进编辑区 → 采纳(不用说话,走同一条写回路径)。
明确的边界:
- 不是输入法:不接管键盘、不替换系统输入法,不在光标处裸插入——写回走「剪贴板 + 模拟粘贴」,自动写回已落地(见下);但终端逐字注入、中文 IME 组字态、管理员窗口这三项加固仍未做。
- 不是会议转写工具:v1 只处理一个人的麦克风输入,会议记录是后续方向。
- 不是云服务:音频只在识别过程中上传,不留存;文本只存本地。
现有语音输入基本是「录音 → 转写 → 得到一段文字」,写作时真正想要的是说话的时候文字已经在长出来。VoicePilot 要做的是:
- 边说边出字,不是说完一段等结果。
- 自动收敛成文:正在说的是灰色草稿,停顿后定稿成白字——「出口成章」的核心机制。
- 说完成稿即用:结果进剪贴板,可直接粘贴,或按场景/语气润色后使用。
| 里程碑 | 状态 |
|---|---|
| M1 采集 spike(Windows) | ✅ 输出字节率合格、无时钟漂移 |
| M2 主链路(Windows):快捷键 → 采集 → ASR → 悬浮条 → 复制 | ✅ 完成,自测全绿 |
| M4 主应用:润色、场景×语气、自定义预设、本地历史 | ✅ 完成 |
| M3 macOS 适配 + 分发 | 🔄 打包版整条复验清单(阶段 0–6)已于 2026-09-16 从 Finder 启动全过(含焦点类用例、辅助功能授权路径、内网端点取 Key),dmg 已打出并分发;只剩签名公证(未签名 → 首次打开需「右键 → 打开」) |
| M5-A 试用就绪:Key 下发、设置(快捷键可配 + 开机启动)、诊断导出、F12 按打包 .app 复验 | 🔄 进行中:Key 下发(含真机验证)与 F12 按打包 .app 复验已完成(2026-09-16);剩开机启动、诊断导出(F13) |
| 试用反馈批次(2026-09-12 ~ 09-15):条内闭环(润色 / 采纳 / 存常用语 / 打开应用)、采纳写回、常用语 F16、悬浮条窗口行为 | ✅ 已实现并真机验收:Windows 侧门禁全绿;Mac 2026-09-15 首轮暴露的采纳写回两个问题修掉后,2026-09-16 打包版复验全过。Plan 2B 仅剩 Windows 管理员窗口那一格未验(属已接受的代价) |
| M5-B 规模化基建:遥测与错误标记、自动更新、配置下发其余 | ⏸ 未开始 |
| M6 内部试用运行期(50+ 人使用,收集反馈与错误样本) | ⏸ 未开始 |
延迟预算与实测数据、验收标准详见 PRD §6 / §7 / §8。
- 桌面壳:Electron 44 + React 19 + TypeScript + Vite(UI 与框架解耦,将来可迁移 Tauri)
- ASR:阿里云百炼
qwen-audio-3.0-asr-flash-streaming(实时 WebSocket,灰字→白字两态) - 润色 LLM:百炼
deepseek-v4-flash-0731(流式,与 ASR 共用一把 Key;2026-09-12 试用反馈「快捷三项」由deepseek-v4-pro-0813换成 flash,速度优先) - 本地存储:Node 内建
node:sqlite(SQLite,历史 / 预设 / 设置,零原生依赖)
cp .env.example .env在仓库根 .env 里填两个值(都在百炼控制台获取):
DASHSCOPE_API_KEY— API KeyDASHSCOPE_WORKSPACE_ID— 业务空间 ID(不是 API Key,两个都要)
Key 只存在主进程,渲染进程拿不到。开发期从
.env读取;打包版已改由公司内网端点运行时下发(见「Key 下发(内网端点)」),正常启动不会再弹 Key 输入窗——该弹窗已不在启动路径上。取回的 Key 经safeStorage(Windows DPAPI / macOS Keychain)加密存本机;托盘菜单里仍保留「设置 API Key」入口,仅供管理员排查。
cd app
npm install
npm start # vite build && electron .默认快捷键:主快捷键(听写)Windows Ctrl+Shift+Space / macOS ⌥Space;常用语快捷键 Windows Ctrl+Alt+Space / macOS Alt+Shift+Space(两个都能在 Studio 设置页改)。macOS 需在「系统设置 → 隐私与安全性 → 辅助功能」里给 VoicePilot 授权,否则全局快捷键不生效。在悬浮条上说话、停止后「复制 / 采纳 / 润色」;按常用语快捷键可不出声直接挑一条。
cd app
npx tsc --noEmit # 全量类型检查
npm run build # 渲染产物;下面凡带界面的自测都必须先跑这步
VP_SM_SELFTEST=1 npx electron . # 状态机与背压
VP_INJECT_SELFTEST=1 npx electron . # 采纳写回的编排(切前台 → 回读确认 → 才发键);不含真实置前/粘贴
VP_STORE_SELFTEST=1 npx electron . # 存储
VP_UI_SELFTEST=1 npx electron . # 界面自测(隐藏窗口 + 假 bridge)
VP_BAR_SELFTEST=1 npx electron . # 悬浮条几何(真窗口:贴边不漂移 / 每次打开选择器都长到合身高度;需要显示器)
⚠️ VP_UI_SELFTEST与VP_BAR_SELFTEST跑前必须先npm run build:这两条渲染真实界面,读的是dist/renderer。忘了 build 就会拿上一次的产物跑出一片绿,而结论与当前源码无关(已踩过:界面自测曾对着落后一天的包报「全绿」)。其余自测(
VP_POLISH_SELFTEST/VP_I18N_SELFTEST/VP_SHORTCUT_SELFTEST/VP_CONFIG_SELFTEST/VP_ASR_SELFTEST)见app/electron/main.js的分发链;VP_CONFIG_SELFTEST的用法另见下文「Key 下发」。
打包版不再由人工分发 DashScope Key,改为运行时从公司内网 HTTPS 端点取回。试用者装完即用,不需要填任何东西。
# 1. 起服务端(部署在内网机器上,细节见 server/config-endpoint/README.md)
cd <repo>
export VP_CONFIG_TOKEN='<发给客户端的 token>'
export VP_DASHSCOPE_API_KEY='sk-…'
export VP_DASHSCOPE_WORKSPACE_ID='<业务空间 ID>'
export VP_CONFIG_VERSION=1
export VP_TLS_CERT=/etc/ssl/voicepilot/fullchain.pem
export VP_TLS_KEY=/etc/ssl/voicepilot/privkey.pem
node server/config-endpoint/server.js
# 2. 打包前注入端点地址与 token(此文件 gitignore,绝不入库)
cp app/electron/endpoint.example.json app/electron/endpoint.built.json
# 填入真实 token 与**完整端点 URL**(endpoint 字段含 /config,如 https://host/config;
# 客户端原样请求、不会补路径,写成 https://host 会导致每台机器 404)
cd app && npm run dist:win:portable # prepack-check 会拦住缺失/占位/非 https/URL 形态不对的情况
# 3. 轮换 Key
# 改 VP_DASHSCOPE_API_KEY,并把 VP_CONFIG_VERSION 加一,重启服务端即可,不用重发包
# 4. 轮换 token
# 改 VP_CONFIG_TOKEN 之后**必须重新打包重发**(token 是打包时注入的)客户端行为:启动时先读本地缓存(有就立刻可用,并在后台刷新);没有任何可用凭据时才等一次端点(3 秒超时),失败则提示「未获取到授权,请联系管理员」+ 重试。托盘菜单有「重新获取授权」可手动重试,旁边还留着「设置 API Key」供管理员排查。
自测:
cd app
VP_CONFIG_SELFTEST=1 npx electron . # 本地起 mock 端点,离线可跑
node ../server/config-endpoint/test.mjscd app
npm run dist:win:portable # 只打便携单文件版(快,推荐发同事试)
npm run dist:win # 便携 + NSIS 安装包两个都打产物在 app/release/(已 gitignore):
| 文件 | 用途 |
|---|---|
VoicePilot 0.1.0.exe |
便携单文件版,双击即用 |
VoicePilot Setup 0.1.0.exe |
NSIS 安装包(开始菜单 / 桌面快捷方式 / 卸载) |
macOS:
npm run dist:mac # 打 dir + dmg(未签名)产物为 app/release/mac*/VoicePilot.app 与 app/release/VoicePilot-0.1.0.dmg。
macOS 上必须先打包、从
.app启动才能验证辅助功能授权:开发模式npm start跑的是node_modules里的Electron.app(bundle id 不同),系统设置里授权不到 VoicePilot。
发同事试用的流程:
- 把打了内网端点配置的安装包(
VoicePilot 0.1.0.exe)发给对方——不再单独发 API Key - 对方双击 exe 即可用:打包版启动时从内网端点自动取回 Key,正常不需要填任何东西,也不会出现首次启动的 Key 输入窗
- 若提示「未获取到授权,请联系管理员」,多为端点不可达或 token 不匹配,请联系管理员。托盘菜单里也留有「设置 API Key」入口,仅供管理员/开发排查,不是试用者的必经步骤
当前两个平台都未做代码签名。Windows 上 SmartScreen 会提示「未知发布者」,点「仍要运行」即可;macOS 未签名未公证,首次打开需「右键 → 打开」绕过 Gatekeeper。均为内部分发的预期情况(PRD §5.7)。
├── app/ 桌面端(Electron + React + TS)
│ ├── electron/ 主进程(纯 ESM .js):窗口/托盘/快捷键/状态机/ASR/润色/存储
│ ├── src/ 渲染进程(TSX):悬浮条、主应用(润色/历史)、引导、诊断
│ ├── build/ 图标等构建资源
│ └── dist/ 渲染产物(vite 输出,gitignore)
├── spike/ 测量与验证工具(延迟/准确率探针、并发压测、音频转码)
├── demo/ 早期浏览器原型(历史产物,已由桌面端取代)
└── docs/
├── plans/ PRD 与早期设计文档
├── superpowers/ specs 与实现计划
└── *-test-runbook.md 真机验证手册(macOS 总清单 / 采纳写回 / 常用语)
spike/ 是验证工具链,不是产品代码。它负责回答「延迟达不达标、准确率多少、并发上限多少」这类问题,支撑 PRD 里的数据。
- PRD(权威):
docs/plans/2026-09-05-voicepilot-prd.md - 真机验证手册(真机结论只能出自这里,自动化全绿 ≠ 可用):
docs/release-checklist.md— 发版清单:复验 → 部署端点 → 打包 → 分发,跨三台机器的执行顺序与突发处置docs/macos-test-runbook.md— macOS 总清单(阶段 0–6),改完 macOS 相关代码先看它docs/adopt-injection-test-runbook.md— 采纳写回(Plan 2B)docs/common-phrases-test-runbook.md— 常用语(F16)
- 主应用设计:
docs/superpowers/specs/2026-09-06-main-app-design.md - M4 剩余项设计:
docs/superpowers/specs/2026-09-06-m4-remaining-design.md - 采纳写回设计:
docs/superpowers/specs/2026-09-13-adopt-injection-design.md - 常用语设计:
docs/superpowers/specs/2026-09-13-common-phrases-design.md - ASR 实测结论与踩坑:
docs/plans/2026-08-31-engine-mvp-design.md
- macOS 未签名 / 未公证:已能打包运行(托盘图标、不抢焦点、公司内网证书三个打包后才暴露的问题均已修并复验),但未做 Developer ID 签名与公证,首次打开需「右键 → 打开」。辅助功能授权(F12 引导)与焦点类用例都待按打包后从 Finder 启动的
.app复验 —— 2026-09-15 那轮 Mac 真机是控制台启动的,按 runbook 的规矩它不能替代这一步。 - Key 已改为端点下发,但客户端仍持有明文:打包版启动时从公司内网 HTTPS 端点取回 Key(见「Key 下发(内网端点)」),正常不再需要人工分发。
⚠️ 端点下发不等于 Key 不落地——取回后 Key 仍在主进程持有明文,有本机权限的人仍可提取;真正让客户端不持有 Key 只有服务端代理,本期不做,这是已接受的代价。轮换:改服务端VP_DASHSCOPE_API_KEY(并把VP_CONFIG_VERSION加一)重启即可,无需重发包;换 token 需重新打包重发。边界见设计文档 §0。 - 首次引导已启用:职业维度已移除(2026-09-08),F8 改为欢迎页,首次启动弹一次;原
VP_ENABLE_ONBOARDING开关已删除。 - 采纳写回已实现(尽力而为):点「采纳」会把文本写回快捷键触发那一刻的前台窗口(剪贴板 + 模拟一次粘贴键,主进程经
koffi直调系统 API),失败时回退为「已复制,请手动粘贴」。天花板(已接受,不修):① 管理员权限窗口(Windows UIPI)可能收不到非提权进程的合成按键 → 可能静默失败(待验,见 runbook 用例 3);② 终端与部分特殊控件的粘贴行为不一致;③ 中文 IME 组字态可能吞掉 Ctrl+V;④ 剪贴板从不还原(反正文本就留在剪贴板里,失败时手动粘即可)。成功判据是「目标窗口确实到了前台」,不是「粘贴被消费了」——后者原理上不可检,所以 ① 这类漏报无法避免。真机状态(2026-09-15,Mac 控制台启动):首轮暴露两个问题、均已修 —— ① 回填不了(发键从「只给 V 贴 Command 标志再丢进 HID tap」改为整串[⌘↓ V↓ V↑ ⌘↑]并优先投到目标 pid);② 回填成功、条也关了,目标应用却拿不到焦点(改为「先关条 → 等编辑区拆完 → 再还键盘」,且 macOS 空闲态窗口直接隐藏)。⚠️ 修后的版本尚未复验;打包版dlopen的 Mac 侧、以及「管理员权限窗口静默失败」仍是未验项。验证清单见docs/adopt-injection-test-runbook.md。 - 常用语已实现(F16):悬浮条内可用第二个快捷键唤起选择器——搜索 /
↑/↓/Enter/Esc,挑一条落进编辑区再走既有「采纳」写回;条头书签图标可从听写结果一键存一条,Studio 新增「常用语」页可手写 / 改名 / 删除。常用语不与场景语气绑定、不落历史,管理页在 Studio。不含(设计已排除,不是缺陷):占位符 / 模板变量、按场景分组、重复去重、跨设备同步、从历史页提升为常用语、选择器失焦自动关闭。真机状态(2026-09-15,Mac 控制台启动):F16 自身全部通过 —— 选择器能拿到键盘(macOS 上reviewing可聚焦 panel 可正常接受输入,这一条原是最高风险项)、Esc与「再按一次快捷键」都能关闭并归还焦点、常用语不进历史。选中之后的写回与采纳共用同一条路径,那两个问题见上一条(已修、待复验)。验证清单见docs/common-phrases-test-runbook.md。 - 历史搜索未做:当前历史只支持浏览,全文搜索(FTS5)属下一批。
- 开机启动未做:设置界面已交付(语言、主/常用语两个快捷键的录制、权限状态与引导),仍缺「开机启动」(F7,归 M5-A)。「触发模式」已随 2026-09-11 的决定去掉——F1 只保留「按一下开始 / 再按一下停止」单模式;词表本期留空。
- 准确率无 ground truth:字准确率验收依赖内部试用期的错误标记数据(M6)。