ChatGPT の LINE bot(APIGatewa + Lambda) ハンズオン


この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので十分ご注意ください。

はじめに

みなさん「ChatGPT使い倒してますか?」、かくいう私は夜な夜なChatGPTに対して「友達の作り方」や「人に嫌われない方法とは?」なんかを聞いています。
そんな自分もエンジニアの端くれなので、とりあえず身近なところからということで LINEをつかってChatGPTを、より一層楽しめるようにしていきます。


構成図


ハンズオン

構築のながれ

1.LINE Developers での設定 :プロバイダー作成

2.OpenAI での設定 :API鍵作成

3.ローカルでの設定 :LINE APIのSDK + openai インストール

4.AWS CloudFormationによる構築 :APIGateway + Lambda

5.Lambdaにデプロイを実施

6.LINE Webhook での設定


1.LINE Developers での設定 :プロバイダー作成

AWS Lambdaを利用したLINEbotハンズオンの実装「1.LINE Developersでプロバイダーの登録」に従いプロバイダーを設定する。

「3.Lambdaの設定(AWSコンソール)」の「3.5 環境変数の値を確認する」も参照して、後続作業で必要となるチャンネルアクセストークンチャンネルシークレットも確認して、自身がわかる場所に保存する。

2.OpenAI での設定 :API鍵作成

2.1.OpenAI HPでアカウント作成

OpenAIより、画面の「Get started」を押下してアカウントを作成する。

2.2.秘密鍵作成

API keys作成ページより、「Create new secret key」を押下して秘密鍵を作成する


APIキーが発行されるので、自身がわかる場所に保存する。

3.ローカルでの設定   :LINE APIのSDK + ChatGPTのライブラリ openai インストール

LINE公式ドキュメントより、LINE APIのSDK(ソフトウェア開発キット)をインストール

OpenAI ドキュメントより、ライブラリ openai をインストール

# ①LINE APIのSDK インストール(問題なく終了したら次のコマンドを実施する)
tetutetu214@mbp 20230312-chatgpt % python -m pip install line-bot-sdk -t .

# ②ライブラリ openai インストール
tetutetu214@mbp 20230312-chatgpt % python -m pip install openai -t . 

4.AWS CloudFormationによる構築

4.1.デプロイするベースのAPIGateway + LambdaをCFnで作成

手順.3 で実施した①②を含んだコードを zip にまとめて反映するためのベースを作成する。

AWSTemplateFormatVersion: '2010-09-09'
Description: 'HTTP API'
# ------------------------------------------------------------#
#  Metadata
# ------------------------------------------------------------#
Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      - Label:
          default: "Lambda Configuration"
        Parameters:
        - FunctionName
        - Description
        - Handler
        - MemorySize
        - Runtime
        - Timeout
        - TagsName

# ------------------------------------------------------------#
#  InputParameters
# ------------------------------------------------------------#
Parameters:
  FunctionName:
    Type: String
    Default: "cfn-chatgpt"
  Description:
    Type: String
    Default: "cfn-chatgpt"
  Handler:
    Type: String
    Default: "lambda_function.lambda_handler"
  MemorySize:
    Type: String
    Default: "128"
  Runtime:
    Type: String
    Default: "python3.9"
  Timeout:
    Type: String
    Default: "300"
  TagsName:
    Type: String
    Default: "inamura"
# ------------------------------------------------------------#
#  Resources
# ------------------------------------------------------------#
Resources:
# ------------------------------------------------------------#
#  Role Lambda
# ------------------------------------------------------------#
  LambdaRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${FunctionName}-role"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Action: "sts:AssumeRole"
            Principal:
              Service: lambda.amazonaws.com
      Policies:
        - PolicyName: !Sub "${FunctionName}-policy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action:
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                  - "logs:CreateLogGroup"
                Resource: !Sub "arn:${AWS::Partition}:logs:*:*:*"
#  Lambda
# ------------------------------------------------------------#
  Lambda:
    Type: AWS::Lambda::Function
    Properties:
      Description: !Ref Description
      Code:
        ZipFile: |
            import json

            def lambda_handler(event, context):
            # TODO implement
                return {
                    'statusCode': 200,
                    'body': json.dumps('Hello from Lambda!')
                }
      Environment:
        Variables:
          LINE_CHANNEL_ACCESS_TOKEN: XXXXXXXXXX
          LINE_CHANNEL_SECRET: YYYYYYYYYY
          OPENAI_API_KEY: ZZZZZZZZZZ
      FunctionName: !Sub "${FunctionName}-lmd"
      Handler: !Ref Handler 
      MemorySize: !Ref MemorySize
      Runtime: !Ref Runtime
      Timeout: !Ref Timeout
      Role: !GetAtt LambdaRole.Arn
      Tags:
        - Key: "User"
          Value: !Ref TagsName

# ------------------------------------------------------------#
#  APIGateway
# ------------------------------------------------------------#
  HttpApi:
    Type: AWS::ApiGatewayV2::Api
    Properties:
      Name: !Sub "${FunctionName}-apigateway"
      ProtocolType: HTTP

  HttpApiDefaultStage:
    Type: AWS::ApiGatewayV2::Stage
    Properties:
      ApiId: !Ref HttpApi
      StageName: "default"
      AutoDeploy: true

  HttpApiHelloIntegration:
    Type: AWS::ApiGatewayV2::Integration
    Properties:
      ApiId: !Ref HttpApi
      IntegrationType: AWS_PROXY
      IntegrationUri: !GetAtt Lambda.Arn
      PayloadFormatVersion: '2.0'

  HttpApiHelloIntegrationPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt Lambda.Arn
      Principal: apigateway.amazonaws.com
      SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*/chatgpt"

  HttpApiHelloRoute:
    Type: AWS::ApiGatewayV2::Route
    Properties:
      ApiId: !Ref HttpApi
      RouteKey: ANY /chatgpt
      AuthorizationType: NONE
      Target: !Sub "integrations/${HttpApiHelloIntegration}"

4.2.デプロイ後 Lambda の環境変数を設定

Lambdaの環境変数に今まで取得した値を入力して保存する
・X箇所に 1 で取得した LINEのチャンネルアクセストークン
・Y箇所に 1 で取得した LINEのチャンネルシークレット
・Z箇所に 2 で取得した ChatGPTのAPI Key


5.Lambdaにデプロイを実施

5.1.デプロイ前に Lambdaで実装する内容をlambda_function.pyで作成

下記ファイルを作成する

import os
import sys
import logging
import openai

from linebot import (LineBotApi, WebhookHandler)
from linebot.models import (MessageEvent, TextMessage, TextSendMessage)
from linebot.exceptions import (LineBotApiError, InvalidSignatureError)

logger = logging.getLogger()
logger.setLevel(logging.ERROR)

#環境変数からLINEBotのチャンネルアクセストークンとシークレットを読込
#環境変数からChatGpt APIの鍵を読込
channel_secret = os.getenv('LINE_CHANNEL_SECRET', None)
channel_access_token = os.getenv('LINE_CHANNEL_ACCESS_TOKEN', None)
openai.api_key = os.getenv("OPENAI_API_KEY")

#トークンが確認できない場合エラー出力
if channel_secret is None:
    logger.error('Specify LINE_CHANNEL_SECRET as environment variable.')
    sys.exit(1)
if channel_access_token is None:
    logger.error('Specify LINE_CHANNEL_ACCESS_TOKEN as environment variable.')
    sys.exit(1)

#apiとhandlerの生成(チャンネルアクセストークンとシークレットを渡す)
line_bot_api = LineBotApi(channel_access_token)
handler = WebhookHandler(channel_secret)

#Lambdaのメインの動作
def lambda_handler(event, context):

#認証用のx-line-signatureヘッダー
    signature = event["headers"]["x-line-signature"]
    body = event["body"]

#リターン値の設定
    ok_json = {"isBase64Encoded": False,
               "statusCode": 200,
               "headers": {},
               "body": ""}
    error_json = {"isBase64Encoded": False,
                  "statusCode": 500,
                  "headers": {},
                  "body": "Error"}

#LINEからのメッセージを ChatGPTに送信、受信したテキストをLINEで返信
    @handler.add(MessageEvent, message=TextMessage)
    def message(line_event):
        text = line_event.message.text

        completion = openai.ChatCompletion.create(
          model="gpt-3.5-turbo",
          messages=[
            {"role": "user", "content": text}
          ]
        )
  #受信したテキストをCloudWatchLogsに出力する
        print(completion.choices[0].message.content)
        text=completion.choices[0].message.content.lstrip()

        line_bot_api.reply_message(line_event.reply_token, TextSendMessage(text=text))

#例外処理としての動作
    try:
        handler.handle(body, signature)
    except LineBotApiError as e:
        logger.error("Got exception from LINE Messaging API: %s\n" % e.message)
        for m in e.error.details:
            logger.error("  %s: %s" % (m.property, m.message))
        return error_json
    except InvalidSignatureError:
        return error_json

    return ok_json

5.2.lambda_function.pyを含めてzip化

赤枠内全てを選択して zip でまとめる(一番下の赤枠は 5.1で作成したコードを指す)


5.3.Lambda にデプロイ

zip を Lambda にデプロイ


6.LINE Webhook での設定

6.1.LINE Webhook設定値取得

Lambda設定 > トリガーより APIGatewayエンドポイントの値を取得

6.2.LINE Webhook設定

LINE コンソールから、手順1 で作成したプロバイダーへ移動して、Messaging API設定を選択して赤枠部分にAPIエンドポイントを入力


6.3.LINE Webhook設定の確認

Webhook設定配下の検証を押下して下記画面が出力されることを確認する


挙動の確認

1.LINEのQRコード読取りで友達登録


2.ChatGPTとのやりとりが実現される


3.無料利用枠を確認する

OpenAI HP より Usageを確認することで利用金額を把握することが可能です。


さいごに

基本的にAPIに文章を送っただけですが、少しだけChatGPTとの仲が深まったように思えます。
ChatGPTのドキュメントを読めばもう少し気の利いた実装も出来そうですが、今回の検証はここまでとします。
ちなみに、友達の作り方は「少しの勇気と積極性で、自分の興味分野を開示する」必要があるみたいです。ChatGPTに従って、楽しく積極的にブログを通じて自分を発信できればいいかと思いました。

Last modified: 2023-03-12

Author