SayIt
一款原生 macOS 菜单栏语音转文字工具。按下全局快捷键就能说话转文字,支持本地 Whisper 转录,整个过程不需要离开当前窗口。
产品机会
SayIt 的起点是一个简单的效率缺口。系统自带的听写功能会弹出一个打断写作流的模态窗口。云端转录工具虽然能用,但每个词都要经过别人的服务器往返一次,网络一断就失效。
我想做的是一个更接近系统快捷键的工具:从任意位置触发,本地转录,粘贴结果,然后继续在原来的窗口里写。
为什么做成菜单栏工具
做成全窗口应用会直接削弱产品的核心价值。语音转文字只有在使用间隙中消失,才更像一个效率原语:需要时可见,不需要时安静。菜单栏给了应用一个常驻位置,但不占据工作空间。
选择用原生 macOS 应用(而非 Electron 套壳)是一个刻意的决定。这个产品是被拿来和系统工具比较的,不是和其他应用比较;它必须像 Spotlight 一样轻,而不是像一个浏览器标签页。
从想法到 v1.0.5
SayIt 由我独立设计、开发、签名、公证,并通过 GitHub Releases 公开发布。下面记录的是它从 SwiftUI 草图到公开 macOS 二进制文件的路径。
- 01
产品概念
将产品定义为一个菜单栏语音转文字工具:全局快捷键、单一主操作、无全窗口 UI,并默认端侧处理。
- 02
SwiftUI 原型
搭建了 popover 表面、麦克风选择器与引擎设置,验证整个交互能否容纳在一个小型悬浮面板中。
- 03
whisper.cpp 集成
接入端侧 Whisper 实现完全本地转录,包括模型选择以及模型缺失或下载中时的降级行为。
- 04
快捷键与权限
实现了全局快捷键捕获、麦克风访问提示以及辅助功能权限流程,使应用可以从任意活跃窗口触发。
- 05
公证与分发
搭建了签名、公证和 GitHub Releases 分发管线,使应用在 macOS 上干净安装,不会触发 Gatekeeper 警告。
- 06
公开发布 (v1.0.5)
经历了五个公开版本迭代,基于我日常使用中的体验,持续优化麦克风的稳定性、HUD 反馈和首次引导流程。
产品界面与核心控制
产品以紧凑的 popover 为中心:一个主操作按钮、一个麦克风选择器、一个转录引擎选项,以及轻量级状态消息。界面在不被需要时保持安静,这更符合「工具」而不是「传统全窗口应用」的预期。
这个界面的设计决策是抵抗功能膨胀。每增加一个控件,都会让应用离「按快捷键、说话、粘贴」的核心体验更远一步。
一键式录音流程
交互被压缩成一个可靠的切换操作:开始录音,停止并转录,然后自动复制结果。录音时长、实时音量、慢速转录提示和菜单栏 HUD 反馈让应用保持可理解,但不过度占用视觉注意力。
HUD 承担了大部分工作。一旦快捷键形成肌肉记忆,用户根本不需要看 popover;菜单栏图标和一个短暂的浮层就足以确认系统正在正确运行。
始终端侧
选择 whisper.cpp 而非云端 API,首先是产品决策,其次才是技术决策。本地转录意味着应用离线也能工作,没有按请求计费,也给用户一个容易理解的隐私保证:语音数据留在本机。
代价是模型体积与冷启动成本。应用暴露了引擎和模型选择功能,让轻量机型的用户可以选更小的模型,而更关注准确率的用户可以选更大的模型。
权限与快捷键的门槛
发布一个 macOS 工具最难的部分不是功能本身,而是操作系统要求的信任梯度。SayIt 需要麦克风权限来捕获音频,需要辅助功能权限来向其他应用粘贴文本。每一次权限弹窗都是用户可能流失的节点,而且弹窗由 macOS 渲染,不受应用控制。
解决方案是把首次引导设计成围绕这些弹窗展开,而非围绕应用自己的 UI:在 macOS 弹出请求之前先解释为什么需要该权限,并在用户拒绝后提供一条可恢复的路径回到系统设置。快捷键本身使用标准的全局快捷键 API,配置面板允许用户在不重启应用的情况下重新绑定按键。
设备韧性与生态适配
麦克风的可靠性最终成为产品中最脆弱的部分。蓝牙耳机、外置声卡、连续互通麦克风、合盖状态都会让输入设备出现或消失。一个在句中丢失输入信号的转录工具,比一个从未启动的工具更糟糕。
应用显式处理设备变更:它监控输入路由的变化,当所选麦克风消失时自动回退到一个合理默认值,并支持连续互通麦克风切换。这样在合盖和外接显示器环境下,iPhone 作为麦克风可以即插即用。
发布一个经过公证的 macOS 应用
要让除了我自己以外的人也能安装,代码库必须通过三道关卡:使用有效 Developer ID 证书进行代码签名、通过 Apple 公证以满足 Gatekeeper 要求,以及通过 GitHub Releases 分发的干净的发布产物。
每一步单独来看都不大,组合起来却很折磨人。entitlements、hardened runtime、notary submission、stapling 和下载链接路径必须全部对齐,才能让一个陌生人双击应用就直接打开。把这条发布管线做可靠,是 v1.0.5 不需要每次手动处理的关键。
构建概览
SayIt 的表面面积很小,但深度不浅。音频采集、转录、权限和分发每一层都必须达到生产级标准,用户双击下载的二进制文件时体验才会干净。
- 独立产品交付
- 独立设计并开发,覆盖产品界面、音频管线、转录引擎、权限体验以及签名、公证和分发。
- 默认隐私优先
- 音频从不离开设备。whisper.cpp 本地运行,模型选择暴露给用户,让不同硬件可以自己权衡准确率和速度。
- 适配真实生态
- 处理输入设备变更,支持连续互通麦克风切换,在权限缺失或模型缺失时可预期地降级。
反思
SayIt 是我从「为幻灯片做设计」转向「为二进制文件做设计」的项目。popover 密度、HUD 时机、模型选择、权限文案都要回答同一个问题:这仍然像一个系统工具,还是开始像一个 App?
在这个作品集中,SayIt 是我把一个聚焦产品想法做成真实软件的最清楚例子:定义问题,塑造交互模型,选择合适的技术路径,最后交付一个经过签名和公证、今天就能下载的 macOS 产品。