Microsoft Teams Bot by Python


# 概要
職場でTeamsを使い始めるらしいので、よい使い道を調べていたところ、まだPreview版ですがPythonでBotが作成できるらしいのでやってみました。

Python用のSDK(Preview版)
https://github.com/microsoft/botbuilder-python

これまでに調べた範囲では、Pythonを使ってTeamsのBot自体を作るわけではなく、TeamsのSDKを使ってPython(FlaskやDjango)でウェブサーバを立てて、それを接続先として登録したBotをTeamsから追加する形になるようです。(Bot自体はただの通過点)

https://stackoverflow.com/questions/51484875/how-to-deploy-ms-botframework-in-python-to-azure
> As far as my knowledge BOT is app service hosted on Azure. So to publish your bot application you will need to follow the same steps involved in publishing Python web app to Azure.

全体の流れとしては、以下のようになります。
1. AzureのApp Serviceでウェブサーバを構築(Flaskサーバを動かすコンテナ)
2. ウェブサーバにコードをpushしてビルドする
3. AzureのBot FrameworkでBotを作成し、上記ウェブサーバのURLを登録
4. TeamsのチャットにBotをメンバーとして追加する


# 前提条件
以下は完了していることを前提にしています。

1. Azureアカウント作成(Free Trialで作成)
2. ローカルPCでのPython実行環境(必須ではない。自分はWindows + PyCharm + virtualenv)

アカウントは課金が気になりますが、Free Trialにしたところ、少なくとも1か月は大丈夫そうです。課金体系の説明が意味不明だったのでいったん放置しています…。今のところクレジットカード情報すら要求されてはいないです。

# App Serviceの準備
Azure Portalから実施
https://portal.azure.com/#create/Microsoft.WebSite

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/681e51ea-5ca4-53f9-1d25-c1ad41a0e97a.png)

リソースグループを適当に作成。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/80782d40-9c24-e181-6a4a-06e7338385c3.png)

名前がホスト名になります。他はお好みで。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/799917e8-d2fa-7433-aad8-87771e7ce618.png)

スペック選択。F1だとSSL通信ができないようだったので、B1を選択。(SSL通信ができないとBotから連携できない。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/a476a59b-24a4-fe10-c285-c0a95b162877.png)

ここのプランはOSなどの組み合わせで勝手に決まるようです。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/85cbe5f5-af10-5ed2-7f17-b1f433ceac93.png)

他は特に指定せずに完了し、少し待つとDeploy完了しました。
これだけだとただのPythonコンテナなので、そこにコードを入れていきます。
作成したWeb Appのページから、デプロイセンター→Local Gitを選択。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/8e430376-88bc-bc37-1bd7-32bcce785065.png)

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/dc812a41-7978-ebdc-e6dc-d6fc5d5fa7ec.png)

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/107d383c-6ef0-878e-7f97-1b814ea9937c.png)

この時点でGit用のURLが「概要」ページに表示されるので控えておきます。

# Local repositoryとの連携(自PC側の操作)
以下を参考にしました。
https://docs.microsoft.com/ja-jp/azure/app-service/deploy-local-git

Azure PortalからCloud Shellを開いて、Deployment userを作成します。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/3e46c1e3-f4bb-0979-30bc-a835b72d3e0b.png)

```shell-session
{S Azure:\> az webapp deployment user set --user-name ikedak2 --password xxxxxxx
  "id": null,
  "kind": null,
  "name": "web",
  "publishingPassword": null,
  "publishingPasswordHash": null,
  "publishingPasswordHashSalt": null,
  "publishingUserName": "ikedak2",
  "scmUri": null,
  "type": "Microsoft.Web/publishingUsers/web"
}
Azure:/
Azure:/e:\>
{S Azure:\> az webapp deployment user show
  "id": null,
  "kind": null,
  "name": "web",
  "publishingPassword": null,
  "publishingPasswordHash": null,
  "publishingPasswordHashSalt": null,
  "publishingUserName": "ikedak2",
  "scmUri": null,
  "type": "Microsoft.Web/publishingUsers/web"
}
Azure:/
```

PyCharmのCheckout from Version Controlメニューからcloneを行います。
これをcloneすると、完全にからっぽのプロジェクトが作成されますので、
通常通りInterpreterを設定し、コードを追加していきます。
ただ、まずは適当にREADME.mdだけ入れて、Commit&Pushしておきます。その際、Push先はazureブランチにする点に注意。
Pushする際に聞かれるアカウントは、先ほど作成したapp serviceのdeployment userの情報を使用します。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/87488982-7a1c-a477-f4d6-ec3fabd3f3c8.png)

これだけだと何も動かないので、ウェブサービスのコードを追加してPushします。
とりあえずコードは[公式にあるサンプル](https://github.com/microsoft/botbuilder-python/tree/master/samples/06.using-cards)をそのまま使用しています。

ローカルはこんな感じになります。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/ead5cdf5-94ca-1360-0622-65309e8f46cb.png)

この状態でapp.pyを実行し、そのURLに対して[Bot Emulator](https://github.com/microsoft/botframework-emulator)を実行してみるとこの段階ではうまく動作していることが確認できます。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/468e19c5-cb21-acf6-f544-c375882ee4ab.png)

これらのコードをvenvフォルダ以外git addして、remoteのazureブランチにpushします。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/9dbfd1e8-76e6-276a-f720-a5f06393ee33.png)

ちなみに、cloneした直後に空の状態でpushせず、いきなりコードを入れると、push時に以下のようなエラーで失敗しました。

```shell-session
Enumerating objects: 21, done.
error: inflate: data stream error (incorrect header check)
error: unable to unpack 70352b204fa4de283af24d1387e79b56edf3a9f7 header
Counting objects: 100% (21/21), done.
Delta compression using up to 8 threads
Compressing objects: 100% (20/20), done.
error: inflate: data stream error (incorrect header check)
error: unable to unpack 70352b204fa4de283af24d1387e79b56edf3a9f7 header
fatal: loose object 70352b204fa4de283af24d1387e79b56edf3a9f7 (stored in .git/objects/70/352b204fa4de283af24d1387e79b56edf3a9f7) is corrupt
fatal: the remote end hung up unexpectedly
fatal: the remote end hung up unexpectedly
fatal: the remote end hung up unexpectedly
error: failed to push some refs to 'https://ikedak2@teams-python-testbot-ik.scm.azurewebsites.net:443/Teams-Python-TestBot-ik.git'
```

自分の場合はもう一度一からプロジェクトを作成しなおして、上記の手順通りに実施しなおしています。

## Flaskアプリケーションの構成について
全て[公式](https://docs.microsoft.com/ja-jp/azure/app-service/containers/how-to-configure-python)に書いていますが、AzureのWebAppの仕様として、PythonのコードであればFlaskまたはDjangoが前提となります。
Flaskの場合、app.pyまたはapplication.pyというファイルがデフォルトではメインのファイルとして扱われ、その中のappというインスタンスがFlaskインスタンスとみなされます。今回使用するsampleのコードはFlaskインスタンスがAPPなので、Cloud Shellからカスタムスクリプトを設定する必要がありました。

```shell-session
az webapp config set --resource-group Python-Bot --name <app name>	 --startup-file "gunicorn --bind=0.0.0.0 --timeout 600 app:APP"
```

またrequirements.txtを元にビルドするので、忘れずに`pip freeze > requirements.txt`を実施し、git addしておきます。
準備ができたら、git pushなりAzure Portalからの再デプロイで、アプリケーションをデプロイしなおすとサイトにアクセス可能になります。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/f8ba321b-6a2f-9dc1-de30-b83f1f51bbf6.png)


# Bot作成
Microsoft Bot Frameworkのページから始めます。
https://dev.botframework.com/bots

Create
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/f58cedb4-cacc-4227-991f-1ecddb86740b.png)

Web App Botではなく、Bot Channels Registrationを選択します。
(Web App BotだとPythonは選択できない?)

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/41cfa2db-8b37-e91e-35d4-bb949837a607.png)

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/dcd90625-842f-cf52-8144-fe2d98b434d6.png)

メッセージングエンドポイントとして、先ほど作成したサーバのボット用エンドポイントのURLを指定する。これはアプリの構成によるが、今回のサンプルでは/api/messagesとなっています。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/ba0ba1af-a66b-3b57-12f1-aad07088be18.png)

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/d20216cd-5c38-6c5c-f127-4e242419f25b.png)

作成出来たら、IDとパスワードを確認します。
「設定」のページからアプリケーションIDを確認します。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/55ef6b80-13c3-f13d-9abc-e5be1a720bba.png)

同じページの「管理」からシークレットのページへ行き、新しいパスワードを生成します。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/47c5eef1-c91f-adde-754f-24defa829503.png)

これらのID、パスワードをPythonのコードに追記します。今回のコードではconfig.py内のAPP_ID、APP_PASSWORDに記載します。(これもCommit&Push)

完了後Botからアクセス可能かをテストします。
作成直後はなぜか失敗したが、しばらく時間を置くとできていました。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/59309d79-46bb-0bb5-8b6d-f69625bd01af.png)

# Teamsから使用可能に
Azure PortalからBotのページを開き、チャンネルにて「Microsoft Teamsチャンネルを構成」を選択。[MS Teams 用 bot を node.js と heroku で作る方法](https://qiita.com/megane42/items/9726ff6a435e1bd90c0c)を参考にさせていただいた。

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/0d50e1c6-b792-88b3-61e2-03e15b77c35e.png)

このUIはかなりわかりにくいと思うが、何もせずに「保存」でOK。

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/11cdc0da-51e9-cd2d-7f7c-1b29e0d2ea84.png)

Teamsが「実行中」の状態になる。これもわかりにくいが、リンクをクリックするとテストできる。

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/4a7b0a2f-d1b5-b60b-4201-b7fd040169a9.png)

ローカルのTeamsアプリケーションで確認可能。

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/a5f9156b-37d8-d4b9-16c1-fa0f35b4fa5e.png)

ローカルのアプリケーション側から使用するには、チャットを開始してメンバーとしてBotのApplication IDを追加すればOK。チャネルへの追加方法は確認中。

# 終わりに
Azureすら初めて触ったので、かなり時間はかかりましたが、概要は把握できました。結局ウェブサーバで処理をするなら、IFTTTとか使ったほうが簡単なのかな、と思ったり。
今回はサンプルコードそのままですが、次は何かオリジナルを作る予定。