카카오 TTS API 사용하기(Javascript)

chaeruru·2021년 11월 6일
0

간단한 미니 프로젝트를 하면서 텍스트를 음성으로 출력하는 작업이 필요했는데 여러 TTS API 중 카카오의 API가 가장 자연스럽다고 판단하여 카카오 API를 사용하기로 결정했다. TTS API를 사용하여 오디오 파일을 받을 때 처음 겪어봐서 난감했던 상황을 해결하는 과정을 기록해보려고 한다.

API 사용하기

우선 미니 프로젝트에서 API 사용 목적은 출력하고싶은 텍스트를 xml로 감싸서 API를 사용하여 xml 데이터를 보낸 후 오디오 파일을 받으면 그 파일을 재생시키는 것이 목적이었다.

Kakao Developers

import axios from 'axios';

window.addEventListener('DOMContentLoaded', async () => {
  const xmlData = '<speak>테스트해보기.</speak>';
  try {
    const { data } = await axios.post('https://kakaoi-newtone-openapi.kakao.com/v1/synthesize', xmlData, {
      headers: {
        'Content-Type': 'application/xml',
        Authorization: `KakaoAK ${API_KEY}`,
      },
    });
    console.log(data);
  } catch (e) {
    console.error(e.message);
  }
});

위의 문서에 나와있는대로 요청을 보내보았다.

받은 data를 콘솔로 확인해보니 난해한 문자들이 있어서 당황스러웠다.

그래서 바로 data를 확인하지 않고 받은 응답을 먼저 확인해보았다.

데이터가 깨져있어서 어떻게 진행해야할 지 막막하던 찰나에

headers에 content-type으로 audio/mpeg인 것을 확인한 후 Audio MDN을 찾아 보았다.

Audio and Video Delivery - Developer guides | MDN

let context;
  let request;
  let source;

  try {
    context = new AudioContext();
    request = new XMLHttpRequest();
    request.open("GET","http://jplayer.org/audio/mp3/RioMez-01-Sleep_together.mp3",true);
    request.responseType = "arraybuffer";

    request.onload = function() {
      context.decodeAudioData(request.response, function(buffer) {
        source = context.createBufferSource();
        source.buffer = buffer;
        source.connect(context.destination);
        // auto play
        source.start(0); // start was previously noteOn
      });
    };

    request.send();

  } catch(e) {
    alert('web audio api not supported');
  }

위의 코드는 Audio MDN에 있는 코드로 요청을 보내서 audio 파일을 받고 재생하는 예제이다.

내가 원하던 상황과 비슷하다고 판단했고 여기서 주의 깊게 본 부분은 request.responseType = "arraybuffer" 였다.

그럼 나도 요청에 대한 응답을 arraybuffer로 받으면 되겠다 싶어서 axios npm 문서에서 옵션을 찾아보았다.

axios

역시나 responseType 이 있었고 그중에서 arraybuffer 또한 있었다.

const { data } = await axios.post('https://kakaoi-newtone-openapi.kakao.com/v1/synthesize', xmlData, {
	 headers: {
	   'Content-Type': 'application/xml',
			Authorization: `KakaoAK ${API_KEY}`,
   },
   responseType: 'arraybuffer',
});

따라서 다음과 같이 responseType: 'arraybuffer' 을 추가하고 다시 data를 확인해보았다.

이상한 문자가 나오던 아까와 다르게 arraybuffer 형태로 나오는 것을 볼 수 있다.

이제 arraybuffer를 얻었으니 마지막으로 재생만 남았다. 재생은 아까 MDN에 있는 코드를 그대로 활용하였다.

const { data } = await axios.post('https://kakaoi-newtone-openapi.kakao.com/v1/synthesize', xmlData, {
	 headers: {
	   'Content-Type': 'application/xml',
			Authorization: `KakaoAK ${API_KEY}`,
   },
   responseType: 'arraybuffer',
});

const context = new AudioContext();
context.decodeAudioData(data, buffer => {
	const source = context.createBufferSource();
  source.buffer = buffer;
  source.connect(context.destination);
  source.start(0);
});

드디어 성공적으로 목소리가 출력되었다

최종 코드

import axios from 'axios';

window.addEventListener('DOMContentLoaded', async () => {
  const xmlData = '<speak>테스트해보기.</speak>';
  try {
    const { data } = await axios.post('https://kakaoi-newtone-openapi.kakao.com/v1/synthesize', xmlData, {
      headers: {
        'Content-Type': 'application/xml',
        Authorization: `KakaoAK ${API_KEY}`,
      },
      responseType: 'arraybuffer',
    });
    const context = new AudioContext();
    context.decodeAudioData(data, buffer => {
      const source = context.createBufferSource();
      source.buffer = buffer;
      source.connect(context.destination);
      source.start(0);
    });
  } catch (e) {
    console.error(e.message);
  }
});

마무리

이번 경험을 통해서 음성 파일을 받았을 때 어떻게 다룰지 알게 됐고, 추가로 arraybuffer나 blob, stream 라는 존재들을 이번에 알게 됐는데, 이것들이 어떤 개념인지 공부할 계획이다.

profile
알고리즘과 프론트엔드 부셔버리기

0개의 댓글