Voice Wake и Push-to-Talk
Режимы
- Режим Wake-word (по умолчанию): всегда включенный распознаватель речи ждет триггерных токенов (swabbleTriggerWords). При совпадении он начинает захват, показывает оверлей с частичным текстом и автоматически отправляет после тишины.
- Push-to-talk (удержание правой клавиши Option): удерживайте правую клавишу Option для немедленного захвата — триггер не нужен. Оверлей появляется при удержании; отпускание завершает и пересылает после короткой задержки, чтобы вы могли настроить текст.
Поведение runtime (wake-word)
- Распознаватель речи находится в VoiceWakeRuntime.
- Триггер срабатывает только при наличии значимой паузы между wake word и следующим словом (~0,55 с разрыв). Оверлей/chime могут начаться на паузе даже до начала команды.
- Окна тишины: 2,0 с при течении речи, 5,0 с, если услышан только триггер.
- Жесткая остановка: 120 с для предотвращения неконтролируемых сеансов.
- Дебаунс между сеансами: 350 мс.
- Оверлей управляется через VoiceWakeOverlayController с зафиксированной/волатильной окраской.
- После отправки распознаватель перезапускается чисто, чтобы слушать следующий триггер.
Инварианты жизненного цикла
- Если Voice Wake включен и разрешения предоставлены, распознаватель wake-word должен слушать (кроме явного захвата push-to-talk).
- Видимость оверлея (включая ручное закрытие через кнопку X) никогда не должна препятствовать возобновлению распознавателя.
Режим отказа зависшего оверлея (предыдущий)
Ранее, если оверлей застревал видимым и вы закрывали его вручную, Voice Wake мог казаться "мертвым", потому что попытка перезапуска runtime могла быть заблокирована видимостью оверлея, и последующий перезапуск не планировался.
Укрепление:
- Перезапуск wake runtime больше не блокируется видимостью оверлея.
- Завершение закрытия оверлея вызывает VoiceWakeRuntime.refresh(...) через VoiceSessionCoordinator, поэтому ручное закрытие X всегда возобновляет прослушивание.
Специфика Push-to-talk
- Обнаружение горячей клавиши использует глобальный монитор .flagsChanged для правой клавиши Option (keyCode 61 + .option). Мы только наблюдаем события (без поглощения).
- Конвейер захвата находится в VoicePushToTalk: немедленно запускает речь, передает partials в оверлей и вызывает VoiceWakeForwarder при отпускании.
- Когда начинается push-to-talk, мы приостанавливаем wake-word runtime, чтобы избежать конкурирующих аудио-захватов; он автоматически перезапускается после отпускания.
- Разрешения: требуется Microphone + Speech; просмотр событий требует утверждения Accessibility/Input Monitoring.
- Внешние клавиатуры: некоторые могут не предоставлять правую клавишу Option, как ожидается — предложите резервную комбинацию клавиш, если пользователи сообщают о пропусках.
Пользовательские настройки
- Переключатель Voice Wake: включает wake-word runtime.
- Удерживайте Cmd+Fn для разговора: включает монитор push-to-talk. Отключено на macOS < 26.
- Выборщики языка и микрофона, живой измеритель уровня, таблица триггерных слов, тестер (только локально; не пересылает).
- Выбор микрофона сохраняет последний выбор, если устройство отключается, показывает подсказку об отключении и временно возвращается к системному по умолчанию, пока оно не вернется.
- Звуки: chimes при обнаружении триггера и при отправке; по умолчанию системный звук macOS "Glass". Вы можете выбрать любой файл, загружаемый NSSound (например, MP3/WAV/AIFF) для каждого события или выбрать Без звука.
Поведение пересылки
- Когда Voice Wake включен, транскрипты пересылаются активному шлюзу/агенту (тот же локальный или удаленный режим, используемый остальной частью приложения mac).
- Ответы доставляются последнему использованному основному провайдеру (WhatsApp/Telegram/Discord/WebChat). Если доставка не удается, ошибка регистрируется, и выполнение все еще видно через логи WebChat/сеанса.
Полезная нагрузка пересылки
- VoiceWakeForwarder.prefixedTranscript(_:) добавляет подсказку машины перед отправкой. Общий между путями wake-word и push-to-talk.
Быстрая проверка
- Включите push-to-talk, удерживайте Cmd+Fn, говорите, отпустите: оверлей должен показать partials, затем отправить.
- При удержании уши в строке меню должны оставаться увеличенными (использует triggerVoiceEars(ttl:nil)); они опускаются после отпускания.