2016/5/2

Web Speech APIで途切れない音声認識

どうも、クラゲです。
Web Speech APIを使って途切れない音声認識を行います!
こちらのデモはPCの内蔵マイクに向かって音声を入力してリアルタイムに認識させています。

実際のデモが体験できるページはこちら
https://secure1689.sakura.ne.jp/kurage.jellyware.jp/voice_recognition/

この「途切れない」というのが今回のミソです。Web Speech APIはJavaScriptで非常に簡単にプログラミングできますが、数秒経つと音声認識が停止してしまいます。そうなると手動で再開しなければいけなかったり、再開の度にマイクの使用許可を聞かれて毎回タップするのが面倒です。
そんな面倒な手間を解放し、途切れずに長時間、音声認識を続ける技を紹介します!

【 コツ 】

1.サーバーに置くこと
ローカルだとそもそもWeb Speech APIは動作しません

2.HTTPSを使うこと
HTTPだとマイクの使用許可を毎回許可する必要があります

3.関数の呼び方に工夫
音声認識終了後、停止後、エラー時などに関数を再び呼びますが、そこにコツがあります

【 必要なソフト/サービス 】

【 必要なスキル 】

  • htmlを少々
  • JavaScriptを少々
    (コピペで作る分にはスキル無しでもOK)

【 おおまかな作業の流れ 】

  • 最小コードで実験
  • うまく実行されない場合
  • 無料のホスティングサービス
  • 機能を追加
  • 長時間途切れることなく使う
  • マイクの使用許可アラートを最初の1回だけにする

【 詳細 】

まずは最小コードで実験

たったこれだけのhtmlファイルで音声認識が出来てしまいます!

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Web Speech API</title>
<script>
window.SpeechRecognition = window.SpeechRecognition || webkitSpeechRecognition;
var recognition = new webkitSpeechRecognition();
recognition.lang = 'ja';
 
recognition.onresult = function(event){
    var results = event.results;
    for (var i = event.resultIndex; i<results.length; i++)
        document.getElementById('result_text').innerHTML = results[i][0].transcript;
}
</script> 
</head>
<body>
<textarea id="result_text" cols="100" rows="10">
</textarea>
<br>
<input type="button" onClick="recognition.start();" value="音認開始">
</body>
</html>

サーバーにファイルを置いて、ブラウザはChromeで動作確認してください。

うまく実行されない場合

サーバに置くこと
ローカル上で起動してもダメで、サーバー上で起動する必要があります。
サーバー持ってない人は、後で紹介する無料のホスティングサービスがありますのでそちらを活用してみてください。

マイクの使用を許可すること
起動がうまくいくと以下のようなアラートが表示されます

許可を選ばないと音声認識されません

マイクの設定を適切に行うこと
全く認識されない場合は、マイクの設定の問題です
chromeの設定 -> 詳細設定を表示 -> コンテンツの設定 -> マイク
で適切なデバイスに変更してください

chromeの設定

詳細設定を表示

コンテンツの設定

マイクを選択

MacBookの内蔵マイクの場合
macbookの内蔵マイクでうまくいかない場合は、「環境ノイズリアクションを使用」のチェックを外してみてください

ブラウザ再起動
それでもダメなら、Chromeを再起動してみてください

無料のホスティングサービス

サーバーを持っていない人はこちらを活用してみてください
https://www.bitballoon.com/

メールアドレスとパスワードを設定すれば無料で簡単に即時使えます。
作成したファイルをフォルダに入れて、そのフォルダをドラッグ&ドロップすればOKです。ftpソフトなどは一切不要です。
単体ファイルじゃなくて、フォルダに入れてUPするのがポイントです

機能を追加

先ほどのシンプルなコードだと物足りないので、肉付けします

変換途中の経過を表示
recognition.interimResults = true で 変換途中も認識
isFinalを使えば変換終了したかを判定できる

音声認識を継続させる
recognition.continuous = true で連続で音声認識できる

音声認識の状態を表示
onsoundstart,onsoundend,onerrorを用いることにより状態が分かる

これらの機能を追加したソースです

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Web Speech API</title>
<script>
window.SpeechRecognition = window.SpeechRecognition || webkitSpeechRecognition;
var recognition = new webkitSpeechRecognition();
recognition.lang = 'ja';
recognition.interimResults = true;
recognition.continuous = true;
 
recognition.onsoundstart = function(){
  document.getElementById('status').innerHTML = "認識中";
};
recognition.onnomatch = function(){
  document.getElementById('status').innerHTML = "もう一度試してください";
};
recognition.onerror= function(){
  document.getElementById('status').innerHTML = "エラー";
};
recognition.onsoundend = function(){
  document.getElementById('status').innerHTML = "停止中";
};
 
recognition.onresult = function(event){
    var results = event.results;
    for (var i = event.resultIndex; i<results.length; i++){
      if(results[i].isFinal)
        document.getElementById('result_text').innerHTML = results[i][0].transcript;
      else
        document.getElementById('result_text').innerHTML = "[途中経過] "+ results[i][0].transcript;
    }
}
</script> 
</head>
<body>
<textarea id="result_text" cols="100" rows="10">
</textarea>
<br>
<textarea id="status" cols="100" rows="1">
</textarea>
<br>
<input type="button" onClick="recognition.start();" value="音認開始">
</body>
</html>

ずっとしゃべり続けていると、音声認識も連続でできるようになったと思います
しかし、無音で数秒経過すると、音声認識ができなくなってしまいます。
次にこれを攻略します

長時間途切れることなく使う

まず、先ほどのscript全体を関数化します
音声認識停止もしくは音声認識が完了になったら全体関数を呼ぶようにします。
エラーの場合は、flag_speechというフラグを用意し、認識途中でない場合のみ全体関数を呼びます。

<!DOCTYPE html>
<html>
 
<head>
    <meta charset="UTF-8">
    <title>Web Speech API</title>
    <script>
        var flag_speech = 0;
 
        function vr_function() {
            window.SpeechRecognition = window.SpeechRecognition || webkitSpeechRecognition;
            var recognition = new webkitSpeechRecognition();
            recognition.lang = 'ja';
            recognition.interimResults = true;
            recognition.continuous = true;
 
            recognition.onsoundstart = function() {
                document.getElementById('status').innerHTML = "認識中";
            };
            recognition.onnomatch = function() {
                document.getElementById('status').innerHTML = "もう一度試してください";
            };
            recognition.onerror = function() {
                document.getElementById('status').innerHTML = "エラー";
                if(flag_speech == 0)
                  vr_function();
            };
            recognition.onsoundend = function() {
                document.getElementById('status').innerHTML = "停止中";
                  vr_function();
            };
 
            recognition.onresult = function(event) {
                var results = event.results;
                for (var i = event.resultIndex; i < results.length; i++) {
                    if (results[i].isFinal)
                    {
                        document.getElementById('result_text').innerHTML = results[i][0].transcript;
                        vr_function();
                    }
                    else
                    {
                        document.getElementById('result_text').innerHTML = "[途中経過] " + results[i][0].transcript;
                        flag_speech = 1;
                    }
                }
            }
            flag_speech = 0;
            document.getElementById('status').innerHTML = "start";
            recognition.start();
        }
    </script> 
</head>
 
<body>
    <textarea id="result_text" cols="100" rows="10">
    </textarea>
    <br>
    <textarea id="status" cols="100" rows="1">
    </textarea>
    <br>
    <input type="button" onClick="vr_function();" value="音認開始">
</body>
 
</html>

これで途切れることなく使えるようになりましたが、マイクの許可をしなければいけないので実用的ではありません
最後にこれを攻略します

マイクの使用許可アラートを最初の1回だけにする

これは、httpsにすることにより実現できます
無料でhttpsが使えるホスティングサービスは中々ありませんが、herokuを使うことによりそれが実現可能になります。
herokuは元々動的なサイトを扱うためのサービスですが、静的なサービスを扱うことも可能です。

heroku登録
https://www.heroku.com/

名前とメアド登録で簡単にユーザー登録できます

heroku toolbeltインストール
シリアルコンソールでHerokuコマンドを使えるようにするツール
https://toolbelt.heroku.com/

DLして実行すればインストール完了
その後、Hello,world的なアプリの作り方はこちらを参考にどうぞ!
参考:http://www.tam-tam.co.jp/tipsnote/program/post5199.html

静的サイトとしてUP
githubから以下のソースコードをzip downloadして解凍します
https://github.com/nulltask/heroku-static-provider

ローカルのフォルダ名を任意に変えて置きます
クラゲはstatic_pageとしました

cd static_page

herokuで新しいアプリケーションを作ります

heroku create

リポジトリを作成

git init
heroku git:remote -a アプリケーション名

herokuへデプロイする

git add .
git commit -am "make it better"
git push heroku master
heroku open

これで hello world と出てくるはず
ここまで成功したら、先ほどダウンロードしたフォルダの中にpublicというフォルダがあると思いますので、その中のindex.htmlを先ほど作ったものに変えます。
これでももう1回デプロイすれば完成です!
以上、Web Speech APIを使った途切れない音声認識でした。

こちらのサイトを参考にさせていただきました

http://qiita.com/inouet/items/2c9e218c05f547bb6852

http://kesin.hatenablog.com/entry/2013/08/27/Web%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AB%E9%AB%98%E6%A9%9F%E8%83%BD%E3%81%AA%E9%9F%B3%E5%A3%B0%E8%AA%8D%E8%AD%98%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8BWeb_Speech_API

http://blog.kidapu.com/archives/644

https://html5-examples.herokuapp.com/taptap_experiment_2.html

http://null.ly/post/56856650450/heroku-%E3%81%A7-3-%E5%88%86%E3%81%A7%E9%9D%99%E7%9A%84%E3%82%B5%E3%82%A4%E3%83%88%E3%82%92%E5%85%AC%E9%96%8B%E3%81%97%E3%82%88%E3%81%86