TinySTT
一个 Typeless 风格的开源精简版 macOS 语音输入工具。常驻右上角菜单栏,按一下右 Option 开始说话,再按一下,把文字写到当前输入框。
原生 Swift + SwiftUI,无第三方依赖,无账号、API key 或订阅。TinySTT 是全本地的语音转文字(STT)工具。本项目与 Typeless 无隶属关系。
默认交互
- 右 Option:按一次开始,再按一次结束;设置中可重新绑定,也可改为按住说话。
- Esc:取消当前录音或收尾,丢弃本次文字。
- 固定中文(普通话):使用系统本地模型;夹杂英文的效果取决于模型,不做自动语言切换。
- 保留识别标点,自动补句号:不删除口头语、不改写、不合并内部空格;可关闭补句号。
- 实时字幕和音量条,不抢走输入焦点;可关闭字幕或固定到屏幕底部。
- 默认连续 12 秒无声自动结束,可在设置中关闭。
- 完成自动输入后播放清脆的「叮」声,可在设置中关闭提示音。
菜单栏展示待机、准备、录音和处理中状态。录音时图标呼吸,处理时旋转;菜单里可开始/结束、取消、查看权限和模型状态、复制上次结果、打开设置或退出。待机时不运行图标动画。
环境与构建
需要 macOS 26+、包含 macOS 26+ SDK 的 Xcode / Swift 工具链。本次验证平台为 Apple Silicon;Intel 尚未验证。系统语音模型单独安装,不包含在 app 包体中。
./scripts/test.sh
./scripts/build.sh
open dist/TinySTT.app
产物为 dist/TinySTT.app,构建脚本会组装图标、Info.plist 并验证代码签名。无需 .xcodeproj,也无需 swift run。请从 .app 启动,以正确关联系统权限。
日常使用时退出旧版本,将 app 放入 /Applications 后再启动;在通用设置中开启登录启动。系统若要求批准登录项,需要到系统设置确认。
固定签名身份
脚本依次选择 TINYSTT_SIGN_IDENTITY、可用 Apple Development 身份、TinySTT Dev 身份,否则使用 ad-hoc 签名并发出提示。
# 已有签名身份时
TINYSTT_SIGN_IDENTITY='Apple Development: Your Name (TEAMID)' ./scripts/build.sh
# 没有身份时,可在自己的终端运行,导入本地开发证书
./scripts/setup-signing.sh
自签名证书可能需要在「钥匙串访问」中设置信任后才能被 codesign 使用。请自行操作系统信任与密码提示。固定身份、bundle id 和安装路径有助于保持辅助功能授权;ad-hoc 重建通常需要重新授权。脚本不提供 Developer ID 公证,公开二进制分发还需独立完成签名与公证。
首次使用
- 启动 app,允许麦克风,在「隐私与安全性 → 辅助功能」中允许 TinySTT。若系统提示输入监控,也需在相应页面授权。辅助功能授权后会自动重试热键。
- 打开「设置与测试语音 → 语音」,检查模型状态。首次下载需要网络,下载完成后的识别在本机进行;失败时可重试。
- 点「开始测试」检查实时识别,结束后查看结果。此模式不向任何应用写入文字。
- 回到目标输入框,按右 Option;首次若显示「正在准备本地识别」,等变为「聆听中」再说话,再按一次结束并写入。
「模型已安装」不代表引擎已经就绪,菜单和语音设置会分别显示两种状态。自动模式遇到分析器加载失败时,会记住本进程的降级结果,避免每次录音重新等待失败引擎。旧版本地引擎首次使用需单独允许系统「语音识别」权限;授权期间不会显示正在录音。
若没有文字,可用语音页「检查本地识别(合成语音)」检查当前选择的引擎,区分本地引擎故障与麦克风输入问题。该检查使用固定测试文本,不采集麦克风,也不写入其他应用。系统服务恢复后可点「重新准备引擎」,清除本进程的失败降级状态。
设置有通用、快捷键、语音、关于四个页面。语音页可在自动、本地 SpeechTranscriber、本地 DictationTranscriber 和旧版本地识别间选择。自动模式优先 SpeechTranscriber,不支持时降级;旧版强制 requiresOnDeviceRecognition,额外需要系统语音识别权限,缺少本地能力时不会转为云端识别。
文字写入与隐私
默认通过 Unicode 键盘事件直接写入当前输入框并替换选区,不读写剪贴板;支持中文、英文、emoji 和长文本。设置仍提供仅 AX 和自动粘贴两种兼容方式;只有显式选择自动粘贴时才临时占用剪贴板并在未被其他操作改动时恢复。输入事件已发出不代表所有应用均已接收;必要时从菜单「复制上次识别结果」找回文字。
录音期间切换前台应用,或结束时进入安全输入模式,会阻止自动写入并将文字保留在本进程的上次识别结果中。密码等 Secure Input 场景不触发录音。取消中的会话不会回写结果。
不保存音频文件、不上传录音,不记录识别原文;本次结果只在进程内保留,退出后清除。设置使用 UserDefaults。诊断日志位于 ~/Library/Logs/TinySTT.log,记录错误、字符数和时间,超过约 1 MB 轮换为 .log.1;系统崩溃报告位于 macOS 的 DiagnosticReports 目录。模型下载由 Apple 系统服务完成。
测试
./scripts/test.sh
./scripts/build.sh
# 用真实本地模型识别系统合成语音,需先安装模型
./dist/TinySTT.app/Contents/MacOS/TinySTT --selftest
./dist/TinySTT.app/Contents/MacOS/TinySTT --selftest --dictation
./dist/TinySTT.app/Contents/MacOS/TinySTT --selftest --legacy
# 真实 AppKit 输入、选区替换和剪贴板不变检查,无需语音模型
# 通过 LaunchServices 启动,以沿用 app 的系统权限归属
open -n -W --stdout /tmp/tinystt-input-test.log dist/TinySTT.app --args --selftest --input
自动回归覆盖文字处理、热键编码、重采样、超时以及启动/收尾取消竞态。模型自检使用实时速率喂入合成语音,输出首字和收尾时间;它不代表真人麦克风、全局热键或跨应用写入验收。本机恢复系统 ANE 服务后,SpeechTranscriber 与 DictationTranscriber 均通过真实中文模型自检,真实麦克风测试也能返回字幕;验收详情见 TESTING.md。
计划中的首字 <300 ms、结束到上屏 <500 ms、空闲 CPU <1%、内存 <80 MB 是验收目标,不是跨设备保证。首次加载模型、说话前静音、系统调度和应用粘贴处理都会影响数据。日志中的 release to insertion dispatch 仅测到写入请求发出。
开发
Sources/TinySTT/
App/ 应用生命周期与听写状态机
Hotkey/ 全局按键与改绑
Speech/ 模型、预热、本地识别与音频采集
Text/ 选区写入、剪贴板回退、标点
UI/ 菜单栏、非激活字幕、四页设置
Support/ 偏好、权限、登录启动、日志
Tests/ Swift Testing 回归
Resources/ 图标与 Info.plist
scripts/ 构建、测试、签名、图标生成
重建图标包:swift scripts/make-icon.swift Resources。图标以独特的 T 字母为主体,将语音波形融入字母轮廓。源图为 Resources/AppIcon-source.png,生成提示词保存在 Resources/Logo.prompt.txt;脚本使用原生 AppKit 生成 16–1024 px PNG 和 ICNS。
许可证
MIT。系统语音框架与下载模型由 Apple 提供,不随本项目再分发。