Rainbow Engine

IT技術を分かりやすく簡潔にまとめることによる学習の効率化、また日常の気付きを記録に残すことを目指します。

IT技術 (Technology)

OpenAIのAPIを使ったSlackボットの作り方

投稿日:2023年6月16日 更新日:

 

<目次>

(1) OpenAIのAPIを使ったSlackボットの作り方
 (1-1) やりたいこと
 (1-2) 前提条件
 (1-3) サンプルコード

(1) OpenAIのAPIを使ったSlackボットの作り方

(1-1) やりたいこと


Slackボット
に問いかけると、OpenAIのAPIからの回答が返ってくるようにしたい
 
(動画111)

(1-2) 前提条件

・①Slackボットの初期作成が完了している。
 
・②Open AIのAPIが疎通済

(1-3) サンプルコード

(サンプルプログラム)
import os
import time
from dotenv import load_dotenv
from slack_bolt import App
from slack_sdk import WebClient
# Flaskクラスのインポート
from flask import Flask, request,jsonify
from slack_bolt.adapter.flask import SlackRequestHandler
#ソケットモード用
from slack_bolt.adapter.socket_mode import SocketModeHandler
# 環境変数読み込み
import env
# ロギング
import traceback
# OpenAI
import openai
import pkg_resources

# モードに応じて書き換え
BOT_USER_ID = "ご自身のBOT_USER_ID"
# Botトークン(Flask)
WEBAPPS_SLACK_TOKEN = "ご自身のxoxbから始まるトークン"
WEBAPPS_SIGNING_SECRET = "ご自身のSigning Secret"
# Botトークン(ソケットモード)
SOCK_SLACK_BOT_TOKEN = "ご自身のxoxbから始まるトークン"
SOCK_SLACK_APP_TOKEN = "ご自身のSigning Secret"
# OpenAIのAPI設定
openai.api_key = "ご自身のOpenAI API Key"
# openai.api_version = "2022-02-16"  # 使用するバージョンを指定
openai_version = pkg_resources.get_distribution("openai").version

# モード入れ替え(WebAPサーバ実行=Flask/ローカル実行=ソケットモード)
def app_mode_change(i_name):
    if i_name == "__main__":
        return App(token=SOCK_SLACK_BOT_TOKEN)
    else:
        return App(token=WEBAPPS_SLACK_TOKEN, signing_secret=WEBAPPS_SIGNING_SECRET)

# グローバルオブジェクト
s_app = app_mode_change(__name__)
# Flaskクラスのインスタンス生成
app = Flask(__name__)
#app.config['JSON_AS_ASCII'] = False
handler_flask, handler_socket = None,None

#ソケットーモードの場合のハンドラ設定
if __name__ == "__main__":
    handler_socket = SocketModeHandler(app=s_app, app_token=SOCK_SLACK_APP_TOKEN, trace_enabled=True)
#Flaskでのハンドラー設定
else:
    handler_flask = SlackRequestHandler(s_app)

# Flask httpエンドポイント
# 疎通確認用1
@app.route('/', methods=['GET', 'POST'])
def home():
    return "Hello World Rainbow 2!!"
# 疎通確認用2
@app.route("/test", methods=['GET', 'POST'])
def hello_test():
    return "Hello, This is test.2!!"

#イベント登録されたリクエストを受け付けるエンドポイント
@app.route("/slack/events", methods=["POST"])
def slack_events():

    # ------------------------------------
    # Challenge用
    # ------------------------------------
    # # Slackから送られてくるPOSTリクエストのBodyの内容を取得
    # json =  request.json
    # print(json)
    # # レスポンス用のJSONデータを作成
    # # 受け取ったchallengeのKey/Valueをそのまま返却する
    # d = {'challenge' : json["challenge"]}
    # # レスポンスとしてJSON化して返却
    # return jsonify(d)

    # ------------------------------------
    # 本番用
    # ------------------------------------
    return handler_flask.handle(request)

@s_app.event("message")
@s_app.event("app_mention")
def respondToRequestMsg(body, client:WebClient, ack):
    ack()
    type = body["event"].get("type", None)
    # 二重で応答するのを防ぐため、メンションの時のイベントのみ応答対象とする
    if type == 'app_mention':
        try:
            #-----------------------------------
            # Slackのイベント情報から各種パラメータを取得
            input_text = body["event"].get("text", None)
            bot_user_id = os.environ.get('BOT_USER_ID')
            channel = body["event"]["channel"]
            ts = body["event"]["ts"]
            thread_ts = body["event"].get("thread_ts", None)
            user = body["event"]["user"]
            attachment_files = body["event"].get("files", None)

            # OpenAIからの返答を生成
            output_text = generate_response(input_text)
            time.sleep(3)  # n秒待機 (実施しないと「The server responded with: {'ok': False, 'error': 'no_text'}」になる)
            # Slackに返答
            client.chat_postMessage(channel=channel, text=output_text ,thread_ts=ts)

        except Exception as e:
            print("-------------------------------------------------")
            print("======== react_to_msg 例外発生:"+str(e))
            traceback.print_exc()

# 前回の会話のリスト
previous_conversation = []
def generate_response(prompt):

    global previous_conversation  # 前回の会話のリストをグローバル変数として使用する
    print(previous_conversation)
    # previous_conversationは前回の発言のリストです
    # ここでは、previous_conversationをテキストに変換して、promptに追加しています
    prompt = "".join(previous_conversation) + "\n" + prompt
    print("-------------------------------------------------"+prompt)

    # APIを使用して、応答を生成します
    response = openai.Completion.create(
        model="text-davinci-003",
        prompt=prompt,
        max_tokens=200,
        n=1,
        stop=None,
        temperature=0.5,
    )

    # 応答のテキストを取得します
    message = response.choices[0].text.strip()
    # previous_conversationの最大長を10に制限する
    previous_conversation = previous_conversation[-9:] + [prompt, message]
    return message

# __name__はPythonにおいて特別な意味を持つ変数です。
# 具体的にはスクリプトの名前を値として保持します。
# この記述により、Flaskがmainモジュールとして実行された時のみ起動する事を保証します。
# (それ以外の、例えば他モジュールから呼ばれた時などは起動しない)
if __name__ == '__main__':
    EXEC_MODE = "SLACK_SOCKET_MODE"
    # Slack ソケットモード実行
    if EXEC_MODE == "SLACK_SOCKET_MODE":
        handler_socket.start()
    # Flask Web/APサーバ 実行
    elif EXEC_MODE == "FLASK_WEB_API":
        # Flaskアプリの起動
        # →Webサーバが起動して、所定のURLからアクセス可能になります。
        # →hostはFlaskが起動するサーバを指定しています(今回はローカル端末)
        # →portは起動するポートを指定しています(デフォルト5000)
        app.run(port=8000, debug=True)

Adsense審査用広告コード


Adsense審査用広告コード


-IT技術 (Technology)
-

執筆者:


comment

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

関連記事

シーケンス図の書き方やサンプルのご紹介(内部設計)

  <目次> (1) シーケンス図の書き方やサンプルのご紹介(内部設計)  (1-1) シーケンス図を作る目的  (1-2) シーケンス図の書き方  (1-3) ご参考:縦軸の単位について …

no image

Miroでプランを確認する方法

  <目次> (1) Miroでプランを確認する方法  (1-1) 確認方法  (1-2) 【注意点】基本的にプラン(≒Subscription)は「アカウント」ではなく「チーム」に紐づく …

プロセス構成図の書き方とサンプルのご紹介

  <目次> (1) プロセス構成図の書き方とサンプルのご紹介  (1-1) プロセス構成図の目的  (1-2) プロセス構成図の書き方  (1-3) プロセス構成図のサンプル (1) プロ …

Slackで入力フォームを作る方法についてご紹介

  <目次> (1) Slackで入力フォームを作る方法についてご紹介  (1-1) STEP0:前提条件  (1-2) STEP0:前提条件  (1-3) STEP1:Slackでボット用 …

no image

Kerasでロジスティクス回帰を実装した例をご紹介

  <目次> (1) Kerasでロジスティクス回帰を実装した例をご紹介  (1-1) 実装のフローとポイント  (1-2) 実装例 (1) Kerasでロジスティクス回帰を実装した例をご紹 …

  • English (United States)
  • 日本語
Top