rcmdnk's blog
Last update

BERT/GPT-3/DALL-E 自然言語処理・画像処理・音声処理 人工知能プログラミング実践入門

OpenAIのAPIを使って SlackからWebページの要約を頼むコマンドを作ってみました。

やりとりする場所として簡単に無料で使えるGoogle Apps Scriptを使っています。

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と。
      • できたらInstall your appからインストール先のworkspaceにインストール。
      • このページはあとでも使うのですぐにSlashコマンドの編集が出来るように開いたままにしておいた方が楽。

追記: 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
  • slack-gas-url, params, secretsというスクリプトファイルを作る。
  • 上のレポジトリの同じ名前のファイルからそれぞれ内容をコピペ。
  • params.gsの編集:
    • 受け答えを英語にしたい場合にはlangenに変更。
    • promptや返信文も必要であればよしなに変更。
    • chunkLengthoverlapの調整:
      • とりあえず最初はデフォルトのままで良いはず。
      • 必要であれば調整。
  • 歯車ボタンからプロジェクトの設定ページへ:
    • ページ下にあるプロパティの設定で新しく値を追加
      • 名前: 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

とか打ってみます。

そうするとすぐにアプリから返信が来ますが、そこからしばらく待ちます。 数分すると、要約がコマンドを打ったチャンネルに送られてきます。

20230326_slackreply.png

改善できそうなところ

プロンプト

主には 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として与えるものと何が違うのか、ちょっと理解してないです。。

ついでに優れた編集者とか追加してみたりもしましたがそれでもあまり違いはありませんでした。

Chat completion - OpenAI API

追記ここまで

chunkの区切り方

後は長文の要約を上に書いたように細切れのchunkに分けて、その要約を集めてきて要約の要約、みたいなことをしているのですが、 これを作る際のテキストの区切り方の工夫はいくらでもやりようがあるかとは思います。

現状では単に文字数で区切ってます。 単に文字数なので単語の途中とかで切れることもありますが、句切れ部分の意味を保つためにoverlapのパラメータ分の文字数を前後のchunk両方に含めて、どちらかでは完全な文レベルで残っているようにしています。

これも長くしすぎればchunkの数が増えて時間もコストもかかりますが結構適当に設定してあります。

トークン数の計算

また、chunkの長さはchunkLengthで3000としていますが、現在ChatGPT (gpt-3.5-turbo)はAPIでトークン数で4096の制限があります。 この数はpromptとchunkの文章、さらには返信の要約文を合わせたものから計算されます。

トークンは英語だと単語数の3/4程度ですが、日本語だと文字数の数10%増しな感じの量になります。

What are tokens and how to count them? OpenAI Help Center

なので日本語のために一旦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中…)

Sponsored Links
Sponsored Links

« Google Apps Script (GAS)でHTML解析 Python製コマンドラインツールをHomebrewで配布する »

}