macOS companion app
Голосовий оверлей
Життєвий цикл голосового накладання (macOS)
Аудиторія: контриб’ютори застосунку macOS. Мета: забезпечити передбачувану поведінку голосового накладання, коли фраза активації та режим «натисни й говори» перетинаються.
Поточний задум
- Якщо накладання вже видиме через фразу активації, а користувач натискає гарячу клавішу, сесія гарячої клавіші приймає наявний текст замість його скидання. Накладання залишається відкритим, доки гаряча клавіша утримується. Коли користувач відпускає її: надіслати, якщо є обрізаний текст, інакше закрити.
- Одна лише фраза активації досі автоматично надсилає після тиші; режим «натисни й говори» надсилає одразу після відпускання.
Реалізовано (9 грудня 2025 р.)
- Сесії накладання тепер мають токен для кожного захоплення (фраза активації або режим «натисни й говори»). Оновлення часткового/фінального тексту, надсилання, закриття та рівня відкидаються, коли токен не збігається, що запобігає застарілим callback.
- Режим «натисни й говори» приймає будь-який видимий текст накладання як префікс (тож натискання гарячої клавіші, поки накладання активації відкрите, зберігає текст і додає нове мовлення). Він очікує до 1,5 с на фінальну транскрипцію, перш ніж повернутися до поточного тексту.
- Журналювання сигналу/накладання виводиться на рівні
infoв категоріяхvoicewake.overlay,voicewake.pttіvoicewake.chime(початок сесії, частковий текст, фінальний текст, надсилання, закриття, причина сигналу).
Наступні кроки
- VoiceSessionCoordinator (actor)
- У кожен момент володіє рівно однією
VoiceSession. - API (на основі токенів):
beginWakeCapture,beginPushToTalk,updatePartial,endCapture,cancel,applyCooldown. - Відкидає callback із застарілими токенами (запобігає повторному відкриттю накладання старими розпізнавачами).
- У кожен момент володіє рівно однією
- VoiceSession (model)
- Поля:
token,source(wakeWord|pushToTalk), зафіксований/тимчасовий текст, прапорці сигналу, таймери (автоматичне надсилання, бездіяльність),overlayMode(display|editing|sending), крайній строк cooldown.
- Поля:
- Прив’язка накладання
VoiceSessionPublisher(ObservableObject) віддзеркалює активну сесію у SwiftUI.VoiceWakeOverlayViewрендериться лише через publisher; він ніколи не змінює глобальні singletons напряму.- Дії користувача в накладанні (
sendNow,dismiss,edit) викликають координатор із токеном сесії.
- Уніфікований шлях надсилання
- На
endCapture: якщо обрізаний текст порожній → закрити; інакшеperformSend(session:)(відтворює сигнал надсилання один раз, пересилає, закриває). - Режим «натисни й говори»: без затримки; фраза активації: необов’язкова затримка для автоматичного надсилання.
- Застосувати короткий cooldown до wake runtime після завершення режиму «натисни й говори», щоб фраза активації не запускалася повторно негайно.
- На
- Журналювання
- Координатор виводить журнали
.infoу subsystemai.openclaw, категоріяхvoicewake.overlayіvoicewake.chime. - Ключові події:
session_started,adopted_by_push_to_talk,partial,finalized,send,dismiss,cancel,cooldown.
- Координатор виводить журнали
Контрольний список налагодження
-
Потоково переглядайте журнали під час відтворення завислого накладання:
sudo log stream --predicate 'subsystem == "ai.openclaw" AND category CONTAINS "voicewake"' --level info --style compact -
Перевірте, що активний лише один токен сесії; застарілі callback має відкидати координатор.
-
Переконайтеся, що відпускання в режимі «натисни й говори» завжди викликає
endCaptureз активним токеном; якщо текст порожній, очікуйтеdismissбез сигналу чи надсилання.
Кроки міграції (запропоновано)
- Додати
VoiceSessionCoordinator,VoiceSessionіVoiceSessionPublisher. - Переробити
VoiceWakeRuntime, щоб створювати/оновлювати/завершувати сесії замість прямого звернення доVoiceWakeOverlayController. - Переробити
VoicePushToTalk, щоб приймати наявні сесії та викликатиendCaptureпісля відпускання; застосувати cooldown runtime. - Під’єднати
VoiceWakeOverlayControllerдо publisher; прибрати прямі виклики з runtime/PTT. - Додати інтеграційні тести для прийняття сесії, cooldown і закриття за порожнього тексту.