はじめに
みなさん「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に従って、楽しく積極的にブログを通じて自分を発信できればいいかと思いました。