ロボット(TJBot zero)に韓国語を喋らせるのに苦労したこと


#はじめに
[「ラズパイとNode-REDでロボット(TJBot zero)を作ろう！ 」](https://bmxug.connpass.com/event/133056/)ハンズオンで作ったTJBot zeroに韓国語を喋らせるのにちょっと苦労しました。その時に学んだ４つの苦労と実際に喋らさせたフローを参考までに投稿します。

# やりたかったこと
今回やりたかったことは起動時に「 こんにちは、僕の名前は　TJBotです。」とスピーカーから喋るところを、「 안녕하세요 내 이름은 TJBot입니다. 」に変えて韓国語で喋らせることです。
<img width="556" alt="スクリーンショット 2019-07-01 16.41.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209170/f02f42fb-50d3-62fc-7390-ee1e79dcb0fa.png">

# 苦労１ openjtalkでは韓国語が喋れない  
openjtalkでは韓国語が出力できなかったので,かわりにWatsonの Text to Speech + Speackerapiの組み合わせで喋らせようとしたが、残念ながら現時点ではWatsonのText to Speechは韓国語サポートしていませんでした。

代替案を探すとGoogle Cloud Text-to-Speech, Azure Speech Services, Amazon Polyで実現できることがわかったので,今回はgoogle TTS node使って実装することにしました。

(参考情報）

- Google
    - [google Cloud Text-to-Speech API](https://cloud.google.com/text-to-speech/docs/voices)
    - [google TTS node](https://flows.nodered.org/node/node-red-contrib-google-tts)

- Azure
    - [Speech Services の言語とリージョンのサポート](https://docs.microsoft.com/ja-jp/azure/cognitive-services/speech-service/language-support)

    - [node-red-contrib-cognitive-services](https://flows.nodered.org/node/node-red-contrib-cognitive-services)

- Amazon
    - [Amazon polly (TTS)](https://aws.amazon.com/jp/blogs/machine-learning/amazon-polly-adds-9-aws-regions-korean-language-support-and-a-new-indian-english-voice/)
    - [Amazon polly (TTS) node](https://flows.nodered.org/node/node-red-contrib-polly-tts)

# 苦労２ node-red-contrib-google-ttsをインストールすると依存関係のパッケージが大量に削除されてしまう。
googleのtext-to-speechを使うために、node-red-contrib-google-ttsをインストールすると下記出力の通り５５１のパッケージが削除されて、既に動いてたノードが動作しなくなりました。

```
pi@raspberrypi:~/.node-red $ npm install node-red-contrib-google-tts
+ node-red-contrib-google-tts@1.1.1
added 5 packages from 4 contributors, removed 551 packages and audited 8 packages in 305.2s
found 0 vulnerabilities
```

- 削除されたパッケージの一覧（一部）

```
image-caption-generator-service
ui_group
ui_tab
camerapi-takephoto
openjtalk
image-caption-generator
base64
watson-translator
visual-recognition-v3
ui_button
ui_template
google-translate
opencv
hostip
embedded-file
speakerpi-output
```

- 回避策  
回避策として、Node-Redを再構築して、再構築時にNode-Redのパッケージをインストールする時に一番最初にnode-red-contrib-google-ttsインストールして、他のパッケージが削除されないようにしました。

<img width="1001" alt="スクリーンショット 2019-07-02 2.11.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209170/530cc27e-5307-f914-f5ca-6f3d34ad8558.png">


なお、Node-Redの再構築には、tjbotzero-raspbianリポジトリのinstall.shを使用しました。

- [install.shを変更した箇所](https://github.com/daihiraoka/tjbotzero-raspbian/commit/811c91c303599341076f47c755ca9552a1589be4#diff-6c75b33708b6032161ca971373c7a7e8)

# 苦労3 text-to-speechした結果をspeakerapiに渡すと、アナログ時代のテレビ放送終了後の「ざーぁー」って音が流れて音声は出ない。
 
node-red-contrib-google-ttsのtext-to-speechした結果は、MP3形式で返却されてspeakerapiが受け付けるのがwav形式と形式が合っていないのが原因でした。

MP3形式からwav形式に変換するために [node-red-contrib-media-utils](https://flows.nodered.org/node/node-red-contrib-media-utils)をインストールすると、、、

# 苦労4 node-red-contrib-media-utilsをインストールすると依存関係のパッケージが大量に削除されてしまう。

```
pi@raspberrypi:~/.node-red $ npm install node-red-contrib-media-utils
> easy-ffmpeg@0.0.15 postinstall /home/pi/.node-red/node_modules/easy-ffmpeg
> node install.js
+ node-red-contrib-media-utils@0.0.8
added 21 packages from 27 contributors, removed 494 packages, moved 3 packages and audited 212 packages in 366.285s
found 2 high severity vulnerabilities
  run `npm audit fix` to fix them, or `npm audit` for details
```
下図のように赤線のノードがunknownになって使えなくなります。
<img width="686" alt="スクリーンショット 2019-07-01 17.08.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209170/244ae012-5a1e-3b07-b292-f0485fb33cd9.png">

再び、tjbotzero-raspbianリポジトリのinstall.shに　node-red-contrib-google-ttsのインストールの前に、node-red-contrib-media-utilsのインストールを追加して、Node-Redの再構築を行いました。

<img width="852" alt="スクリーンショット 2019-07-02 2.13.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209170/bdacf479-11f0-d77d-7f2d-704c9fc912c8.png">

- [今回作成したinstall.shを改造したスクリプト](https://github.com/daihiraoka/tjbotzero-raspbian/blob/master/rebuild-node-red.sh)

  
# 韓国語を喋らせてみよう

TJBot Zeroのベースパッケージにnode-red-contrib-media-utils　と node-red-contrib-google-ttsノードを追加することで下図のフローで、韓国語を喋らせることができました。
<img width="707" alt="スクリーンショット 2019-07-02 1.06.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209170/e5d840e0-6a43-1f90-ab8f-e4e9764b16d8.png">　
今回作成したフローの各ノードは下記処理になってます。 

1. " greeting " インジェクションノードでフローの実行
1. " create sentence " テンプレートノードで喋らせるメッセージ「 안녕하세요 내 이름은 TJBot입니다. 」を設定
- " google tts" ノードで、メッセージを韓国語でtext to speechして、結果をMP3音源のURLで返却
- " ffmpeg conversion " ノードで、MP3から wavに変換
- " msg.speechに変換 "ノードで speakerapiのinput形式であるmsg.speechに変換
- "speakerapi output node"ノードで msg.speechのwav音源を再生

- 再現できるようにフローコードは、下記になります。

```
[{"id":"d5ff45ed.ea2588","type":"inject","z":"f7e611e7.f7e29","name":"greeting","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":140,"y":1400,"wires":[["4ca551f9.fa6f2"]]},{"id":"4ca551f9.fa6f2","type":"template","z":"f7e611e7.f7e29","name":"create sentence","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"안녕하세요 내 이름은 TJBot입니다.","output":"str","x":340,"y":1400,"wires":[["a97baa63.56edf8"]]},{"id":"5f3de479.c1e16c","type":"ffmpeg-conversion","z":"f7e611e7.f7e29","name":"","format":"wav","audiochannels":"mono","x":190,"y":1500,"wires":[["f7c0e0be.69a3c"]]},{"id":"a97baa63.56edf8","type":"google-tts","z":"f7e611e7.f7e29","name":"","inputField":"payload","inputFieldType":"msg","outputField":"payload","outputFieldType":"msg","languageField":"ko-KR","languageFieldType":"str","speedField":"1","speedFieldType":"num","x":540,"y":1400,"wires":[["5f3de479.c1e16c"]]},{"id":"57dfae26.95142","type":"speakerpi-output","z":"f7e611e7.f7e29","choose":"streambased","filename":"","channels":"1","bitdepth":"16","samplerate":"22050","name":"","x":640,"y":1500,"wires":[[]]},{"id":"f7c0e0be.69a3c","type":"function","z":"f7e611e7.f7e29","name":"msg.speechに変換","func":"msg.speech = msg.payload\nreturn msg;","outputs":1,"noerr":0,"x":410,"y":1500,"wires":[["57dfae26.95142"]]}]
```

# まとめ
今回、TJBot Zeroに韓国語を喋らせるには、追加のパッケージの導入が必要で、色々苦労した結果、以下の事がわかりました。

- 韓国語を直接スピーカーから喋らせる方法はないので、text-to-speechを経由してspeakerpiから出力しなければならない。
- npm install する時に依存関係のあるノードが原因で消えて動かなくなってしまうことがある。
    - .node-redフォルダのバックアップをしてからインストールしよう
    - 依存関係で失敗する場合は、 tjbotzero-raspbianリポジトリのinstall.shのNode-Redのnodeをインストールする箇所を改造してインストールしてみよう 
- speakerpiはMP3は非対応
    - node-red-contrib-media-utilsで、MP3->WAV変換をしてから再生させよう
- speakerpiは 変数msg.speechで受け取るので、msg.payloadから変換して渡す必要がある。

- IBMのWatsonのText to Speechは wavで返却できるので、もし韓国語をサポートしていたならば、直接speackerpiに送る事ができて苦労する必要はなかったです。韓国語サポート早期希望します。

今回は、TJBot Zeroに韓国語を喋らせるのが目的でしたが、他の言語を喋らせるのも今回のパターンで実現する事ができますので是非お試しください！

#### [FacebookのTJBotFanページ](https://www.facebook.com/groups/547028405784779/)でコミュティーのみなさんと情報交換をしていますので、ご参加ください！