语音覆盖层简介
语音覆盖层(Voice Overlay)是 OpenClaw macOS 应用的语音交互入口,支持两种触发方式:唤醒词激活(Wake Word)和按键说话(Push-to-Talk,PTT)。当你说出唤醒词或按住快捷键时,屏幕上会出现一个浮动覆盖层显示正在识别的文字,松手或静默后自动发送给 AI 助手。
两种触发方式
唤醒词模式: 说出预设的唤醒词后,覆盖层弹出,系统持续识别语音,在检测到静默时自动发送识别结果。
按键说话模式(PTT): 按住快捷键时激活语音识别,松开快捷键时立即发送当前识别的内容,无需等待静默检测。
文字采用机制(关键特性)
当你按住 PTT 快捷键时,如果覆盖层因为唤醒词已经显示了部分识别文字,PTT 会采用已有文字作为前缀,而不是丢弃重来。具体行为:
- 唤醒词激活 → 覆盖层显示识别中的文字
- 此时按住 PTT 快捷键 → PTT 等待最多 1.5 秒获取最终识别结果,然后将其作为前缀
- 继续说话 → 新内容追加到前缀之后
- 松开 PTT → 有内容则发送,无内容则关闭覆盖层
这个设计确保了两种输入方式之间的平滑过渡,不会丢失已识别的文字。
会话令牌机制
每次语音捕获(无论唤醒词还是 PTT)都持有一个唯一的会话令牌。所有的部分结果、最终识别、发送和关闭操作都需要携带匹配的令牌才会被处理。这防止了「幽灵回调」问题:旧的异步识别结果不会意外重新打开已关闭的覆盖层。
架构组件
| 组件 | 职责 |
|---|---|
VoiceSessionCoordinator |
Actor,管理单个活跃会话,提供令牌化 API |
VoiceSession |
模型,持有令牌、文字缓冲区、计时器和覆盖层状态 |
VoiceSessionPublisher |
将活跃会话镜像为 SwiftUI ObservableObject |
VoiceWakeOverlayView |
UI 视图,完全通过 Publisher 驱动,不直接调用 Coordinator |
覆盖层状态(overlayMode)包含:display(展示中)、editing(编辑中)、sending(发送中)。
发送逻辑
- 文字内容去掉首尾空格后为空 → 静默关闭覆盖层,不播放提示音
- 有实质内容 → 播放提示音 + 转发给 AI + 关闭覆盖层
- PTT 松开后对唤醒词运行时施加短暂冷却期,防止立即再次激活
调试与日志
实时流式查看语音覆盖层相关日志:
sudo log stream \
--predicate 'subsystem == "ai.openclaw" AND category CONTAINS "voicewake"' \
--level info \
--style compact
日志覆盖的事件类别:
voicewake.overlay:覆盖层的显示与关闭voicewake.ptt:PTT 按键事件和文字采用voicewake.chime:提示音触发
验证清单
调试覆盖层问题时,检查以下几点:
- 同一时间只有一个活跃的会话令牌
- 过期的异步回调被 Coordinator 正确丢弃
- PTT 松开时调用了携带活跃令牌的
endCapture - 空文字输入产生静默关闭(无提示音、无发送)
使用建议
- 在安静环境下,唤醒词模式体验最佳
- 嘈杂环境或需要精确控制发送时机时,PTT 模式更可靠
- iOS 上的语音功能在后台时属于尽力而为,重要交互建议在前台进行