Pei's Lab

VoiceText APIを使ってgoogle homeを喋らせる

久しぶりにgoogle home(google nest)ネタです。

ここ数ヶ月、google-home-notifierが不調なようで、google nestがうまく喋ってくれなくなっていました。

はじめに前回までにラズパイの初期設定と、使用するデバイスのIP固定を行いました。今回は、いよいよgoogle-home-notifierを使ってgooglehomeを喋らせます。使用したコードtest.jsconst googlehome = require('google-home-notifier')const language = ...
raspberry piでgoogle-homeを喋らせる - Pei's Lab

こちらの記事でも書いたとおり、google ttsの仕様が変わるたびに設定を調整しなければならないのは承知していたのですが、どうも設定がうまく行きませんでした。

もともとgoogle-home-notifierに不満もあったのでVoiceTextに乗り換えることにしました。VoiceText web APIはReadSpeaker社が公開しているwebAPIでテキストを音声に変換することができます。ReadSpeaker社ではこのAPIだけでなく多くのTTS(Text To Speech)サービスを提供しており、オリジナルのナレーションを作成できたりもします。(API使わせてもらうので宣伝)

Webに声を、感情を。高品質な音声合成VoiceTextが、簡単に使えるWeb APIに。
VoiceText Web API - cloud.voicetext.jp

はじめに

この記事は下記の記事の続きという前提で執筆しています。

はじめに我が家には1歳過ぎの子供がいます。少しずつ話せる様になってきましたが、文字の入力はおろか、文字が読める様になるのもまだまだ遠い未来です。そこで、外出中の私と自宅の子供がコミュニケーションを取れる環境を作っていきたいと思います。今回は第一弾...
LINEで送ったメッセージをGoogleHomeで喋らせる 第1弾 - Pei's Lab

つまり、Firebaseなどからgooglehomeに喋らせたいメッセージをnode.jsで受信し、google-home-notifierで喋らせるという基本構成はできているものとします。

全体構成は下記のとおりです。

テキストメッセージをVoiceText web APIによって音声ファイルに変換し、Raspberry Piのストレージに保管します。

保管した音声ファイルは外部からhttpでアクセスできるようにnginxを使ってURLを発行します。

google homeにこのURLを通知することで、ラズパイ内の音声ファイルにアクセスして再生してくれます。

音声ファイルの保存先としてmicrosoftのazureやgoogleのcloud storageのようなクラウドストレージサービスを使った実装例は見つかったのですが(ちょまどさんのマッチョのやつとか)、raspberry piをストレージとして使用する例は見かけなかったので試してみました。

googlehomeの制御自体はgoogle-home-notifierと同じで良いので、既存コードをベースに修正を加えていく方針にします。

完成品は次のようになります。

https://peislab.com/wp-content/uploads/2021/07/新しいビデオ.mp4

nginxの設定

まずはラズパイをwebサーバーとして使えるようにしていきます。

今回はnginxを使用します。Apacheでも構いません。

>sudo apt update
>sudo apt upgrade
>sudo apt install nginx

これだけでひとまずwebサーバーとして使えるようになり、同じネットワーク(LAN)からはhttp://(raspberry piのIPアドレス)/ でラズパイにアクセスできるようになります。

IPアドレスを固定していない方はこちらを参照して固定しておいてください。

はじめにPCからラズパイへssh接続をしたり、ラズパイからgooglehomeを操作したりするときに、IPが変わってしまうとその都度設定を変更しなければなりません。コントロールが簡単になる様にラズパイとgooglehomeのIPを固定しましょうIPの固定方法IPの固定はルータの管...
raspberry pi、googlehomeのIP固定 - Pei's Lab

同じネットワーク内の他のPC、スマホなどから上記URLにアクセスすると、次のような画面になります。

この画面が確認できたらnginxの設定はひとまずOKです。

私の環境では、デフォルトでスタートアップに設定されたようで、ラズパイを再起動しても問題なくアクセスできました。

もしラズパイを再起動したときにアクセスできなくなってしまった場合は

>systemctl enable nginx

を実行してもう一度再起動して見てください。

webサーバーとしてのrootは/var/www/htmlになっているので

cd /var/www/html
で移動します。続いて
>sudo mkdir media
>cd media
>sudo mkdir VoiceText

としてVoiceText APIで生成した音声を入れるディレクトリを作成します。自分がわからなくならなければ同じ構成でなくても大丈夫です。

node.js実行時にファイル作成ができるようにchownコマンドやchmodコマンドで適切なアクセス権を設定しておいてください。777にしておけばセキュリティは保障できませんが、動作はすると思います。

VoiceText Web API

VoiceText Web APIを使用するためには事前登録をしてAPIキーを取得しておく必要があります。

Webに声を、感情を。高品質な音声合成VoiceTextが、簡単に使えるWeb APIに。
VoiceText Web API
- cloud.voicetext.jp

こちらのページから登録を行っておいてください。

続いてvoicetext web apiに簡単にアクセスするためのライブラリを入れます。

>npm install voicetext

簡単なテストプログラムを作成して、音声ファイル作成の動作確認をしてみます。全体構成でいうと③〜⑤の部分です。

 var fs = require("fs");
 var VoiceText = require('voicetext');
 voice = new VoiceText("取得したAPIキー");
 var text = "音声ファイル作成のテストです。";
 voice
 .speaker(voice.SPEAKER.HIKARI)
 .speak(text, function(e, buf){
   if(e){
     console.error(e);
   }
   fs.writeFile('/var/www/html/media/VoiceText/voice.wav', buf, function(e){
     if(e){
       console.error(e);
     }
   })
 })

このコードを実行すると指定したパスに音声ファイルが保存されます。

同じネットワーク内の他のPCなどから”http://(ラズパイのIP)/media/VoiceText/voice.wav”にアクセスすると音声が確認できます。

ここまででVoiceText Web APIの使いこなしは終了です。あとはgoogle homeと連携させるプログラムを書いていきます。

google-home-notifier修正

上記のテストプログラムを既存のgoogle-home-notifierに組み込んでいきます。

google-home-notifierのコードは”node_modules¥google-home-notifier¥google-home-notifier.js”です。

このコードは所有者がrootになっていると思うので、chownコマンドで適切なユーザーに所有者を切り替えたり、chmodコマンドでアクセス権を変えたりしてください。

コードを読み解くとgetSpeechUrlという関数で音声の作成と、google homeへの通知を行なっているようです。

そこで下記の通りコードを修正します。

var getSpeechUrl = function(text, host, callback) {
   // VoiceText Web APIを使用したコードに修正
   voice = new VoiceText("取得したAPIキー");
   voice
     .speaker(voice.SPEAKER.HIKARI)
     .speak(text, function(e, buf){
       if(e){
         console.error(e);
       }
       fs.writeFile('/var/www/html/media/VoiceText/voice.wav', buf, function(e){
         if(e){
           console.error(e);
         }
       })
     })
   onDeviceUp(host, "http://(ラズパイのIP)/media/VoiceText/voice.wav", function(res){
     console.log(res);
     callback(res)
    });
   // 元々のコード
   // googletts(text, language, 1).then(function (url) {
   //   onDeviceUp(host, url, function(res){
   //     callback(res)
   //   });
   // }).catch(function (err) {
   //   console.error(err.stack);
   // }); };

元々のコードを見ると、googletts関数で音声を生成し、Promiseのthenを使ってコールバックを受け取りその中でonDeviceUpという処理を呼んでいるようです。

今回は簡単にするため、onDevideUpはVoiceText Web APIの処理が終わった後に特に工夫せず呼んでいます。

これで完成です。若干バグがあるようなので原因が分かったらアップデートします(分かった方いらっしゃったらコメントお願いします。)