LINEBOT+Open Jtalkで初音ミクに全力人力でしゃべらせてみた

逃げ恥を見ていて、ガッキーがペッパー君と楽しそうに話しているのを見て、ロボット欲しいなと思ったけれども、小遣いでは買えそうにないので、代わりになるものを作ってみた。

# 構想
入力した内容をそのまま話させる。INはなんでも良いが、一般人でもイメージしやすいようにLINEがベター。

LINEからの入力はSSL証明書が用意されたサーバが必要で、普段はVPSかAWSに無料のLetsEncryptを設定して対応しているが、今回はその方法ではうまくいかない。
なぜならサーバから音声を出したいので、ローカルでサーバを運用する必要があるからだ。

環境は ノートPC(windows10）にのせたvirtualbox+vagrantで行うこととした。

# キーワード
ググってみたところ、入力した文字を音声化するのとローカルサーバをSSLで外部公開できるライブラリが見つかった。
- Open Jtalk（入力した日本語を音声化する）
- ngrok（ローカル環境をテンポラリで外部公開する）

# Open Jtalk環境構築
centosにOpen Jtalkをインストールする。Oopen Jtalkを利用するには当該ライブラリ以外にhts_engine APIと辞書ファイル、音声ファイルが必要となってくるのでインストールする。
## hts_engine APIのインストール

```bash
$wget http://downloads.sourceforge.net/hts-engine/hts_engine_API-1.09.tar.gz
...
$tar zxvf hts_engine_API-1.09.tar.gz
...
$cd hts_engine_API-1.09
$./configure
...
config.status: creating Makefile
$make
...
$make install
...
$which hts_engine
usr/local/bin/hts_engine
```
## Open Jtalkのインストール
```bash
$wget http://downloads.sourceforge.net/open-jtalk/open_jtalk-1.09.tar.gz
...
$tar zxvf open_jtalk-1.09.tar.gz
...
$cd open_jtalk-1.09
$./configure
...
config.status: creating Makefile
$make
...
$make install
...
$which open_jtalk
/usr/local/bin/open_jtalk
```
## 辞書のインストール
Open Jtalkで使う辞書のインストールを行う。

```bash
$mkdir /usr/local/share/open_jtalk
$wget http://sourceforge.net/projects/open-jtalk/files/Dictionary/open_jtalk_dic-1.07/open_jtalk_dic_utf_8-1.07.tar.gz
...
$tar zxvf open_jtalk_dic_utf_8-1.07.tar.gz
...
$su -
$mv open_jtalk_dic_utf_8-1.07 /usr/local/share/open_jtalk/
```
# 初音ミク音声をOpen Jtalkで
Open Jtalkでは音声サンプルがいくつか用意されているが、今回はそれらを利用せず、個人が作っている初音ミクの音声を利用させていただく。
.htsvoice形式までの作り方はいかが参考になる。
<TABLE ALIGN=CENTER><TR><TD WIDTH=400px>
 <A HREF="http://karaage.hatenadiary.jp/entry/2016/07/22/073000" TARGET="_blank"><STRONG>Open JTalkで初音ミクの声でおしゃべりさせる@Mac/Linux/Raspberry Pi - karaage. [からあげ]</STRONG></A>
 <A HREF="http://b.hatena.ne.jp/entry/http://karaage.hatenadiary.jp/entry/2016/07/22/073000" TARGET="_blank">
 <IMG BORDER="0" SRC="http://b.hatena.ne.jp/entry/image/http://karaage.hatenadiary.jp/entry/2016/07/22/073000" BORDER="0" ALT="" /></a>
 <BR>
 Voice.htsvoice... 
 </TD>
 <TD WIDTH=150px>
 <IMG STYLE="float:left;margin-right:.5em;" SRC="http://capture.heartrails.com/120x120/cool?http://karaage.hatenadiary.jp/entry/2016/07/22/073000" ALT="" WIDTH="120" HEIGHT="120" />
 </TD></TR>
</TABLE>
上記でできたhtsvoiceファイルを音声ファイルとして適当な場所に保存する。

```bash
$mkdir /usr/local/share/hts_voice/miku
$mv Voice.htsvoice /usr/local/share/hts_voice/miku/miku.htsvoice
```
以上でOpen Jtalkの環境ができたのでテストをしてみよう。
## Open Jtalkのテスト

```bash
$echo '今日は晴れです' | /usr/bin/tr -d '\n' | open_jtalk \
        -m /usr/local/share/hts_voice/miku/miku.htsvoice \
        -ow /tmp/output.wav -x /usr/local/share/open_jtalk/open_jtalk_dic_utf_8-1.09

$sudo aplay /tmp/output.wav
```
無事PCから音声が流れたらOKだ。出ない場合は僕も引っかかったがvirtualboxの設定でオーディオが無効になっている可能性があるので、一度vagrantを落としてオーディオを有効にしてから試してほしい。

# プログラム
LINEからメッセージを受信して、Open Jtalkを話すプログラムを書いてみよう。
今回はPHPを選択する。LINEが提供するSDKから[LINEBotTiny](https://github.com/line/line-bot-sdk-php/blob/master/line-bot-sdk-tiny/LINEBotTiny.php)を利用する。

```php:callback.php
<?php

require_once('./LINEBotTiny.php');

$channelAccessToken = 'YOUR_ACCESS_TOKEN';
$channelSecret = 'YOUR_SECRET';

$client = new LINEBotTiny($channelAccessToken, $channelSecret);

foreach ($client->parseEvents() as $event) {
    switch ($event['type']) {
        case 'message':
            $message = $event['message'];

            switch ($message['type']) {
                case 'text':
                    $client->replyMessage(array(
                        'replyToken' => $event['replyToken'],
                        'messages' => array(
                            array(
                                'type' => 'text',
                                'text' => 'きちんと話したよ'
                            )
                        )
                    ));

                    // DB
                    $mongo = new Mongo();

                    $db = $mongo->selectDB("mikubot");

                    $coll = $db->selectCollection("messages");

                    $coll->insert( (array('message' => $message['text'], 'ts' => new MongoDate() )) );

                    // open_jtalk
                    exec("sudo /usr/local/bin/line_talk \"". $message['text']. "\"");

                    break;
                default:
                    error_log("Unsupporeted message type: " . $message['type']);
                    break;
            }
            break;
        default:
            error_log("Unsupporeted event type: " . $event['type']);
            break;
    }
};
?>
```
基本はecho_bot.phpを真似しただけだが、このPHPでは追加で2つの要素が入っているので追記しておく。
一つ目はmongdbに話したい内容をためることにした。今はLINEから入力した内容のみを話す人力知能だけれども、いつか人工知能になってくれることを祈って。
二つ目はexecの部分だ。
line_talk コマンドの中身を書いておく。

```bash
$ cat line_talk                                                                                                                  
/bin/sh

echo $1 | /usr/bin/tr -d '\n' | open_jtalk \
        -m /usr/local/share/hts_voice/miku/miku.htsvoice \
        -ow /tmp/output.wav -x /usr/local/share/open_jtalk/open_jtalk_dic_utf_8-1.09/

sudo aplay /tmp/output.wav
```
上記PHPをapacheなり、nginxなり、php -S localhost:8080なりでローカルサーバをたてて配置する。
このときhttpsの設定は必要なくhttpの事だけ考えてよい。

# LINE Messaging APIをvagrantから利用する
## LINE Messaging APIの設定
初めてだと少しわかりづらいがQiitaなどに沢山情報が落ちているので検索してみよう。

## ngrokの設定
ngrokをインストールする。

```bash
$npm i -g ngrok
```

## ngrokの起動

```bash
$nngrok http 80
ngrok by @inconshreveable                                                                                                                     (Ctrl+C to quit)
                                                                                                                                                              
Session Status                online                                                                                                                          
Version                       2.1.18                                                                                                                          
Region                        United States (us)                                                                                                              
Web Interface                 http://127.0.0.1:4040                                                                                                           
Forwarding                    http://xxxxxxx.ngrok.io -> localhost:80                                                                                        
Forwarding                    https://xxxxxxx.ngrok.io -> localhost:80  
```
https://xxxxxxx.ngrok.io をコピー。

## webhook
LINE Messaging API のWebhook URLにhttps://xxxxxxx.ngrok.io/XXXX/callback.php を設定する。

# 動作
じんりきみーくの完成。
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">じんりきみーく <a href="https://t.co/RJlIJc5qR3">pic.twitter.com/RJlIJc5qR3</a></p>&mdash; momochan_qiita (@momochan_qiita) <a href="https://twitter.com/momochan_qiita/status/810780806566256640">2016年12月19日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>