ollamaを使ったSlack AIボット開発2

# ollamaを使ったSlack AIボット開発2

前回までは②まで終わりました。

- ①ollama導入
- ②ollama APIの使用
- ③Slack Socket modeを用いたボット作成（ここ）
- ④ollamaとボットを組み合わせてAIボットの完成

SlackAPIを使用する部分に最も手間取りました。
以下のような構成でBot作成を行います。
前回までで、LLM（ollama API server）の動作確認まで終わったという感じです。今回はPython Bot App（Python）の部分の動作確認（簡易コード）まで終わらせます。

![architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3937639/1312e272-d769-48eb-9f93-f006b27d5a87.png)

## Slack Botについて
よくわからない部分もありましたが、私の理解を書いておきます。同じ所で躓いた同志の一助になれば幸いです。
AIチャットの作成では、Slackユーザからのアクションに対して応答する必要があります。この場合、何らかの方法でSlackからの情報を受け取る窓口を用意する必要があります。このSlackからの情報を受け取る窓口の種類がざっくりと2種類あります。

- 公開URLが必要なBot形式（HTTP経由での通信で機能を実現、EventAPI）
- 公開URLがいらない形式（Web Socket）

今回は公開URLの用意が面倒なので、公開URLがいらない方向で進めますが、SlackはEventAPIを推奨しているみたいです。ネット上の情報ではRTM方式という方式が公開URLを必要としない方式として登場しますが、RTM方式はサポート終了し、その後にRTMの役割の代替手段としてSocket Modeがあるみたいです。[参考](https://github.com/slackapi/node-slack-sdk/issues/921#issuecomment-582637385)

さて、二つの方法の違いは、
- EventAPI=ポストを用意したらSlackが投函してくれる
- Web Socket=こちらから電話をかけて繋ぎっぱなしにしておく
のような感じです。EventAPIではポスト(全世界公開)を用意する分少し手間がかかります。

### Socket ModeでのSlack Bot作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3937639/3e082d0a-a247-4be4-bd88-047a92446793.png)
- この「アプリを追加する」のボタンからBotアプリを追加して、`https://api.slack.com/apps/your_app_ID/general`の設定画面まで行き、そこからは以下の記事を参考にして作成しました。
[Slack ソケットモードの最も簡単な始め方](https://qiita.com/seratch/items/1a460c08c3e245b56441)

BotAPP作成において以下のTOKENとIDを用意する必要があります。
- Bot User OAuth Token: `xoxb-***`
- App-Level Tokens: `xapp-***`
- channel ID: `C07***`

上二つのTOKENはそれぞれBot設定画面の`OAuth&permissions`, `Basic Information`から得ることができます。また、channel-IDはSlackアプリの`#channel_name`の部分をクリックすると確認できます。


## Slack Bot動作確認
準備が整ったので、Slack Botの動作確認を行います。`slack_bolt`というライブラリを使ってWeb Socket通信を行います。
```
pip install slack_bolt
```
ライブラリのチュートリアルは[Bolt 入門ガイド](https://tools.slack.dev/bolt-python/ja-jp/getting-started)です。venvで新しいPython環境を作成して作業するのが良いと思います。

### Bolt app 使い方
- [Bolt 入門ガイド](https://tools.slack.dev/bolt-python/ja-jp/getting-started)にも説明がありますが、軽く説明します。

>以下入門ガイドより引用
>```python
>import os
>from slack_bolt import App
>from slack_bolt.adapter.socket_mode import SocketModeHandler
>
># ボットトークンとソケットモードハンドラーを使ってアプリを初期化します
>app = App(token=os.environ.get("SLACK_BOT_TOKEN"))
>
># アプリを起動します
>if __name__ == "__main__":
>    SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start()
>```

- 基本的にはアプリケーションを初期化し、起動するだけでBoltAppが動作し、Web Socket通信ができるようになります。
- この際の`SLACK_BOT_TOKEN`が先ほどの`xoxb-***`、`SLACK_APP_TOKEN`が`xapp-***`です。
- これを実行するとBolt Appが起動し、Web Socket通信にてSlackからの応答を得られる状態になります。

### Hello World
それではBolt Appを用いて、ユーザのメッセージに応答するBotを作ってみます。

- ユーザがBotをメンションして[メッセージ] ->  「[メッセージ]」 from appと返答する

```python
import os
import re
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler
from dotenv import load_dotenv, find_dotenv

# .envファイルの読み込み
load_dotenv(find_dotenv())
# 環境変数からSlackのトークンとチャンネルを取得
slack_bot_token = os.environ.get("SLACK_BOT_TOKEN")
app_token = os.environ.get("SLACK_APP_TOKEN")
slack_channel = os.environ.get("SLACK_CHANNEL")

# Slackアプリの初期化
app = App(token=slack_bot_token)

@app.event("app_mention")
def response(ack, event, say):
    ack()
    text = event["text"]

    # メンションを除去（<@U123ABC456> のような形式）
    # cleaned_text = re.sub(r"<@[\w]+>", "", text).strip()
    cleaned_text = re.sub(r"<@[\w]+(?:\|[\w.-]+)?>", "", text).strip()

    thread_ts = event.get("thread_ts")

    gpt_reply = f"「{cleaned_text}」 from app"

    if thread_ts:
        say(text=gpt_reply, thread_ts=thread_ts)
    else:
        say(text=gpt_reply)

# アプリ起動
if __name__ == "__main__":
    SocketModeHandler(app, app_token).start()
```

- Slackでのメンションをイベントとして受け取って、返信するBotができました
- 前回のollamaのコードと組み合わせればAIチャットBotを作れそうです
- 上記コードで使っているslack boltのapiについては[ドキュメント](https://tools.slack.dev/bolt-python/api-docs/slack_bolt/index.html)にあります。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3937639/94cf647b-9917-4f4b-8d26-294deb94e5da.png)

私はBotの名前を論文翻訳くんにしているので上のように動作します。
次回はここまでで作成したコードを組み合わせてAIチャットBotを作成します。