技術は私たちの力。技術は私たちの楽しみ。 Creative Developer BLOG 技術部ブログ
Technology is our strength. Technology is what we enjoy.

LINEのMessages APIでAPIに触れてみる

2018-10-19 
研修期間も終わり正式にシステム部配属になった泉本です。
何をやろうかと本屋でネタを探していたところ「LINEBot」なる文字を発見。
Botといったら自動返信のイメージ。業務中APIを使っていろんなことをしてますが僕自身APIを直接触ったことがないので、LINEという開けたサービスを用いてAPIに触ってみたいなと思い、取り組んでみることにしました。

STEP1 そもそもBotって…?

まずは一般に言われるBotとは何か、LINEBotはどのように違うのかを調べてみました。

botの定義

調べてみるとbotとは「Robot」の略称で、人間に代わって作業を行うコンピュータープログラムの総称のようです。
オンラインゲームなどではNPCのことを「Bot」と呼んだりもしますが今回はコンピュータやインターネットの分野においては、作業を自動化するプログラムを指しています。

今回挑戦するLINEBotとは?

今回挑戦するLINEBotというのは、LINE上で動く自動返信プログラムです。
2016年4月にLINE社がMessaging APIというものを公開し、一般の方でも簡単(?)にLINEBotを作れるようになりました。

最近ではソーシャルゲームの販促手段(事前登録のためにLINEアカウントを追加して、など)としてよく使われているのを目にします。
他にもLINEから公式で出ている翻訳のBotだったり、使い方によっては雑談をしてくれるBotだったり、用途は様々に及びます。

今回は初めてということもあり、とりあえず定番のオウム返しBotを作ってみようと思います。

STEP2 環境構築

今回オウム返しBotを作成するにあたり参考にしたのがこちら
『LINE BOTを作ろう! Messaging APIを使ったチャットボットの基礎と利用例』
本

LINE BOTを作ろう! Messaging APIを使ったチャットボットの基礎と利用例(定価2,800円+税)

必要になるもの

PHP

http://www.php.net/
プログラミング言語。他にもRubyとか選択可能ですがかじったことのあるものを選択
Heroku

Heroku: クラウド・アプリケーション・プラットフォーム

https://jp.heroku.com/
PHPで書いた諸々のファイルをこのHerokuというPAAS(サーバやOS、データベースなどの「プラットフォーム」と呼ばれる部分を、インターネット越しに使えるようにしてくれるサービスの一つ)にデプロイすることで、簡単にLINEBotに反映させることが出来ます。
Github

Github

https://github.com/
ローカル環境で書いたコードをHEROKUで参照するためにGitを用います。HerokuではHerokuGit、container registry、Githubのいずれかを利用してデプロイします。
本ではDropBoxを用いていたのですが、サービス対象外となっていたためGithubを用いることに

LINE Developers

https://developers.line.me/ja/
・LINE Developers
→ここにプログラムを適用させることで実機の方で挙動の確認、およびサービスの配信が出来ます

STEP3 開発

そんなこんなで開発環境の構築が完了しました。
ここからやっとコードを書いていきます。

LINEBotへ反映するまでの流れ

実際にLINEBotに反映させるための諸々の設定にはHerokuを用いるので、ローカル環境、仮想環境問わずに開発は行えるみたいです。
Windowsのメモリ領域が怪しいので仮想環境でやることにします。

LINEBotで動くようになるまでの大まかな流れとしては下記の通りになります。
①PHP(開発に用いる言語)とHerokuをローカル環境にDL
②HerokuとGithubのユーザ登録
③Githubでリポジトリ作成
④HerokuへGithubで作成したリポジトリをデプロイする
⑤LINE Developersに登録、「Messages API」を使用するプロジェクトを作成し、その時に発行されるACCESS_TOKENやCHANNEL_SECRETをHerokuの設定に埋め込む
⑥実際のLINEアカウントで確認

まだわかりづらいですね
さらに大まかに分けると
①コード開発
②Githubを通してHerokuへデプロイ
③Herokuを通してLINEBotへ反映される

実際にMessages APIを触ってみる

Messages APIを触ってみたいと思います。
参考にしたのが本だったのでコピペが使えず、インターンの時に本を見て掲示板などを作ったなぁと思い出しながらかなりの量を記述することになりました。
スペルミスやPHPのルールに苦戦しながらなんとか以下を記述しました。

Messages APIのひな形を記述



//Composerでインストールしたライブラリを一括読み込み
require_once __DIR__ . '/vendor/autoload.php';

// アクセストークンを使いCurlHTTPClientをインスタンス化
$httpClient = new \LINE\LINEBot\HTTPClient\CurlHTTPClient(getenv('CHANNEL_ACCESS_TOKEN'));

// CurlHTTPClientとシークレットを使いLINEBotをインスタンス化
$bot = new \LINE\LINEBot($httpClient, ['channelSecret' => getenv('CHANNEL_SECRET')]);

// LINE Messaging APIがリクエストに付与した署名を取得
$signature = $_SERVER['HTTP_' . \LINE\LINEBot\Constant\HTTPHeader::LINE_SIGNATURE];

// 署名が正当かチェック。正当であればリクエストをパースし配列へ
// 不正であれば例外の内容を出力
try{
$events = $bot->parseEventRequest(file_get_contents('php://input'),$signature);

} catch(\LINE\LINEBot\Exception\InvalidSignatureException $e) {
error_log('parseEventRequest failed. InvalidSignatureException =>'.var_export($e, true));

} catch(\LINE\LINEBot\Exception\UnknownEventTypeException $e) {
error_log('parseEventRequest failed. UnknownEventTypeException =>'.var_export($e, true));

} catch(\LINE\LINEBot\Exception\UnknownMessageTypeException $e) {
error_log('parseEventRequest failed. UnknownMessageTypeException =>'.var_export($e, true));

} catch(\LINE\LINEBot\Exception\InvalidEventRequestException $e) {
error_log('parseEventRequest failed. InvalidEventRequestException =>'.var_export($e, true));
}

//配列に格納された各イベントをループで処理
foreach ((array)$events as $event){
// MessageEventクラスのインスタンスでなければ処理をスキップ
if(!($event instanceof \LINE\LINEBot\Event\MessageEvent)){
error_log('Non Message event has come');
continue;
}
// TextMessageBuilderクラスのインスタンスでなければ処理をスキップ
if(!($event instanceof \LINE\LINEBot\Event\MessageEvent\TextMessage)){
error_log('Non Message event has come');
continue;
}
//オウム返し
$bot->replyText($event->getReplyToken(), $event->getText());

}

//テキストを返信。引数はLINEBot、返信先、テキスト
function replyTextMessage($bot,$replyToken,$text) {
// 返信を行いメッセージを取得
// TextMessageBuilderの引数はテキスト
$response = $bot->replyMessage($replyToken, new \LINE\LINEBot\MessageBuilder\TextMessageBuilder($text));

//レスポンスが異常な場合
if(!$response->isSucceeded()){
//エラー内容を出力
error_log('Failed! '. $response->getHTTPStatus . ' '.$response->getRawBody());
}
}

//画像を返信。引数はLINEBot、返信先、画像URL、サムネイルURL
function replyImageMessage($bot,$replyToken,$originalImageUrl,$previewImageUrl){
// ImageMessageBuilderの引数は画像URL、サムネイルURL
$response = $bot->replyMessage($replyToken, new \LINE\LINEBot\MessageBuilder\ImageMessageBuilder($originalImageUrl, $previewImageUrl));
if(!$response->isSucceeded()){
error_log('Failed! '. $response->getHTTPStatus . ' '.$response->getRawBody());
}
}

//位置情報を返信。引数はLINEBot、返信先、タイトル、住所、緯度、経度
function replyLocationMessage($bot, $replyToken, $title, $address, $lat, $lon) {
//LocationMessageBuilderの引数はダイアログのタイトル、住所、緯度、経度
$response = $bot->replyMessage($replyToken, new \LINE\LINEBot\MessageBuilder\LocationMessageBuilder($title,$address,$lat,$lon));
if(!$response->isSucceeded()){
error_log('Failed! '. $response->getHTTPStatus . ' '.$response->getRawBody());
}
}

//スタンプを返信。引数はLINEBot、返信先、スタンプのパッケージID、スタンプID
function replyStickerMessage($bot, $replyToken, $packageId, $stickerId) {
//StickerMessageBuilderの引数はスタンプのパッケージID、スタンプID
$response = $bot->replyMessage($replyToken, new \LINE\LINEBot\MessageBuilder\StickerMessageBuilder($packageId, $stickerId));
if(!$response->isSucceeded()){
error_log('Failed! '. $response->getHTTPStatus . ' '.$response->getRawBody());
}
}

//動画を返信。引数はLINEBot、返信先、動画URL、サムネイルURL
function replyVideoMessage($bot, $replyToken, $originalContentUrl, $previewImageUrl) {
//VideoMessageBuilderの引数は動画URL、サムネイルURL
$response = $bot->replyMessage($replyToken, new \LINE\LINEBot\MessageBuilder\VideoMessageBuilder($originalContentUrl, $previewImageUrl));
if(!$response->isSucceeded()){
error_log('Failed! '. $response->getHTTPStatus . ' '.$response->getRawBody());
}
}

//オーディオファイルを返信。引数はLINEBot、返信先、ファイルのURL、ファイルの再生時間
function replyAudioMessage($bot, $replyToken, $originalContentUrl, $audioLength) {
//AudioMessageBuilderの引数は動画URL、サムネイルURL
$response = $bot->replyMessage($replyToken, new \LINE\LINEBot\MessageBuilder\AudioMessageBuilder($originalContentUrl, $audioLength));
if(!$response->isSucceeded()){
error_log('Failed! '. $response->getHTTPStatus . ' '.$response->getRawBody());
}
}

//複数のメッセージをまとめて返信。引数はLINEBot、返信先、メッセージ(可変長引数)
function replyMultiMessage($bot, $replyToken, ...$msgs) {
//MultiMessageBuilderをインスタンス化
$builder = new \LINE\LINEBot\MessageBuilder\MultiMessageBuilder();
// ビルダーにメッセージをすべて追加
foreach($msgs as $value){
$builder->add($value);
}
$response = $bot->replyMessage($replyToken,$builder);
if(!$response->isSucceeded()){
error_log('Failed! '. $response->getHTTPStatus . ' '.$response->getRawBody());
}
}

// Buttonsテンプレートを送信。引数はLINEBot、返信先、代替テキスト、画像URL、タイトル、本文、アクション(可変長引数)
function replyButtonsTemplate($bot, $replyToken, $alternativeText,$imageUrl,$title,$text, ...$actions) {
// アクションを格納する配列
$actionArray = array();
// アクションをすべて追加
foreach($actions as $value) {
array_push($actionArray, $value);
}
//TemplateMessageBuilderの引数は代替テキスト、ButtonTemplateBuilder
$builder = new \LINE\LINEBot\MessageBuilder\TemplateMessageBuilder(
$alternativeText,
// ButtonTemplateBuilderの引数はタイトル、本文
// 画像URL、アクションの配列
new \LINE\LINEBot\MessageBuilder\ButtonTemplateBuilder($title,$text,$imageUrl,$actionArray)
);
$response = $bot->replyMessage($replyToken, $builder);
if(!$response->isSucceeded()){
error_log('Failed! '. $response->getHTTPStatus . ' '.$response->getRawBody());
}
}

//Confirmテンプレート返信。引数はLINEBot、返信先、代替テキスト、本文、アクション(可変長引数)
function replyConfirmTemplate($bot, $replyToken, $alternativeText,$text, ...$actions) {
$actionArray = array();
foreach($actions as $value) {
array_push($actionArray, $value);
}
$builder = new \LINE\LINEBot\MessageBuilder\TemplateMessageBuilder(
$alternativeText,
// Confirmテンプレートの引数はテキスト、アクションの配列
new \LINE\LINEBot\MessageBuilder\ConfirmTemplateBuilder($text,$actionArray)
);
$response = $bot->replyMessage($replyToken, $builder);
if(!$response->isSucceeded()){
error_log('Failed! '. $response->getHTTPStatus . ' '.$response->getRawBody());
}
}

//Carouselテンプレートを返信。引数はLINEBot、返信先、メッセージ(可変長引数)
//ダイアログの配列
function replyCarouselTemplate($bot, $replyToken, $alternativeText, $columnArray) {
$builder = new \LINE\LINEBot\MessageBuilder\TemplateMessageBuilder(
$alternativeText,
// Carouselテンプレートの引数はダイアログの配列
new \LINE\LINEBot\MessageBuilder\CarouselTemplateBuilder($columnArray)
);
$response = $bot->replyMessage($replyToken, $builder);
if(!$response->isSucceeded()){
error_log('Failed! '. $response->getHTTPStatus . ' '.$response->getRawBody());
}
}

?>

面白いと思ったAPIを一つ紹介

replyImageMessageというAPIでプレビュー画像(ラインで画像を受け取りタップする前)とオリジナル画像(画像をタップで出てくる)ものがあり、そこをいじることでプレビューと全く違った画像を出せるので悪戯に使えそうだなと思いました。
プレビュー画像

プレビュー画像

テキストを打つと画像が送られる
オリジナル画像

タップで表示される画像

このように全く異なった画像を表示できます。

最後に

コピペを用いれない、かつあまり触ったことのない言語を試したことで進捗としてはあまり芳しくないなと思いながら作業していました。

環境構築の方に時間がとられたため、コードの方に時間があまり取れなかったり、作成しようとしていたものが課金必須だったりと、計画性のなさが目立ってしまったなと思います。

それと昨年?の勉強会で菊田さんがMessages APIを使って名刺のOCRの仕組みを作ってるのを本日19日に気づきました…完全な下位互換ですね

Perlができないうちに他の言語に手を出すのもどうかと思いましたがやってみて楽しかったので少しずつ触ってみようと思いました。
記事一覧へ