7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Lambdaを使用してLINEとChatGPTを連携してみた。

Last updated at Posted at 2023-03-08

はじめに

こんにちは、山田です。
今回はLambdaを使用して、LINEとChatGPTを連携させてみたので構築手順に関して記載していきます。
よろしくお願いします。

構成図

構成図は以下の通りです。
空白の図.png
AWSサービスとしては、API GatewayLambdaDynamoDBを使用します。
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テーブル」に関しては、以下のように変更します。
image.png

Lambda関数の作成

AWSのマネジメントコンソールにログイン後、Lambdaのコンソール画面に移動します。
「関数の作成」をクリックし、ランタイムは「python3.7」を選択します。
image.png

以下のコードを記載します。

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の値を設定します。
スクリーンショット 2023-03-08 211443.png

API Gatewayの作成

API Gatewayのコンソール画面に移動します。
移動後に「APIを作成」をクリックし、HTTP APIを選択します。
スクリーンショット 2023-03-08 210353.png
統合は「Lambda」を選択、作成したLAmbda関数を指定し、API名を付けたら「次へ」をクリックします。
image.png
後の設定はデフォルトのままとし、「作成」をクリックします。
image.png

Lambda関数を確認し、トリガーにAPI Gatewwayが追加されていることを確認します。
スクリーンショット 2023-03-08 212620.png

LINE Developers

LINE Developerにログインし、「Webhook URL」をAPI GatewayのURLに設定します。
スクリーンショット 2023-03-08 213835.png

動作確認

LINEでメッセージを送信し、回答が返ってくることを確認します。
image.png

DynamoDBを確認し、メッセージが保存されていればOKです。
image.png

終わりに

今回はLambdaを使用して、LINEとChatGPTを連携させる手順に関して記載しました。
次はChatGPT APIの使用料金をCloudWatchにて監視する方法について記載していこうと思います。
ありがとうございました。

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?