👋

【ChatGPT × Slack Bolt】メンションしたら答えてくれるSlack BOTを作ってみた

2023/03/04に公開

使ったもの

  1. Glitch
  2. Slack Bolt
  3. openai-node

ここでは Glitch というサードパーティのサービスを使って作業を進めていきます。Glitch はウェブ上で動く IDE で、「リミックス」 (この Remix は GitHub で言う所の clone のようなものと考えてください) することにより元のソースをコピーして新規の自分のプロジェクトとして作業を進めていきます。ブラウザ上で実行できますので、デプロイの必要もありません。
Remix リンク: https://glitch.com/edit/#!/remix/slack-bolt-hello-world

引用元: https://api.slack.com/lang/ja-jp/hello-world-bolt#:~:text=と思います。-,ソースコード,-ここでは Glitch

Slack BoltのGlitchでのテンプレートをSlack公式が用意してくれています。

また、Slack Boltのページの「Events API を使ってアプリを作成する」から、今回使うSlackアプリも作成してください。

コード

index.js
const { App } = require('@slack/bolt');
const { Configuration, OpenAIApi, ChatCompletionRequestMessageRoleEnum } = require("openai");

// TODO: .envファイルに、自身のものを設定する。.envファイルをGitで管理しないよう注意。
// OPENAI_API_TOKEN, SLACK_SIGNING_SECRET, SLACK_BOT_TOKEN, SLACK_APP_TOKEN, SLACK_BOT_ID

const app = new App({
  signingSecret: process.env.SLACK_SIGNING_SECRET,
  token: process.env.SLACK_BOT_TOKEN,
  appToken: process.env.SLACK_APP_TOKEN,
  socketMode: true,
  port: process.env.PORT || 3000,
})

app.event("app_mention", async ({ event, client, say }) => {
  // スレッドのトップのメッセージであればthread_ts、スレッド中のメッセージであればtsを取得する。
  const threadTs = event.thread_ts ? event.thread_ts : event.ts;
  
  try {
    // スレッドのメッセージを取得
    const threadMessagesResponse = await client.conversations.replies({
      channel: event.channel,
      ts: threadTs,
    });
    const threadMessages = threadMessagesResponse.messages

    const slackBotId = process.env.SLACK_BOT_ID;
  
    // OpenAI APIに渡すためのメッセージオブジェクトを作成する。
    const mentionMessages =
      threadMessages.map(message => {
        // メンション付きのものだけを抽出する。ここら辺は好み。
        if(message.text?.includes(`<@${slackBotId}>`) || message.text?.includes(`<@${message.user}>`)){
          const role = message.user === slackBotId ? ChatCompletionRequestMessageRoleEnum.Assistant : ChatCompletionRequestMessageRoleEnum.User
          return { role: role, content: message.text }  
        };
      }).filter(e => e) // undefinedを除く


    const configuration = new Configuration({
      apiKey: process.env.OPENAI_API_TOKEN
    });
    const openai = new OpenAIApi(configuration);

    // Chat completions APIを呼ぶ
    const response = await openai.createChatCompletion({
      model: "gpt-3.5-turbo",
      messages: [
        {
          role: ChatCompletionRequestMessageRoleEnum.System,
          content: "あなたは有能なアシスタントです。",
        },
        ...mentionMessages,
      ],
    });
    const message = response.data.choices[0].message?.content;
  
    // Slack APIを呼んで回答を送信
    await say(
      {
        text:`<@${event.user}>\n ${message}`,
        thread_ts: threadTs
      }
    );

  } catch (e) {
  
    await say(
      {
        text:`<@${event.user}>\n 不具合が発生しました。開発者にお問い合わせください。`,
        thread_ts: threadTs
      }
    );

  }
});

// Start your app
(async () => {
  await app.start(process.env.PORT || 3000);
  console.log('⚡️ Bolt app is running!');
})();

終わりに

記事のタイトルには「ChatGPT」と書いてしまいましたが、正確には「ChatGPTで使われている言語モデル」を使っています。

ChatGPTの凄さが知れたのと同時に、Glitch,Slack Boltの便利さも実感しました。この2つはおそらく今後めちゃ使うと思います。

その他、参考にさせていただいたもの

Discussion