AzureOpenAI(ChatGPT)を使ったエンタープライズ向けMattermostBotをサクッと実装する

## はじめに

北國フィナンシャルホールディングス デジタルバリューの 北 です。  
銀行のシステムを開発しています。

話題のChatGPTを導入して生産性向上を図りたい！でも、扱うデータに配慮をおきたい！
そういう場合の できるだけ手軽な方法 を検討してみました！という記事となります。

## 対象読者

* チャットツールに Mattermost を使用しているエンジニア
* もっと ChatGPT を社内に広めたい人たち

## つくるもの

さっそく作るものです。
見ての通り、MattermostでChatGPTと連携して動くBot です。

![mm_azure_openai_gpt_3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133866/0c030535-2dca-9b51-6233-2cc25418054f.gif)

:::note info
Tips: [Mattermost公式のブログに同様のもの](https://mattermost.com/add-chatgpt-to-mattermost/) があります。しかし、OpenAI 本家と連携するもので、Azure OpenAI Service は未対応だったため、今回 新たに実装してみます。
:::

## 前提

* Mattermost が 構築済であること
* Azure OpenAI Service の利用申請を行っていること
* Azure OpenAI Service のオプトアウト申請を行っていること

Azure OpenAI Service の前提は下記が非常に良くまとまっています。
先輩方に学ばさせていただきましょう。

https://dev.classmethod.jp/articles/usage-rules-for-azure-openai-service/

## 全体構成

サクッと作るので非常に単純です。
Botを図の真ん中 Azure Container Instance (ACI) で動かすという構成です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133866/cec0fbce-86c8-feb3-57cd-94690d28ce5f.png)


## 機能

1. いずれのチャンネルでも Botにメンションすると回答する
1. スレッド内の会話を踏まえて回答する

:::note info
Tips: 上記 1. について Privateチャンネルでも ChatGPTを活用できるよう、Mattermost Outgoing Webhook を用いた 一般的なBotの実装からあえて変更しています
:::

### Mattermostの設定

アカウントを作って AccessTokenを作成するだけです。

<details><summary>具体的には以下のようにして行います。</summary>

**[アカウントの作成]**
![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133866/8d6571fd-107d-40ae-8716-cff0f37b2970.png)
![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133866/bd7c008f-759a-8009-9964-8afea3334d26.png)

* invite link を ブラウザで開きます

![003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133866/59bba625-eb78-6087-4291-2fdd49da0843.png)

* 各項目を埋めて作成完了です。

![004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133866/6439d51e-ca68-ac1a-6f17-81ce8fe09f7c.png)

**[アクセストークンの作成]**

* 事前に admin権限をもつユーザで PersonalAccessToken 作成を有効にします

![101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133866/4c72e2c9-f3dc-2013-cbe1-9e8ffd8225b7.png)
![102.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133866/5911d706-0779-7b75-9517-b8a25e648e1a.png)

* 作成したbot用のユーザにPersonalAccessTokenを作成する権限を与えます

![103.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133866/4b1925a4-670f-deda-0857-dd916e2e869a.png)
![104.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133866/11f055e2-4f6d-2b96-f630-d9b26c0a4659.png)
![105.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133866/13a52531-9c79-6fe0-1994-53634f61b37a.png)

* 以下の Edit で作成できます。作成後は `AccessToken` を控えておいてください。

![106.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133866/3714f412-ade8-7516-0036-2dd85d746326.png)

</details>

### 実装

てっとり早く最終的なソースを以下に添付します。

https://github.com/kita-atsushi/mattermost_bot/tree/supportAzureOpenAI

下記に詳細を記載しますが、あるGitHubリポジトリを活用しつつ、Azure OpenAI Service の差分を埋めるだけです。 **Azure OpenAI Service と OpenAI との差分が少なくて驚きました。ステキですね :relaxed:**

#### Azure OpenAI Service への適応

すでに出来合いのMattermost bot が以下にあったため、それを活用させてもらいます。

https://github.com/hibobmaster/mattermost_bot

どこを修正すれば良いかを見極めるために、若干のコードリーディング が必要です。手っ取り早く導入したいのであれば、下記 [デプロイ](#デプロイ) まで読み飛ばしてもOKです。

**[コードリーディング]**

コードを読むと仕様はシンプルです。

* `main.py`を実行すると Botのように振舞うプログラムが起動
* あるキーワードが指定されたら OpenAI にAPIを実行して会話に応答

また、内部の仕組みとしてもシンプルです。

* MattermostDriver でBotのように動作
* httpx (Httpクライアント) で OpenAI にAPIを実行

**[コードの修正]**

今回活用するソースコードも OpenAI 本家を利用する実装となっていますが、Azure OpenAI Service に対応させる必要があります。細かいこと気にせず、サクッと動かすには 以下のように **OpenAIのendpoint と 認証ヘッダだけ 修正をすれば良い** です。

https://github.com/kita-atsushi/mattermost_bot/commit/f03c01d0998eec798828d714c865be50f6bf1842

上記ソースの時点で [こちらの環境変数](https://github.com/hibobmaster/mattermost_bot/blob/5c736cf86d1266e669b8d1cd3328291d97312450/main.py#L29-L35) 設定後、`main.py` を実行して プログラムが起動すると、Mattermost で以下のスクショのようになります。この段階では `!gpt ping` や `!chat ping` を 打ち込むと反応が出るはずです！

![mm_azure_openai_gpt_2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133866/5e4da5fe-681c-ea7a-85c2-9bd361588b7e.gif)

あとはこれを起点に、修正・リファクタリングしていきます。
さらに Botのように振舞わせるならば、メンションに反応し、スレッド内のやりとりについて、回答できたら良い感じです。

https://github.com/kita-atsushi/mattermost_bot/tree/supportAzureOpenAI

同様に動かして以下のようになります。

![mm_azure_openai_gpt_3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133866/0c030535-2dca-9b51-6233-2cc25418054f.gif)

これで出来上がりです！ :tada:

### デプロイ

ポータビリティを意識し、Azure Container Instance (ACI) で構築してみます。
あらかじめ コンテナイメージをビルドし、Azure Container Registry (ACR) に pushします。

* Git pull

```bash
git clone -b supportAzureOpenAI https://github.com/kita-atsushi/mattermost_bot.git
cd mattermost_bot
```

* Dockerイメージ Build & Push

```bash
docker build -t chatgpt-mmbot:0.0.1 .
docker tag chatgpt-mmbot:0.0.1 <ACRリソース名>.azurecr.io/chatgpt-mmbot:0.0.1
docker push <ACRリソース名>.azurecr.io/chatgpt-mmbot:0.0.1
```

* ACI 構築

```bash
az container create -g <リソースグループ名> \
  --location <リージョン名> \
  --name aci-chatgpt-mmbot-jpeast \
  --image <ACRリソース名>.azurecr.io/chatgpt-mmbot:0.0.1 \
  --registry-username "<ACRのユーザ名>" \
  --registry-password "<ACRのパスワード>" \
  --restart-policy Never \
  --environment-variables \
    SERVER_URL="<MattermostのFQDN>" \
    USERNAME="<Mattermostアカウントのユーザー名>" \
  --secure-environment-variables \
    LOGIN_ID="<Mattermostアカウントのメールアドレス>" \
    ACCESS_TOKEN="<Mattermostアカウントのアクセストークン>" \
    OPENAI_API_KEY="<Azure OpenAI Service AccessKey>" \
    OPENAI_API_ENDPOINT="<Azure OpenAI Service URL>"
```

わかりづらい変数値は 以下で例を示します。

<details><summary>※environment-variables と secure-environment-variables オプション補足</summary>

| 変数名 | 説明 | 値の例 |
| --- | --- | --- |
| SERVER_URL | MattermostのFQDN | `my-mattermost.com` |
| USERNAME | Mattermostアカウントのユーザー名 | `@myuser` |
| LOGIN_ID | Mattermostアカウントのメールアドレス | `myuser@example.com` |
| ACCESS_TOKEN | Mattermostアカウントのアクセストークン | xxx |
| OPENAI_API_KEY | Azure OpenAI Service AccessKey | yyy |
| OPENAI_API_ENDPOINT | Azure OpenAI Service URL | `https://myopenaiservice.openai.azure.com/openai/deployments/gpt-35/chat/completions?api-version=2023-03-15-preview` |
</details>

上記コマンド実行後、Azureポータル上で ACIの状態が 実行中 であるか確認します！

![スクリーンショット 2023-05-19 082648.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133866/b96939a3-fe7f-b540-08f7-eb6188e18b5e.png)

最後に 冒頭に示した通り、Mattermostでbotにメンションし反応するか確認しましょう！

## これから

今回は スピード最優先で 動かしてみました。
つぎは 拡張性を加味して LangChain または Semantic Kernel で 実装する予定です。