2021年07月31日 更新

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

どうも、クラゲです。
Web Speech APIを使って途切れない音声認識を行います!

目次

[TOC]

デモ体験

実際のデモが体験できるページはこちら
https://monomonotech.jp/kurage/assets/scripts/iot/webspeechapi_voice_recognition

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

コツ

HTTPSサーバーに置くこと

ローカルやHTTPサーバーだと動作しなかったり、マイクの使用許可を毎回許可する必要があり実用的ではありません。

関数の呼び方に工夫

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

必要なサービス

  • Chromeブラウザのみ

必要なスキル

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

まずは最小コードで実験

たったこれだけの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>

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

うまく実行されない場合

HTTPSサーバに置くこと

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

マイクの使用を許可すること

起動がうまくいくと以下のようなアラートが表示されます。

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

マイクの設定を適切に行うこと

全く認識されない場合は、マイクの設定の問題です。
chromeの設定 > プライバシーとセキュリティ― > サイトの設定 > マイク
で適切なデバイスに変更してください。

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

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

24時間で消えますが、サインインしなくてもいきなりサーバーにアップロードすることが出来ます。

ローカルPCにてフォルダを新規作成します。フォルダ名は何でもOKです。その中にindex.htmlを新規作成して先程のコードをコピペします。
そのフォルダをドラッグ&ドロップするだけでできます。
単体ファイルじゃなくて、フォルダに入れて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>

これで途切れることなく使えるようになりました!

参考にさせていただいたサイト

以上、Web Speech APIを使った途切れない音声認識でした。