Slackbot(Azure Functions×FastAPI)でAzure AI Search(旧Cognitive Search)でベクトル検索をやってみた

### やりたいこと
ファイルに関する質問をSlackメンションに投げると回答を返してくれる。

### どうやるか
事前に対象ファイルをAzure AI Searchに読み込ませておく(ベクトルインデックス化)
Slackから質問がきたら、OpenAIやCosmosDBを連携させながらAI Search検索を行い
その検索結果を基にOpenAIで回答を生成してSlackに返す。

今回のslackbot作成にあたり、こちらを大変参考させて頂きました🙏
誠に有難うございます🙇
https://zenn.dev/microsoft/articles/jp-openai-5v1

### フローイメージ
```mermaid
sequenceDiagram
  participant sl as slack
  participant af as Azure Functions<br>(slackbot)
  participant cd as Azure CosmosDB
  participant cg as OpenAI(ChatGPT)
  participant oa as OpenAISearch

  sl->>af: メンションに質問
  af->>cd: 対象チャネル&スレッド<br>の会話履歴を一括取得
  cd-->>af: 
  af->>cg: 会話履歴を基に、会話の文脈に見合った<br>検索クエリを生成してくれるように依頼
  cg-->>af: 
  af->>oa: ベクトルインデックス検索
  oa-->>af: 
  af->>cg: 検索結果と質問を基に<br>回答文言の生成を依頼
  cg-->>af: 
  af->>sl: 回答が返ってくる
```

### 事前準備
・MicroSoftアカウント
・Azureサインイン
・Python
・VSCode
・npm

### 作業環境
・Windows

### 作業項目
1. SlackAPI準備
2. Azure OpenAI準備
3. Azure Functions準備
4. VSCode&プロジェクトソース準備
5. Azure AI Search準備
6. Azure AI Searchデータ投入
7. Azure Cosmos DB準備
8. 動作確認(ローカル)
9. 動作確認(Azure Fuctions)


### 1. SlackAPI準備
- 以下にアクセスしてslackbotアプリを作成する
　https://api.slack.com/apps

　（１）ベクトル検索用
　（２）通常質問用
 
　　※今回はベクトル検索の説明なのですが、ついでに通常の質問も別APIで試せるので
 　　　そちらのSlackAPIも併せて作成しておきます

　　※「Event Subscriptions」にslackbotのURLをセットするのですが、疎通がOKに
　　　ならないと設定ができないためここでは一旦スルーする
　
　　　以下を参考にさせて頂きました🙇
　　　https://www.beex-inc.com/blog/slackbot-aws-lambda

### 2. Azure OpenAI準備
- Azure portalでOpenAIをデプロイする
　https://portal.azure.com/

　（１）AISearch検索クエリ・回答作成用　⇒　gpt-35-turboモデル
　（２）ベクトル検索データ作成用　⇒　text-embedding-ada-002モデル

　　以下を参考にさせて頂きました🙇
　　https://qiita.com/AGV_morinaga/items/04c1b3f505efca8b1511

### 3. Azure Functions準備
- Azure portalでSlackBot用のAzure Functionsを用意する
　https://portal.azure.com/
 
　　以下を参考にさせて頂きました🙇
　　https://qiita.com/pkopko-b8/items/0083c86af60339435e00

### 4. VSCode&プロジェクトソース準備
- VSCodeの設定とソースを展開する

　（１）VSCode拡張機能から「Azure Functions」を取得する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114591/b0ad552d-ec87-5b8b-6362-af83167ed59d.png)

　（２）「azure-functions-core-tools」をインストールする
```
npm install -g azure-functions-core-tools
```

　（３）Azure Functionsの初期プロジェクトを生成する

1. VSCode拡張機能Azureで「Create Function」を選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114591/52d1fd4f-418b-8e48-1635-7331dfda761c.png)
2. 空のディレクトリを作成＆選択する(今回はsampleとしました)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114591/90cadfbb-8c8f-88cb-7fe3-b5b83e1a83dd.png)
3. Pythonを選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114591/2792cb32-76fe-7612-f9e0-e485bc67eae7.png)
4. Model V2を選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114591/e1963131-8990-dbe2-bd3e-79bd292ee4f3.png)
5. Python x.x.xを選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114591/8187705e-f010-33e6-35b0-3da9bc9c6c9b.png)
6. HTTP triggerを選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114591/0e800117-2e38-3010-fc43-18d52085c4e3.png)
7. ANONYMOUSを選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114591/b39888c5-a8d3-826f-8e1d-e1a2ee5da1a5.png)
8. 以下プロジェクトをダウンロードして「sample」に上書きする
https://github.com/totoaoao/slackbot-chatgpt-for-azure

　※いきなり上記プロジェクトを「sample」ディレクトリに入れても良いのですが
　　VSCodeとAzure Functionsの連携方法があっても良いのかなと思いましたので
　　記載しておきました👍(あと.venvも生成されないので)

### 5. Azure AI Search準備
- Azure portalでファイルベクトル検索用のAI Searchを用意する
　https://portal.azure.com/

　以下を参考にさせて頂きました🙇
　参照：https://qiita.com/tatsuki-tsuchiyama/items/fc268beebd5bdead63e4

### 6. Azure AI Searchデータ投入
- 上で準備したAI Searchに対象ファイルデータを投入する

　（１）Azure AI Searchに取り込みたいファイルをプロジェクト下のlangchain/filesに置く
 
　（２）ライブラリをインストールする
```
pip install --r requirements.txt
```
- .envに環境変数を設定する
https://github.com/totoaoao/slackbot-chatgpt-for-azure/blob/main/.env#L15-L19
```
AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME
AI_SEARCH_ENDPOINT
AI_SEARCH_SERVICE_NAME
AI_SEARCH_API_KEY
AI_SEARCH_INDEX_NAME
```
- 実行する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114591/b9994901-d574-3608-0be3-c401c776f23a.png)


### 7. Azure Cosmos DB
- Azure portalで会話履歴用のAzure Cosmos DBを用意する

　以下を参考にさせて頂きました🙇
　https://qiita.com/ymasaoka/items/3784c64baf30bbe7b761

### 8.動作確認(ローカル)
- 環境変数を設定してPythonを起動する。
Slack通知をローカルにポートフォワードさせるURLを作成しSlackアプリにセットする。
対象メンションに質問すると回答が返ってくる。

　（１）環境変数を設定する
　　https://github.com/totoaoao/slackbot-chatgpt-for-azure/blob/main/.env

 ```
BOT_TOKEN='Slackトークン_通常ChatGPT用'
SLACK_SIGNING_SECRET='Slackシークレットキー_通常ChatGPT用'
BOT_TOKEN_AI_SEARCH='Slackトークン_ベクトル検索用'
SLACK_SIGNING_SECRET_AI_SEARCH='Slackシークレットキー_ベクトル検索用'
OPENAI_API_BASE='OpenAIエンドポイント'
OPENAI_API_VERSION='OpenAIバージョン'
OPENAI_API_KEY='OpenAI APIキー'
GPT_DEPLOYMENT_NAME='OpenAIデプロイ名'
GPT_DEPLOYMENT_MODEL='OpenAIデプロイモデル'
COSMOS_DB_HOST='CosmosDBエンドポイント'
COSMOS_DB_MASTER_KEY='CosmosDB APIキー'
COSMOS_DB_ID='CosmosDB ID名'
COSMOS_DB_CONTAINER_ID='CosmosDB コンテナID'
AI_SEARCH_API_KEY='AI Search APIキー'
AI_SEARCH_ENDPOINT='AI Search エンドポイント'
AI_SEARCH_SERVICE_NAME='AI Search サービス名'
AI_SEARCH_INDEX_NAME='AI Search インデックス名'
 ```

 　（２）「Attach to Python Funcsions」をクリックしてPythonを起動する
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114591/4ef96fae-beac-826b-c83a-7f49ff9e7246.png)

　　　　以下が表示されるようであれば「Debug anyway」選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114591/77b14404-98c3-6d5a-ee17-6ed66d3cbbe7.png)


　（３）Slack通知を受信してローカルにポートフォワードさせるようにする
　　　①ngrokをダウンロードする
　　　https://ngrok.com/
　　　②ngrok.exeを起動して以下コマンド実施
```
ngrok http 7071
```
　　　③発行されたURLをSlackアプリの「Event Subscriptions」にセットする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114591/4683df83-12b7-715a-b043-032857c9845f.png)

　　　（１）ベクトル検索用：発行URL
　　　（２）通常質問用：発行URL/ai_search

　　　④問題なければSlackに対象アプリのメンションと質問をいれると
   　　　　以下のような回答が得られるようになる

##### ファイルに関する質問
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114591/0c4d249f-3be2-361b-b436-bd0e6f86935c.png)

##### 通常の質問
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114591/5db67176-e824-c3b3-1512-cbe2306b0d87.png)



### 9.動作確認(Azure Functions)
- 環境変数を設定してプロジェクトをAzure Functionsへデプロイする。
Azure FunctionsのURLをSlackアプリにセットする。
対象メンションに質問すると回答が返ってくる。

　（１）Azure portalのAzure Functionsにある「構成」⇒「新しいアプリケーション設定」で
 　　　　環境変数を設定する
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114591/2a63aa41-6484-4d5c-39ec-accc41b6c49e.png)

　（２）VSCode「Azureアイコン」⇒「デプロイアイコン」⇒「Deploy to Function App」で
 　　　対象となるAzure Functionsにデプロイする
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114591/3d36fbd5-96fa-77f1-94ed-145883255753.png)

　（３）Azure FunctionsのURLを「関数のURLの取得」から取得して、Slackアプリの
 　　　「Event Subscriptions」にセットする
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114591/1252482c-2d91-b059-a963-f16f4bb7496e.png)

　（４）問題なければ上記と同様の回答が得られるようになる