はじめに
こんにちは、山田です。
今回はLambdaを使用して、LINEとChatGPTを連携させてみたので構築手順に関して記載していきます。
よろしくお願いします。
構成図
構成図は以下の通りです。
AWSサービスとしては、API Gateway
、Lambda
、DynamoDB
を使用します。
CahtGPTから得られた回答に関しては、DynamoDBに保存します。
API Gatewayに関しての復習
API Gatewayは、Lambda関数をHTTPSプロトコル経由で呼び出すための仕組みです。
HTTPAPIとRESTAPI
以下のHTTP APIとREST APIの主な違いについて記載します。
デザイン
REST APIは、リソースベースのデザインを採用しており、HTTPメソッドを使用してリソースに対するアクションを指定します。一方、HTTP APIは、機能ベースのデザインを採用しており、APIに対するアクションを指定するためにHTTPメソッドの代わりに操作名を使用します。
レスポンス形式
REST APIは、JSON、XML、HTML、またはテキスト形式で応答を返すことができますが、HTTP APIはJSON形式の応答のみをサポートしています。
キャッシング
HTTP APIは、HTTP/2プロトコルを使用するため、HTTP/1.1のREST APIよりも効率的にキャッシングができます。HTTP/2は、1つのコネクションで複数のリクエスト/レスポンスを処理できるため、リクエストのオーバーヘッドが減少し、レスポンスの応答速度が向上します。
クライアントライブラリ
HTTP APIは、クライアントライブラリがAWS SDK v3で提供されています。一方、REST APIは、AWS SDK v2やその他のHTTPクライアントライブラリを使用する必要があります。
セキュリティ
HTTP APIは、AWS Identity and Access Management(IAM)ロールとAWS PrivateLinkを使用して、APIエンドポイントを保護することができます。REST APIは、AWS Identity and Access Management(IAM)ロールとAPI Gatewayのカスタム認証を使用して、エンドポイントを保護することができます。
Lambdaプロキシ統合
HTTP APIもREST APIもLambda統合プロキシをオンにすることができます。
Lambdaプロキシ統合は、AWS API Gatewayで利用可能な統合タイプの1つで、Lambda関数をAPI Gatewayに直接統合するために使用されます。この統合タイプを使用すると、API GatewayはLambda関数を呼び出してリクエストを処理し、Lambda関数が返すレスポンスをAPI Gatewayがクライアントに返します。
Lambdaプロキシ統合を使用すると、API Gatewayのデフォルトの統合レスポンスやマッピングテンプレートを使用する代わりに、Lambda関数のレスポンスを直接返すことができます。
これにより、より柔軟性のあるレスポンス処理が可能になります。
Lambdaプロキシ統合がオフになっている場合、API Gatewayはレスポンスを作成するために、Lambda関数を呼び出すのではなく、API Gatewayの統合レスポンステンプレートを使用します。
つまり、「どのURLを、どのLambdaに渡すのか」「受け取ったヘッダーやクエリ文字列などを、どのイベント引数に設定するのか」
等をすべて設定する必要があります。
構築手順
以下より、実際の構築手順について記載していきます。
事前作業
事前に以下のサイトよりアカウント登録し、LINE API KEYとOpenAI API KEYを取得しておきます。
DynamoDBの作成
DynamoDBのコンソール画面に移動し、「messageテーブル」と「sequenceテーブル」を作成します。
「sequenceテーブル」に関しては、以下のように変更します。
Lambda関数の作成
AWSのマネジメントコンソールにログイン後、Lambdaのコンソール画面に移動します。
「関数の作成」をクリックし、ランタイムは「python3.7」を選択します。
以下のコードを記載します。
import json
import os
import requests
import boto3
import time
import decimal
def next_seq(table, tablename):
# DynamoDBのテーブルを更新するためのupdate_item関数を呼び出す
response= table.update_item(
Key={
'tablename' : tablename # プライマリキーを指定する
},
UpdateExpression = "set seq = seq + :val", # seq属性を更新する
ExpressionAttributeValues={
':val' : 1 # seqに加算する値を指定する
},
ReturnValues='UPDATED_NEW' # 更新後の項目値を返すように指定する
)
# 更新後のseqの値を返す
return response['Attributes']['seq']
def lambda_handler(event, context):
#環境変数より値取得
chatgpt_api_key = os.environ['ChatGPT_API_KEY']
line_api_key = os.environ['LINE_API_KEY']
# LINE Messaging APIからのリクエストをパースする
body = json.loads(event['body'])
# LINE Messaging APIから送信されたイベントオブジェクトを取得する
events = body.get('events', [])
# イベントオブジェクトが空の場合は、何もしない
if not events:
return {
'statusCode': 200,
'body': json.dumps({'message': 'success'})
}
# イベントオブジェクトを処理する
reply_token = events[0]['replyToken']
message = events[0]['message']['text']
user_id = events[0]['source']['userId']
#ChatGptのリクエストURL
url = "https://api.openai.com/v1/chat/completions"
#ChatGPTに対するリクエストを作成する
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer " + chatgpt_api_key
}
#モデルは「gpt-3.5-turbo」を使用。
payload = {
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": message}]
}
#質問に対する応答文取得。
response = requests.post(url, headers=headers, data=json.dumps(payload))
response_data = json.loads(response.content.decode('utf-8'))
#改行コードを消す。
response_data = response_data['choices'][0]['message']['content'].lstrip()
#DynamoDBにメッセージの内容を書き込む処理を以下より記載。
dynamodb = boto3.resource('dynamodb')
#シーケンスデータ取得
seqtable = dynamodb.Table('sequence')
nextseq = next_seq(seqtable, 'message')
#現在のUNIXスタンプを得る。
now = time.time()
#messageテーブルに登録する。
messagetable = dynamodb.Table('message')
messagetable.put_item(
Item = {
'id': nextseq,
'message': response_data,
'accepted_at': decimal.Decimal(str(now))
}
)
# LINE Messaging APIに対するレスポンスを作成する
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + line_api_key}
data = {'replyToken': reply_token,
'messages': [
{
'type': 'text',
'text': response_data
}
]
}
# LINE Messaging APIにレスポンスを送信する
response = requests.post('https://api.line.me/v2/bot/message/reply', headers=headers, data=json.dumps(data))
# レスポンスのステータスコードをログに出力する
print(response.status_code)
# Lambda関数のレスポンスを返す
return {
'statusCode': 200,
'body': json.dumps({'message': 'success'})
}
環境変数にLINEとOpenAIのAPI KEYの値を設定します。
API Gatewayの作成
API Gatewayのコンソール画面に移動します。
移動後に「APIを作成」をクリックし、HTTP APIを選択します。
統合は「Lambda」を選択、作成したLAmbda関数を指定し、API名を付けたら「次へ」をクリックします。
後の設定はデフォルトのままとし、「作成」をクリックします。
Lambda関数を確認し、トリガーにAPI Gatewwayが追加されていることを確認します。
LINE Developers
LINE Developerにログインし、「Webhook URL」をAPI GatewayのURLに設定します。
動作確認
LINEでメッセージを送信し、回答が返ってくることを確認します。
DynamoDBを確認し、メッセージが保存されていればOKです。
終わりに
今回はLambdaを使用して、LINEとChatGPTを連携させる手順に関して記載しました。
次はChatGPT APIの使用料金をCloudWatchにて監視する方法について記載していこうと思います。
ありがとうございました。