Perl Hackers Hub

第44回LINE Messaging APIで作るchatbot―LINE::Bot::APIとngrokでお手軽に(2)

前回の(1)こちらから。

Echo botを作ってみよう

(1)でbotを開発する環境が整いました。⁠2)以降では公式SDKとPSGIPerl Web Server Gateway Inter face/Plackを利用して実装します。

リスト1は入力されたテキストをオウム返しする簡単なEcho botです。最初に、前節で作成したLINE@アカウントをLINE::Bot::APIで利用するための設定が必要です。(1)がその設定で、Developer centerで取得したChannel SecretとChannel Access Tokenを記述します。(2)からは通常のPSGIアプリケーションです。

リスト1 echo.psgi
use strict;
use warnings;
use Plack::Request;
use LINE::Bot::API;
use LINE::Bot::API::Builder::SendMessage;

my $bot = LINE::Bot::API->new(    ―(1)
  channel_secret => 'Channel Secret',
  channel_access_token => 'Channel Access Token',
);

sub {    ―(2)
  my $req = Plack::Request->new(shift);

  unless ($bot->validate_signature($req->content,    ―(3)
            $req->header('X-Line-Signature'))) {
    return [200, [], ['bad request']];
}

my $events = $bot->parse_events_from_json(
                     $req->content);    ―(4)
  for my $event (@{ $events }) {    ―(5)
    if ($event->is_user_event && $event->is_message_event
          && $event->is_text_message) {    ―(6)
      my $messages = LINE::Bot::API::Builder::SendMessage
        ->new->add_text( text => $event->text );    ―(7)
      my $res = $bot->reply_message($event->reply_token,
                  $messages->build);    ―(8)
      ... unless $res->is_success; # error handling
    }
  }

  return [200, [], ["OK"]];
};

Webhookイベントを受信する

botとして作成されたLINE@アカウントに対して一般ユーザーからのメッセージが送信されると、Developer centerで設定したWebhook URL宛にWebhook event objectと呼ばれるJSONオブジェクトが送信されます。bot開発者は、このJSONオブジェクトを受信して適切な処理をする必要があります。

(1)で、ngrokによって作成されたURLをWebhook URLとして設定しており、localhostの5000番ポートでWebhook event objectを受け取れる状態になっています。そのため、リスト1のecho.psgiをplackup echo.psgiとして起動するだけでEcho botが動作します。

受信したメッセージを署名検証する

Webhook URLに対して、偽造したWebhook eventobjectを送信されると、bot側の処理によっては動作の不具合やセキュリティリスクが生じることになります。

LINEのサーバからのリクエストにはX-Line-Signatureヘッダが付与されています。bot側はこのヘッダの値を検証することで、正規のLINEサーバからのリクエストであることを確認できます。公式SDKでは(3)のvalidate_signatureメソッドを利用して署名検証が行えます。公式SDKを利用すれば簡単に署名検証ができるので、リクエストごとに必ず署名検証を行ってください。

Webhook event objectを処理する

ユーザーがbotにメッセージを送信したり、友だちの追加などのイベントが発生したりするタイミングで、LINEサーバからWebhook URLにWebhook event objectを送信します。公式SDKでは、このJSONオブジェクトをパースしてPerlのオブジェクトに変換するparse_events_from_jsonメソッドが提供されていますので、(4)と同じくリクエストボディを簡単にパースできます。

個人開発規模のbotでは一度の送信につき1つのイベントが送信されますが、人気があるbotなど短時間に大量のメッセージが送信される状況になると、一度の送信で複数個のイベントが送信されてきます。そのため、botの実装側では必ず(5)のループ処理を行う必要があります。

本節ではMessage Eventのみを取り扱っていますが、Messaging APIでは主に次に示すイベントが利用できます。

Message Event
テキスト、画像、スタンプなどが送信されたとき
Follow Event
botがユーザーから友だち登録されたとき
Unfollow Event
botがユーザーからブロックされたとき
Join Event
botがグループまたはトークルームに招待されて参加したとき[5]
Leave Event
botがグループから退出させられたとき

LINE::Bot::API::Eventでイベントの処理をする

(4)parse_events_from_jsonメソッドでイベントのパースを行うと、JSONオブジェクトの内容に適したLINE::Bot::API::Eventのオブジェクトが生成されます。これには(6)で記したように受け取ったイベントの種別を簡潔に判断するためのメソッドが実装されています。主なメソッドは表1で示しました。詳細はLINE::Bot::API::Eventのオンラインドキュメントをご覧ください。(6)ではユーザーとの1対1のトークの中で、Textタイプと呼ばれる単純なテキストメッセージを受けとったときに、Echo botとして反応するよう実装しています。

表1 主なイベントオブジェクトのメソッド
説明メソッド例
送信元の種類is_user_event、is_group_event、is_room_event
イベントの種類is_message_event、is_follow_event、is_unfollow_event、is_join_event、is_leave_event
Message Eventでのメッセージの種類is_text_message、is_image_message、is_sticker_message

返信用のメッセージを作成する

前項までは、ユーザーから発生したイベントをbotで処理する方法について解説しました。本項では、bot側からユーザーに向けてメッセージを送信する方法を解説します。Messaging APIでユーザーにメッセージを送信するためには、Send message objectを利用して送信用APIを呼び出す必要があります。

公式SDKではSend message objectを簡単に構築するためのLINE::Bot::API::Builder::SendMessageが実装されており、(7)のとおり簡単に送信用のオブジェクトを作成できます。また、次に示したコードのメソッドチェインを使って、仕様で許されている個数[6]までのメッセージを作成できます。

LINE::Bot::API::Builder::SendMessage->new
    ->add_text( text => $event->text )
    ->add_image(
      image_url => '...', preview_url => '...'
    )
  ->build;

メッセージを返信する

Messaging APIには、ユーザーからのメッセージに返信するためのReply Message APIが用意されています。これを利用すればユーザーからの問いかけに反応するbotを簡単に実装できます。

Webhook URLで受信したイベントの中で、このReply Message APIを利用した返信が可能なイベントだった場合には、イベントオブジェクトの中には返信用のトークンとしてreplyTokenが含まれます。Echo botなどのユーザーからの入力に返信するタイプのbotでは、(8)reply_tokenを使ってreply_messageメソッドを呼び出すことで、適切な返信先にメッセージを送信できます。

replyTokenは一度使うと再利用が不可能になり、イベントを受信してから短期間でトークンが無効になるので、早めに返信を行う必要があります。

自発的にメッセージを送信する

前節ではEcho botを実装したので、ユーザーからのメッセージに返信する方法を紹介しましたが、Messaging APIにはbot側からユーザーに対して自発的にメッセージを送信するためのしくみもあります。

送信先のIDを取得する

LINE BOTは、ユーザーとの1対1のトーク以外に、トークルームやグループにも参加できます。ユーザーならuserIdグループならgroupIdと、それぞれ固有の送信元IDを持っており、次に示したコードで送信元IDが取得できます。

my $from_id;
if ($event->is_user_event) {
  # ユーザーIDを取得
  $from_id = $event->user_id;
} elsif ($event->is_group_event) {
  # グループIDを取得
  $from_id = $event->group_id;
} elsif ($event->is_room_event) {
  # トークルームIDを取得
  $from_id = $event->room_id;
}

返信のAPIとは違い、送信用のAPIでは送信元IDを送信先のIDとして使用します。送信用APIの用途としては、定時バッチ処理などによる定期的なメッセージ配信などがあると思います。バッチ処理でのメッセージ配信を行うには、送信元IDをbot側のストレージに保存しておく必要があります。

1つの送信先に送信する

単独の送信先にメッセージを送信するには、Push message APIを利用します。公式SDKではpush_messageメソッドを利用することで送信可能で、次のコードで送信できます。

$bot->push_message($from_id, $messages->build);

複数人に同時に送信する

定時バッチ処理の配信では、複数人のユーザーに対して同じメッセージを送信する要件があると思います。この要件に対してPush message APIを1ユーザーごとに呼び出していてはコストがかかります。それを解決するためにMulticast APIが提供されており、公式SDKではmulticastメソッドから利用できます。

$bot->multicast([$user1_id, $user2_id, $user3_id, ...],
                $messages->build);

Multicast APIの制限としては、トークルームとグループへの送信には利用できず、最大で150名までのuser_idしか指定できません。Push message APIを150回呼び出すよりも効率的ですので、条件がそろった場合には積極的に使いましょう。

<続きの(3)こちら。>

WEB+DB PRESS

本誌最新号をチェック!
WEB+DB PRESS Vol.130

2022年8月24日発売
B5判/168ページ
定価1,628円
(本体1,480円+税10%)
ISBN978-4-297-13000-8

  • 特集1
    イミュータブルデータモデルで始める
    実践データモデリング

    業務の複雑さをシンプルに表現!
  • 特集2
    いまはじめるFlutter
    iOS/Android両対応アプリを開発してみよう
  • 特集3
    作って学ぶWeb3
    ブロックチェーン、スマートコントラクト、NFT

おすすめ記事

記事・ニュース一覧