まるっとワーク

データ分析・電子工作など気になることを残していきます

AWSを活用してLINEのチャットボットを作る

AWSサービス(Lambda + API Gateway)とLINEを連携させて、チャットボットを作成した時のメモを残します。
最終目標として、LINEで尋ねたワードをChatGPTに投げて、返答結果をLINEに返すといったシステムを作ることを想定しており、
その前段階として、まずはAWSサービスとLINEを連携させるところまでを作り、LINEメッセージをオウム返しするシステムを作ります。

ほぼ同一のシステムを作られた、ありがたい先人方(以下)の知恵を借りて作っていったのですが、クラウドを用いたシステムに慣れていないところがあり、ハマった部分が各所にあるので、そこを重点的に記載して、同じミスをしないようにする。
AWS Lambda + Python + LINE Botで傘が必要か教えてもらう - Qiita
AWSを活用してLINEチャットボットを作ってみた!① | リウコムTechブログ
Lambdaを使用してLINEとChatGPTを連携してみた。 - Qiita


目次

使用環境

AWS Lambda ランタイム python3.9
AWS API Gateway
・LINE (developers)

開発手順

  1. LINE Message APIを使うための環境を整える
  2. AWS の環境を整える+LINEと連携する
  3. AWS Lambdaでコード実行(動作確認)

実装

LINE Message APIを使うための環境を整える:様々な方がやり方を説明している為、簡潔に説明

  • LINE Developersに登録する
  • チャネルを作成する

まずは、LINE Developersに登録します。(URL)
その後、公式ドキュメントの記載に従って、チャネルを作成します。今回は、メッセージのやり取りをしたいので、Messaging APIチャネルを選択して、作成する。
作成が完了したらこのステップは終了!ただ、後のことを考えて、"Messaging API設定"の一番下、"チャンネルアクセストークン"を押下し、その値は控えておく。
Message APIを使用するときに、認証が必要であり、チャンネルアクセストークンはその認証手段として利用する。

LINE Developer


AWS の環境を整える+LINEと連携する:結構苦戦したので、詳しく説明

AWS Lambda関数の作成

AWSコンソールにログインして、Lambdaの画面を開き、関数->関数作成を押下する。
以下のような画面が出るので、関数名は適当に記入、ランタイムは"Python3.9"を設定する。

関数

タイムアウト設定

デフォルトは5秒に設定されていますが、API等 別のシステムとやり取りをする場合は、タイムアウトが起こり得るため、30秒程度まで伸ばした設定に変更する。

AWS Lambdaレイヤー作成

AWS Lambda上で使えないモジュールがある場合は、レイヤーを作成して対応する。
今回は、LINE BOT開発用のline-bot-sdkをインストールして、レイヤーとして設定する必要があります。
また、ChatGPTの使用を想定すると、openaiもインストールして、同様にレイヤーとして設定する必要があります。

  • ローカルでpipコマンドを使って必要モジュールファイルをダウンロード


以下コードでは、"python”フォルダを作成して、そのフォルダに必要モジュールファイルを格納、zip化する

$ mkdir python
$ cd C:\Users\user\python
$ pip install line-bot-sdk -t ./
$ pip install openai -t ./ #openaiモジュールもレイヤーに追加する場合
$ cd ../
$ zip python.zip python/* #zip化する

  • zipファイルをアップロードする

初歩的なのですが、フォルダ構成を間違えて、lambdaで必要なモジュールのimportでエラーが出来ないことで詰まりました。
フォルダ構成は以下(URL)の通りに設定して、アップロードする必要があります。
zipファイルの構成は以下の通り

@@.zip
  -python
    |-@@@
    |-@@@

  • 作成したzipファイルをLambdaレイヤーに設定する。
レイヤー作成

環境変数の登録

環境変数の役割: 環境毎に値が変わるものの管理に使用し、ソースの修正の手間を省かせる。
特定パラメータ(API Key等)を環境変数に設定して、呼び出して使う。

環境変数の設定方法は、URLを参考にする。
今回のシステムでは、以下2点(Openai_ACCESS_TOKENはChatGPT APIを使用する時だけ使用)を環境変数として設定した。
キーは任意に入力し、値にAPIキーを入力して、コード内で呼び出して(LINE_CHANNEL_ACCESS_TOKEN = os.environ['LINE_CHANNEL_ACCESS_TOKEN']という感じ)使う。
LINE Message APIのチャンネルアクセストークンはキー: LINE_CHANNEL_ACCESS_TOKENの値に入力して、今回は設定した。

環境変数

API Gatewayの作成/設定

ここがかなり苦戦したので、詳しく説明していくが、まだ完全に理解できておらず随時付け足す。

Lambdaの関数画面で、以下画像では左下に"API Gateway"という文字とアイコンが存在するが、初期は存在しない。
"+トリガーを追加"個所をクリックして、ウィンドウを開く。

トリガー追加


ウィンドウが開いたのち、"API Gateway"を選択すると以下画像のような設定画面が現れる。

詳細設定

今回はAPIタイプ REST API/セキュリティは"開く"を選択して使用する。
正直APIの種類については分かっていない部分が多く(以下のようなwebページで勉強したのですが・・・)、後々勉強して記載していく。
qiita.com
また、セキュリティに関しても本来は、IAMポリシーを使って使用ユーザーを制限することがベストプラクティスみたいですが・・・一旦は全てに開放する設定にしています。
Amazon API Gateway のセキュリティのベストプラクティス - Amazon API Gateway

上記の通り作成すると、先程の関数ウィンドウのトリガー欄に、API Gatewayが作成される。

API Gateway


API Gatewayの名前をクリックして、詳細を設定する。
以下画像では、"Resources"欄に"/POST"という1つしか存在しないが、当初は"ANY"が存在している。
"ANY"はすべてのHTTPメソッドをサポートしており、そのままでもこのような目的のために使えるのでは?と思っているが、具体的な設定方法が分からなかった為、先人たちの方法にしたがって対応する。
"ANY"メソッドは削除して"POST"メソッドを作成する。POSTメソッドは、HTTP POSTリクエストをサポートしており、HTTP POSTとは、クライアントからの入力内容をWebサーバに送信するために使用するメソッドのこと。

詳細設定


POSTメソッド作成時の設定は以下の通り、"Lambda Function"の入力を求められるが、そこにはLambda 関数名を入力する。

POST

作ろうとしているシステムでは、AWS API GatewayへのHTTP POSTリクエストはLINEから来ることを想定しているが、LINEから来たかどうかの検証をする方法として、署名の検証方法が推奨されているようなので試しに入れてみる。恐らく、この設定がなくても問題なく動作すると思っているが、検証はしていない。もし間違っていたらコメントで教えていただけますと嬉しいです。
メッセージ(Webhook)を受信する | LINE Developers

設定方法は、"Method Request"を選択

メソッドリクエス


HTTP Request Headers欄に"X-Line-Signature"を入力して設定する。

メソッドリクエスト詳細

  • API のデプロイ

"Resources"の横の"Actions"欄から、Deploy APIを選択することで、APIをデプロイ(設置)することができる。
これを忘れて、次工程がうまくいかず、、、参考までにデプロイ方法はこちらのURLに載っています。
デプロイ時のStage名などは、任意に設定する。

  • Webhookの設定

"Stages"選択し、デプロイ時のStage名を選択すると、以下のような画面が現れる。
Invoke URLがリクエストするURLになるので、ここにLINEの送信先が来るように設定する。

リクエスト確認


Webhookとは、ウェブアプリケーションの機能の1つで、外部のサービスやアプリケーションに対して、特定のイベントが発生した際に自動的に通知を送信することができる仕組み。
今回では、LINE上でメッセージを受けた際にそのメッセージと通知の連絡をAWS API Gatewayにリクエストする際に使う。以下の通り、LINE DevelopersのページでWebhook設定個所があるので、上記API GatewayInvoke URLを入力し、"検証"ボタンを押下する。その結果、"成功"と記載されたウィンドウが出れば、問題なく設定できている。

Webhook設定

AWS Lambdaでコード実行(動作確認)

コード作成

Lambda関数では、以下コードを作成/実行する。
LINEからはjson形式のリクエストが送信される。json形式というのをすっかり忘れており、json形式の読み込みでも少しはまってしまった・・
jsonデータは"json.loads"を使うことで、辞書dictなどのオブジェクトとして読み込むことができ、処理ができる。

import json
import urllib.request
import os
from linebot import LineBotApi
from linebot.models import TextSendMessage
from datetime import datetime 

#######APIキーを取得
# 環境変数からLINE Botのチャネルアクセストークンを取得
LINE_CHANNEL_ACCESS_TOKEN = os.environ['LINE_CHANNEL_ACCESS_TOKEN']
# チャネルアクセストークンを使用して、LINE BotのAPIインスタンスを作成
LINE_BOT_API = LineBotApi(LINE_CHANNEL_ACCESS_TOKEN)

########説明
#LINEで入力されたテキストは ['events’][0]['message’]['text’] に入っている
#受信したメッセージに対してリプライを行うには、replyTokenの値を使用する

# ログ出力関数
def logging(errorLv, lambdaName, errorMsg):
    loggingDateStr=(datetime.now()).strftime('%Y/%m/%d %H:%M:%S')
    print(loggingDateStr + " " + lambdaName + " [" + errorLv + "] " + errorMsg)
    return

def lambda_handler(event, context):
    logging("info", context.function_name, "実行開始")
    logging("error", context.function_name, "エラーログテスト")
    if json.loads(event["body"])["events"][0]["type"] == "message":
        if json.loads(event["body"])["events"][0]["message"]["type"] == "text":
            replyToken = json.loads(event["body"])["events"][0]['replyToken']# リプライ用トークン
            messageText = json.loads(event["body"])["events"][0]["message"]["text"]# 受信メッセージ
            LINE_BOT_API.reply_message(replyToken, TextSendMessage(text=messageText))# メッセージを返信(受信メッセージをそのまま返す)

    return {'statusCode': 200, 'body': json.dumps('Reply ended normally.')}


Lambda関数を実行する際、手動で実行(Test)する際は、"Execution results"欄(以下画像)に実行結果が吐き出されるが、今回ケースの場合のエラー確認方法に困った。

Test


そう、今回の系は、LINEにメッセージを送り、そのリクエストがAWS API Gatewayに送られ、Lambda関数が実行される。こういうケースの場合、どこにエラー結果が表示されるのだろう・・・
そうですAmazon CloudWatch この存在を知って助かりました。

Amazon CloudWatchの、ログ->ロググループを選び、対象となるLambda関数を選択すると、実行毎のログを確認できる。
これで、LINEにメッセージを送った後、の結果を追うことができ、エラー処理も対応できる。

CloudWatch

実行結果

LINEでメッセージを送った際の実行結果は以下の通り、意図通り、オウム返しをすることができました。
>

実行結果

まとめ

今回は、AWSサービスとLINEを連携させ、LINEメッセージをオウム返しするシステムを作りました。
次は、ChatGPTと連携させて、ChatGPTへの質問結果をLINEで返すところまでをまとめようと思います。