LINE Botとおしゃべりする。

Botを使ってリマインドなど必要な連絡を行うのは楽しいです。
もう少し何かしゃべってほしいのと、LINEのBotトライアルアカウントを取得したので、動作確認を兼ねてHeroku + ドコモ雑談対話APIで動かしてみました。
たくさんの先人のおかげで比較的楽に構築できました(-人-)

# 使うもの
* [Heroku: Cloud Application Platform](https://www.heroku.com/) 今回はPHP(Silex)を使います。
* LINE BOT API Trial Account ([追加募集枠が26日から開始](https://linecorp.com/ja/pr/news/ja/2016/1340))
* [ドコモ雑談対話API](https://dev.smt.docomo.ne.jp/?p=docs.api.page&api_name=dialogue&p_name=api_reference)

# セットアップ
## Heroku
[Getting Started on Heroku with PHP](https://devcenter.heroku.com/articles/getting-started-with-php#introduction) に従って、順番にセットアップを行います。
チュートリアルの流れとしては、アカウントの取得からサンプルコードをデプロイして、ログの確認や環境変数の定義など一通りのことが試せるようになっていますので、実践してみると理解が深まると思います。

今回は、FixieとHeroku Redisというアドオンを利用するのでheroku createコマンドなどで作成したアプリケーションに、ダッシュボードから追加します。
![スクリーンショット 2016-04-28 2.48.48.png](https://qiita-image-store.s3.amazonaws.com/0/118488/eb99137a-bc53-83b6-3278-82011ff03693.png)
### Fixie
trialbot-apiにアクセスするためにはServer IP Whitelistを登録する必要があって、IPアドレスを固定するために、Fixieを利用します。
Fixieを追加すると、Proxy URLとOutbound IPsが発行されるので、Proxy URLはtrialbot-apiにアクセスする際に設定して、Outbound IPsはServer IP Whitelistに登録します(後述)。
![スクリーンショット 2016-04-28 2.49.52.png](https://qiita-image-store.s3.amazonaws.com/0/118488/684e9c78-2ebf-b8aa-e913-d627017ce7d6.png)
### Redis
Remote Dictionary Server。オープンソースのKVSです。
雑談会話APIで、会話を続けるにはAPIから返されるcontextの値を保持しておいて、2回目以降の会話に設定する必要があるため、Redisを使ってcontextを保存します。今回設定する項目は特にありません。

また、この時点でFIXIE_URLとREDIS_URLの環境変数が登録されています。Herokuのダッシュボードから作成したアプリケーションを選択してSettingタブから確認できます。LINEのIDやDOCOMOのAPIキーなども登録しておくとgetenv()でphpから取得できます。![スクリーンショット 2016-04-28 3.13.17.png](https://qiita-image-store.s3.amazonaws.com/0/118488/c3ab2a51-eea2-8094-0b27-97afc5957616.png)



## LINE BOT API Trial Account
BOTのNameとApp Iconは好きなものを設定しておくと、自然とモチベーションが高まります。Callback URLの項目にはHerokuで作成するアプリケーションを設定しておきます。

```
https://hoge-fuga-buro.herokuapp.com:443/callback
```
Server IP Whitelistも設定します。
![スクリーンショット 2016-04-28 2.59.55.png](https://qiita-image-store.s3.amazonaws.com/0/118488/f60d770a-7e61-8e7a-5a80-8766cb41a388.png)
※サブネットマスクが24-30になっていてユニキャストアドレスは指定できないのかと思いましたがサブネットマスクは空にしておけばよさそうです。


## ドコモ雑談対話API
新規登録して、APIキーを取得しておきます。[ここ](https://dev.smt.docomo.ne.jp/?p=docs.api.page&api_name=dialogue&p_name=api_reference)から申請できます。
API keyが発行されるので、上述の通りHerokuの環境変数に登録します。
![スクリーンショット 2016-04-28 3.53.06.png](https://qiita-image-store.s3.amazonaws.com/0/118488/2d061188-d201-fb0a-abd7-789b530e10a6.png)

# コード
```lang:index.php
<?php
require_once __DIR__.'/vendor/autoload.php';
use Symfony\Component\HttpFoundation\Request;
date_default_timezone_set('Asia/Tokyo');
$app = new Silex\Application();
$app->post('/callback', function (Request $request) use ($app) {
    $body = json_decode($request->getContent(), true);
    foreach ($body['result'] as $msg) {
        //fromとメッセージを取得
        $from = $msg['content']['from'];
        $message = $msg['content']['text'];
        //Redisからcontextを取得
        $redis = new Predis\Client(getenv('REDIS_URL'));
        $context = $redis->get($from);
        //雑談対話APIを叩く
        $response = dialogue($message, $context);
        //contextをRedisに保存する
        $redis->set($from, $response->context);
        //LINEに返信
        $post_data = [
            "to" => [
                $from
            ],
            "toChannel" => "1383378250",
            "eventType" => "138311608800106203",
            "content" => [
                "contentType" => 1,
                "toType" => 1,
                "text" => $response->utt
            ]
        ];
        $ch = curl_init("https://trialbot-api.line.me/v1/events");
        curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
        curl_setopt($ch, CURLOPT_PROXY, getenv('FIXIE_URL'));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            "Content-Type: application/json; charser=UTF-8",
            "X-Line-ChannelID: ". getenv('LINE_CHANNEL_ID'),
            "X-Line-ChannelSecret: ". getenv('LINE_CHANNEL_SECRET'),
            "X-Line-Trusted-User-With-ACL: ". getenv('LINE_MID')
        ]);
        curl_exec($ch);
        curl_close($ch);
    }
    return 0;
});
function dialogue($message, $context) {
    $post_data = array('utt' => $message);
    $post_data['context'] = $context;
    // DOCOMOに送信
    $ch = curl_init("https://api.apigw.smt.docomo.ne.jp/dialogue/v1/dialogue?APIKEY=". getenv('DOCOMO_API_key'));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        "Content-Type: application/json; charser=UTF-8"
    ]);
    $result = curl_exec($ch);
    curl_close($ch);
    return json_decode($result);
}
$app->run();
```
```lang:composer.json
{
    "require": {
        "silex/silex": "^1.3",
        "predis/predis": "1.0.3",
        "heroku/heroku-buildpack-php": "*"
    }
}
```

## 概要
* LINE BotのCallback URLの項目に設定したエントリポイント(/callback)でリクエストを受け取ります。
* 取得したメッセージを雑談対話APIにリクエストしてレスポンスをLINE Botに返します。
* 雑談対話APIから返されるcontextの値をRedisで保持します。
* composer.jsonにはアドオンの設定などを記述します。
* .htaccessやProcfileはたいしたことはしていないので下記ソースコードを参照してください。

# ソースコード
https://github.com/tkitauji/silex-heroku-app

# 動作確認
若干性格に問題がありそうな気がしますがおしゃべりできました。
Botも雑談APIもまだまだ触りの部分だけなので、これから拡張していきたいと思います。
![image1.PNG](https://qiita-image-store.s3.amazonaws.com/0/118488/baee40ba-821c-2198-e301-b1cee4f3c70a.png)

# 注意点
無料で構築したので、いろいろと制限があります。Herokuは30分アクセスがなければスリープしますが無料プランは1日6時間以上スリープする必要があります。Fixieは月間100MB/500Requestsまで無料です。また無料プランでもクレジットカードの入力が必要です。Redisも25MBまでなら無料です。

# 参考
* [Getting Started on Heroku with PHP | Heroku Dev Center](https://devcenter.heroku.com/articles/getting-started-with-php#introduction)
* [Heroku×PHPでHello world!表示手順](http://qiita.com/aoioooii/items/e1b76ce35d88d008919d)
* [PHP+HerokuでLINE BOT作ってみた](http://qiita.com/qckanemoto/items/7c148fcc595cec4aa59a)
* [LINE BOTでりんな風の自分専用女子高生BOTを作ってみた (Python & Heroku)](http://qiita.com/shiraco/items/58a33b878fa5f1180d75)
* [これからPHPでLINE Botづくりを始める人向けの簡易スターターキット](http://qiita.com/tmtysk/items/2f33c7e08caefbf55548)
* [【LINE Bot】Heroku+PHP+雑談対話APIで会話Bot作ってみた](http://qiita.com/shanonim/items/f90ee13180ee70a1903d)