macOS companion app
Голосовое наложение
Жизненный цикл голосового оверлея (macOS)
Аудитория: участники разработки приложения для macOS. Цель: обеспечить предсказуемое поведение голосового оверлея при одновременном использовании слова активации и функции «нажми и говори».
Поведение
- Если оверлей уже отображается после срабатывания слова активации и пользователь нажимает горячую клавишу, сеанс горячей клавиши принимает существующий текст вместо его сброса. Оверлей остаётся на экране, пока удерживается горячая клавиша. После отпускания: отправить, если после удаления пробелов текст не пуст; в противном случае закрыть.
- При использовании только слова активации содержимое по-прежнему автоматически отправляется при наступлении тишины; функция «нажми и говори» отправляет его сразу после отпускания клавиши.
Реализация
VoiceSessionCoordinator(apps/macos/Sources/OpenClaw/VoiceSessionCoordinator.swift) — единственный владелец активного голосового сеанса. Это одноэлементный экземпляр@MainActor @Observable, а не актор. API:startSession,updatePartial,finalize,sendNow,dismiss,updateLevel,snapshot. Каждый сеанс содержит токенUUID; вызовы с устаревшим или несовпадающим токеном отбрасываются.VoiceWakeOverlayController(VoiceWakeOverlayController+Session.swift) отображает оверлей и передаёт действия пользователя (requestSend,dismiss) обратно координатору через токен сеанса. Сам компонент никогда не владеет состоянием сеанса.- Функция «нажми и говори» (
VoicePushToTalk.begin()) принимает текст любого видимого оверлея какadoptedPrefix(черезVoiceSessionCoordinator.shared.snapshot()), поэтому нажатие горячей клавиши при отображаемом оверлее слова активации сохраняет текст и добавляет к нему новую речь. После отпускания функция ожидает окончательную расшифровку до 1.5 с, а затем при её отсутствии использует текущий текст. - При
dismissоверлей вызываетVoiceSessionCoordinator.overlayDidDismiss, что запускаетVoiceWakeRuntime.refresh(state:), поэтому прослушивание слова активации возобновляется после ручного закрытия кнопкой X, закрытия из-за пустого текста и закрытия после отправки. - Единый путь отправки: если после удаления пробелов текст пуст, закрыть оверлей; в противном случае
sendNowодин раз воспроизводит звуковой сигнал отправки, передаёт текст черезVoiceWakeForwarder, а затем закрывает оверлей.
Журналирование
Голосовая подсистема — ai.openclaw; каждый компонент ведёт журнал в собственной категории:
| Категория | Компонент |
|---|---|
voicewake.coordinator |
VoiceSessionCoordinator |
voicewake.overlay |
VoiceWakeOverlayController/VoiceWakeOverlay |
voicewake.ptt |
Горячая клавиша и захват для функции «нажми и говори» |
voicewake.runtime |
Среда выполнения слова активации |
voicewake.chime |
Воспроизведение звукового сигнала |
voicewake.sync |
Синхронизация глобальных настроек |
voicewake.forward |
Пересылка расшифровки |
voicewake.meter |
Монитор уровня микрофона |
Контрольный список отладки
-
Просматривайте поток журналов при воспроизведении зависшего оверлея:
bash sudo log stream --predicate 'subsystem == "ai.openclaw" AND category CONTAINS "voicewake"' --level info --style compact -
Убедитесь, что активен только один токен сеанса; устаревшие обратные вызовы отбрасываются координатором.
-
Убедитесь, что при отпускании клавиши функции «нажми и говори» всегда вызывается
end()с активным токеном; если текст пуст, ожидается закрытие без звукового сигнала и отправки.
Связанные материалы
Was this useful?