Let 2s say something by rπ
前回では何をやりたいかを明確にしてみた。
さて今回はRaspberry Piのセットアップをしていくのだが
まずはリモートからGoogle Home miniを喋らせることが
できるのかを調べてみた。
そしたらAPIがもうあるようで、有志の方たちが既に
実現していたので、ありがたく使わせていただく。
What lang should I write it down?
言語を何にしようかな?
GoogleだからやっぱいGoとかPythonがいいのかな?
ラズパイで動かせるぐらいのライトな感じで
そんなに面倒くさくないのがいいなと思ったら
このサイトでも採用しているNode.jsがいいかなぁと。
ってことで決定。
Let Google Home say something
喋らせるAPIがあるようで、そのnpmで公開されていた。
google-home-notifierという形で
公開されているので、さっそく使ってみる。
installation
導入してみる。
$ npm install google-home-notifier
|
README.mdにしたがって、ちょい修正したあと試用。
const googlehome = require('google-home-notifier'); const language = 'ja'; const deviceaddress = 'Google-Home-Mini-xxxxxxxxxxxxxxxxxxxxx'; var message = 'こんにちは。私はGoogleです。';
googlehome.device(deviceaddress, language); googlehome.notify(message, (res) => { console.log(res); }
|
こんなのを書いてgooglehometest.jsなんてファイルで保存して
実行してみる。
しばらくしてGoogle Home miniから
「ポリン」
「こんにちは わたしはグーグルです」
というなんとも機械的な声が聞こえてくる。
こいつ・・・動くぞ・・・

早速簡単に使えるようにクラスにしてモジュール化してみる。
const googlehome = require('google-home-notifier'); const language = 'ja'; const deviceaddress = 'Google-Home-Mini-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; var message = 'こんにちは。私はGoogleです。';
class GoogleSpeaker { meow(text){ if (!text) { text=message; } googlehome.device(deviceaddress, language); googlehome.notify(text, (res) => { console.log(res); }); return true; } } module.exports = GoogleSpeaker;
|
GoogleSpeaker.jsなんて名前でいつでも以下のように
呼び出せるようにする。
const googleSpeaker=require('./GoogleSpeaker'); gs=new GoogleSpeaker(); gs.meow('オマエんちー。おっばけやーしきー。');
|

Do me favor change your voice
なんか機械的な声で一部の人には受け入れられそうだけど
私はもっと人間味ある感じがいいなと思う。
そこで調べたら、OpenなAPIで日本語の文章を
いろんな声で喋ってくれるサイトを発見。
VoiceText APIというもので
TTSサービスをWebで展開している。
wave音源で保存できるみたいなのでこれは使わない手はない。
権利的なところも家で使用する分には良さそうだ。
このサイトで利用登録を行うとトークンが発行される。
Web APIを使用する際にはこのトークンが必要になるようだ。
さてさらに調べるとどうやらこちらもNode.jsにて簡単に扱えるように
している有志の方がいらっしゃった。本当にみなさんすごい。
voicetext
ありがたく使わせていただく。
テストしてみる。
const fs = require('fs'); const VoiceText = require('voicetext'); const voice = new VoiceText('xxxxxxxxxxxxxxxxx');
voice .speaker(voice.SPEAKER.HIKARI) .emotion(voice.EMOTION.HAPPINESS) .emotion_level(voice.EMOTION_LEVEL.HIGH) .volume(150) .speak('おしょうさん、はなれててくだちいな。', (e, buf) => { if(e){ console.error(e); }else{ fs.writeFileSync('./voicetexttest.wav', buf, 'binary'); } });
|
これをvoicetexttest.jsなんてファイルで保存する。
実行してみると同じ階層にvoicetexttest.wavってファイルが保存されている。
$ node voicetexttest.js $ ls GoogleSpeak.js package-lock.json voicetexttest.js node_modules package.json voicetexttest.wav $
|
再生する手段が今はないのでWindows機から再生したら
ちゃんと再生された。

さて、これをGoogle Homeに渡さにゃならんのだが
それを行うにはもうひとつ用意しなくてはいけない
ものがありそうだ。
Application Server
google-home-notifier.jsがどうやってGoogle Homeに
テキストを渡しているかをソースを見ていたら、
どうやらGoogle翻訳のTTSサービスに渡しているらしい。
そのTTSサービスから返ってくるURLをGoogle Homeに
渡しているようだ。
テキストを渡しているわけではないのか。
そのURLは音源のURIになっておりGoogle Homeが
そこからwave音源をダウンロードして再生しているようだ。
なるほど、とても良くできている。
機械的な声の正体はGoogleのTTSサービスだったのか。
ここをVoiceTextのTTSサービスに置き換えれば声を
変えられるってことなわけで
voicetext.jsで保存したwaveファイルを
Google Homeにダウンロードさせればいいわけなんだが
調べてみたら、簡単に実現するにはexpressモジュールで
常駐サービス作るのが手っ取り早そうだ。
てことで早速やってみる。
勉強も兼ねてgetとsetみたいな機能を用意して
/get/XXXX.wav
/set/?textMessage=XXXXXXX
こんな感じにアクセスしたらgetはwaveファイルを吐いて
setはテキストをしゃべらせようかなと。
あ、POSTデータにつけるようにしたほうがいいな。
で、express-ipfilterモジュールをつかって
アクセス制限もしておく。
さらにアクセスログも書いてほしいのでmorganモジュールも追加。
$ npm install express body-parser express-ipfilter morgan
|
さて、書いてみるか。
const fs = require('fs'); const express = require('express'); const ipfilter = require( 'express-ipfilter' ).IpFilter; const morgan = require('morgan'); const bodyParser = require('body-parser'); const googleSpeak = require('./GoogleSpeak');
const app = express(); const serverPort = 8080; const ips = [ '127.0.0.1', '192.168.44.12', '192.168.44.222' ];
app.use( ipfilter( ips ) );
app.use(morgan()); if (app.get('env') == 'production' ){ var stream = fs.createWriteStream(__dirname + '/log/access.log', { flags: 'a' }); app.use( morgan({ stream: stream }) ); }; const urlencodedParser = bodyParser.urlencoded({ extended: true });
app.use(function(req, res, next) { res.header( "Access-Control-Allow-Origin", "*"); res.header( "Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); next(); }); app.use(bodyParser.json());
app.get('/googlehome/get/:audioName', (req, res) => { const audioName = req.params.audioName; if(!audioName)res.status(400).send('NG'); const file = fs.readFileSync(__dirname + '/' + audioName, 'binary'); res.setHeader('Content-Length', file.length); res.write(file, 'binary'); res.end(); });
app.post('/googlehome/set/', (req, res) => { const textMessage = req.body.textMessage; if(!textMessage)res.status(400).send('POST data was not found'); const gs = new googleSpeak(); gs.meow(textMessage, function(result){ console.log(result); }); res.status(200).send('OK'); res.end(); });
app.listen(serverPort, () => { console.log('api server is starting.'); })
|
さて、これをapserver.jsみたいなファイルで保存しておいて
起動する。
$ node apserver.js api server is starting $
|
これで、localhostのTCP8080ポートでListenしているはずだと。
さっそくcurlつかってテストをしてみる。
$ curl http://localhost:8080/googlehome/get/voicetexttest.wav >temp.wav $ curl -X POST http://localhost:8080/googlehome/set/ -H "Accept: application/json" -H "Content-type: application/json" -d '{ "textMessage" : "さんをつけろよ、デコスケ野郎!" }'
|

このApplication Server越しにwaveファイルを渡してみようかなと。
今回はここまで。
コメント: