こんにちは。chatGPTすごいですね。
Slackを使われている方なら、Slackに組み合わせて使いたいと思いますよね。
こんな感じです。
chatGPTに対応するSlack Botはいろいろなところで実装例も示されていますが、Slack Botのサンプルのデフォルトがjavascriptのため、javascriptで実装したものが多いようです。
当記事では、Slack Botをpythonで実装した例をご紹介します。
このコード例では、Botをローカルホストで実行させることができます。
Slack側のBotの導入設定は、マニュアル通りに実施してください。
Bot コード例 (python)
chatbot.py
import os
from dotenv import load_dotenv
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler
import openai
load_dotenv()
app = App(token=os.environ["SLACK_BOT_TOKEN"])
openai.api_key = os.environ["OPENAI_API_KEY"]
BOTUID = "<@HOGEHOGE>" # 設定したbotのIDに変更する
prev_messages = []
system_message = "You are ChatGPT, a large language model trained by OpenAI. Answer as concisely as possible."
MAX_PREV_MESSAGES = 20
def generate_prompt(messages, input_message):
messages.append({"role": "user", "content": input_message})
print("prompt: " + str(messages))
return messages
def get_response(messages):
response = openai.ChatCompletion.create(model="gpt-3.5-turbo", messages=messages)
res = response["choices"][0]["message"]["content"]
print("ChatGPT: " + res)
return res
def save_messages(thread_ts, input_message, text):
global prev_messages
prev_messages.append({"thread_ts": thread_ts, "role": "user", "content": input_message})
prev_messages.append({"thread_ts": thread_ts, "role": "assistant", "content": text})
if len(prev_messages) > MAX_PREV_MESSAGES:
prev_messages.pop(0)
def add_prev_messages(messages, thread_ts):
global prev_messages
for mes in prev_messages:
if mes["thread_ts"] == thread_ts:
messages.append( {"role": mes["role"], "content": mes["content"] })
return messages
@app.event("app_mention")
def on_mention(event, say):
global prev_messages, system_message
input_message = event["text"]
thread_ts = event.get("thread_ts") or None
channel = event["channel"]
# スレッド内でメンション付きで呼ばれた場合は無視する
if thread_ts != None:
return
# メンションで付けられたslackボット名を削除する
input_message = input_message.replace(BOTUID, "")
# システムプロンプト(性格付け)を付与
messages = [{"role": "system", "content": system_message}]
prompt = generate_prompt(messages, input_message)
response_text = get_response(prompt)
# スレッドを作って、スレッド内に応答する
response = app.client.conversations_replies(channel=channel, ts=event["ts"])
thread_ts = response["messages"][0]["ts"]
say(text=response_text, thread_ts=thread_ts, channel=channel)
save_messages(thread_ts, input_message, response_text)
@app.event("message")
def on_message(event, say):
global prev_messages
# スレッド内での処理の場合のみ実行
if "thread_ts" in event:
messages = []
input_message = event["text"]
channel = event["channel"]
thread_ts = event["thread_ts"]
# メンションで付けられたslackボット名を削除する
input_message = input_message.replace(BOTUID, "")
messages = add_prev_messages(messages, thread_ts)
# messages長=0、すなわち既存のchatGPT生成スレッドではない場合は何もしない
if len(messages) == 0:
return
prompt = generate_prompt(messages, input_message)
response_text = get_response(prompt)
say(text=response_text, thread_ts=thread_ts, channel=channel)
save_messages(thread_ts, input_message, response_text)
if __name__ == "__main__":
handler = SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"])
handler.start()
やり取りの履歴は20件まで記憶しています。ただし、すべてのスレッドで共有しているため、複数並行してやり取りしているとすぐに履歴を消費してしまうでしょう。その場合は20をもっと大きな数字にしてください。
参考文献
なお、コード作成にあたっては下記を参考にさせていただきました。ありがとうございます。
BotをAWS上で動かす場合の例