Skip to content
广告 · 本站推荐广告

语音覆盖层生命周期(macOS)

目标受众:macOS 应用贡献者。目标:在唤醒词和按住说话重叠时保持语音覆盖层的可预测性。

当前设计意图

  • 如果覆盖层已因唤醒词可见,用户按下快捷键时,快捷键会话接管现有文本而不是重置它。在快捷键按住期间覆盖层保持显示。用户松开时:如果有修剪后的文本则发送,否则关闭。
  • 单独的唤醒词在静默时仍然自动发送;按住说话在松开时立即发送。

已实现功能(2025 年 12 月 9 日)

  • 覆盖层会话现在每次捕获(唤醒词或按住说话)都携带一个 token。当 token 不匹配时,部分/最终/发送/关闭/级别更新会被丢弃,避免过期回调。
  • 按住说话会接管任何可见的覆盖层文本作为前缀(因此在唤醒覆盖层显示时按快捷键会保留文本并附加新语音)。它在回退到当前文本之前等待最多 1.5 秒获取最终转录。
  • 提示音/覆盖层日志以 info 级别输出到类别 voicewake.overlayvoicewake.pttvoicewake.chime(会话开始、部分、最终、发送、关闭、提示音原因)。

后续步骤

1. VoiceSessionCoordinator(actor)

  • 同一时间恰好拥有一个 VoiceSession
  • API(基于 token):beginWakeCapturebeginPushToTalkupdatePartialendCapturecancelapplyCooldown
  • 丢弃携带过期 token 的回调(防止旧识别器重新打开覆盖层)。

2. VoiceSession(模型)

  • 字段:tokensource(wakeWord|pushToTalk)、committed/volatile 文本、提示音标志、计时器(自动发送、空闲)、overlayMode(display|editing|sending)、冷却截止时间。

3. 覆盖层绑定

  • VoiceSessionPublisherObservableObject)将活跃会话镜像到 SwiftUI。
  • VoiceWakeOverlayView 仅通过 publisher 渲染;它从不直接修改全局单例。
  • 覆盖层用户操作(sendNowdismissedit)带会话 token 回调到 coordinator。

4. 统一发送路径

  • endCapture 时:如果修剪后文本为空 → 关闭;否则 performSend(session:)(播放一次发送提示音,转发,关闭)。
  • 按住说话:无延迟;唤醒词:可选的自动发送延迟。
  • 按住说话结束后对唤醒运行时应用短暂冷却,防止唤醒词立即重新触发。

5. 日志

  • Coordinator 在子系统 ai.openclaw 中输出 .info 日志,类别为 voicewake.overlayvoicewake.chime
  • 关键事件:session_startedadopted_by_push_to_talkpartialfinalizedsenddismisscancelcooldown

调试清单

在重现粘滞覆盖层时流式传输日志:

bash
sudo log stream --predicate 'subsystem == "ai.openclaw" AND category CONTAINS "voicewake"' --level info --style compact
  • 验证只有一个活跃会话 token;过期回调应被 coordinator 丢弃。
  • 确保按住说话松开始终使用活跃 token 调用 endCapture;如果文本为空,预期 dismiss 且无提示音或发送。

迁移步骤(建议)

  1. 添加 VoiceSessionCoordinatorVoiceSessionVoiceSessionPublisher
  2. 重构 VoiceWakeRuntime 以创建/更新/结束会话,而不是直接操作 VoiceWakeOverlayController
  3. 重构 VoicePushToTalk 以接管现有会话并在松开时调用 endCapture;应用运行时冷却。
  4. VoiceWakeOverlayController 连接到 publisher;移除运行时/PTT 的直接调用。
  5. 添加会话接管、冷却和空文本关闭的集成测试。

基于MIT协议开源 | 内容翻译自 官方文档,同步更新