2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

技術チャレンジ部のとも(Tomo)です。チームTPACで自動運転AIチャレンジ2024参加中です。
こちらの記事で作ってみたDiscordのボットを、Slackに移植してみました。

素人なので、変なことを言っていたらすいません!

設計方針

Discordで作ったボットのアーキテクチャをなるべく流用するために、以下の方針としました。

  • PythonのライブラリからSlack APIを使用する
  • Pythonスクリプトがクライアントになる

Slackのボット

フレームワーク

Slackのボットには様々な実装方法があるようです。Slackの開発者ページでは、Boltという公式フレームワークがトップで紹介されています。
Boltには、Python版であるBolt for Pythonがあるので、これを使用してみます。
Bolt入門ガイドでは、ソケットモードが使用されています。ソケットモードでは、HTTPでは必要なRequest URLのエンドポイントを用意しないで済みそうなので、設計方針にも合いそうです。
また、入門ガイドには、

ソケットモードは、Slack アプリ開発をとりあえず始めてみるときやあなたのチームだけのためのアプリをつくるときにおすすめのやり方です。

とあり、お試しにはちょうどよさそう。この方法では、LegacyやClassicな仕組みもうまく避けられそうです。

Slackアプリの作成

Bolt入門ガイドに沿って作ってみます。

  • アプリの作成
    • Create New App -> From scrachでボット名とワークスペースを設定
  • ボットトークンへのスコープの追加
    • OAuth & Permissions -> Bot Token Scopes -> Add an Oauth Scopeで以下を追加
    • chat:write …メッセージの投稿に必要
    • app_mentions:read …メンション内容の取得に必要
  • アプリレベルトークンの取得
    • Basic Information -> App-Level Tokens -> Generate Token and Scopesで以下を実施
      • Token Nameにトークンの名前を入力
      • Add Scopeでconnections:write を追加 …ソケットモードに必要
      • Generateボタンでアプリレベルトークンを生成し、メモ
  • ソケットモードの有効化
    • Socket Mode -> Connect using Socket Mode -> Enable Socket Modeをオン
  • イベント取得の設定
    • Event Subscriptions -> Enable Eventsをオンにする
    • Subscribe -> Add Bot User Eventで、app_mention を追加 …メンションイベントの取得に必要
  • アプリのワークスペースへのインストールとボットトークンの取得
    • OAuth & Permissions -> Install App to Workspaceでアプリをインストール
      • Bot User OAuth Access Tokenをメモ
  • 必要に応じてアイコンや名前の見直し
    • Basic Information -> Display Informationなどの見直しと変更を行い、Save Changesで保存

作ってみて分かったのですが、メンションイベント取得時に、メッセージ内容も取得できるようです。

Pythonスクリプト

Boltパッケージのインストール

pip install slack_bolt

Discord用に使ったスクリプトの修正

Discordの記事で使ったPythonスクリプトを修正します。
主な修正点は以下の通りです。

素人が一番とまどったのは、非同期の部分です。Bolt for Pythonの「ソケットモードの利用」の「Async (asyncio) の利用」には、

aiohttp のような asyncio をベースとしたアダプターを使う場合、アプリケーション全体が asyncio の async/await プログラミングモデルで実装されている必要があります。AsyncApp を動作させるためには AsyncSocketModeHandler とその async なミドルウェアやリスナーを利用します。

とあり、Discordの時もこのようになっていたのですね。今回はAsyncSocketModeHandlerが使用できそうです。

また、Slack APIでは、ソケットモードでも3秒以内の応答が必要とのことで、LLMの長い生成時間を考えると、まずはack()で応答を返す必要がありそうです。(ということに記事を書きながら気づいた…書いてよかった…)
これは非同期でも対応できるとのことで、こちらの記事が大変参考になりました。

これらの情報とChatGPTの支援を受けて修正したPythonスクリプトがこちらです。

import asyncio
import os
from slack_bolt.async_app import AsyncApp
from slack_bolt.adapter.socket_mode.aiohttp import AsyncSocketModeHandler
from dotenv import load_dotenv
import aiohttp

load_dotenv()
DIFY_KEY = os.getenv("DIFY_API_KEY")

app = AsyncApp(token=os.environ.get("SLACK_BOT_TOKEN"))

@app.event("app_mention")
async def handle_app_mention_events(event, say, ack):
    await ack()

    user = event['user']
    query = event['text']
    url = 'http://localhost/v1/chat-messages'
    headers = {
        'Authorization': f'Bearer {DIFY_KEY}',
        'Content-Type': 'application/json'
    }
    data = {
        'query': query,
        'response_mode': 'blocking',
        'user': user,
        'conversation_id': '',
        'inputs': {}
    }

    async with aiohttp.ClientSession() as session:
        async with session.post(url, headers=headers, json=data) as response:
            if response.status == 200:
                json_response = await response.json()
                answer = json_response.get('answer', 'No answer provided.')
                await say(answer)
            else:
                error_message = await response.text()
                await say(f'APIエラー: {response.status}, メッセージ: {error_message}')

async def main():
    handler = AsyncSocketModeHandler(app, os.environ["SLACK_APP_TOKEN"])
    await handler.start_async()

if __name__ == "__main__":
    asyncio.run(main())

ファイル.envには、SlackのボットトークンをSLACK_BOT_TOKENに、SlackのアプリレベルトークンをSLACK_APP_TOKENに、DifyのAPIキーをDIFY_API_KEYに、それぞれ設定しておきます。

DifyのSystemプロンプト

みなさまをサポートできるように、少しだけ、こんなふうに変えてみました。
dify-system-prompt.png

実行

ボットをテキストチャンネルに招待する必要があるようです。とりあえずメンションすると招待できたので、これで招待しました。
そして、聞いてみると…

slack-chat.png

アツい!

今後に向けて

Slackの表記は、Markdownとは異なるmrkdwnだそうなので、これに対応させてみたいですね。
今回はOpenAI API以外はオンプレ前提で、実行環境も一般のご家庭のため、SLAは一般のご家庭品質です。FaaS化すると、アーキテクチャが大幅に変わりそうですが、勉強になりそうです。
あとは、先ほどのtpac_gorillaくんのコメントにもありましたが、大会を通じて貴重な経験を楽しめればと思います!

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?