간단한 미니 프로젝트를 하면서 텍스트를 음성으로 출력하는 작업이 필요했는데 여러 TTS API 중 카카오의 API가 가장 자연스럽다고 판단하여 카카오 API를 사용하기로 결정했다. TTS API를 사용하여 오디오 파일을 받을 때 처음 겪어봐서 난감했던 상황을 해결하는 과정을 기록해보려고 한다.
우선 미니 프로젝트에서 API 사용 목적은 출력하고싶은 텍스트를 xml로 감싸서 API를 사용하여 xml 데이터를 보낸 후 오디오 파일을 받으면 그 파일을 재생시키는 것이 목적이었다.
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 문서에서 옵션을 찾아보았다.
역시나 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 라는 존재들을 이번에 알게 됐는데, 이것들이 어떤 개념인지 공부할 계획이다.