---
read_when:
    - Настройка поведения голосового оверлея
summary: Жизненный цикл голосового оверлея при пересечении wake-word и push-to-talk
title: Голосовой оверлей
x-i18n:
    generated_at: "2026-06-28T23:12:57Z"
    model: gpt-5.5
    postprocess_version: locale-links-v1
    provider: openai
    source_hash: 5b30f50512e557bd5a50f0e4e8b7955a847b3b554694347d56638581fcda9514
    source_path: platforms/mac/voice-overlay.md
    workflow: 16
---

# Жизненный цикл голосового оверлея (macOS)

Аудитория: контрибьюторы приложения для macOS. Цель: сделать поведение голосового оверлея предсказуемым при наложении слова активации и режима «нажми и говори».

## Текущий замысел

- Если оверлей уже виден из-за слова активации и пользователь нажимает горячую клавишу, сессия горячей клавиши _принимает_ существующий текст вместо его сброса. Оверлей остается видимым, пока горячая клавиша удерживается. Когда пользователь отпускает ее: отправить, если после обрезки пробелов есть текст, иначе закрыть.
- Только слово активации по-прежнему автоматически отправляет при тишине; режим «нажми и говори» отправляет сразу при отпускании.

## Реализовано (9 декабря 2025 г.)

- Сессии оверлея теперь несут токен для каждого захвата (слово активации или режим «нажми и говори»). Обновления partial/final/send/dismiss/level отбрасываются, если токен не совпадает, что предотвращает устаревшие обратные вызовы.
- Режим «нажми и говори» принимает любой видимый текст оверлея как префикс (поэтому нажатие горячей клавиши при открытом оверлее активации сохраняет текст и добавляет новую речь). Он ждет до 1,5 с финальную транскрипцию, прежде чем откатиться к текущему тексту.
- Логи звукового сигнала/оверлея выводятся на уровне `info` в категориях `voicewake.overlay`, `voicewake.ptt` и `voicewake.chime` (старт сессии, partial, final, send, dismiss, причина звукового сигнала).

## Следующие шаги

1. **VoiceSessionCoordinator (актор)**
   - Владеет ровно одной `VoiceSession` за раз.
   - API (на основе токенов): `beginWakeCapture`, `beginPushToTalk`, `updatePartial`, `endCapture`, `cancel`, `applyCooldown`.
   - Отбрасывает обратные вызовы с устаревшими токенами (предотвращает повторное открытие оверлея старыми распознавателями).
2. **VoiceSession (модель)**
   - Поля: `token`, `source` (wakeWord|pushToTalk), зафиксированный/изменяемый текст, флаги звукового сигнала, таймеры (auto-send, idle), `overlayMode` (display|editing|sending), срок окончания cooldown.
3. **Привязка оверлея**
   - `VoiceSessionPublisher` (`ObservableObject`) зеркалирует активную сессию в SwiftUI.
   - `VoiceWakeOverlayView` отображает состояние только через publisher; он никогда не изменяет глобальные singleton напрямую.
   - Действия пользователя в оверлее (`sendNow`, `dismiss`, `edit`) вызывают координатор с токеном сессии.
4. **Единый путь отправки**
   - При `endCapture`: если текст после обрезки пробелов пустой → закрыть; иначе `performSend(session:)` (один раз воспроизводит звуковой сигнал отправки, пересылает, закрывает).
   - Режим «нажми и говори»: без задержки; слово активации: опциональная задержка для auto-send.
   - Применить короткий cooldown к runtime слова активации после завершения режима «нажми и говори», чтобы слово активации не сработало повторно сразу.
5. **Логирование**
   - Координатор выводит логи `.info` в subsystem `ai.openclaw`, категории `voicewake.overlay` и `voicewake.chime`.
   - Ключевые события: `session_started`, `adopted_by_push_to_talk`, `partial`, `finalized`, `send`, `dismiss`, `cancel`, `cooldown`.

## Контрольный список отладки

- Потоково просматривайте логи при воспроизведении залипающего оверлея:

  ```bash
  sudo log stream --predicate 'subsystem == "ai.openclaw" AND category CONTAINS "voicewake"' --level info --style compact
  ```

- Проверьте, что активен только один токен сессии; устаревшие обратные вызовы должны отбрасываться координатором.
- Убедитесь, что отпускание в режиме «нажми и говори» всегда вызывает `endCapture` с активным токеном; если текст пустой, ожидайте `dismiss` без звукового сигнала или отправки.

## Шаги миграции (предлагаемые)

1. Добавить `VoiceSessionCoordinator`, `VoiceSession` и `VoiceSessionPublisher`.
2. Отрефакторить `VoiceWakeRuntime`, чтобы он создавал/обновлял/завершал сессии вместо прямого обращения к `VoiceWakeOverlayController`.
3. Отрефакторить `VoicePushToTalk`, чтобы он принимал существующие сессии и вызывал `endCapture` при отпускании; применять cooldown runtime.
4. Подключить `VoiceWakeOverlayController` к publisher; удалить прямые вызовы из runtime/PTT.
5. Добавить интеграционные тесты для принятия сессии, cooldown и закрытия при пустом тексте.

## Связанные материалы

- [Приложение macOS](/ru/platforms/macos)
- [Голосовая активация (macOS)](/ru/platforms/mac/voicewake)
- [Режим разговора](/ru/nodes/talk)
