はじめに
先日LTをする機会がありまして、この記事の題通り、翻訳こんにゃくを1時間で作れる話をしてきました。
主題としては、「1時間で作れること」がメインなのですが、技術的な部分をもう少し聞きたいという声がありましたので、ここにざっくりとまとめます。詳しくはリポジトリを眺めてください。
作ったものはこちら
翻訳こんにゃくなんて1時間くらいで作れるもんなんやで。#ドラえもん #翻訳こんにゃく #javascript pic.twitter.com/mNPSsxIpAC
— たいら (@fmstiara) 2019年6月19日
コードに関してはこちらを→Githubリポジトリ
翻訳こんにゃくの仕様
翻訳こんにゃくといえば、ドラ○もんのひ○つ道具として有名です。それを食べることで、あらゆる言語を理解することができます。自分の知らない言語を話すことができ、聞き取って理解することができるという代物です。
ここでは、翻訳こんにゃくをWebアプリケーションとして実装します。
フローはこんな感じ。
環境
クライアントサイドは、JQueryやReactは特に使わず、生のJSで記述します。
サーバサイドは、Node.js(v8.9.4)で記述します。
音声認識・音声合成にはWebSpeechAPIに含まれる、SpeechRecognitionとSpeechSynthesisを使います。
翻訳には、Microsoftが提供するTranslatorTextAPIを使います。
また、クライアントとサーバ間をWebSocketで通信します。
以降で、WebSpeechAPI、TranslatorTextAPI、WebSocket通信について、翻訳こんにゃくを1時間で作るのに十分な内容だけ説明します。
Web Speech API
Web Speech APIは、音声認識のSpeech Recognitionインタフェースと、音声合成のSpeech Synthesisインタフェースから構成されるAPIです。インターネット接続せずにローカルな環境で動作し、簡単な記述で音声認識と音声合成を試すことができます。1時間で翻訳こんにゃくを作る上では、最適です。
Speech Recognition
const recognition = new webkitSpeechRecognition;
recognition.lang='en-US';
recognition.start();
recognition.onresult = function(e){
console.log(e.results[0][0].transcript);
}
SpeechRecognitionを試すだけなら、これだけで動きます。
インスタンスを生成して、認識する言語を設定し、start()
を実行するだけです。
onresult
イベントで認識結果を取得できます。
SpeechRecognitionでは、認識の途中結果や、連続で認識し続けるなども可能です。
const recognition = new webkitSpeechRecognition;
recognition.continuous = true; //連続認識
recognition.interimResults = true; //途中結果を吐き出す
詳細はこちらをどうぞ
Speech Synthesis
const synth = window.SpeechSynthesis;
const utterance = new SpeechSynthesisUtterance("Hello world");
synth.speak(utterance);
音声合成をするには、発話情報(SpeechSynthesisUtterance
)をSpeechSynthesis
のspeak()
に渡してやるだけでOKです。これだけで、ブラウザが"Hello world"と喋ってくれます。
SpeechSynthesisUtteranceをいじることで、声色や声の高さ、速さなどを調整できます。
const synth = window.SpeechSynthesis;
const voices = synth.getVoices();
let utterance = new SpeechSynthesisUtterance();
utterance.lang = 'ja-JP';
utterance.text = 'こんにちは';
utterance.pitch = 1.5; //高さ 0.0~2.0 default:1
utterance.rate = 1.0; //速さ 0.1~10.0 default:1
utterance.voice = voices[0]; //声色
声色はたくさんあります。2019/06/19時点で66種類。
Translator Text API
MicrosoftのAPIを選択した理由は特になく。Web Speech APIのように、インターネット接続せずにローカルで動き、簡単な記述で済むものがあればよかったのですが、特に見つからない(というより、探してない)ので、使った次第です。
このAPIはPOSTしたテキストの言語を自動で推定して、指定した言語に翻訳してくれます。
POSTで送るものは、翻訳先の言語と翻訳したい元のテキストです。
基本、こちらの公式ドキュメントをなぞるだけで、十分です。
const request = require('request');
const uuidv4 = require('uuid/v4');
function translate(_text){
return new Promise((resolve, reject)=>{
const subscriptionKey = 'xxxxxxxxxxxxxxxxxxxxxxxx';
let options = {
method: 'POST',
baseUrl: 'https://api.cognitive.microsofttranslator.com/',
url: 'translate',
qs: {
'api-version': '3.0',
'to': 'ja' // ここで翻訳先の言語を指定
},
headers: {
'Ocp-Apim-Subscription-Key': subscriptionKey,
'Content-type': 'application/json',
'X-ClientTraceId': uuidv4().toString()
},
body: [{
'text': _text // 翻訳したいテキスト。今回で言えば、音声認識したテキスト。
}],
json: true,
};
request(options, function(err, res, body){
if(err) {
console.log(err);
return
}
let json = JSON.stringify(body, null, 4);
let data = JSON.parse(json);
resolve(data[0]["translations"][0]["text"]);
});
})
}
WebSocket
今回作ったシステムでは、クライアントとサーバ間をWebSocketで通信しているので、その話もついでにしましょう。
WebSocketはウェブアプリケーションにおいて、クライアントとサーバの低コストに双方向通信を簡単に実現するための通信規格です。チャットでクライアントとサーバの間を何度も通信するときに使ったりします。今回は、音声認識するたびにサーバに送って、翻訳したテキストをクライアントに返すという通信をしたいので、WebSocketを使おうということです。
Node.jsではsocket.ioというライブラリを使うことで、Webアプリケーションに簡単にWebSocketを組み込むことができます。npmやyarnを使ってsocket.ioをインストールしましょう。
socket.io
socket.ioはイベントベースでWebSocket通信を可能にするライブラリです。クライアントとNode.jsサーバ用の機能を含んでいます。
<!-- クライアント側 -->
<script>
//これだけでサーバにWebSocketで接続できます。
const socket = io();
// 'from-client'というイベント名で'Hello'というメッセージを送ります。
socket.emit('from-client', 'Hello');
// 'from-server'というイベント名でメッセージが来たら、それをconsole出力します。
socket.on('from-server', msg=>{console.log(msg)});
</script>
//サーバ構築にはexpressを使います。
const app = require('express')();
const http = require('http').Server(app);
const server = http.listen(3000, ()=>{});
const io = require('socket.io')(http);
// 接続時の処理
io.on('connection', socket => {
// 'from-client'というイベント名で、clientからメッセージを受信
socket.on('from-client', msg => {
// 'from-server'というイベント名で、clientにメッセージを送信
io.emit('server:message', msg);
});
});
1時間で作る話
この辺の基本的な技術を組み合わせてしまえば、翻訳こんにゃく(みたいなもの)を作れてしまいます。
何も難しいものは使っていません。APIとか組み合わせれば、作れるものは無限大だぜ
という話をLTでしました。新しい技術はどんどん触って、技術の引き出しを増やしていきたいですね。