개요 · 범위
3계층 STT 중 최후 폴백. OpenAI Realtime 내장 전사·External STT(#4/#9)가 결과를 못 줄 때 브라우저 네이티브 Web Speech API(SpeechRecognition, ko-KR)로 아동 발화를 텍스트화해 핑퐁이에 입력한다.
세션 매니저(#1)가 구동: fallbackTranscriptionEnabled일 때 활성. 전사 결과는 onTranscription → sendMessage(transcript)로 텍스트 입력 전송. 데이터채널 이벤트(speech_started/output_audio_buffer)에 맞춰 start/stop이 토글된다.
SpeechRecognition 설정 initializeSpeechRecognition L36
recognition.continuous = true;
recognition.interimResults = true; // 중간 결과로 빠른 처리
recognition.lang = "ko-KR";
recognition.maxAlternatives = 3; // 다중 후보 중 최고 confidence 선택
// 가능 시 Google Speech API serviceURI 선호
미지원 브라우저(webkitSpeechRecognition/SpeechRecognition 둘 다 없음)면 null 반환 → 폴백 비활성.
결과 처리 setupSpeechRecognition onresult L95
- final 결과: 최대 3개 alternative 중 최고 confidence 선택 →
handleFallbackTranscription.
- interim 결과: 최신 interim을 보관하고 1500ms 타임아웃 설정 → 그 안에 final이 안 오면 best interim을 결과로 사용(빠른 응답성 ↔ 정확성 타협).
- final 도착 시 pending interim 타임아웃 취소.
전사 게이트 (에코 방지) handleFallbackTranscription L65
아래 조건을 모두 통과해야만 전사를 내보낸다:
audioInputEnabled && sessionActive && enabled
&& !isUserTalking && !isPeerTalking
&& recognitionId === currentRecognitionId
- !isPeerTalking: 핑퐁이 발화 중에는 막아 AI 음성이 마이크로 들어가 전사되는 에코를 차단. 세션 매니저가 output_audio_buffer 이벤트에 맞춰 start/stop도 한다(#1).
- recognitionId 매칭: start마다 id 증가. stop 시 0으로 무효화 → 옛 인식 인스턴스의 stale 타임아웃/결과가 새 세션에 끼어드는 것 방지.
생명주기 · 에러 start/stop/onend/onerror
- start: enabled+audioInputEnabled일 때만. 새 recognitionId 발급 → 인스턴스 생성·setup·start.
- onend 자동 재시작: continuous가 끊기면(브라우저가 주기적으로 종료) session/enabled/audioInput 활성 시 100ms 후 재시작.
- stop: recognition.stop + id=0 무효화 + interim 타임아웃 정리.
- onerror: no-speech/audio-capture/network는 일시 오류(무시), not-allowed/service-not-allowed는 권한 거부 로깅, aborted는 의도적 정지(재시작 안 함), 그 외 unknown은 안전상 폴백 비활성.
함정 · 주의
- 폴백은 보조: 정확도·언어 지원이 External STT/OpenAI보다 낮다. 주 경로가 동작하면 쓰지 않는다.
- recognitionId 무효화 필수: stop 시 id=0으로 안 바꾸면 옛 interim 타임아웃 결과가 새 발화에 섞임.
- isPeerTalking 게이트: 빠지면 AI 음성이 폴백으로 다시 전사되는 에코 루프. 세션 매니저의 start/stop 토글과 이중 방어.
- 브라우저 의존: Web Speech API 미지원(일부 인앱 브라우저)이면 폴백 자체가 없음 → 주 경로 장애 시 무전사.
- onend 재시작 루프: 조건(session/enabled/audioInput)이 잘못 유지되면 stop 후에도 재시작될 수 있음 → updateEnabled(false)가 stop을 호출하는 구조에 의존.
파일 · 라인 레퍼런스
| 파일/심볼 | 역할 |
| use-stt-fallback.ts | Web Speech API 래퍼 |
| initializeSpeechRecognition (L36) | 설정·미지원 가드 |
| setupSpeechRecognition (L91) / handleFallbackTranscription (L65) | 결과 처리·게이트 |
| use-session-manager.ts (sttFallback) | 구동·start/stop 토글 |