Heroku
TwitterAPI
linebot

Heroku × LINEBot × Twitterで猫Botを作ってみた

最初に

  • ネタ的には多くの猫好きエンジニアがやりそうなこと・・・。
  • 2016年12月頃に作ったものなので色々古いかもです。
  • 当初の構成図ではラズパイとwebカメラを使用してIoT的な監視botを作りたかったのですが運用開始直前に家庭内稟議で否認され実現できませんでした:sob:
    • 電気代の問題
    • 猫のプライバシー問題
  • 各種設定は参考サイトが詳しいのでここでは作成までの道のりを記載します。

構成図

初期

猫Bot初期構成図.jpg

現実

猫Bot妥協構成図.jpg

heroku設定

初期設定

@Arashiさんの記事を参考にさせて頂きました。
参考)http://qiita.com/Arashi/items/b2f2e01259238235e187

fixieインストール

LINE BOT API の呼び出しには Server IP Whitelist に接続元 IP の指定が必要なのでこいつが必要
https://elements.heroku.com/addons/fixie
@yuya_takeyamaさんの記事を参考にさせて頂きました。
参考)https://qiita.com/yuya_takeyama/items/0660a59d13e2cd0b2516

config設定方法

http://dackdive.hateblo.jp/entry/2016/01/26/121900

LINE設定

BOT APIの登録

https://at.line.me/jp/
https://www.panzee.biz/archives/9115

APIリファレンス

https://developers.line.me
https://devdocs.line.me/ja/?php#reply-message

twitter設定

twitterアプリケーション登録

https://dev.twitter.com/apps

twitterSDK

https://github.com/abraham/twitteroauth

PHPでTwitterのツイートを取得・表示する方法

http://2m3g1.com/751.html

heroku上に設定する環境変数

値は各個人の設定に変えてあげてください。

heroku.config
heroku config:set LINE_TOKEN=LINE_TOKEN_HOGE
heroku config:set FIXIE_URL=HEROKU_FIXIE_URL
heroku config:set APP_NAME=HEROKU_APP_NAME
heroku config:set tw_consumer_key=TW_CONSUMER_KEY
heroku config:set tw_consumer_secret=TW_CONSUMER?SECRET
heroku config:set tw_access_token=TW_ACCESS_TOKEN
heroku config:set tw_access_token_secret=TW_ACCESS_SECRET

heroku上にデプロイしたアプリケーションのディレクトリ設定

以下のように配置します。

|--index.php ← LINEとTwitterをごにょごにょするプログラム
|--twitteroauth ← twitterのSDK
|  |--.gitignore
|  |--.travis.yml
|  |--LICENSE.md
|  |--README.md
|  |--autoload.php
|  |--composer.json
|  |--phpmd.xml
|  |--phpunit.xml
|  |--src
|  |  |--Config.php
|  |  |--Consumer.php
|  |  |--HmacSha1.php
|  |  |--Request.php
|  |  |--Response.php
|  |  |--SignatureMethod.php
|  |  |--Token.php
|  |  |--TwitterOAuth.php
|  |  |--TwitterOAuthException.php
|  |  |--Util
|  |  |--Util.php
|  |  |  |--JsonDecoder.php
|  |  |--cacert.pem

プログラム

index.php
<?php
//--------------------------------
// Line Input
//--------------------------------
$php_input = json_decode(file_get_contents('php://input'));
$text = $php_input->{"events"}[0]->{"message"}->{"text"};
$reply_token = $php_input->{"events"}[0]->{"replyToken"};

//--------------------------------
// Create Media By Twitter 
//--------------------------------
$response_content = getResponseContent($reply_token,$text);

//--------------------------------
// Line Bot 
//--------------------------------
postLineBot($response_content);

function createHttpHeader() {
    $header = array(
        'Content-Type: application/json; charset=UTF-8',
        'Authorization: Bearer '.getenv("LINE_TOKEN")
    );
    return $header;
}
function getResponseContent($reply_token,$text) {
    if((strpos($text, '絹') !== false) || (strpos($text, '鱈') !== false)){
        return createImageResponse($reply_token);
    }
    return createTextResponse($reply_token,"はらへった〜");

}
function createTextResponse($reply_token,$message) {
    $response_format_text = [ 
        "type" => "text",
        "text" => $message 
    ];

    $post_data = array(
        "replyToken" => $reply_token,
        "messages" => [$response_format_text]
    );

    return $post_data;
}
function createImageResponse($reply_token) {
     $tw_auth = getTwitterAuth();
     $req = $tw_auth->get("statuses/user_timeline",array("count"=>"5"));
     $media_url = array();
     foreach($req as $key => $val){
        $media_url[] = [
           "type" => "image",
           "originalContentUrl" => $val->entities->media[0]->media_url_https.":small",
           "previewImageUrl" => $val->entities->media[0]->media_url_https.":thumb"
        ];
     }

    if(count($media_url) === 0) return createTextResponse($reply_token,"ねむい〜");

    $media_id = mt_rand(0,count($media_url)-1);
    $post_data = array(
        "replyToken" => $reply_token,
        "messages" => [$media_url[$media_id]]
    );

    return $post_data;
}

function getTwitterAuth() {
    require_once("./twitteroauth/autoload.php");
    $consumer_key = getenv("tw_consumer_key");
    $consumer_secret = getenv("tw_consumer_secret");
    $access_token = getenv("tw_access_token");
    $access_token_secret = getenv("tw_access_token_secret");
    $to = new \Abraham\TwitterOAuth\TwitterOAuth($consumer_key,$consumer_secret,$access_token,$access_token_secret);
    return $to;
}

function postLineBot($response_content){
    $ch = curl_init("https://api.line.me/v2/bot/message/reply");

    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($response_content));
    curl_setopt($ch, CURLOPT_HTTPHEADER, createHttpHeader());
    curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
    curl_setopt($ch, CURLOPT_PROXY, getenv("FIXIE_URL"));
    curl_setopt($ch, CURLOPT_PROXYPORT, 80);
    $result = curl_exec($ch);
    curl_close($ch);
}

デモ

その他参考サイト

http://qiita.com/chibi929/items/a368fdc3ef3485302302
http://qiita.com/ttskch/items/7c148fcc595cec4aa59a
http://qiita.com/kurouw/items/f00229e51818d80ae643
http://qiita.com/TetsuyaImagawa/items/7517b287e68efe21c0cc
http://qiita.com/Kosuke-Szk/items/eea6457616b6180c82d3

その他参考サイト(qiita以外)

http://m-shige1979.hatenablog.com/entry/2016/10/14/080000
http://ola.kironono.com/entry/2016/04/09/205251
http://iti.hatenablog.jp/entry/2016/04/27/113053
http://furyu.hatenablog.com/entry/20160225/1456353020