0
3

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.

SlackからChatGPTを使う

Last updated at Posted at 2023-02-24

概要

ChatGPT 面白いですよね。
いつ仕事奪われるかとドキドキします。
「そんなChatGPTがSlackから使えたら便利かも?」と思い、2023-03-01 に公開されたChatGPTのAPIを利用して作ってみました。

※ご注意
ChatGPTのAPIは従量課金なのでご注意ください。
無料枠があるので一旦は使えます。

アーキテクチャ

Slash Commandで質問 > API Gateway > AWS Lambda(一次受け) > AWS Lambda(本処理) > ChatGPTに問い合わせ > Slackチャンネルに回答

ポイント
Slash Commandは3秒以内にレスポンスを返す必要がある一方、OpenAIのAPIレスポンスは数秒かかるため1プロセスでの実現はできません。
そのため AWS Lambda を2段階に分けて、非同期起動した AWS Lambda で ChatGPT を利用してSlackチャンネルに投げ込む形としました。

手順

  1. OpenAIアカウントでAPI_KEY取得
  2. AWS Lambda(本処理)作成
  3. AWS Lambda(一次受け)作成
  4. API Gatewayでルート設定し、バックエンドにAWS Lambda(一次受け)を設定
  5. SlackアカウントでSlash Command作成

順に説明していきます。

1.OpenAIアカウントでAPI_KEY取得

こちらから発行します。

Account API Keys - OpenAI API
https://platform.openai.com/account/api-keys

2.AWS Lambda(本処理)作成


import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    logger.info(event)
    logger.info(context)

    # application/x-www-form-urlencoded で受信するのでデコードする
    logger.info(event["body"])
    import base64
    kv = base64.b64decode(event["body"]).decode("utf-8")
    logger.info(kv)
    import urllib
    parsed = urllib.parse.parse_qs(kv)
    # logger.info(parsed)
    name = parsed["user_name"][0]
    prompt = parsed["text"][0]
    response_url = parsed["response_url"][0]

    import os
    model_url = os.environ["MODEL_URL"]
    model = os.environ["MODEL"]

    import requests
    response = requests.post(model_url,
        headers={
            "Content-Type": "application/json",
            "Authorization": "Bearer %s" % os.environ["OPEN_API_KEY"]
        },
        json={
            "model": model,
            "messages": [
                {"role": "user", "content": prompt,},
            ]
        }
    )

    import json
    values = json.loads(response.text)
    logger.info(values)
    payload = {"response_type": "in_channel","text": prompt + "\n\n".join([choice["message"]["content"] for choice in values["choices"]])}
    requests.post(response_url,data=json.dumps(payload),headers={"content-type": "application/json"})

    return {
        "statusCode": 200,
        "body": ""
    }
環境変数名
OPEN_API_KEY 「1.」で取得したもの
MODEL_URL https://api.openai.com/v1/chat/completions
MODEL gpt-3.5-turbo

requestsモジュールを利用しているので同梱するなり、AWS Lambda Layersで読み込むなりしてください。

API仕様はこちらです。
Chat completion - OpenAI API
https://platform.openai.com/docs/guides/chat

ポイント
・呼び出し元チャンネルに回答するためにリクエストに含まれる response_url を利用しています。
・チャンネル内のユーザ全員に見えるようレスポンスに response_type=in_channel を設定しています。
・Slash Commandは他ユーザには見えないのでレスポンスに追加するよう調整しています。

一次受けから本関数を呼び出すためにLambda関数名を控えておきます。

3.AWS Lambda(一次受け)作成


import logging
import os
import json

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

import boto3
client = boto3.client("lambda")

def lambda_handler(event, context):
    logger.info(event)

    res = client.invoke(
      FunctionName=os.environ["INVOKE_FUNCTION_NAME"],
      InvocationType="Event", # 非同期
      Payload=json.dumps(event)
    )
    logger.info(res)

    return {
        "statusCode": 200,
        "body": "しばし待たれよ"
    }

環境変数名
INVOKE_FUNCTION_NAME 「3.」で控えたもの

起動時間優先でboto3のインスタンス作成をトップレベルで行うようにしました。

4.API Gatewayでルート設定し、バックエンドにAWS Lambda(一次受け)を設定

今回は慣れている HTTP API で実装しました。
AWS Lambda Function URLでも良いです。

エンドポイントを控えておきます。

5.SlackアカウントでSlash Command作成

こちらの「Slack APIの作成」の項目を参考にさせていただきました。
Request URLに「4.」で控えたエンドポイントを設定します。

【小ネタ】SlackのスラッシュコマンドからLambdaを実行させる方法 | DevelopersIO
https://dev.classmethod.jp/articles/lambda-api-slack-command/

結果

00e85350.png

課題

・このアーキテクチャでもコールドスタートだとタイムアウトするかもしれません。安定化させたい場合はメモリ割り当てを強化してください。なお費用。

参考URL

API Reference - OpenAI API
https://platform.openai.com/docs/api-reference/introduction

Introducing ChatGPT and Whisper APIs
https://openai.com/blog/introducing-chatgpt-and-whisper-apis

Slack Bot をサーバーレスで運用する時の、タイムアウト対策【小技】 - Qiita
https://qiita.com/saken649/items/b70e462ae41614b72f77

AWS LambdaからLambdaを非同期で呼び出す(Python) - Qiita
https://qiita.com/ume1126/items/8170a10fad6b21f0f54a

「ChatGPTのAPI」と「GPT-3のAPI」は同じものなの?違うものなの?について
https://did2memo.net/2023/02/23/chatgpt-chatgpt-api-vs-gpt-3-api/#chatgptapigpt-3api

余談

これを作るにあたって ChatGPT にも聞いてみました。
ヒントになりました。ありがとう!

0
3
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
0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?