【Microsoft Azure】Azure Logic Appsを使ってLINE Bot開発

# Azure Logic Appsとは
Microsoftが提供する、Azure上でGUIを操作しアプリやシステムをノンコーディングでプログラミングするサービスです。詳しくは[こちら](https://docs.microsoft.com/ja-jp/azure/logic-apps/logic-apps-overview)。
今回はこのサービスを用いて、LINEBotを作成していこうと思います。

# 1. LINE Messaging APIの登録
1. [Line Developers コンソール](https://developers.line.biz/console/)にアクセス。ログイン情報は、普段使っているLINEのアカウントでログインして構いません。
2. Providersの隣にある[Create]をクリック。適当な名前を入力してください。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/db58c150-f56b-aa4e-b702-9a11ba20d105.png)  
3. 作成出来たら、チャネルを作成します。画面のCreate a Messaging API channelをクリック。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/a043c7ef-6858-81f3-ff42-677301b7321a.png)  
4. 情報を入力し規約に同意して[Create]。自分の場合は、画像のように記入しました。メールアドレスはLINEのアカウントのアドレスじゃなくても構いません。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/4a78b788-2e5e-cbf7-4751-92f6217125ef.png)  
5. Messaging APIのタブを開き、下の方にあるChannel Access Tokenの[Issue]をクリック。メモしておきます。![channelaccess.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/9926d13a-0da2-37df-c62f-7e01c99b6fda.png)  

# 2. ぐるなびAPIのアカウント登録
1. ぐるなび Web Serviceの[新規アカウント発行ページ](https://ssl.gnavi.co.jp/api/regist/?p=input)へアクセス。
2. ユーザー情報を入力し、アプリケーション情報は[試しに利用]を選択。利用規約に同意し発行。
3. [マイページ](https://ssl.gnavi.co.jp/api/mypage)にアクセスし、アプリケーション情報のアクセスキーをメモ。![gurunavitoken.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/6eea1219-eb54-7ea4-02a2-ecbeb1c4ef5d.png)

# 3. LUISの作成
1. [Azure ポータル](https://portal.azure.com/#home)へアクセス。
2. 検索欄に「LUIS」と入力し、Marketplaceの**Language Understanding**をクリック。
3. 項目を入力して作成。自分は画像のようにしました。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/9ac8957e-b242-3dc0-7877-7ef0d4d1e971.png)  
4. リソースに移動し、[LUISポータル](https://www.luis.ai/)へ移動。[Login/Sign up]をクリック![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/33527fa2-1357-e2a4-de81-4735626977c1.png)
5. メアドを入力し、確認画面がでるので[はい]をクリック。  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/e89df3e9-5301-86c4-9f3c-11e90d245806.png)  
6. [My apps](https://www.luis.ai/applications)に移動し、**SubscriptionとAuthor Resourcesを選択して**、New app for conversationをクリック。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/863abdee-6470-0524-cc15-88046afee92f.png)  
7. NameとCultureを入力し、作成。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/50cdf8b1-726b-7273-d72c-39fc0332fed7.png)  
8. IntentsのCreateから、新しいインテントを作成![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/9b095644-f4ce-d8c0-1d70-27aec39ce935.png)  
9. 作成したインテント名をクリックし、ユーザの文章の例文をいくつか入力。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/d26c0b99-405b-d31e-7067-4ac1ef33612a.png)  
10. 例文の地名をクリックし、「location」タグを作成しタグ付けする。作成時に表示されるTypeの選択は、**Machine Learned**にチェック。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/a50e0500-30c7-aa42-a621-4dd26825d31a.png)  
11. ほかの地名も同様に「location」でタグ付け
12. 例文のお店のカテゴリをクリックし、10と同様に「category」でタグ付け
13. 右上の[Train]をクリック。
14. Trainの左のマークが緑になったら学習完了。ためしに[Test]で文章の認識ができているか確認。Type a test utteranceに試したい文章を入力し、InspectのML entitiesでちゃんと認識されていました。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/147e7c83-3116-0ae0-6a3a-c8121d309e60.png)  
15. [Publish]をクリックし、Product Slotを選択して[Done]。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/12ffc1f4-0f1f-d1cc-2de4-a8051d4a7017.png)  
16. [Manage]->[Azure Resources]とクリックし、Primary KeyとEndpoint URLをメモ。![luiskey.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/3ff74653-2a6d-43e7-fcbd-db95fe77df93.png)

# 4. Azure Logic Appsの作成(**手順ごとに保存を忘れずに!!!!!!!!**)
### ロジックアプリの作成
1. [Azure ポータル](https://portal.azure.com/#home)へアクセス。
2. 「Logic Apps」と検索し、ロジックアプリの作成をクリック。必要項目を入力。**リソースグループはLUIS作成時に使用したものを使ってください**。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/b14a7f59-3a49-4342-aa09-bc240b0c53e9.png)  
3. 作成後リソースに移動しロジックアプリデザイナーをクリック。自分の場合[リソースへ移動]がクリックできなかったので、すべてのリソースから行きました。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/5d2c7a01-b9f4-3487-97d5-42119d50428a.png)

---
### LINEからのメッセージをトリガーにするアクションの作成  
4. 一般的なトリガーで開始するの中の[HTTP要求の受信時]をクリック。
5. 要求本文のjsonスキーマは、[Messaging APIリファレンス](https://developers.line.biz/ja/reference/messaging-api/#common-properties)のWebhookイベントオブジェクトの例をコピーし、[サンプルのペイロードを使用してスキーマを生成する]にペーストして生成。
6. HTTP POSTのURLをLINE DeveloperのChannel Access Tokenが表示されているページの、Webhook URLの欄ににコピペしUpdate。![linewebhook.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/c7b09185-8f6b-87c9-e6e6-3b6fcdaab6d0.png)

### 各種変数の初期化
---
7. デザイナーに戻り、新しいステップ->ビルトイン->変数->変数を初期化するとクリックし、文字列型の変数「エリア名」を作成。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/d798dae1-f156-8354-4243-8500d971aba5.png)  
8. 7を繰り返し、「エリアコード」「カテゴリー名」「カテゴリーコード」「店名」「紹介文」を全て文字列型で初期化。初期値は空欄。

---
### ラインのメッセージをLUISで解釈し、変数に代入
9. 新しいステップ->ビルトイン->制御->For eachと進み、eventsを入力。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/593e6528-79ae-0c7c-1146-f644525c8b2f.png)
10. **For each内のアクションの追加**から、LUISのGet predictionを選択。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/1c83fcf9-14c5-d930-de3a-1378a7ff78b6.png)
11. 接続名は任意、API Keyとendpointは手順3-16でメモしたものを使う。
12. App IdはLUISで作成したものを選択。Utterance Textはいったんaaaa。Add new parameterからDesired Intentにチェックし、3-8で作成したIntent名を選択。**保存を忘れずに!**![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/c2bd9c3a-0ce8-2f39-898e-888ae138104d.png)  
13. 上部のメニューからコードビューを選択し、aaaaと打った部分を探し、"q":"aaaa"を"q":"@{items('for_each')?['message']?['text']}"に変更。(for eachブロック内の現在参照中のeventsのメッセージのテキストを参照する)
14. **For each内のアクションの追加**から、for eachをもう一つ作成。入力するリストは、Entities Arrayを選択。For each2の横の・・・->設定から、コンカレンシー制御をON、並列処理の次数を1にする。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/6981e98f-5831-450a-fdb2-6b4d2d216de6.png)
15. **For each2内のアクションの追加**からビルトイン->制御->スイッチを追加。オンの部分に「Entities Array Entity Type」を動的なコンテンツから選択。ケースの次の値に等しいの部分に「location」を直入力、ケースのすぐ下のアクションを追加から[変数の設定]を追加し、エリア名を「Entities Array Entity Value」に動的なコンテンツから選択。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/26014532-26e0-4401-91c1-d9e343fa133c.png)
16. ケースを追加し、同様にcategoryに等しいならカテゴリー名を「Entities Array Entity Value」に設定。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/09160cf3-a639-2e26-65e2-85af90c02c52.png)

---
### カテゴリー名からカテゴリーコードを取得
17. **新しいステップ**をクリック。ビルトイン->HTTP->HTTPと選択し、方法を「GET」、URIを「 https://api.gnavi.co.jp/master/CategorySmallSearchAPI/v3/?keyid=ぐるなびのアクセスキー 」と記入する。一度URIにアクセスして、結果を見てみると作業が想像しやすいかもしれません。
18. 新しいステップをクリック、ビルトイン->データ操作->JSONの解析と選択し、コンテンツに**HTTPの本文**を動的なコンテンツから選択。
19. スキーマは1のURIの結果を、[サンプルのペイロードを使用してスキーマを生成する]に入力して生成。
20. 新しいステップをクリック、For eachを追加し、「category_s」を動的なコンテンツから選択。
21. **For each3内のアクションの追加**から、ビルトイン->制御->条件と選択し、「category_s_name」と「カテゴリー名」が等しいという条件を作る。(次の値を含むでも可)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/ffe3fe8f-2400-d476-cc8a-253e08b360c2.png)
22. trueの場合のアクションを追加、変数の設定でカテゴリーコードをcategory_s_codeに設定。

---
### エリア名からエリアコードを取得
17. **新しいステップ**をクリック。ビルトイン->HTTP->HTTPと選択し、方法を「GET」、URIを「 https://api.gnavi.co.jp/master/GAreaLargeSearchAPI/v3/?keyid=ぐるなびのアクセスキー 」と記入する。一度URIにアクセスして、結果を見てみると作業が想像しやすいかもしれません。
18. 新しいステップをクリック、ビルトイン->データ操作->JSONの解析と選択し、コンテンツに**HTTPの本文**を動的なコンテンツから選択。
19. スキーマは1のURIの結果を、[サンプルのペイロードを使用してスキーマを生成する]に入力して生成。
20. 新しいステップをクリック、For eachを追加し、「garea_large」を動的なコンテンツから選択。
21. **For each3内のアクションの追加**から、ビルトイン->制御->条件と選択し、「areaname_l」と「エリア名」が次の値を含むという条件を作る。
22. trueの場合のアクションを追加、変数の設定でエリアコードをareacode_lに設定。

---
### コードを用いてレストラン検索、返信
23. **新しいステップ**をクリック、HTTPを追加し、方法をGET、URIを「 https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=ぐるなびのアクセスキー&areacode_l=@{variables('エリアコード')}&category_s=@{variables('カテゴリーコード')}&hit_per_page=1 」と入力。
24. 新しいステップをクリック、JSONの解析を追加、コンテンツに**HTTP2の本文**を動的なコンテンツから選択。
25. スキーマは、HTTP2のURIに適当な値を入力して(例 https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=ぐるなびのアクセスキー&areacode_s=AREAS2196&category_s=RSFST09004&hit_per_page=1 )表示されたjsonからスキーマを自動生成
26. 新しいステップ、For each追加、JSONの解析2からの「rest」を入力。
27. **For each4内のアクションの追加**から、変数の設定を追加、店名をnameに、さらにもう一つつくり、紹介文をpr_shortにする。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/6a73c4a1-94b2-54d8-760f-f9f354c0d8e7.png)  
28. 新しいステップ、HTTP追加で画像のように記入。ヘッダのAuthorizationは手順1-5でメモしたもの。本文の変数は動的なコンテンツから選択してください。replyTokenをHTTP要求の受信時から選択した場合、HTTP3が自動的にfor each5に内包されます。![http.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/4fddf079-7956-cbbc-a4a0-16aac9c729f0.png)

# 5.いざ実行
1. Line Developers コンソールのチャネルにQRコードがあります。読み取って友達追加。
2. 渋谷で牛丼とか打ってみる
3. 返信来ない
4. Logic Appの概要から、実行の履歴を表示。失敗してます。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/777281b8-e89a-f302-7148-0615173da6ad.png)
5. JSON解析2でエラー。partyとlunchのtypeが間違っていたそう、スキーマの生成に使ったお店の情報が完璧じゃなかったためと考えられる。ぐるなびAPIの仕様を参照して修正。

```
[
  {
    "message": "Invalid type. Expected String but got Integer.",
    "lineNumber": 0,
    "linePosition": 0,
    "path": "rest[0].party",
    "value": 3500,
    "schemaId": "#/properties/rest/items/properties/party",
    "errorType": "type",
    "childErrors": []
  },
  {
    "message": "Invalid type. Expected Integer but got String.",
    "lineNumber": 0,
    "linePosition": 0,
    "path": "rest[0].lunch",
    "value": "",
    "schemaId": "#/properties/rest/items/properties/lunch",
    "errorType": "type",
    "childErrors": []
  }
]
``` 

間違ってるの多分ここだけじゃないと思うが、一旦返信来たのでOK。仕様みてちゃんとtypeを打とう。あと、「四谷でうなぎ」とうったら、LUISが「う」だけをcategoryとみなしてたので、再学習もする必要あり。

<img width="375" alt="IMG_1245.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/5063edd5-80c7-e6a9-87bf-6d1375e6c155.jpeg">


# 6. (補足)エリア・カテゴリが存在しない場合にメッセージを返す。
レストラン検索APIは、エリアコードやカテゴリーコードが空文字列でも結果を返してくれますが、誤解を招くのでメッセージを返すだけにしてみます。
エリアコード、カテゴリーコードの代入が終わったところで条件を追加し、「カテゴリー名が空文字列と等しい　または　エリア名が空文字列と等しい」という条件を設定し、trueの場合にLINEにリプライを返してロジックアプリの実行を終了させます。下記画像参照
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/8b81f543-3a59-bcdb-2a28-748c08b52f69.png)
結果
<img width="375" alt="IMG_1247.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416672/e9432174-e97e-b6e4-d83c-1a2293327629.jpeg">