【ChatGPT】OpenAIのPlaygroundで作成したAssistantsをLINEから呼び出せるようにした話

全体の流れ

イメージ的には下の添付画像を参考にしてください!

①まず、OpenAIのPlaygroundでAssistantsを作成しておきます。

Playgroundというのは直感的な画面でOpenAIのAPIが利用できる公式サービスです。
AssistantsというのはChatGPTに前提知識や特定の情報を与えることによって、その情報をもとにChatGPTに回答させる機能です。

②LINEの公式アカウントを作成します。

Bot的な感じで、Messaging APIで自動返信を行います。基本的に無料で使えます。ありがてぇ…!

③LINEとAssistantsを連携させます。

言語はPythonで、Lambda上で動作するようになっています。
このコード内では、LINEのAPIでユーザーからの入力メッセージを取得→OpenAIのAPIでAssistantsにメッセージを投げるという動作と、その逆で生成された回答をLINEのユーザーにフィードバックするという動作までを担当します。

ちなみに、ちょっとめんどくさくなってしまってLambdaの詳しい説明は省いています…すいません…

Assistantsの作成

こちらにアクセスして、Assistantsを作成して前提知識を与えます。作成した時、左上に出てくる「asst_〇〇」がAssistants IDです。コード上からこのassistantsを呼び出す際に使います。

✅ 左下のFileから、ChatGPTに与えたい情報が入ったファイルをアップロードします。
その上のRetrievalをオンにすることによって、ChatGPTにこのファイルからの情報を参考にすることを許可できます。

✅ Instructionsには、回答の方向性を決める指示を入力しておきます。プロンプトで言うところの「あなたは教師です。小学生でもわかるように以下の文を要約してください。」みたいな部分です。

全て設定できたら保存を押して、Assistants IDをメモっておきます。

LINEアカウントの作成

普段使っている個人のLINEアカウントでコンソールにログインして、新しいチャンネルを作成します。この時、Messaging APIを選択してください。

設定する項目

作成したチャンネルの「Messaging API設定」タブで設定する項目があります。

✅ Webhook設定の項目から、Webhookの利用をオンにします。その上のURLはLambdaの関数URLを入力することになるので、Lambda関数を作成したらここに入力します。

これでLINE上でユーザーから送られてきたメッセージ情報がLambdaに送られるようになります。

✅ LINE公式アカウント機能を必要に応じて無効にします。友だち追加した時の「追加ありがとうございます!」みたいなメッセージを消したりできます。

メモしておく項目

APIを利用するために必要になるシークレットやトークンを取得します。

✅ チャネル基本設定タブから、チャネルシークレットをコピーします。

✅ Messaging API設定タブから、長期アクセストークンを発行してコピーします。

以上でLINE側の設定は完了です。続いてPythonでこれらを連携させます!

コード

こちらがPythonのコードです。先ほど取得したシークレットやトークンはLambdaの環境変数に設定しています。

Lambdaレイヤーはlinebotとopenaiを追加しています。

import json
import logging
import os
import sys
import time
import re

from openai import OpenAI
client = OpenAI()

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

# INFOレベル以上のログメッセージを拾うように設定
# Set to pick up log messages above the INFO level
logger = logging.getLogger()
logger.setLevel(logging.INFO)

# 環境変数からチャネルアクセストークンキー取得
# Obtain channel access token key from environment variable
CHANNEL_ACCESS_TOKEN = os.getenv('CHANNEL_ACCESS_TOKEN')
# 環境変数からチャネルシークレットキーを取得
# Get channel secret key from environment variable
CHANNEL_SECRET = os.getenv('CHANNEL_SECRET')

# それぞれ環境変数に登録されていないとエラー
# Error if not registered in the environment variable, respectively.
if CHANNEL_ACCESS_TOKEN is None:
    logger.error(
        'LINE_CHANNEL_ACCESS_TOKEN is not defined as environmental variables.')
    sys.exit(1)
if CHANNEL_SECRET is None:
    logger.error(
        'LINE_CHANNEL_SECRET is not defined as environmental variables.')
    sys.exit(1)

line_bot_api = LineBotApi(CHANNEL_ACCESS_TOKEN)
webhook_handler = WebhookHandler(CHANNEL_SECRET)

answer = ""

def chatgpt(line_message):
    client = OpenAI(
        api_key=os.getenv('OPENAI_API_KEY'),
    )
    
    # create a thread
    thread = client.beta.threads.create()
    my_assistant = client.beta.assistants.retrieve(os.getenv("ASSISTANT_ID"))
    
    # create a message with the message from LINE and throw it to the thread
    message = client.beta.threads.messages.create(
        thread_id=thread.id,
        role="user",
        content=line_message,
    )
    
    # run the thread with assistants
    run = client.beta.threads.runs.create(
      thread_id=thread.id,
      assistant_id=my_assistant.id,
      instructions=my_assistant.instructions,
    )
    
    # run and wait until the status will be "completed"
    while not run.status == "completed":
        run = client.beta.threads.runs.retrieve(
            thread_id=thread.id,
            run_id=run.id
        ) 
        time.sleep(0.5)
    
    # retrieve the message object from the assistants from the thread
    messages = client.beta.threads.messages.list(
      thread_id=thread.id
    )
    
    # retrieve the response message from the message object
    assistant_messages = []
    for thread_message in messages.data:
        role = thread_message.role
        if role == "assistant":
            for content in thread_message.content:
                content = content.text.value
                assistant_messages.append({"role": role, "content": content})
    print(assistant_messages[0]['content'])
    return assistant_messages[0]['content']

# ユーザーからのメッセージを処理する
# Process messages from users
@webhook_handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    
    responce = chatgpt(event.message.text)
    regex_pattern = r"【.*?】"
    cleaned_message = re.sub(regex_pattern, '', responce)
    
    # 応答トークンを使って回答を応答メッセージで送る
    # Send your answer in a response message with a response token.
    line_bot_api.reply_message(
        event.reply_token, TextSendMessage(text=cleaned_message))

def lambda_handler(event, context):

    # ヘッダーにx-line-signatureがあることを確認
    # Ensure that the header has x-line-signature
    if 'x-line-signature' in event['headers']:
        signature = event['headers']['x-line-signature']

    body = event['body']
    # 受け取ったWebhookのJSON
    # JSON of the received webhook
    logger.info(body)


    try:
        webhook_handler.handle(body, signature)
    except InvalidSignatureError:
        # 署名を検証した結果がLINEプラットフォームからのWebhookでなければ400を返す
        # If the result of verifying the signature is not a webhook from the LINE platform, 400 is returned.
        return {
            'statusCode': 400,
            'body': json.dumps('Webhooks are accepted exclusively from the LINE Platform.')
        }
    except LineBotApiError as e:
        # 応答メッセージを送る際LINEプラットフォームからエラーが返ってきた場合
        # If an error is returned from the LINE platform when sending a response message
        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 {
        'statusCode': 200,
        'body': json.dumps('Success!')
    }

つまづいた点

openaiのライブラリですが、ローカルでは正常に動いているのにLambda上では以下のようなエラーが出て動きませんでした。
AWS Lambda Error on fast API: No module named ‘pydantic_core._pydantic_core’

これを解決してくれたのが、こちらのコミュニティでram3さんが作成してくれている、Lambdaレイヤー専用のカスタムライブラリを使用することで解決しました。

調べて出てきた方法をいくつか試して全然ダメだったところ、こちらを発見して救われました。もうram3さんに足向けて寝れませんね。どこにいらっしゃるのかご連絡待ってます。


Comments

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です