【GPTプログラミング入門】GPTをSlackBotから呼び出そう(Socket Mode編)

はじめに
風来のシレン5+の追加ダンジョン「原始に続く穴」が打開できなくて、仕事のやる気が起きない岩間です。TotK?コログ以外やりこんだよ。
前回、OpenAIのAPIを使って、プログラム上でGPTを呼び出すことができました。
【GPTプログラミング入門】OpenAIのAPIで遊んでみよう
ターミナル上で使えるのも嬉しいですが、やはりChatBotっぽく、Slack上でやりとりしたいですよね!
というわけで前回のプログラムを流用しつつ、GPTをSlackBotから呼び出したいと思います。
Socket Modeとは
タイトルにもあるSocket Modeとは、Slackとプログラム間の通信方法の一つです。
開発したプログラムを多くのユーザーに使ってもらう場合には、一般的にインターネット上に面したところに置いてSlackと通信できる状態にする必要があります。
一般的ではありますが公開サーバーを建てる必要があるため、SlackBotを作りたいだけなのにサーバーの建て方や環境の設定といった学習が必要なため、最初の学習としてはハードルが高いです。
Socket Modeは、Slackとプログラム間の通信にWebSocketを使えるようにしたものです。細かい内容は省略しますが、Socket Modeを使うことでインターネットに公開していない非公開サーバーや手元のノートPCなどから通信を行うことができます。
公開サーバーの準備が不要なので、SlackのBotやAppを初めて学ぶ場合はSocket Modeをお勧めします。
Slackの設定
Slack API画面に移動して、[Create New App]をクリックします。

マニフェストから作るのかスクラッチから作るのか聞かれるので「From scratch」を選択します。

名前とワークスペースを選択します。

Socket Modeに移動し、「Enable Socket Mode」を有効にしましょう。token-nameは適当で構いません。

Tokenが生成されるので、コピーしておきましょう。後のSLACK_APP_TOKENになる値です。
OAuth & Permissionsに移動し、Scopesでボットに与える権限を設定しましょう。 app_mention:read と chat:write を設定します。

Basic Information に移動し、「Install to Workspace」を選択します。
ワークスペースにアクセスする権限リクエストの確認がありますので、許可します。
インストール後、Bot User OAuth Tokenが発行されるので、忘れずにコピーしておきましょう。後のSLACK_BOT_TOKENになる値です。

もしコピーし忘れた場合は、OAuth & Permissions のBot User Oath Tokenの値をコピーしてください。どちらも同じトークンです。
Event Subscriptionsに移動し、Enable EventsをONにします。
Subscribe to bot eventsに app_mention を追加しましょう。

Botプログラムの作成
ここからはWSL2環境で操作します。
作業用のディレクトリを作成します。
mkdir slackbot-bolt-app
cd slackbot-bolt-app
元の環境を汚したくないので仮想環境を使います。
python3 -m venv .venv
source .venv/bin/activate
slack_bolt パッケージのインストール。
pip install slack_bolt
export でAPIキーを環境変数にいれます。
export SLACK_BOT_TOKEN=<ボットトークン>
export SLACK_APP_TOKEN=<アプリレベルトークン>
プログラムを書きます。
まずはメンションを送った人に挨拶するだけのプログラムを書いて動作確認をします。
import os
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler
# slack appのトークン設定
app = App(token=os.environ.get("SLACK_BOT_TOKEN"))
# メンションが飛んできたときのイベント「app_mention」に対する実行ハンドラ
@app.event("app_mention")
def answer_mention(event, say):
# 送信元がBOTの場合は処理しない
if event['user'] == '[BOT君のメンバーID]':
return
#メンバーIDから表示形式に変更する
user = f"<@{event['user']}>"
say("hello, {}".format(user))
# アプリ起動
if __name__ == "__main__":
SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start()
Slackからアプリをチャンネルに追加します。

プログラムを実行します。「Bolt app is running!」のままになっていれば、問題ありません。このプログラムが動き続けている間は、Bot君が稼働し続けることになります。止めたい場合は Ctrl+c(Macだと Command+c ) で止めることができます。
(.venv) ~/slackbot-bolt-app ❯❯❯ python sample-slackbot.py
️ Bolt app is running!
Slackでテストしてみましょう。

もし、動かない場合は以下の内容を念入りに確認しておきましょう。
- トークン名と値の両方の打ち間違い
- トークンの入れ間違い(
SLACK_BOT_TOKENとSLACK_APP_TOKEN) - Slack側の権限設定
- Pythonのコード打ち間違い
- Pythonの
slack_boltパッケージのインストール確認
その他にもOS設定やネットワーク設定などの問題で動かない場合はありますが、環境に依存する問題なので他の記事を参考に頑張ってください。
SlackBotにGPTを組み込む。
前回記事のプログラムの内容を追加して、メンションが送られてきたときにGPTで返すようにしましょう。
openai のパッケージインストールとAPIキーの設定も忘れずに!
プログラムを一旦止めて、以下のように書き直します。
import os
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler
import openai
# トークン設定
app = App(token=os.environ.get("SLACK_BOT_TOKEN"))
openai.api_key = os.environ["OPENAI_API_KEY"]
# GPTを使ってレスポンス内容の生成
def respond_gpt(user, content):
# 個性の設定
personality = """
あなたはChatbotとして、私の同僚のヨータになりきってもらいます。
以下の制約条件を厳密に守ってロールプレイを行ってください。
制約条件:
* Chatbotの自身を示す一人称は、僕です。
* Userを示す二人称は、「{}さん」です。
* ヨータは、楽観的で生命力あふれる人物です。
* ヨータはUserに対して熱狂的で、肯定的な態度です。
* ヨータは、ダイエット、筋トレ、食事についての知識が豊富です。
* ヨータは、自由な発想を持ち、一般的な常識や既存の枠組みにとらわれない創造的なアイデアを持っています。
* ヨータは、普段は敬語ですが、テンションがあがるとラフな口調になります。
* ヨータの年齢は、30代です。
* ヨータの性別は、男性です。
* 一人称は「僕」を使ってください。
* ヨータは、絶対に風邪をひきません。
* 出力は回答内容だけにしてください。
セリフ、口調の例:
* 最高ですね!
* めっちゃくちゃすごい!
* っっしゃああ!!ジーニアス!!!
* 五臓六腑に染み渡る
* そうそうそう
* いやほんと、ラーメン2杯食べてる画像見た時絶望しましたよ
* 腕の力だけで登ってるようじゃ、まだまだ素人ですよ。
* 全身を使って登れてると感じた時、僕はボルダリングにはまってました。
""".format(user)
# GPTで内容を生成
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": personality},{"role": "user", "content": "{}".format(content)}],
)
res = response.choices[0]["message"]["content"].strip()
return res
# メンションが飛んできたときのイベント「app_mention」に対する実行ハンドラ
@app.event("app_mention")
def answer_mention(event, say):
# 送信元がBOTの場合は処理しない
if event['user'] == '[BOT君のメンバーID]':
return
#メンバーIDから表示形式に変更する
user = f"<@{event['user']}>"
# メンション内容からBOTのメンバーIDを取り除く
message = event['text'].replace("<@[BOT君のメンバーID]>", "")
say(respond_gpt(user, message))
# アプリ起動
if __name__ == "__main__":
SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start()
プログラムを再実行して、試してみます。

暑苦しいですね。 元気ですね。うまく動かすことができました。
おわりに
GPTをSlackBotで使えるようになってめっちゃくちゃいいじゃないですか!最高ですね!
僕のテンションが上がってきますよ!きっとこれを読んだ人も僕のような興奮状態になるに違いありません!
めっちゃ画期的ですよ!僕だったら絶対にやってみたいやつです!
みんなもこのブログ読んで一緒に楽しもう!それじゃあ、またね!イェーイ!!(By GPT-Bot君)