OpenAI API + Slack Bolt なんちゃってChatGPTを作る! – 実装編

はじめに

元記事をご覧でない方は、そちらを先にご覧いただくことをお勧めします。

詳しいソースコードはこちらです。

こちらは、Slack & ChatGPTのBotを作成する上での、実装方法や実装上あった問題などについて解説する記事となっております。

使用言語はTypeScriptです。AltJSの実質的王者です。今回はこいつに助けられましたが、苦しめられました。

Node.js + Dockerでデプロイするつもりで作成しました。Dockerでいくつかのツールをデプロイしている環境があるため、それに合わせています。 Cloudflare Wokersや、AWS Lambdaのような、サーバーレスで実行するようにもできますが、今回は割愛。

今回の開発は同期の 内山 くんと共同で行ったため、記事執筆も二人で行っております。

目次

  1. プログラムの構造・使用ライブラリ
  2. 気をつけた点
  3. まとめ

プログラムの構造・使用ライブラリ

プログラムの使用ライブラリは、以下のようになっています。 いずれもnpmパッケージです。

パッケージ名用途リンク
@slack/boltSlack API@slack/bolt-npm
openaiOpenAI APIopenai-npm
dotenv環境変数dotenv-npm

後ほど触れますが、このBoltというのがかなりの曲者でした。以前Discord.jsでDiscordのボットを作成したことがあるのですが、それとは悪い意味でかなり違いました。

OpenAIのnpmパッケージは非常に使いやすく、動作も単純です。

dotenvは、環境変数などを内部で認識するために利用しています。

Program_Structure

プログラムの大まかな構造

プログラムの依存関係を、dependency-cruiserで可視化したものです。

プログラムの挙動が単純なためシンプルですが、utils内でもSlack Boltのインスタンスが必要なため、app.tsで独立させました。

file処理内容
src/index.tsBotの起動,イベント挙動の定義
src/app.tsBoltのAppインスタンスの初期化
src/utils/index.ts会話履歴などの配列操作関数などを定義
src/utils/ai.tsOpenAI API関連の関数

気をつけた点

今回TypeScriptを利用したので型についてです。

Slack Boltの型にはかなりの時間を費やしました。

実際、このようなissueが立っているくらいです。

https://github.com/slackapi/bolt-js/issues/826

Developer experience building Slack apps with Bolt using TypeScript #826

今回開発するに当たって、特に困った2個を紹介しようと思います。調べてもなかなか出て来なかったので、困ってる人もいるかと思います。

1つ目

app.message(/.*/, ({ message }) => {}

で取得したmessageを型付けようと思いました。 なんとかGenericMessageEventという型を見つけることがでしました。

ですが、、

const msg: GenericMessageEvent = message;

これだとダメです。

const msg: GenericMessageEvent = message as GenericMessageEvent;

このようにしなければエラーを吐いてしまいます。 また、メッセージの型は複数あり、このGenericMessageEventにしておけば全てのメッセージを網羅してくれそうです。 詳しくはここらへんをご参照ください。

2つ目

続いて、本Botでは

app.client.conversations.replies()

を使用しています。これで返ってくる型がMessage[]なんですが、Message型ってなんやねん。

これはslack web apiのメソッドなので、試しにこのようにしてみました。

import { Message } from '@slack/web-api';

案の定、存在しないと怒られてしまいます。

正解はこうでした。ChatGPTに教えてもらいました。ChatGPTってやっぱりすごい。

import { Message } from '@slack/web-api/dist/response/ConversationsRepliesResponse';

こんなの誰がわかるねん

こんなのわかるわけないですね。最初、ソースコードからMessageを探し出してそのまま貼り付けていました。 ともあれ、それよりは全然いい形にすることができました。

まとめ

今回の開発で存在感のあるトピックに関して、それぞれまとめます。

TypeScript

今回の開発を振り返ると、やはりTypeScriptの偉大さに気づかされます。JavaScriptで同じプログラムを記述しようとすると、おそらく二倍ほど時間が掛かったのではないかと思います。 Slack Boltのところの、型が見つからない問題などもありますが、基本的にそのオブジェクトがどの状態なのか、どのプロパティ、メンバを持つのかが確定するのは素晴らしいです。

Slack Bolt

こいつには苦戦させられました。しかし、webhookでのイベント駆動方式が基本となっていて、discordなどwebsocketが基本のものとはかなり毛色が違うため、アプローチとしては面白かったです。 複雑なアプリケーションが書きたい方は、StackOverflowを読むと良いと思います。公式ドキュメント、リファレンスはあまり参考になりません。 Bolt自体はTypeScriptで書かれているようなので、さらに頑張って欲しいところです。

OpenAI API(GPT)

また、Boltはアレですが、OpenAI側のライブラリはかなり出来が良い印象でした。使い方が単純なため複雑なアプリケーションにも簡単に溶け込ませることができます。npm以外に、Pythonのpipなどにも同様のライブラリがあるようです。 使用言語に関してライブラリが大きな問題となりやすい中、複数言語に跨ってかなりできの良いライブラリがあるのは素晴らしいですね。