AWS Polly
- polly란, Amazon에서 제공하는 TTS 서비스입니다.
- 생성된 음성을 S3 버킷에 저장할 수도 있고, 파일째로 다운받을 수도 있습니다.
- 별도 구축도 필요 없고, 단순히 Tool 정도로만 기능이 제공되고 있습니다.
- 그러나 제공되는 aws-sdk를 이용하면 이런 polly의 기능을 API 형태로 활용할 수 있게 되는데요, 오늘은 이를 이용해 다음과 같은 간단한 서비스(?)를 만들어 보려고 합니다.
- 클라이언트가 어떤 텍스트를 요청하면
- 람다가 작동해 Polly 서비스를 통해 TTS처리된 음성파일을 얻고
- 다시 람다는 해당 파일을 S3버킷에 저장한 뒤
- 클라이언트에게 그 파일을 재생시켜 준다.
- 물론 S3 버킷에 구지 저장 하지 않고, AudioStream을 바로 전달해서 클라이언트측에서 audio를 재생하도록 할 수도 있겠지만, 이것저것 연계해서 써보면서 배울 수 있는 점을 찾기 위해 S3에 파일을 저장하는 것 까지 넣어 보았습니다.
Polly 서비스 간단히 사용해 보기
- 먼저 Polly를 aws 웹상에서 간단히 사용해 보는 것 부터 시작하는 게 좋겠네요.
- 아래 polly 콘솔에 접속하여 간단히 TTS 프로그램을 이용해 봅시다.
- 요기
* Polly 요금제
5백만 자 무료
AWS 프리 티어를 12개월간 달마다 제공
- 일반 텍스트에 원하는 문자열을 입력하고
- 음성 듣기를 누르면 바로 재생이,
- MP3 다운로드를 누르면 말 그대로 다운로드가,
- S3에 합성 버튼을 누르면 mp3파일이 지정된 S3로 전송 됩니다.
Lambda 서비스를 활성화해 Polly API 호출해 보기
- Lambda 설정에 관한 좋은 블로그 글이 있어 소개 드릴게요
- 요기
- 간단히 람다 함수를 하나 생성한 뒤, 다음과 같이 작성해 봅니다
- 저는 javascript로 구성하였구요..
- 자세한 사용법에 대해서는 제 주석과 AWS 공식 문서를 참고해 주세요!
- 공식 문서는 요기
const AWS = require("aws-sdk");
AWS.config.update({ region: "ap-northeast-2" });
// Polly API를 사용하기 위한 객체 생성
var polly = new AWS.Polly();
// S3 API를 사용하기 위한 객체 생성
var s3 = new AWS.S3({
params: {
Bucket: "...", // 본인이 생성한 S3 버킷명을 입력해주세요.
},
});
exports.handler = (event, context, callback) => {
var pollyParams = {
OutputFormat: "mp3",
Text: "TEST", // polly가 읽게 될 문자열입니다.
TextType: "text",
VoiceId: "Seoyeon", // polly가 지원하는 성우(?) 종류 입니다.
};
polly.synthesizeSpeech(pollyParams, function (err, data) {
if (err) {
// Polly API 콜에 실패하는 경우, Lambda의 callback을 통해 처리합니다.
// 당연하게도 Polly API는 비동기로 진행 되며 3번째 인자인 callback 설정을 통해 처리할 수 있도록 되어 있습니다.
callback("polly failed: ", err);
} else {
var s3param = {
Key: "test.mp3",
ContentType: "audio/mpeg",
// polly.synthesizeSpeech의 결과로 떨어지는 data의 AudioStream key에 스트림이 담겨져 옵니다.
Body: data.AudioStream,
ACL: "public-read",
};
s3.putObject(s3param, function (err, data) {
// S3 API를 사용해 파일을 저장해 볼게요.
if (err) {
callback("s3 failed: ", err);
} else {
// 모두 성공한 경우 200 응답과 함께 OK 문자열을 전송합니다.
callback(null, {
statusCode: 200,
body: "OK",
});
}
});
}
});
};
- 위와 같은 람다를 구성한 뒤 실행하면
-
Seoyeon 님이 읽어주시는 “테스트” 라는 오디오파일(mp3)이 지정한 S3 버킷에 ‘test.mp3’ 라는 이름으로 저장되는 것을 확인 하실 수 있을 거에요.
- 저의 경우는 이때 조금 애먹었던게 AWS 서비스간의 권한 설정 부분이었는데, 테스트용 장난감이니 쿨하게 모든 권한을 오픈해 주었습니다.
- lambda - s3
- lambda - polly
- lambda - api gateway
TTS 변환할 문자를 동적으로 지정해 보자
- 여러 가지 방법이 있겠지만…
-
저는 람다에 연결된 API Gateway를 이용해 queryString으로 전달하기로 하였습니다.
- lambda가 실행될 때, 함수 파라미터로 들어오는
event
라는 객체가 뭔가 값이 들어 있을 것 같아 알아보니.. event.queryStringParameters
이라는 객체에 담겨 들어오는걸 알게 되었습니다.- 그렇다면 이제 동적으로 세팅할 수 있겠네요 !
- 기존 코드에서 poly API에 사용하는 파라미터 부분을 다음과 같이 수정해 줍니다.
let message = "지정된 문자가 없습니다.";
if (event.queryStringParameters && event.queryStringParameters.text) {
message = event.queryStringParameters.text;
}
var pollyParams = {
OutputFormat: "mp3",
Text: message,
TextType: "text",
VoiceId: "Seoyeon",
};
- 이제 동적으로 얻어낼 수 있겠군요 !
- 이왕이면 S3에 적재하는 파일명도 동적으로 생성하도록 리팩토링 해 봅시다
let itemName =
Math.floor(Math.random() * 100) + "_" + new Date().getTime() + ".mp3";
var s3param = {
Key: itemName,
ContentType: "audio/mpeg",
Body: data.AudioStream,
ACL: "public-read",
};
-
자, 이제 이 람다는 다음과 같은 작업을 수행합니다.
- gateway가 호출될 때 들어오는 querystring 파라미터중 ‘text’ 값을 얻습니다.
- 없는 경우는 ‘지정된 문자가 없습니다.’ 가 기본값이 되구요.
- 대상 문자열을 Polly의 synthesizeSpeech 기능을 사용해 Seoyeon님이 읽어주는 오디오 파일로 변환 합니다.
- 응답받은 AudioStream을 mp3 포맷으로 S3에 적재하는데,
- 그때 저장되는 파일명은 “랜덤정수_unixtime().mp3” 가 됩니다.
-
S3 버킷에 직접 접속해 확인해 보면, 요청을 줄 때마다 파일 하나가 생성되고, 실행시켜보면 text 파라미터로 전달했던 문자열을 읽어주고 있습니다.
이왕이면…
- 작업을 하다 보니 이왕이면 API Gateway를 호출하면 생성된 mp3파일을 바로 재생 시키면 더 재밌겠다는 생각이 들었습니다.
- 그래서 해 봤습니다.
- 이 때 새로 알게 된 사실이… http response에 status를 302로 주고,
-
헤더의 Location에 위치를 지정하면 브라우저에서 응답을 받음과 동시에 해당 위치로 redirect 하게 되더군요..
- s3버킷에 putObject함수의 성공 콜백을 다음과 같이 수정해 주었습니다.
callback(null, {
statusCode: 302,
headers: {
Location: `https://나의_s3_엔드포인트/${itemName}`,
},
body: "OK",
});
- callback 인자의 1번째 파라미터로는 에러가 들어가기 때문에 , 에러가 아니므로 null을 지정한 부분을 참고해주세요.
- 짜잔. 이제 이 람다를 배포하고 API gateway로 접근해보면 실제로 생성된 mp3 파일이 재생되는 모습을 볼 수 있습니다.
- 데모 서버를 띄워서 보여드리고 싶지만.. 직접 구현해 보는 즐거움을 뺏는 것 같아 별도로 제공하지는 않을게요!
무엇을 더 할 수 있을까?
- AWS에 있는 제품들을 이것저것 들여다보고 있으면 재밌는 것들이 참 많은데요.
- 이 Polly도 그 중 하나였던 것 같습니다.
-
그렇다면 이런 장난감 말고 이걸로 어떤 일들을 할 수 있을까 한번 생각 해 봤습니다.
- 비설치형 TTS 웹툴 제공 (은 이미 과포화 상태인것 같군요.)
- 언론사 등지에서 뉴스 내용을 간단히 읽어주는 TTS기능 도입 (웹 편의성 제공 목적)
- 챗봇 등에 적용해서 응답해주고자 하는 음성을 읽어주는 스트리밍 서비스 접목
- 등을 생각 해 보며 이만 글을 마쳐 보겠습니다…