Voice Wake & Push-to-Talk

모드

  • 웨이크 워드 모드 (기본값): 항상 켜져 있는 Speech recognizer가 트리거 토큰 (swabbleTriggerWords)을 대기합니다. 일치 시 캡처를 시작하고 부분 텍스트와 함께 오버레이를 표시하며 침묵 후 자동 전송합니다.
  • Push-to-talk (Right Option 홀드): 오른쪽 Option 키를 눌러 즉시 캡처—트리거 불필요. 누르고 있는 동안 오버레이가 나타남; 릴리스하면 짧은 지연 후 완료 및 포워드하여 텍스트를 조정할 수 있습니다.

런타임 동작 (웨이크 워드)

  • Speech recognizer는 VoiceWakeRuntime에 있습니다.
  • 트리거는 웨이크 워드와 다음 단어 사이에 의미 있는 일시 중지가 있을 때만 실행됩니다 (~0.55초 간격). 명령이 시작되기 전에도 일시 중지 시 오버레이/chime이 시작될 수 있습니다.
  • 침묵 창: 음성이 흐를 때 2.0초, 트리거만 들렸을 때 5.0초.
  • 하드 스톱: 폭주 세션을 방지하기 위해 120초.
  • 세션 간 디바운스: 350ms.
  • 오버레이는 커밋된/휘발성 색상과 함께 VoiceWakeOverlayController를 통해 구동됩니다.
  • 전송 후, recognizer는 다음 트리거를 듣기 위해 깔끔하게 재시작합니다.

라이프사이클 불변성

  • Voice Wake가 활성화되고 권한이 부여되면, 웨이크 워드 recognizer가 듣고 있어야 합니다 (명시적 push-to-talk 캡처 중 제외).
  • 오버레이 가시성 (X 버튼을 통한 수동 취소 포함)은 recognizer가 재개되는 것을 절대 방지해서는 안 됩니다.

고착된 오버레이 실패 모드 (이전)

이전에는 오버레이가 표시된 상태로 고착되고 수동으로 닫으면, 런타임의 재시작 시도가 오버레이 가시성에 의해 차단되고 후속 재시작이 예약되지 않아 Voice Wake가 "죽은" 것처럼 보일 수 있었습니다.

강화:

  • Wake 런타임 재시작은 더 이상 오버레이 가시성에 의해 차단되지 않습니다.
  • 오버레이 취소 완료는 VoiceSessionCoordinator를 통해 VoiceWakeRuntime.refresh(...)를 트리거하므로, 수동 X-취소는 항상 듣기를 재개합니다.

Push-to-talk 특수성

  • 핫키 감지는 오른쪽 Option (keyCode 61 + .option)을 위한 전역 .flagsChanged 모니터를 사용합니다. 이벤트만 관찰합니다 (삼키지 않음).
  • 캡처 파이프라인은 VoicePushToTalk에 있습니다: 즉시 Speech를 시작하고, 오버레이로 partials를 스트리밍하며, 릴리스 시 VoiceWakeForwarder를 호출합니다.
  • Push-to-talk이 시작되면 웨이크 워드 런타임을 일시 중지하여 오디오 탭이 충돌하지 않도록 합니다; 릴리스 후 자동으로 재시작합니다.
  • 권한: Microphone + Speech 필요; 이벤트 보기에는 Accessibility/Input Monitoring 승인 필요.
  • 외부 키보드: 일부는 예상대로 오른쪽 Option을 노출하지 않을 수 있음—사용자가 누락을 보고하면 폴백 단축키 제공.

사용자 대면 설정

  • Voice Wake 토글: 웨이크 워드 런타임 활성화.
  • Hold Cmd+Fn to talk: push-to-talk 모니터 활성화. macOS < 26에서 비활성화.
  • 언어 및 마이크 선택기, 라이브 레벨 미터, 트리거 워드 테이블, 테스터 (로컬 전용; 포워드하지 않음).
  • 마이크 선택기는 디바이스가 연결 해제되면 마지막 선택을 보존하고, 연결 해제 힌트를 표시하며, 반환될 때까지 일시적으로 시스템 기본값으로 폴백합니다.
  • 소리: 트리거 감지 및 전송 시 chimes; 기본값은 macOS "Glass" 시스템 소리. 각 이벤트에 대해 NSSound-로드 가능한 파일 (예: MP3/WAV/AIFF)을 선택하거나 No Sound를 선택할 수 있습니다.

포워딩 동작

  • Voice Wake가 활성화되면, transcript가 활성 gateway/agent로 포워딩됩니다 (mac 앱의 나머지 부분에서 사용되는 동일한 로컬 vs 원격 모드).
  • 답장은 마지막으로 사용된 main provider (WhatsApp/Telegram/Discord/WebChat)로 전달됩니다. 전달이 실패하면 오류가 로그되고 실행은 여전히 WebChat/세션 로그를 통해 표시됩니다.

포워딩 페이로드

  • VoiceWakeForwarder.prefixedTranscript(_:)는 전송 전에 머신 힌트를 앞에 추가합니다. 웨이크 워드와 push-to-talk 경로 간에 공유됩니다.

빠른 검증

  • Push-to-talk을 켜고, Cmd+Fn을 누르고, 말하고, 릴리스: 오버레이가 partials를 표시한 다음 전송해야 합니다.
  • 누르고 있는 동안, 메뉴 바 귀가 확대된 상태로 유지되어야 합니다 (triggerVoiceEars(ttl:nil) 사용); 릴리스 후 떨어집니다.