Життєвий цикл голосового накладання (macOS)
Аудиторія: учасники розробки застосунку macOS. Мета: зберегти передбачувану поведінку голосового накладання, коли перетинаються ключове слово пробудження та push-to-talk.Поточний задум
- Якщо накладання вже видиме через ключове слово пробудження і користувач натискає гарячу клавішу, сеанс гарячої клавіші підхоплює наявний текст замість його скидання. Накладання залишається відкритим, доки утримується гаряча клавіша. Коли користувач відпускає її: надіслати, якщо є текст після обрізання пробілів, інакше закрити.
- Лише ключове слово пробудження, як і раніше, автоматично надсилає після тиші; push-to-talk надсилає одразу після відпускання.
Реалізовано (9 грудня 2025 року)
- Сеанси накладання тепер мають токен для кожного захоплення (ключове слово пробудження або push-to-talk). Оновлення partial/final/send/dismiss/level відкидаються, якщо токен не збігається, що запобігає застарілим зворотним викликам.
- Push-to-talk підхоплює будь-який текст видимого накладання як префікс (тож натискання гарячої клавіші, поки накладання пробудження активне, зберігає текст і додає нове мовлення). Він очікує до 1.5 с на фінальну транскрипцію, а потім повертається до поточного тексту.
- Логування chime/overlay записується на рівні
infoу категоріяхvoicewake.overlay,voicewake.pttіvoicewake.chime(початок сеансу, partial, final, send, dismiss, причина chime).
Наступні кроки
- VoiceSessionCoordinator (actor)
- Керує рівно одним
VoiceSessionодночасно. - API (на основі токенів):
beginWakeCapture,beginPushToTalk,updatePartial,endCapture,cancel,applyCooldown. - Відкидає зворотні виклики, що містять застарілі токени (це не дає старим розпізнавачам знову відкрити накладання).
- Керує рівно одним
- VoiceSession (model)
- Поля:
token,source(wakeWord|pushToTalk), committed/volatile text, прапорці chime, таймери (auto-send,idle),overlayMode(display|editing|sending), крайній термін cooldown.
- Поля:
- Прив’язка накладання
VoiceSessionPublisher(ObservableObject) відображає активний сеанс у SwiftUI.VoiceWakeOverlayViewрендериться лише через publisher; він ніколи не змінює глобальні singleton безпосередньо.- Дії користувача в накладанні (
sendNow,dismiss,edit) викликають coordinator із токеном сеансу.
- Уніфікований шлях надсилання
- Під час
endCapture: якщо текст після обрізання пробілів порожній → закрити; інакшеperformSend(session:)(один раз відтворює chime надсилання, пересилає, закриває). - Push-to-talk: без затримки; ключове слово пробудження: необов’язкова затримка для автонадсилання.
- Застосовуйте короткий cooldown до runtime пробудження після завершення push-to-talk, щоб ключове слово пробудження не спрацьовувало знову негайно.
- Під час
- Логування
- Coordinator записує логи
.infoу підсистеміai.openclaw, категоріїvoicewake.overlayіvoicewake.chime. - Ключові події:
session_started,adopted_by_push_to_talk,partial,finalized,send,dismiss,cancel,cooldown.
- Coordinator записує логи
Контрольний список для налагодження
-
Передавайте логи під час відтворення завислого накладання:
- Переконайтеся, що активний лише один токен сеансу; coordinator має відкидати застарілі зворотні виклики.
-
Переконайтеся, що відпускання push-to-talk завжди викликає
endCaptureз активним токеном; якщо текст порожній, очікуйтеdismissбез chime або надсилання.
Кроки міграції (рекомендовано)
- Додайте
VoiceSessionCoordinator,VoiceSessionіVoiceSessionPublisher. - Переробіть
VoiceWakeRuntime, щоб він створював, оновлював і завершував сеанси замість безпосередньої взаємодії зVoiceWakeOverlayController. - Переробіть
VoicePushToTalk, щоб він підхоплював наявні сеанси й викликавendCaptureпри відпусканні; застосовуйте cooldown runtime. - Підключіть
VoiceWakeOverlayControllerдо publisher; приберіть прямі виклики з runtime/PTT. - Додайте інтеграційні тести для підхоплення сеансів, cooldown і закриття за порожнього тексту.