はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】WebGLでなるべく簡単に音声認識をしてみた

はじめに

今回はWebGLで音声認識をしてみる記事になります!

f:id:hanaaaaaachiru:20191006202651g:plain

Unityで音声認識をしようと思うと、Unityの標準のものやJuliusGoogle Cloud Speech APIなどがあります。

しかし、ブラウザ上で動かすとなると様々な制限があるので私が調べた範囲では、Web Speech API一択なような気がしました。

そこでUnityでWeb Speech APIを使った記事を見たところ、WebSocketSharpというライブラリを用いて通信をするものがほとんどです。

ぶっちゃけたところWebSocketについてはミジンコ並の知識すら持っていないので、ぐぬぬ・・・と思っていたところ、公式にこんなページがあることを見つけました。

docs.unity3d.com

このページの冒頭を引用させてもらうと、

Web 用のコンテンツを構築するときは、Web ページ上の他の要素とやり取りする必要があります。また、Web API を使用して Unity が現在デフォルトで公開していない機能を実装したい場合もあるかもしれません。 いずれの場合も、ブラウザーの JavaScript エンジンと直接やり取りする必要があります。Unity WebGL はこれを行うためのさまざまな方法を提供します。

とのことで、これを使えばWebSocketSharpすら使う必要ないんじゃね?っということで実際にやってみました!

追記)サンプルを公開してみました。是非体験してみてね。
https://hanachiru.github.io/WebSpeeshAPITest2/
※WebSpeechAPIはChromeのみ対応です

自作WebGLテンプレートを作成する

まずは以下の公式サイトにもあるように、WebGLテンプレートを作成します。

WebGL テンプレートの使用 - Unity マニュアル

WebGLテンプレートはEdit -> ProjectSettings -> Playerから見れるやつのことですね。

f:id:hanaaaaaachiru:20190920055141p:plain

Assets/WebGLTemplates/テンプレート名/index.htmlを作成します。私はテンプレート名をCustomにしました。

f:id:hanaaaaaachiru:20190920055427p:plain

このindex.htmlに必要最低限のHTMLソースを書きます。

<!DOCTYPE html>
<html lang="en-us">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Unity WebGL Player | %UNITY_WEB_NAME%</title>
    <script src="%UNITY_WEBGL_LOADER_URL%"></script>
    <script>
    var gameInstance = UnityLoader.instantiate("gameContainer", "%UNITY_WEBGL_BUILD_URL%");
    </script>
  </head>

  <body>
    <div id="gameContainer" style="width: %UNITY_WIDTH%px; height: %UNITY_HEIGHT%px; margin: auto"></div>
  </body>  
</html>

あと自分のテンプレートを選択しておくのを忘れないでおきましょう。

Chromeで試してみる

まずはUnityで使うためのJavascriptのコードが動くかChromeで試してみましょう。

<script>
    function Start(){
		SpeechRecognition = webkitSpeechRecognition || SpeechRecognition;
		const recognition = new SpeechRecognition();

		recognition.continuous = true;

		recognition.onnomatch = function(){
			window.alert("ページの再読み込みをしてください。")
		};

		recognition.onerror = function(){
			window.alert("エラーが発生しました。再接続をします。")
			Start();
		};

		recognition.onsoundend = function(){
			window.alert("音声入力が停止しました。再接続します。")
			Start();
		}

		recognition.onresult = (event) => {
			window.alert(event.results[event.results.length - 1][0].transcript);
		};

		recognition.start();
    }

    Start();
</script>

Web Speech APIを使った簡単なHTMLコードを書いてみました。

是非これをローカルサーバーで実行してみてください。

f:id:hanaaaaaachiru:20190920061259g:plain

JacaScriptからUnityのメソッドを呼び出す

次にJavaScriptからUnityのメソッドを呼び出してみましょう。

docs.unity3d.com

これをするためには以下のコードを使います。

SendMessage(objectName, methodName, value);
引数 意味
objectName シーンのオブジェクトの名
methodName 現在オブジェクトにアタッチされているスクリプトのメソッド名
value 文字列、数字など

これと先程のJavaScriptのコードをWebGLテンプレート(index.html)に合体させてみました。

<!DOCTYPE html>
<html lang="en-us">
<head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Unity WebGL Player | %UNITY_WEB_NAME%</title>
    <script src="%UNITY_WEBGL_LOADER_URL%"></script>
    <script>
        var gameInstance = UnityLoader.instantiate("gameContainer", "%UNITY_WEBGL_BUILD_URL%");

        function Start() {
            SpeechRecognition = webkitSpeechRecognition || SpeechRecognition;
            const recognition = new SpeechRecognition();

            recognition.continuous = true;

            recognition.onnomatch = function () {
                window.alert("セットアップに失敗しました。ページの再読み込みをしてください。")
            };

            recognition.onerror = function () {
                console.log("エラーが発生しました。再接続をします。")
                Start();
            };

            recognition.onsoundend = function () {
                console.log("音声入力が停止しました。再接続します。")
                Start();
            }

            recognition.onresult = (event) => {
                gameInstance.SendMessage('GameManager', 'OnMessage', event.results[event.results.length - 1][0].transcript);
            };

            recognition.start();
        }

        Start();
    </script>
</head>

<body>
    <div id="gameContainer" style="width: %UNITY_WIDTH%px; height: %UNITY_HEIGHT%px; margin: auto"></div>
</body>
</html>

JavaScriptコードを Unity から呼び出す方法もあるのですが、どうせずっと実行している必要があるのでその方法はとりませんでした。

というか実際にやってみたらうまく動かなかったんですよね・・・。HelloWorld的な奴は動いたのでコードがダメだったんだとは思いますが。

UnityでC#のスクリプトを書く

最後にゲームオブジェクトにアタッチするコードを書きます。

using UnityEngine;
using UnityEngine.UI;

public class Sample : MonoBehaviour
{
    [SerializeField] private Text _text;

    public void OnMessage(string message)
    {
        Debug.Log("Recieved a message");
        _text.text = message;
    }
}

もはやこれは説明不要ですね。

忘れずにゲームオブジェクトにアタッチして任意のテキストの参照をインスペクターから設定しましょう。

またゲームオブジェクトの名前はSendMessageに対応しなければならないので、今回の場合はGameManagerです。

試してみる

最後にプロジェクトをWebGLでビルドしましょう。

すると最初に貼ったGIFのような動きをすると思います。

さいごに

この方法ならWebSocketSharpを使わずに簡単に音声認識ができました。

実際に使ってみた感じ音声認識の精度は抜群に良いと思います。

ただ私自身理解が及んでいないことがたくさんあるので、なにか追記やこうした方がいいんじゃない?といったご意見をコメント等にいただけると嬉しいです。

またこちらの記事はUnityとJavaScriptの連携をとても簡潔にまとめてくださっていてよかったら見てみてください。
UnityのWebGLで外部JavaScriptライブラリを使う - Qiita

追記)いくつか改善をしたところをまとめてみました。こちらも是非。
【Unity】WebGLでなるべく簡単に音声認識をしてみた② - はなちるのマイノート