Web APIを使って、特定の音声に対して返答するWebアプリの作成

##背景
ひとり暮らししていると
家に帰って**「ただいま」** といっても返答がない

######　悲しい…

そんなことありますよね。
この悲しさを少しでも緩和してくれるアプリを作成しました。

##制作物
このCodepenを参考にしました。

https://codepen.io/ukkz/pen/xxqzQwP

こちらのCodePenでは音声の認識と出力が別になっています。

今回は、
Web APIを使用し、特定の入力音声に応じて音声が出力されるように作成しました。

```html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>あいさつ返答</title>
</head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
<body>

    <h1>あいさつ返答アプリ</h1>
    <div id="app">
        <p>
            音声読み込み
            <button @click="listen">{{ recogButton }}</button> {{ result }}
        </p>
        <p>
            発話させる（日本語）<br>
            <input v-model="message" /> <button @click="say">しゃべって！</button>
        </p>
    </div>
    <script>
        //音声認識
        const app = new Vue({
            el: '#app',
            data: {
                recogButton: 'スタート！',
                recog: null,
                result: '',
                speech: null,
                message: '',
            },
            mounted() {
                // 音声認識の準備
                const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.msSpeechRecognition || null;
                this.recog = new SpeechRecognition();
                this.recog.lang = 'ja-JP';
                this.recog.interimResults = false;
                this.recog.continuous = false;

                // 音声認識が開始されたら
                this.recog.onstart = () => {
                    this.result = '';
                    this.recogButton = '聴き取り中…';
                };

                // 音声を認識できたら
                this.recog.onresult = (event) => {
                    // 認識されしだい、this.resultにその文字をいれる
                    // Vueなので、文字をいれただけで画面表示も更新される
                    this.result = event.results[0][0].transcript;
                    //修正箇所
                    if (this.result == 'おはよう' || this.result == 'おはようございます') this.speech.text = this.result;
                    else if (this.result == 'いただきます') this.speech.text = '召し上がれ';
                    else if (this.result == 'ごちそうさま' || this.result == 'ごちそうさまでした') this.speech.text = 'お粗末さまでした';
                    else if (this.result == 'ただいま') this.speech.text = 'おかえり';
                    else if (this.result == 'ただいま帰りました') this.speech.text = 'おかえりなさいませ、ご主人様';
                    else if (this.result == 'ありがとう' || this.result == 'ありがとうございます') this.speech.text = 'どういたしまして';
                    else if (this.result == 'ごめんなさい' || this.result == 'すいません') this.speech.text = '気にしないでね';
                    else if (this.result == 'こんにちは') this.speech.text = this.result;
                    else if (this.result == 'はじめまして') this.speech.text = this.result;
                    else if (this.result == 'お疲れ様' || this.result == 'お疲れ様でした' || this.result == 'お疲れ') this.speech.text = this.result;
                    else this.speech.text = "すみません、よくわかりません";
                    return new Promise((res) => {
                        this.speech.onend = () => res();
                        speechSynthesis.speak(this.speech);
                    });
                };

                // 音声認識が終了したら
                this.recog.onspeechend = () => {
                    this.recog.stop();
                    this.recogButton = '再開';
                };

                // 認識できなかったら
                this.recog.onerror = () => {
                    this.result = '（認識できませんでした）';
                    this.recog.stop();
                    this.recogButton = '再開';
                };

                // 発話の準備
                this.speech = new window.SpeechSynthesisUtterance();
                this.speech.lang = 'ja-JP';
                // または、ブラウザが対応している言語のうちja-JPな最初のボイスを使う
                window.speechSynthesis.onvoiceschanged = () => {
                    const voices = window.speechSynthesis.getVoices();
                    this.speech.voice = voices.find(voice => voice.lang == 'ja-JP');
                    console.log(this.speech.voice);
                };
            },
            methods: {
                // 認識（聞き取り）
                listen() {
                    this.recog.start();
                },
                // なんかしゃべる（いちおう非同期対応）
                async say() {
                    return new Promise((res) => {
                        this.speech.text = this.message;
                        this.speech.onend = () => res();
                        speechSynthesis.speak(this.speech);
                    });
                },
            },
        });
    </script>
</body>

</html>
```
###完成したコードペン

https://codepen.io/tomosukesan/pen/wvqwLyp

##変更点とコード解説
`this.recog.onresult`メソッド内の`this.result`に入力された音声が格納されるため
そこをif文で条件分岐させました。

返答させたい文章が`this.speech.text`変数に格納されています。

もっといろんな音声に対応させたい場合は`fork`して編集してみてください。

##Tips
■CodePenのプラグイン
　各言語の右側に歯車マークがあります。
　そこでプラグインの設定や確認ができます。
　CodePen外で使用する際は、適宜挿入が必要でした。
■Web API
・これいれるだけでバイブレーションが使えます。
　何かに使用できそうです...
`window.navigator.vibrate(2000);`

https://developer.mozilla.org/ja/docs/Web/API/Vibration_API

・公式ドキュメント ＞ インターフェース
　大量にありますが、いずれ全てに目を通したいと思います。

https://developer.mozilla.org/ja/docs/Web/API