slack-gpt-url-summary-gas
スクリプトは上のレポジトリにあります。
やっていることは
- Google Apps Script(GAS)でWeb appを作り、そのURLにSlackのSlashコマンドでURLを投げる。
- Slashコマンドは3秒以内に返信がないとエラーになるので、一時的な返信を行い、一方でGASの中で別途実行トリガーをかける。
- トリガーで実行するジョブの中でOpenAI APIを使ってChatGPT (gpt-3.5-turbo)に受け取ったURLのページのテキストの要約を作るよう頼む。
- トークンの制限のため、一気に全部読ませることができないので、適当に区切ってそれらの要約を作らせ、さらに最後に作った要約から全体の要約を作らせる。
- できた要約をIncoming Webhookを使ってSlackに投げる。
といった感じ。
Slashコマンドの3秒ルールのため直接返信を返せないのでGASでちょっと工夫が必要です。
設定方法
Slack側
- 新しいSlashコマンドを作る
- Slack APIのページからCreate New App:
- From scarchを選んで
- App Nameは適当にWeb summary by ChatGPTとか。
- インストール先のworkspaceを選ぶ。
新しいIncoming Webhookを作る。左にあるリンクの中からIncoming Webhookへ。Add New Webhook to Workspaceをクリックし、返信先のチャンネルを設定して、作ったWebhook URLをメモしておく。- Slashコマンドが送る
response_url
を使うことで問い合わせたチャンネルに直接返すように変更。
- 新しいSlashコマンドを作る。
- 左のリンクの中からSlash Commandsのリンクへ飛ぶ。
- Command名は
web_sum
とか。日本語版では3行の箇条書きでまとめて、ということにしてるので個人的にはsangyo
というコマンド名にしてます。 - Request URLは後でGASの設定が終わったら入れるのでとりあえずdummyでhttps://example.comとか。
- Short descriptionも適当にSummarize web page.とか。
- Usage Hintには
URL
と。
- Command名は
- 左のリンクの中からSlash Commandsのリンクへ飛ぶ。
- できたらInstall your appからインストール先のworkspaceにインストール。
- このページはあとでも使うのですぐにSlashコマンドの編集が出来るように開いたままにしておいた方が楽。
- From scarchを選んで
- Slack APIのページからCreate New App:
追記: 2023/03/26
Incoming Webhookはアプリの中でも作れるのでそっちを使う。
追記ここまで
追記: 2023/03/27
Slash commandのresponse_url
を使うのでWebhookのURLはいらないように変更。
追記ここまで
これで/web_sum
とかのコマンドがSlackで使えるようになっているはずです。
GAS側
- Goole Apps Script Homeから新しいプロジェクトを作成。
- ライブラリの右にある
+
ボタンを押して以下のスクリプトIDのライブラリの追加:- Cheerio:
1ReeQ6WO8kKNxoaA_O0XEQ589cIrRvEBA9qcWpNqdOP17i47u6N9M5Xh0
- Cheerio:
- slack-gas-url, params, secretsというスクリプトファイルを作る。
- 上のレポジトリの同じ名前のファイルからそれぞれ内容をコピペ。
- params.gsの編集:
- 受け答えを英語にしたい場合には
lang
をenに変更。 prompt
や返信文も必要であればよしなに変更。chunkLength
とoverlap
の調整:- とりあえず最初はデフォルトのままで良いはず。
- 必要であれば調整。
- 受け答えを英語にしたい場合には
- 歯車ボタンからプロジェクトの設定ページへ:
- ページ下にあるプロパティの設定で新しく値を追加
- 名前:
OPENAI_API_KEY
, 値は https://platform.openai.com/account/api-keys からOpenAIのAPI Keyを取得
- 名前:
- ページ下にあるプロパティの設定で新しく値を追加
- できたら上の方にあるデプロイボタンから新しいデプロイへ。
- 左の種類の選択からウェブアプリを選択。
- 説明には適当に(空欄でもとりあえずはOK)。
- 次のユーザーとして実行は自分。
- アクセスできるユーザーは**全員。
- 設定したらデプロイ
- ウェブアプリのURLが出てくるのでこれをコピー。
- コピーしたものを上で作ったSlackのSlashコマンドのRequest URLに入れる。
追記: 2023/03/27
OPENAI_API_KEYをプロパティで管理するように変更。
追記ここまで
使い方
これでSlackで/web_sum
とか自分で決めた名前のコマンドが使えるようになっているはずなので、
/web_sum https://ja.wikipedia.org/wiki/ChatGPT
とか打ってみます。
そうするとすぐにアプリから返信が来ますが、そこからしばらく待ちます。 数分すると、要約がコマンドを打ったチャンネルに送られてきます。
改善できそうなところ
プロンプト
主には params.gsで設定しているパラメーターですが、 プロンプトに関しては、あなたは優秀な編集者ですとか役を指定したほうがもっとうまくいったりするかもしれません。
その辺のよりよりプロンプトがあればPull Request出してくれたり何かしらで教えていただけるとありがたいです。
追記: 2023/03/26
最初はuser
のroleで指示出しも要約用のコンテンツも送っていましたが、
せっかくChat.Completionの
system
というroleで役割を与えてuser
が与えるコンテンツを要約するように変更。
feat: use system role, change variable prompet to system · rcmdnk/slack-gpt-url-summary-gas@9bc17f1
promptで文章の場所とかを指定しなくて良い分スッキリとできます。
返信内容はそれほど変わりないような。system
の部分が通常のuser
として与えるものと何が違うのか、ちょっと理解してないです。。
ついでに優れた編集者とか追加してみたりもしましたがそれでもあまり違いはありませんでした。
追記ここまで
chunkの区切り方
後は長文の要約を上に書いたように細切れのchunkに分けて、その要約を集めてきて要約の要約、みたいなことをしているのですが、 これを作る際のテキストの区切り方の工夫はいくらでもやりようがあるかとは思います。
現状では単に文字数で区切ってます。
単に文字数なので単語の途中とかで切れることもありますが、句切れ部分の意味を保つためにoverlap
のパラメータ分の文字数を前後のchunk両方に含めて、どちらかでは完全な文レベルで残っているようにしています。
これも長くしすぎればchunkの数が増えて時間もコストもかかりますが結構適当に設定してあります。
トークン数の計算
また、chunkの長さはchunkLength
で3000としていますが、現在ChatGPT (gpt-3.5-turbo)はAPIでトークン数で4096の制限があります。
この数はpromptとchunkの文章、さらには返信の要約文を合わせたものから計算されます。
トークンは英語だと単語数の3/4程度ですが、日本語だと文字数の数10%増しな感じの量になります。
なので日本語のために一旦3000とかにしてありますが、英語のページならもっと大きくした方が 各chunkの要約の精度が上がるかもしれませんし、問い合わせの回数は減るのでcostと実行時間は確実に減ります。
この部分はGASでトークン数をぱっと調べるのが面倒そうだったので一旦適当にやってますが、 真面目にトークン数を計算するようにすればもうちょっとギリギリを攻めることも出来ます。
GASのライブラリはまだないと思いますが、 Node.jsだとGPT-3-Encoderというライブラリで見積もり事はできそう。 Pythonのパッケージの tiktoken のIssueでNPM packageは出さないか?という議題は出てます。
要約の要約のやり方
現在は各chunkの要約も最後の要約も同じpromptを使って同じように要約させています。
これに関しては、最初の要約は少し長めにして、最後はぎゅっとまとめるようなことも考えられるかと思います。
単に関数別に作るのが面倒だったので同じにしてあるだけです。。。
Webページからのテキストの抽出
Webページからのテキスト抽出は Cheerioというライブラリを用いて行っています。
extractMainContentの中で、
まずdiv
要素で、main
, main-article
, article-body
などといったクラスのものを見つけてそれらがあればその要素の中身を、
何も無ければbody
要素の中身(もしそれもなければHTML全体)からテキストの抽出を行っています。
この辺はウェブサイトを絞ればもっといい感じに抜き出せると思いますが、 汎用的な感じだとこんな感じで適当に思いつくメインっぽいものを取ってますが これももっと良い方法があれば教えて欲しいところだったりします。
gpt-4
gpt-4が使えればトークン制限が大幅に大きくなるので大概のページが一気に読み込ませられそうです。 それであれば要約ももっといい感じに出来るのではないか、と。 (まだwaiting list中…)