Skip to content

createSpeechRecognizer / isSpeechRecognitionSupported

Web Speech API의 SpeechRecognition을 감싼 것입니다. 소리의 바이트를 담는 AudioRecorder와 짝을 이루며, 이쪽은 플랫폼에 말을 글자로 바꿔 달라고 청합니다.

맨 API는 직접 건드리기보다 한 번 감싸 둘 값어치가 있습니다. 웹킷에서는 아직 접두사가 붙어 있고(webkitSpeechRecognition), lib.dom.d.ts에도 없으며, 별일 아닌 것들(말이 없는 사이, 코드가 부른 stop())을 마이크가 거부당했을 때와 같은 오류 통로로 알려 오기 때문입니다.

사용법

ts
import { createSpeechRecognizer } from 'ranuts/utils';

const mic = createSpeechRecognizer({
  lang: () => currentLocale(), // 한 번이 아니라 녹음할 때마다 새로 읽습니다
  onResult: (text, isFinal) => {
    input.value = text;
  },
  onError: (e) => {
    if (e.kind === 'denied') toast('마이크 사용이 거부되었습니다');
  },
  onStart: () => button.classList.add('recording'),
  onEnd: () => button.classList.remove('recording'),
});

if (!mic.supported) button.style.display = 'none'; // 마이크 버튼을 아예 감춥니다
button.addEventListener('click', () => mic.toggle());

API

isSpeechRecognitionSupported()

boolean을 돌려줍니다. 확인은 부를 때 하며 모듈을 불러올 때 갈무리해 두지 않으므로, 서버에서 그리는 동안 이 모듈을 가져다 두었다가 쪽이 하이드레이션된 뒤에 확인해도 안전합니다.

createSpeechRecognizer(options?)

다시 쓸 수 있는 SpeechRecognizer를 만듭니다. start()는 그때마다 맨 인식기 인스턴스를 새로 만들므로, 함수로 넘긴 옵션(특히 lang)은 만들 때 굳는 것이 아니라 녹음이 시작될 때마다 새로 읽힙니다.

매개변수(SpeechRecognizerOptions)

옵션설명타입기본값
langBCP 47 태그('en-US', 'zh-CN'), 또는 녹음이 시작될 때마다 읽히는 함수string | (() => string)''
continuous말이 끊겨도 처음에서 멈추지 않고 계속 듣습니다booleantrue
interimResults말하는 도중의 중간 결과도 내보냅니다booleantrue
onResult지금까지의 녹음 전체를 받아쓴 글과, 그것이 최종인지를 받아 불립니다(transcript: string, isFinal: boolean) => void-
onError갈래가 나뉜 오류를 받아 불립니다(error: SpeechError) => void-
onStart녹음이 시작될 때 발화합니다() => void-
onEnd녹음마다 한 번, 어떻게 끝났든 발화합니다(멈춤, 시간 초과, 오류)() => void-

SpeechRecognizer

멤버설명타입
supported플랫폼에 음성 인식이 없으면 false. 그때는 어느 메서드도 아무 일을 하지 않습니다boolean(게터)
active지금 녹음이 돌고 있는지boolean(게터)
start()녹음을 시작합니다. 이미 돌고 있으면 무시합니다() => void
stop()지금 녹음을 끝냅니다. 이미 알아들은 것은 남고, 이어서 onEnd가 옵니다() => void
abort()지금 녹음을 끝내고 아직 확정되지 않은 결과를 버립니다() => void
toggle()멎어 있으면 시작하고 돌고 있으면 멈춥니다. 마이크 버튼 하나가 바라는 바로 그 동작입니다() => void

SpeechError

필드설명타입
kind'denied'(마이크가 거부됨, 알릴 만함), 'noSpeech' / 'aborted'(흔한 일이라 대개 보일 것 없음), 'failed'(그 밖의 모든 것)SpeechErrorKind
detail플랫폼 이벤트가 지녔던 날것의 error 문자열string

참고

  1. 어디서나 되는 것은 아닙니다. 파이어폭스에는 SpeechRecognition 구현이 아예 없습니다. 생성자가 있으려니 여기지 말고, 마이크 단추를 보이기 전에 늘 recognizer.supported(또는 isSpeechRecognitionSupported())를 확인하세요.
  2. supportedactive는 게터라 손댈 때마다 다시 따집니다. 만들 때의 값을 붙들어 두지 않습니다. createSpeechRecognizer()window나 벤더 접두사 붙은 생성자보다 먼저 도는 경우(SSR, 하이드레이션 전 모듈 최상위에서의 이른 호출)에 이 점이 중요합니다. 인식기는 진짜 API가 나타나는 순간 그것을 집어 들 뿐, supported === false라고 말한 채 영영 굳지 않습니다.
  3. onResult가 주는 받아쓴 글은 쌓인 것입니다. 증분이 아닙니다. 지금까지의 녹음 전문이며, 중간 결과가 굳어 가면서 고쳐집니다. 직접 이어 붙이지 마세요.
  4. 맨 인식기를 만들거나 그 start()를 부르면 동기로 예외가 날 수 있습니다(Permissions-Policy 제약이나, 이미 녹음이 돌고 있을 때 크롬이 내는 InvalidStateError 따위). createSpeechRecognizer는 이것을 잡아 밖으로 내보내지 않고 onErroronEnd로 알립니다.

MIT 라이선스로 배포됩니다.