useCodeusecode logo

음성인식 API(Web Speech API) - 나만의 시리를 만들 수 있을까?

March 11, 2018

음성인식 API에 대해서 이미 알고 있으시면 가볍게 건너뛰셔도 됩니다. ^^;

브라우저에는 우리가 기본적으로 많이 사용하는 API(geolocation, Web Notification 등등)이외에도 아주 다양한 API들이 존재합니다. 이러한 API는 표준으로 등록 되서 모든 브라우저에서 공통으로 제공하는 API뿐만 아니라 아직 표준으로 등록되지 않은 드래프트 상태의 API까지 다양합니다.

오늘은 그중에서 웹 음성인식 API(Web Speech API)에 대해서 알아보도록 하겠습니다.

이 글을 설명하기 위해 간단한 데모를 만들었으니, 관심이 있다면 아래에서 확인해보세요.

데모: https://fresh-web.github.io/web-speech/

소스: https://github.com/fresh-web/web-speech

모질라 예제 소스: https://github.com/mdn/web-speech-api/

음성인식 API(Web Speech API)는 크게 SpeechSynthesis (Text-to-Speech)와 SpeechRecognition (Asynchronous Speech Recognition) 두 가지로 나뉩니다.

SpeechSynthesis는 텍스트를 음성으로 변환하는 API이고, SpeechRecognition은 음성을 텍스트로 변환하는 API입니다.

SpeechSynthesis의 경우 IE를 제외한 대부분의 모던 브라우저에서는 지원되지만 SpeechRecognition은 현재 메이저 브라우저에선 크롬만 지원됩니다.

노트: 크롬에서 음성인식 API는 서버 엔진을 통해서 제공되기 때문에 오프라인에서는 지원되지 않습니다.

브라우저 지원 현황: https://caniuse.com/#search=speech

Web Speech API Spec: https://w3c.github.io/speech-api/speechapi.html

사실 SpeechRecognition API의 경우 구글 크롬에선 추가된 지 오래되었지만 아직 드래프트 단계입니다.

이번 시간에는 SpeechSynthesis와 SpeechRecognition 중에 SpeechRecognition API에 대해 구체적으로 알아보도록 하겠습니다.

SpeechRecognition 인터페이스는 프로퍼티(Properties), 메소드(Methods), 이벤트 핸들러(Event handlers) 총 부분으로 구성되어 있습니다.

먼저, SpeechRecognition의 프로퍼티는 총 6개가 있습니다.

  • grammars: 현재 SpeechRecognition에서 인식할 문법을 나타내는 SpeechGrammar 객체의 컬렉션을 가져오거나 설정합니다.
  • lang: 현재 언어를 세팅하거나 가져온다. 값이 없다면 html의 lang 속성 또는 user-agent의 언어 값으로 매칭됩니다.
  • continuous: 음성을 인식 될 때 마다 결과를 받을 것인지, 아니면 한 개의 결과만 받을 것인지를 설정 할 수 있습니다. 기본값은 false 입니다.
  • interimResults: 아직 끝나지 않은 상태의 음성을 받을 것인지 아닌지를 설정한다. 기본값은 false 입니다.
  • maxAlternatives: 가능성 있는 음성인식의 값을 최대 몇 개까지 받을 것인지를 설정한다. 기본값은 1 입니다.
  • serviceURI: 음성인식 서비스를 기본 내장 서비스가 아닌 다른 서비스를 이용하여 받고 싶을 때 설정하는 값입니다.

메서드는 3가지가 있습니다.

  • start(): 음성인식을 시작합니다.
  • stop(): 음성인식을 멈춥니다. SpeechRecognitionResult 객체가 event 객체에 포함되서 리턴됩니다.
  • abort(): 음성인식을 중단합니다. 음성인식을 중단하면 SpeechRecognitionResult 객체가 리턴되지 않습니다.

이벤트 핸들러는 총 11개가 있는데, 핸들러 이름만 봐도 어떤 역할을 하는지 이해가 될 거로 생각해서 모두 설명하지는 않고, onresult, onnomatch와 onerror에 대해서만 설명하도록 하겠습니다.

  • onaudiostart
  • onsoundstart
  • onspeechstart
  • onsoundend
  • onaudioend
  • onresult
  • onnomatch
  • onerror
  • onstart
  • onend

onresult

음성인식 서비스가 결과를 리턴하면 실행되는 이벤트입니다. 리턴되는 값은 EventTarget 객체 인데, 이 객체의 results 속성으로 SpeechRecognitionResultList 객체가 들어있고, 이 객체 안에는 다시 SpeechRecognitionResult 객체가 배열 같은 형태로 들어 있습니다. 그래서 음성을 인식하여 text로 변환된 값은 event.results[0][0] 이런 식으로 접근하여 값을 가져올 수 있습니다. 예제를 보면 더 명확하게 이해가 될 것입니다.

this.recognition.onresult = event => {
  const text = event.results[0][0].transcript;

  console.log('transcript', text); // text 변수에 인식된 음성을 text 형태로 변환한 문자가 들어있다.
};

당연히 리턴된 값이 객체이기 때문에 transcript 이외에도 다른 값들도 포함되어 있습니다.

SpeechRecognitionResult의 객체 형태 예제:

{
  {transcript: "텍스트", confidence: 0.8404663801193237},
  isFinal:true
  length:1
}

onerror

음성인식이 되지 않고 error를 뱉으면 실행되는 이벤트입니다. EventTarget 객체의 error 속성값은 아래와 같습니다.

  • no-speech
  • aborted
  • audio-capture
  • network
  • service-not-allowed
  • bad-grammar
  • language-not-supported

onnomatch

음성 인식 서비스가 제대로 된 인식 없이 최종 결과를 반환하면 실행됩니다. confidence 값이 낮을 때 발생 할 수 있습니다.

만들어보기

자, 기본적인 api의 정의와 사용법을 알았으니, 샘플 코드를 만들어보겠습니다. 이번 예제는 간단하게 버튼을 눌러서 음성인식을 시작하고, 이벤트 핸들러가 호출되면 그 값을 화면에 보여주는 간단한 예제를 만들어 보겠습니다. (예제는 리액트로 만들었는데, 리액트와는 전혀 상관이 없습니다. 간단한 소스이기 때문에 리액트를 모르더라도 충분히 이해 할 수 있을 것이다. 아래의 예제소스는 여기에서도 확인 할 수 있다.)

먼저 SpeechRecognition 인터페이스를 초기화합니다.

const Recognition = window.SpeechRecognition || window.webkitSpeechRecognition;

if (!Recognition) {
  alert('Speech Recognition API is not supported in this browser, try chrome');
  return;
}

this.recognition = new Recognition();

한국어를 인식할 수 있도록 언어(lang) 속성값을 한국어로 지정해준다.

this.recognition.lang = 'ko-KR';

이벤트 핸들러를 등록해서 호출되는 이벤트에 따라 테스트를 화면에 노출하도록 합니다.

this.recognition.onresult = event => {
  const text = event.results[0][0].transcript;
  console.log('transcript', text);
  this.setState({ text });
};

this.recognition.onspeechend = () => {
  console.log('stopped');
  this.setState({ show: true });
};

this.recognition.onnomatch = event => {
  console.log('no match');
  this.setState({ text: "Sorry, can't hear" });
};

this.recognition.onstart = () => {
  this.setState({
    listening: true,
  });
};

this.recognition.onend = () => {
  console.log('end');
  this.setState({
    listening: false,
  });
  this.end();
};

this.recognition.onerror = event => {
  console.log('error', event);
  this.setState({
    show: true,
    text: event.error,
  });
};

이벤트를 등록하고 리턴된 결과값이 있으면 그 텍스트를 화면에 뿌려줍니다.

<main className="demo-1">
  {this.state.show ? (
    <Word text={this.state.text} onClose={this.handleClose} />
  ) : (
    <ListenerButton
      onStart={this.start}
      onEnd={this.end}
      disabled={this.state.listening}
      buttonText={this.state.listening ? 'Listening...' : 'Click me to listen'}
    />
  )}
</main>

Web Speech API에 대해서 알아봤습니다. 아직 당연히 드래프트 상태이고, 브라우저 지원도 크롬만 되지만 이러한 API가 정식으로 표준 API로 등록된다면, 이런 API를 활용해서 앱에서만 가능했던 음성 챗봇이라든지, 정말 시리(Siri) 같은 것들을 브라우저에서 볼 수 있지 않을까 상상해봅니다.

참조:

https://davidwalsh.name/speech-recognition

https://w3c.github.io/speech-api/speechapi.html

https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition