Amazon Translate
개발자 안내서

Amazon Translate를 사용하여 채팅 채널 번역

채팅 메시지의 실시간 번역에 Amazon Translate를 사용할 수 있습니다. 이 예제는 Twitch 채널을 사용하지만, 이 예제를 다른 채팅 플랫폼, 고객 서비스 상호 작용, 게시판 등과 같은 실시간 스트리밍 텍스트 번역을 위한 시작점으로 활용할 수 있습니다.

이 예제는 실시간 영어 메시지와 실시간 번역을 나란히 보여 주는 웹 페이지를 사용합니다. Amazon Polly로 메시지를 보내서 텍스트를 음성으로 재생할 수 있습니다. 채팅 중인 사람의 말을 이해하려면 그 사람의 사용자 이름을 입력합니다. 그러면 그 사용자의 메시지만 음성으로 재생됩니다.

다음과 같이 코드를 요약할 수 있습니다.

  • 웹 페이지를 만들기 위한 CSS 및 HTML.

  • Amazon Translate 및 Amazon Polly에 대한 컨트롤러를 만드는 초기화 코드.

  • 채팅 메시지를 받으면 실행되는 콜백 함수.

  • 채팅 메시지를 보내는 함수.

  • Amazon Translate를 호출하여 메시지를 번역하는 함수.

  • Amazon Polly를 호출하여 음성을 합성하는 함수.

  • 웹 페이지를 관리하기 위한 유틸리티 함수.

예제를 구성하려면

  1. AWS SDK for JavaScript를 설치하고 구성합니다. SDK for JavaScript 설치 지침은 JavaScript용 SDK 설치를 참조하십시오.

  2. 예제 코드를 복사하여 웹 서버의 HTML 파일에 붙여 넣습니다.

  3. SDK for JavaScript를 설치한 위치로 <script> 태그를 업데이트합니다.

  4. 리전과 엔드포인트를 Amazon Translate 및 Amazon Polly 작업을 실행하려는 리전으로 변경합니다. Amazon Translate을 지원하는 리전의 목록은 지침 및 제한 사항 단원을 참조하십시오. Amazon Polly를 지원하는 리전의 목록은 Amazon Web Services 일반 참조AWS 리전 및 엔드포인트를 참조하십시오.

  5. 이 예제를 실행하는 데 필요한 최소한의 권한을 갖는 IAM 사용자를 만듭니다. IAM 사용자 생성에 대한 자세한 내용은 AWS Identity and Access Management 사용 설명서AWS 계정에서 IAM 사용자 생성을 참조하십시오. 필요한 권한 정책은 Amazon Translate에 대한 자격 증명 기반 정책(IAM 정책) 사용 단원과 Amazon Polly 개발자 안내서Amazon Polly에서 ID 기반 정책(IAM 정책) 사용 단원을 참조하십시오.

  6. 이전 단계에서 만든 IAM 사용자의 액세스 ID와 비밀 키를 제공합니다.

  7. 해당 계정의 Twitch 사용자 이름과 OAuth 토큰을 제공합니다. Twitch 계정은 https://www.twitch.tv에서 만들 수 있습니다. Twitch OAuth 토큰은 https://twitchapps.com/tmi에서 만들 수 있습니다.

<!doctype html> <html lang="en"> <head> <title>Amazon Translate</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Latest compiled and minified CSS for Bootstrap --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <!-- Custom CSS --> <style> .topHeader { background-color: #6441a4; padding: 10px; border-bottom: solid 1px #cacaca; color: white } .panelHeading { background-color: #6441a4 !important; } .panelBody { min-height: 450px; max-height: 450px;overflow-y: scroll; } body{ margin-left: 0px; margin-right: 0px; height: 100%; } </style> </head> <body> <div class="container-fluid"> <!--Top Header--> <div class="row topHeader"> <div class="col-md-12"> <h4>Amazon Translate - Artificial Intelligence on AWS - Powerful machine learning for all Developers and Data Scientists</h4> </div> </div> <!--Status Label--> <div class="row"> <div class="col-md-12"> <p class="bg-info"> <div id="connecting-div"></div> </p> </div> </div> <div class="row" style="padding: 10px;"> <div class="col-md-6"> <div class="form-inline"> <div class="form-group"> <input type="text" id="channel" class="form-control" value="" placeholder="Channel"/> </div> <div class="form-group"> <select id="sourceLanguage" class="form-control"> <option value="en">en</option> <option value="ar">ar</option> <option value="de" selected="selected">de</option> <option value="es">es</option> <option value="fr">fr</option> <option value="pt">pt</option> <option value="zh">zh</option> </select> </div> <div class="form-group"> <select id="targetLanguage" class="form-control"> <option value="en" selected="selected">en</option> <option value="ar">ar</option> <option value="de">de</option> <option value="es">es</option> <option value="fr">fr</option> <option value="pt">pt</option> <option value="zh">zh</option> </select> </div> <div class="form-group"> <button type="button" class="form-control" id="btn-go" onclick="connect()">Go</button> <button type="button" class="form-control" id="btn-stop" onclick="location.href='index.html';">Stop</button> <span id="status"></span> </div> </div> </div> <div class="col-md-6"> <div class="form-inline"> <div class="form-group"> <input type="checkbox" id="cbSpeak" value="Speak"> Speak Live Translation <input type="text" id="follow" class="form-control" value="" placeholder="follow"/> </div> </div> </div> </div> <!--Chat Boxes--> <div class="row"> <!--Live Chat--> <div class="col-md-6"> <div class="panel panel-primary"> <div class="panel-heading panelHeading">Live Chat</div> <div id="livechatc" class="panel-body panelBody"> <div class="subscribe" id="livechat"></div> </div> </div> </div> <!--Live Chat--> <!--Translated Chat--> <div class="col-md-6"> <div class="panel panel-primary"> <div class="panel-heading panelHeading">Live Translation</div> <div id="livetranslationc" class="panel-body panelBody"> <div class="imageDetected" id="livetranslation"></div> </div> </div> </div> <!--Translated Chat--> </div> <!--Send Message--> <div class="row"> <div class="col-md-11"> <input type="text" id="message" class="form-control"/> </div> <div class=" col-md-1"> <button type="button" class="form-control btn btn-default" id="btn-send" onclick="sendMessage()">Send</button> </div> </div> </div> <!-- Latest compiled and minified JavaScript --> <!-- jQuery first, then Bootstrap JS --> <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> <script src="aws-js-sdk/dist/aws-sdk-all.js"></script> <script src="http://cdn.tmijs.org/js/1.2.1/tmi.min.js" integrity="sha384-eE0n7sm1W7DOUI2Xh5I4qSpZTe6hupAO0ovLfqEy0yVJtGRBNfssdmjbJhEYm6Bw" crossorigin="anonymous"></script> <script> cred = { twitchUsername: "Twitch user name", twitchOAuthToken: "Twitch OAuth token", awsAccessKeyId: "access key", awsSecretAccessKey: "secret key" }; AWS.config.region = 'region'; ep = new AWS.Endpoint('endpoint'); AWS.config.credentials = new AWS.Credentials(cred.awsAccessKeyId, cred.awsSecretAccessKey); window.translator = new AWS.Translate({endpoint: ep, region: AWS.config.region}); /**************************Init and Connect to Chat****************************/ function connect(){ init(); //Twitch Client var options = { options: { debug: false }, connection: { cluster: "aws", reconnect: true }, identity: { username: cred.twitchUsername, password: cred.twitchOAuthToken }, channels: [con.channel] }; window.client = tmi.client(options); window.client.connect(); //Attached Handlers window.client.on("chat", onChat); window.client.on("connecting", onConnecting); window.client.on("connected", onConnected); //Disable UI Elements document.getElementById("sourceLanguage").disabled = true; document.getElementById("targetLanguage").disabled = true; document.getElementById("channel").disabled = true; document.getElementById("btn-go").disabled = true; } function init(){ //Get UI Controls var lc = document.getElementById("livechat"); var lt = document.getElementById("livetranslation") var lcc = document.getElementById("livechatc"); var ltc = document.getElementById("livetranslationc") var cbspeak = document.getElementById("cbSpeak") var follow = document.getElementById("follow"); var sendMessage = document.getElementById("message"); //Cache values con = { channel: document.getElementById("channel").value, sourceLanguage: document.getElementById("sourceLanguage").value, targetLanguage: document.getElementById("targetLanguage").value, liveChatUI: lc, liveTranslationUI: lt, liveChatUIContainer: lcc, liveTranslationUIContainer: ltc, cbSpeak: cbspeak, follow: follow, sendMessage: sendMessage } lc.innerHTML = ''; lt.innerHTML = ''; //Speaker var voiceId = "Joanna"; if(con.targetLanguage == "en") voiceId = "Joanna"; else if(con.targetLanguage == "de") voiceId = "Marlene"; else if(con.targetLanguage == "es") voiceId = "Conchita"; else if(con.targetLanguage == "fr") voiceId = "Celine"; else if(con.targetLanguage == "pt") voiceId = "Ines"; else voiceId = "Joanna"; window.audioPlayer = AudioPlayer(voiceId); } /**************************Init and Connect to Chat****************************/ /**************************Receive and Translate Chat****************************/ function onChat (channel, userstate, message, self) { // Don't listen to my own messages.. if (self) return; //Translate if (message) { var username = userstate['username']; var params = { Text: message, SourceLanguageCode: con.sourceLanguage, TargetLanguageCode: con.targetLanguage }; window.translator.translateText(params, function onIncomingMessageTranslate(err, data) { if (err) { console.log("Error calling Translate. " + err.message + err.stack); } if (data) { console.log("M: " + message); console.log("T: " + data.TranslatedText); //Print original message in chat UI con.liveChatUI.innerHTML += '<strong>' + username + '</strong>: ' + message + '<br>'; //Print translation in translation UI con.liveTranslationUI.innerHTML += '<strong>' + username + '</strong>: ' + data.TranslatedText + '<br>'; //If speak translation in enabled, speak translated message if(con.cbSpeak.checked){ if(con.follow.value == "" || username == con.follow.value) audioPlayer.Speak(username + " says " + data.TranslatedText); } //Scroll chat and translated UI to bottom to keep focus on latest messages con.liveChatUIContainer.scrollTop = con.liveChatUIContainer.scrollHeight; con.liveTranslationUIContainer.scrollTop = con.liveTranslationUIContainer.scrollHeight; } }); } } /**************************Receive and Translate Chat****************************/ /**************************Client Connecting****************************/ function onConnecting (address, port) { document.getElementById("status").innerHTML = " [ Connecting...]" } function onConnected (address, port) { document.getElementById("status").innerHTML = " [ Connected ]" window.audioPlayer.Speak("Connected to channel " + con.channel + ". You should now be getting live chat messages."); } /**************************Client Connecting****************************/ /**************************Send Message****************************/ function sendMessage(){ if(con.sendMessage.value){ message = con.sendMessage.value; var params = { Text: con.sendMessage.value, SourceLanguageCode: con.targetLanguage, TargetLanguageCode: con.sourceLanguage }; window.translator.translateText(params, function onSendMessageTranslate(err, data) { if (err) { console.log("Error calling Translate. " + err.message + err.stack); } if (data) { console.log("M: " + message); console.log("T: " + data.TranslatedText); //Send message to chat window.client.action(con.channel, data.TranslatedText); //Clear send message UI con.sendMessage.value = ""; //Print original message in Translated UI con.liveTranslationUI.innerHTML += '<strong> ME: </strong>: ' + message + '<br>'; //Print translated message in Chat UI con.liveChatUI.innerHTML += '<strong> ME: </strong>: ' + data.TranslatedText + '<br>'; //Scroll chat and translated UI to bottom to keep focus on latest messages con.liveChatUIContainer.scrollTop = con.liveChatUIContainer.scrollHeight; con.liveTranslationUIContainer.scrollTop = con.liveTranslationUIContainer.scrollHeight; } }); } } /**************************Send Message****************************/ /**************************Audio player****************************/ function AudioPlayer(voiceId) { var audioPlayer = document.createElement('audio'); audioPlayer.setAttribute("id", "audioPlayer"); document.body.appendChild(audioPlayer); var isSpeaking = false; var speaker = { self: this, playlist:[], Speak: function (text) { //If currently speaking a message, add new message to the playlist if (isSpeaking) { this.playlist.push(text); } else { speakTextMessage(text).then(speakNextTextMessage) } } } // Speak text message function speakTextMessage(text) { return new Promise(function (resolve, reject) { isSpeaking = true; getAudioStream(text).then(playAudioStream).then(resolve); }); } // Speak next message in the list function speakNextTextMessage() { var pl = speaker.playlist; if (pl.length > 0) { var txt = pl[0]; pl.splice(0, 1); speakTextMessage(txt).then(speakNextTextMessage); } } // Get synthesized speech from Amazon polly function getAudioStream(textMessage) { return new Promise(function (resolve, reject) { var polly = new AWS.Polly(); var params = { OutputFormat: 'mp3', Text: textMessage, VoiceId: voiceId } polly.synthesizeSpeech(params, function (err, data) { if (err) reject(err); else resolve(data.AudioStream); }); }); } // Play audio stream function playAudioStream(audioStream) { return new Promise(function (resolve, reject) { var uInt8Array = new Uint8Array(audioStream); var arrayBuffer = uInt8Array.buffer; var blob = new Blob([arrayBuffer]); var url = URL.createObjectURL(blob); audioPlayer.src = url; audioPlayer.addEventListener("ended", function () { isSpeaking = false; resolve(); }); audioPlayer.play(); }); } return speaker; } /**************************Audio player****************************/ </script> </body> </html>