9.9 KiB
验收记录
日期:2026-10-23。此记录区分代码回归、真实系统测试与尚未通过的验收。
已通过
- SwiftPM debug 编译及 Swift Testing:17 项测试通过,0 失败。
- Release
.app构建,真实 Apple Development 身份签名,沙箱外codesign --verify --strict通过。 - Info.plist 格式、构建/签名/测试脚本语法检查通过。
- 图标脚本生成 10 个尺寸 PNG、1024 px logo 和 ICNS;大图人工查看,16/32 px 简化细节。图标已包含在 app 中。
- 通过 macOS 原生界面检查通用、快捷键、语音和关于页面。右 Option、按一次开始再按一次结束、固定普通话、自动补句号均与用户确认一致;麦克风与辅助功能显示已授权。
- Release app 约 1.3 MiB(不含系统下载模型),满足 <10 MB 包体目标。
自动回归范围
- 标点保留、补句号、引号、内部空格、口头语与空白输入。
- 热键 JSON 往返和左右键命名。
- 静音/有声音量估计与 48 kHz → 16 kHz 重采样。
- 超时不会等待不响应取消的操作结束。
- 准备中结束并立即重开:旧会话不会接管新会话。
- 收尾中取消:不发布结果,不写入。
- 开始录音失败:清理会话与测试状态。
- 正常测试模式结束:保留结果,退出测试模式,不写入。
- 拒绝麦克风:不创建识别会话。
- 识别运行时失败:取消录音并反馈错误。
- Secure Input:不开始采集。
- 右 Option 使用事件自带左右键标志,左键保持按下时仍正确检测右键释放。
- 等待旧版语音授权时取消,不启动麦克风。
- 测试模式返回空文字时明确提示失败。
其中状态机回归使用可控会话替身,不代表真实麦克风和跨应用兼容性。
早期真实模型测试:失败记录(后续恢复见下)
分别运行已签名 app 的 --selftest 与 --selftest --dictation。两者均确认中文系统模型为 installed;备用测试已完成系统合成语音与文件读取。两条路径都在 SpeechAnalyzer 准备阶段被系统语音服务拒绝:
Espresso V2 failure: ANE model load failure:
loadModel:sandboxExtension:options:qos:withReply:: timed out
错误来自 Apple EmbeddedAcousticRecognition / localspeechrecognition 服务,已在沙箱外重现。自检返回非零退出码,不会把空结果或关键词不匹配算作成功。自检有 90 秒总超时保护。
因此没有可报告的成功识别延迟,首字 <300 ms、结束到上屏 <500 ms 均未验收。自动模式包含 SpeechTranscriber → DictationTranscriber → 强制本地 SFSpeechRecognizer 降级;旧版真实麦克风路径未验收,不保证能绕过当前系统服务错误。
资源与待验收项
一次已运行、打开过四页 SwiftUI 设置的进程快照为 CPU 0.0%、RSS 97,840 KiB(约 95.5 MiB)。这不是长期采样,且未达到 <80 MB 内存目标。后续已加入关闭设置即释放界面、录音时才创建 AVAudioEngine、预热 10 分钟后释放;该优化后尚未获得可比的完整资源验收。
下列项目仍需在本地语音服务正常的机器上完成,不能凭单元测试推定通过:
- 真人麦克风:右 Option 开始/结束、Esc 取消、12 秒无声结束。
- TextEdit、Chrome 输入框、终端分别测试插入点、选区替换、剪贴板恢复与失败恢复。终端使用无副作用的测试文本,不按回车执行。
- AX 回读不一致时不会重复粘贴;前台应用改变或安全输入阻止写入;取消后旧会话不写入。
- 模型首次下载、断网下载失败、重试;全本地降级的真实识别。
- 多屏、Space、全屏窗口的 HUD 定位与不抢焦点。
- 菜单栏录音/收尾动画、设置改绑后真实按键、重启后的偏好保存。
- 登录启动与系统批准;长时间待机 CPU、预热过期后内存;实际真人语音延迟。
复现
./scripts/test.sh
./scripts/build.sh
codesign --verify --strict dist/TinyTTS.app
./dist/TinyTTS.app/Contents/MacOS/TinyTTS --selftest
./dist/TinyTTS.app/Contents/MacOS/TinyTTS --selftest --dictation
受限执行环境中 SwiftPM 缓存目录会有不可写提示;脚本已将模块缓存放在仓库 .build。macOS 图像服务、dSYM 和签名信任校验可能需要在普通本机终端执行。沙箱内 CSSMERR_TP_NOT_TRUSTED 已用沙箱外严格签名校验排除,未更改系统信任设置。
本次续作验证
- 重新运行
./scripts/test.sh:14 项通过,0 失败。 - 重新构建 0.1.2,使用现有 Apple Development 固定身份签名,严格签名校验通过。
- 现有日志确认修复后右 Option 事件已触发,备用引擎曾在约 126–198 ms 内开始采集,收到非静音音频,但最终返回 0 字。该记录不能当作成功识别或写入验收。
- 普通本机环境运行
--selftest --legacy:授权状态为notDetermined,明确失败退出。先前 GUI 进程显示已授权与命令行自检结果不同,因此命令行结果不能证明 GUI 权限被撤销,也不能验证旧版识别成功。 - 测试模式现在会对空结果显示错误;取消权限等待后不再继续获取识别会话。
本次重新运行 --selftest 仍以非零状态失败,原始错误为 Espresso V2 failure: ANE model load failure: loadModel:sandboxExtension:options:qos:withReply:: timed out,发生在已安装模型的准备阶段;未采集麦克风。
ANE 恢复与字幕合并修复
先定向重启当前用户的语音识别服务,主模型仍返回同一 ANE 模型加载超时。经用户选择原生管理员授权后,使用 macOS 授权对话框尝试 launchctl kickstart,被 SIP 拒绝;随后通过正常 SIGTERM 终止已确认的 aned 服务,由系统重新拉起,未关闭或修改 SIP。ANE PID 从 588 变为 42024。
恢复后真实模型自检通过:
| 引擎 | 识别关键词 | 音频开始至首字 | 音频结束至最终结果 |
|---|---|---|---|
| SpeechTranscriber | 天气、开会 | 1230 ms | 157 ms |
| DictationTranscriber | 天气、开会 | 581 ms | 89 ms |
这些是固定语句实时喂入的单次结果,包含语音起始内容与模型调度,不代表麦克风首字延迟或跨应用上屏。
GUI 真实麦克风通过扬声器播放固定测试语句:实时字幕返回完整测试句,收尾成功。首次实录发现最终结果的时间起点与临时结果不完全一致,按起点精确匹配使整句重复。现改用时间覆盖范围合并,补充起点偏移、过时临时结果、连续多句的回归测试;修复后再次实录,收尾前后文字一致,不再重复。该次启动采集总耗时 241 ms,收尾 108 ms。
语音页增加「重新准备引擎」,系统服务恢复后无需退出即可清除降级状态。合成语音诊断改为检查当前所选引擎,诊断期间禁止同时开始麦克风测试或更改引擎。
最新自动回归:17 项通过,0 失败。Release 固定身份签名与严格校验通过。主应用包约 1.44 MiB。一次实录后关闭设置的快照为 RSS 106464 KiB、CPU 4.1%;它不是长期空闲采样,不能认定 <80 MB / <1% 目标已通过。
默认直接输入修复(0.1.3)
物理右 Option 已触发录音与结束,得到非空结果;旧版 AX 返回成功但回读不一致,只留下剪贴板结果,不满足自动输入要求。
默认方式现改为 Unicode 键盘事件,直接发送到开始时的目标进程,清除仍按住的修饰键状态,不读写剪贴板。事件分块不拆开 UTF-16 代理对,并标记自发事件以免触发自定义热键。前台进程改变或安全输入仍阻止注入,结果仅保留在进程内供用户找回。显式选择「始终使用粘贴」才走剪贴板兼容路径。
新增 --selftest --input,由正常 LaunchServices 启动已签名 app,创建真实 AppKit 文本输入窗口,自动验证中文/英文/emoji 长文本实际输入、选区替换以及剪贴板版本号保持不变。实测输出:
SELFTEST PASSED (real AppKit Unicode input, selection replacement, clipboard unchanged)
Swift Testing 当前 17 项通过;0.1.3 Release 固定身份签名与严格校验通过。外部应用的物理热键听写验收继续以 UI 实际内容与日志为准,不能只看事件发出。
物理热键与实际输入反馈
用户在本聊天输入框实测右 Option 开始、说话、再次按键结束,并反馈直接输入已通过。同期日志记录多次 SpeechSession 采集及 insert via 直接输入 ok=true,结束到输入事件发出约 64–81 ms。该用户反馈与真实 AppKit 输入自检共同确认当前主链可用;TextEdit 文稿并未收到这次用户测试内容,不把该次测试写成 TextEdit 兼容性通过。Chrome 与终端的独立验收仍未完成。
按用户要求,完成输入提示音改为系统 Glass「叮」声,仅在输入派发成功时播放。开始录音的提示保持原设置。
应用更名
按用户纠正,将当前工程、Swift 模块、测试模块、界面及产物统一改为 TinySTT / dist/TinySTT.app。保留 com.eccstartup.tinystt bundle ID 与既有偏好键以保持权限和设置关联。新的签名覆盖变量为 TINYSTT_SIGN_IDENTITY,仍兼容旧变量和已安装的 TinyTTS Dev 证书。旧验收段落中的 TinyTTS 路径为历史记录;当前复现请使用 README 中的 TinySTT 命令。
新版 T 字母图标使用内置 image_gen 生成,保存项目内源图和完整提示词,再以 AppKit 脚本生成 16–1024 px PNG 及 ICNS;不依赖外部临时图片路径。更名后的 TinySTT.app 再次通过真实 AppKit 直接输入、选区替换与剪贴板未变自检。
最终 TinySTT.app(0.1.3)包体 2840 KiB(约 2.77 MiB),固定身份签名与严格校验通过;包内 ICNS 与项目内图标 SHA-256 完全一致。16/32 px 图标已查看,T 字轮廓可辨。旧名称的构建产物已移除,仅保留 TinySTT.app。