Azure Logic Appsによるノンコーディング・クロスプラットフォーム対応スマートスピーカースキル開発

## 本記事について
日本で主流のスマートスピーカー3大プラットフォーム（Amazon Alexa、Google Assistant、LINE Clova）に対応したスキル（アクション）をノンコーディングで開発する手順です。

ちょっと長いですが、まったくコーディングなしで3大プラットフォームに対応したスマートスピーカースキル開発ができますので、ぜひトライしてみてください（シミュレーターで確認ができるほか、AlexaやGoogle Assistantはスマホアプリ等でスキルを呼び出すことができるので、スマートスピーカー実機がなくても動作確認＆使用ができます！）。

## つくるもの
スキル名：「ダイスローラー」
サイコロの投げる数を指定して、出た目と合計を教えてもらうスキルで、Clovaの公式ドキュメントにチュートリアルとして載っている「[サイコロ遊び](https://github.com/line/clova-extension-sample-dice)」とほぼ同じ内容です。

使用イメージは以下の通りです。

ユーザー「〇〇、ダイスローラーを開いて」
スマスピ「サイコロを振ります。いくつ投げますか？」
ユーザー「3個投げて」
スマスピ「結果は5・3・4で、合計は12でした」

単純ですが、スロット（変数）を用いているのでサンプルとしては申し分ありません。
サイコロもたくさん投げると大変ですが、このスキルなら合計も言ってくれますし、VUIでやるのは地味に便利だったりしますね。これさえあれば物理サイコロは不要です！

Clova本家ではNode.jsで組んでありますが、これを今回は「Azure Logic Apps」を使って完全ノンコーディングで作ります。

## Azure Logic Appsとは
ノンコーディングでさまざまな処理フローを作成できるMicrosoft Azureのサービスです。
豊富なトリガーやテンプレートでさまざまなサービスの連携を簡単に実現できます。
※一般向けにMicrosoft Flowというほぼ同機能のタスク自動化ツールが存在しますが、こちらではHTTPリクエスト/レスポンスで他サービスとつなぐことが無料プランでできなくなってしまったため、Logic Appsを使っていきます。

## この記事でわかること
* Azure Logic Appsの操作方法
* Alexa/Google Assistant/Clovaの対話モデル作成方法
* ノンコーディングでのクロスプラットフォーム対応スキルバックエンドの作成方法

## 準備するもの
* Amazon開発者アカウント - Alexaスキル開発用
* Googleアカウント - Googleアシスタントアクション開発用
* LINEアカウント - Clovaスキル開発用
* Azureアカウント - Logic Appsでのバックエンド開発用

※各アカウントの作成やログイン等は説明内では省略します

## 手順

### 1. Azure Logic AppsでのサイコロAPIの作成
#### 1-1. Logic Appの作成
Azureポータルのダッシュボードより「リソースの作成」からLogic Appを作成します（「Web」などの中にある）。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/b9003321-85f2-3049-73b3-a5061dd3f5c1.png)

Logic Appの名前、サブスクリプション、リソースグループ（ここでは新規で「dice-roller」とした）、場所を設定し「作成」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/1e1792c6-7f3f-714d-4cb3-2815295950a4.png)

デプロイが完了するとこのような通知がくるので、「リソースに移動」します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/c1bf3479-f0a6-7690-ab47-6db8f5e80310.png)

#### 1-2. HTTPトリガーの作成
リソースに移動すると、下のほうにテンプレートで「HTTP要求と応答」というものがあるので、これを選択します（空のアプリを作って自分で作ることも可能です）。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/91cc510f-15e1-cd0f-cbe1-b2cd308625b7.png)

「このテンプレートを使用する」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/2170a53a-6936-9cea-055a-d855abcefb0b.png)

これによりWeb APIのようにURLアクセスでこのアプリを呼び出すことができるようになります。

「HTTP要求の受信時」の「要求本文のJSONスキーマ」のところに以下の内容を入力します。

```json
{
    "type": "object",
    "properties": {
        "count": {
            "type": "integer"
        }
    }
}
```

ちなみにリクエストはこのような形式を想定しています。

```json
{
  "count": 3
}
```

JSON形式のデータで、「count」という名前でサイコロを振る個数を指定します。

#### 1-3. 変数の初期化
「HTTP要求の受信時」の下の「＋」をクリックし、「アクションの追加」をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/ab8c0790-bf45-500b-5ec3-bdd21c3fdada.png)


「Built-in」→「変数」（ボタンを押すと隠れている候補が見れます）の「変数を初期化する」を選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/f9687cb6-ffe9-1dfb-1675-e8c027a00cd4.png)
内容は

* 名前：「合計」
* 種類：「整数」
* 値：「0」

とします。これは結果の読み上げで使用する「合計」の値を入れておくためのものです。

続けて、同様に「変数を初期化する」をさらに３つ追加します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/e3a098eb-0206-ae46-6dce-c16eda46f862.png)

内容は以下の通りです。

読み上げ用の出目の内訳

* 名前：「出目リスト」
* 種類：「文字列」
* 値：「 」※半角スペース

このあとに作成する繰り返し処理の制御用

* 名前：「index」
* 種類：「整数」
* 値：「0」

繰り返し処理の中で使用する、サイコロの出目を保存するための変数

* 名前：「出目」
* 種類：「整数」
* 値：「0」

用意する変数は以上です。

#### 1-4. サイコロを振る繰り返し処理の作成
サイコロを振る処理を作っていきます。
countの数だけ振るので、繰り返し処理を使います。」

まず「変数を初期化する４」の下にアクションを追加し、「Built-in」の「制御」を選択し「まで」アクションを追加してください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/1772e922-03b2-3edb-2785-a528e8199b5a.png)

「まで」（Do until）は、中に書いたアクションをある条件を満たすまで繰り返す処理で、まず繰り返しの終了条件を設定します。
まず左の2つは「index」「次の値に等しい」とします。
「index」は入力欄にフォーカスすると出てくる「動的なコンテンツ」から選択して入力します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/ebef2e25-43af-464c-d58f-21fb2f622390.png)


一番右は「count」の数字を数値（int）に変換したものを入れます。
まず入力欄にカーソルを入れ、「動的なコンテンツ」の選択ウィンドウが出てきたら、「式」に切り替えます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/778f6bf5-e832-66f4-f335-dbd49a6309f4.png)

ここで「変換関数」の「int」関数をクリックし、「fx」内にint()が入ります。()の間にカーソルがある状態だと思うので、そのまま「動的なコンテンツ」に再度タブを切り替え、「count」をクリックします。
すると「fx」内が`int(triggerBody()?['count'])`となるので、OKをクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/852ed4cc-c322-eb0b-d882-589f972c7b7e.png)

これで、「index」の値を繰り返し処理の中で1ずつ増やし、リクエストに含まれていたサイコロを振る個数（count）と同じになったら終了するようになりました。
indexの初期値は0なので、ちょうどcountの数だけ繰り返し処理が行われるという寸法です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/c875ff14-4ce0-1ba6-aeb7-5c647a2e69b5.png)


次に、サイコロを振る処理を作っていきます。
「まで」内にアクションを以下のように４つ作ります。

**① 「変数の値を増やす」**

* 名前：「index」
* 値：「1」

indexを1ずつ増やす処理です（countの値まで増えたら次で終了）。

**②「変数の設定」**

* 名前：「出目」
* 値：rand(1, 6)

値は、以下のように設定します。
任意の数値の間でランダムな値を出力する「rand」関数を使います。

(1) 値にカーソルを入れる
(2) 「式」を選択
(3) 数学関数の「もっと見る」をクリック
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/e9ddd557-0f43-2c86-ff75-fe269a2ddc6b.png)

(4) rand関数をクリック
(5) 引数を入力（「rand(1, 6)」と入力。1から6までの間でランダムな値を得られる）
(6) OKをクリック
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/33f476ef-9d8f-6c18-7947-d20091a8e0f1.png)

するとこのように「rand(...)」という項目が値にセットされます。

**③「変数の値を増やす」**

* 名前：「合計」
* 値：「出目」 ※動的なコンテンツから選択

**④「文字列変数に追加」**

* 名前：「出目リスト」
* 値：「, 」（カンマ＋半角スペース）＋「出目」 ※動的なコンテンツから選択

カンマと半角スペースを入力してから動的なコンテンツから「出目」を選択します。

すべて入力したら、「まで」のブロックはこのようになるはずです。
<img src="https://qiita-image-store.s3.amazonaws.com/0/194664/0a049ecf-b5aa-8f05-f599-ecee74e4dd6b.png" width="500px">

#### 1-5. 結果の返却処理（応答）の作成
一番下の「Response」のブロックで結果の返却処理を作ります。

状態コードは「200」のまま。
ヘッダーには以下の内容を追加します。

`Content-Type` - `application/json;charset=utf-8`

本文には

```json
{
  "result": "結果は  で、合計は  でした。"
}
```

を入力後、動的なコンテンツとして「結果は」のあとに「出目リスト」、「合計は」のあとに「合計」を挿入します。

このようになればOKです。
<img src="https://qiita-image-store.s3.amazonaws.com/0/194664/0994aada-cdf4-f00e-b9b3-be6ad910ae9b.png" width="500px">


#### 1-6. 「count」が渡ってこなかった場合の処理（とひとつだけ振る場合の処理）を作成

「count」がAPIに渡されないと、いくつサイコロを振ればよいのかわからず、処理がうまく動きません（ここまで実装したものだと無限ループにハマって抜けられなくなります）。

そこで、countが渡ってこなかったときの処理を考える必要があります。
「countが渡ってこない場合エラーとする」という考え方もありますが、ここでは「countが渡ってこない場合サイコロを1つだけ振る」という動きにしたいと思います。
countが0でも同様にうまく動かないため、countを「1」とみなすようにします。
countの値で処理を分岐させ、2以上のcountが渡ってきた場合サイコロを複数振り、そうでないときにひとつだけ振るようにしていきます（単一のサイコロと複数のサイコロで結果の伝え方も変えられるので一石二鳥）。

まずは分岐を作ります。
「まで」の手前の矢印にマウスカーソルを当て「＋」をクリックし、出てきた「アクションの追加」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/aa93a2e1-7875-ca1f-2c37-3ebf1d9a8399.png)

「アクションを選択してください」と出るので、「Built-in」の「制御」から「条件」を選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/96cb196d-2260-b3d9-bb25-14f5e28ebca2.png)


条件には、最初の入力欄で以下のようにします。

* 「式」から「変換関数」の「int」を選択
* 「fx」と書かれた欄に`int()`と入るので、その()内に、関数一覧の下のほうにある「操作」の「もっと見る」で表示される「coalesce」を選択
* 「fx」欄に入った`coalesce()`の()内に「動的なコンテンツ」の「count」を入れる
* `triggerBody()?['count']`のあとに`,0`と入力

これらはすべてマウスをぽちぽちするだけで作れます。
「fx」欄内が `int(coalesce(triggerBody()?['count'],0))` になればOKです。
作れたら「OK」を押せば入ります。
あとの2つの入力欄には`次の値以上`、`2`と設定します。

そして、「trueの場合」の分岐のほうにさきほど作った「まで」「Response」のブロックをひとつずつドラッグ＆ドロップで移動させます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/52e5e661-36e5-ad43-5cae-cc7611c55002.png)


次に「falseの場合」のブロックにサイコロをひとつだけ振り応答を返す処理を作ります。

さきほどと同様の要領で、「変数の設定」で「出目」に`rand(1,6)`を設定し、応答で結果を返すようにします。
応答は「Built-in」→「要求」にある「応答」（ここでは日本語になっている）です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/b8c787fb-4d58-88ca-43bb-adf4e234ca2c.png)

状態コードは「200」のままで、ヘッダーには以下の内容。

`Content-Type` - `application/json;charset=utf-8`

本文には以下を設定します。

```json
{
  "result": "結果は [出目] でした。"
}
```
出目は動的なコンテンツです。


分岐全体が以下のようになればOKです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/1b406a2f-9339-9679-1e64-773504e39759.png)

これでサイコロAPIは完成です。
「保存」をクリックして終了です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/692742f9-5489-04a7-9536-a663f5d8a104.png)


### 2. 対話モデルの作成
続いて、各音声アシスタントからこのAPIを呼び出すスキルを作っていきます。

対話モデルの作成は、各プラットフォームともほとんど同じです。

* 「ThrowDiceIntent」という名前のインテントを作成
* 「diceCount」という名前のスロット（Googleの場合はエンティティ）を作成
* 発話のパターンをいくつか登録
* 上記を学習させる

という流れです。
サイコロを投げるインテントとして解釈してもらう発話パターンは、以下のようなものを学習させます。

* サイコロを2つ投げて
* サイコロを8個振って
* サイコロ5個
* 7つ振って
* 4個
* 3つ
* サイコロを振って
* サイコロを投げて
* 振って
* 投げて

ポイントは、個数のみかそうでないか、数値の単位、「投げる」「振る」といった表現の幅に対応させることです。

振るサイコロの個数を指定する数字の部分は、ビルトインの数値型スロット（Googleの場合はエンティティ）として認識させ、それを「diceCount」という名前にします。

#### 2-1. Alexa
##### 2-1-1. スキルの作成
[alexa developer console](https://developer.amazon.com/alexa/console/ask)にアクセス・ログインし、「スキルの作成」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/43736f5c-8e5d-c160-d7e8-8ce5f73a15ad.png)

スキル名には`ダイスローラー`と入力し、デフォルトの言語は`日本語(日本)`を選択します。
「スキルに追加するモデルを選択」では「カスタム」「独自のプロビジョニング」が選択されていることを確認し、「スキルの作成」をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/26be5339-7613-8176-37cd-f4b0fd0e3a75.png)

##### 2-1-2. 呼び出し名の設定
スキルの画面に移ったら、まず呼び出し名を設定します。
呼び出し名は、Alexaにスキルを起動してもらうために話しかける名称です。

左のメニューから「呼び出し名」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/7f359e54-0cc8-3e2a-5a01-5a60b0dd1fc0.png)

「スキルの呼び出し名」に`dice roller`と入力します（英語で入力しないと認識してくれない）。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/770a30a2-779d-6450-fae6-b0892ecf6bd2.png)

##### 2-1-3. インテントの追加
次にインテントを追加していきます。
メニューで、インテントの「追加」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/b7ae86e7-3c14-4094-923a-19b9adb0d408.png)

インテント名に`ThrowDiceIntent`と入力し、「カスタムインテントを作成」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/337466e1-78b6-28db-8719-3183a5805901.png)

##### 2-1-4. スロットの作成
インテント「ThrowDiceIntent」の設定画面に移るので、一番下の「インテントスロット」のセクションで名前（「新しいスロットを作成」と書いてあるところ）に`diceCount`と入力し、隣の「＋」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/c5315920-b394-dd33-c37c-b8ceccaff4b9.png)

スロットタイプで`AMAZON.NUMBER`を選択します（＋を押してから出ないと選択できません）。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/10028861-271e-2818-4c94-2c57eaa7b78b.png)

##### 2-1-5. サンプル発話の登録
サンプル発話を登録していきます。
「サイコロを2つ投げて」などの文章を入れていきますが、数字部分はスロットにする必要があります。
スロットはさきほど作ったdiceCountです。 `{` を入力すると候補が表示されるので、`diceCount`をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/e172aaa8-cfd9-4eb8-8f31-ac96f831191a.png)

同じ要領でいくつかのパターンを登録します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/46db66d8-4487-fba9-cbed-936e210d8797.png)

##### 2-1-6. モデルの保存とビルド
インテント・スロットの登録が完了したので、対話モデルを保存してビルドします。

「モデルを保存」「モデルをビルド」を押し、しばらく待つとビルド成功のメッセージが出ます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/a0eea1fa-5b49-cec6-abd7-a269e0c96001.png)

#### 2-2. Googleアシスタント
##### 2-2-1. アクションの作成
[Actions on Google](https://console.actions.google.com/u/0/)にログインします。

「Add/import project」をクリックし、新規プロジェクトを作ります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/2f496b0e-b410-027f-ee86-df98d0e820a8.png)

プロジェクト名は`dice-roller`とし、言語と国を選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/63dce4ba-a50e-ae5e-1dad-0d9c3bda7310.png)

プロジェクト作成ができ画面遷移したら、下のほうの「More options」の「Conversational」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/db3d777d-e87d-ee27-0d8f-0c1d3ee0d4f6.png)

まず呼び出し名を登録します。「Invocation」をクリックし、「Display name」に`ダイスローラー`と入力し「SAVE」を押します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/f0815ded-d6ae-bb9d-9cef-2ea8470f4a48.png)

次に左のメニューの「Actions」をクリックし、「ADD YOUR FIRST ACTION」をクリックします。
<img src="https://qiita-image-store.s3.amazonaws.com/0/194664/c1a35b18-b00f-e0ec-2e15-8becdb0b2dec.png" width="500px">

「Custom intent」の「BUILD」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/a5d05429-f2f1-a297-6507-dbd195952fe8.png)

するとDialogflowの画面が開きます。ここから対話モデルの作成作業に入ります。

##### 2-2-2. Dialogflowでの対話モデル作成

Dialogflowの画面が開いたら、まず言語を選択し「CREATE」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/7736d994-0990-f860-5278-b97a4ef306bf.png)

すると、インテント作成の画面に移ります。
さきほどのAlexaと同様に、「ThrowDiceIntent」を作っていきましょう。

まずは「CREATE INTENT」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/a3e27bc3-2f2f-8e39-3e93-e3659892d3b3.png)

インテントの作成画面に移るので、「Intent name」に`ThrowDiceIntent`と入力します。

次に発話パターンを登録していきます。
Alexaと異なり、数字を含んだ文章をそのまま入力していきます。
「Training phrases」のセクションで「ADD TRAINING PHRASES」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/d85db21b-2612-2faa-be7c-68c9e8ec0e00.png)

「Add user expression」に`サイコロを2つ投げて`と入力し、Enterを押します。
すると、「2つ」の部分がエンティティ（Alexaでのスロットに相当）としてハイライトされ、それが`@sys.time`型のパラメータではないかと推測されます。
しかし、ここでは数字部分のみ`@sys.number`型のパラメータになってほしいところなので、修正が必要です。

マウスでハイライトされている部分を調整します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/d69553ef-3033-0ff5-f0cc-9eaf684b7f5a.png)

次に`@sys.time`の部分をクリックして`@sys.number`に変更し、パラメータ名も`diceCount`に変更します。
このようになればOKです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/46215ae6-1fb5-5b54-c889-a586bd74a744.png)

同じ要領で、他のパターンも登録していきます（このあとはほとんどパラメータは正しく認識してくれるはずですが、単位が含まれないよう注意してください）。

Alexaと同じパターンを登録しました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/e5b70234-8148-ec40-e977-402ad54eede5.png)

これで対話モデルはOKです。いったん「SAVE」を押して保存しましょう（Dialogflowではビルドは自動でやってくれます）。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/1c20a31f-5bbc-95d0-5f52-c802c02e5bd4.png)

#### 2-3. Clova

##### 2-3-1. LINEアカウントでのログイン
まずは、[LINE Developers](https://developers.line.biz/ja/)のページから、LINEアカウントでログインします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/d669b675-db47-320f-67ee-c2281db63824.png)

##### 2-3-2. プロバイダーの作成
次に、プロバイダーを作成（またはすでに作成済みのプロバイダーを選択）します。
<img src="https://qiita-image-store.s3.amazonaws.com/0/194664/94a3eff2-15e1-0509-f4e8-fa93180d347e.png" width="80%">

プロバイダーは「サービス提供者（企業・個人）の名前」のことで、これから作成するClovaスキルの提供元となります。新規作成する場合は、お好きなプロバイダー名を入力してください。

<img src="https://qiita-image-store.s3.amazonaws.com/0/194664/fb297ccc-4e6e-30ea-49a9-97b4a615e061.png" width="80%">
<img src="https://qiita-image-store.s3.amazonaws.com/0/194664/93b1c951-7ed6-8044-83f4-9ea4afbaddb3.png" width="80%">

##### 2-3-3. チャネル作成
続いて作成（選択）したプロバイダーに、これから作成するスキルのためのチャネルを作成します。
「Clovaスキル」の新規チャネル作成を行っていきます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/f5547f7c-5be4-7246-de7f-5b181d3deca8.png)

チャネル名を`ダイスローラー`とし、「入力内容を確認する」をクリック。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/aafee2ac-c80e-32ba-c558-81fcb0889be8.png)

続けて、「作成してClova Developer Centerに移動」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/4da75423-4774-3b93-670a-466a857c9112.png)

2か所にチェックを入れ、「スキル開発を始める」をクリックしてください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/4ad39380-4c10-8652-af00-4b637fecd40e.png)

「基本情報」の入力を求められるので、それぞれ入力します。

* Extension ID - 他のスキルとかぶらない一意の値（例：jp.co.example.DiceRollerなど）
* スキル名 - `ダイスローラー`
* スキル名 (音声読み上げ) - `ダイスローラー`
* 呼び出し名(メイン) - `ダイスローラー`
* 呼び出し名(サブ) - `dice roller` ※Clovaも英語で聞き取ってくるので、英語の登録が必須です

入力できたら、「作成」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/f4e4f2b1-e9e8-5493-7308-380dc2d057e0.png)

「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/bf6e83b1-493c-682a-734f-ac0ed31b58b4.png)

##### 2-3-4. スロットの登録
対話モデルの編集画面に移るので、Alexa/Googleと同じくインテントとスロットを登録していきます。
まずは、スロットの登録です。今回は単純な数値（振るサイコロの個数）をスロットとして使うので、Clovaに元から用意されているビルトインスロットを使います。

「ビルトイン スロットタイプ」の「追加」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/08d15a60-1980-f4e1-193f-21eacce36767.png)

新しいウィンドウが開くので、「CLOVA.NUMBER」にチェックを入れ、「保存」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/f37b4c76-2d94-b612-7cea-60280bdf7c4a.png)

##### 2-3-5. インテントの登録
そのウィンドウのまま、続けてインテントの登録をしていきます。
「カスタム インテント」の「＋」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/e7403b89-6da4-c11e-6e79-44dc51ef4261.png)

インテント名として`ThrowDiceIntent`と入力し、「作成」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/ad5e974e-eb00-83f2-f80d-445292690fd0.png)

「サンプル発話リスト」に発話パターンを登録していきます。
まず`サイコロを2つ投げて`と入力して「＋」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/f21b8c0d-fa2d-068b-6445-85fe9217f364.png)

登録したサンプル発話の、スロットにしたい数字の部分をマウスで選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/e09a63bc-1757-fe20-5287-26395e2f68e7.png)

「新しいスロットに名前をつける」のところに`diceCount`と入力し、「＋」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/567a14b8-d445-55e5-fb89-78d431265ff7.png)

スロットタイプをビルトインスロットの「CLOVA.NUMBER」にします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/c8d0a460-8838-1372-c0eb-086fe11c3579.png)

このようになればOKです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/d60dba4d-f3e6-271d-370a-a8d51627f699.png)

同様に他の発話パターンも登録していきます（以降はスロットは登録済みのものから選ぶだけになります）。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/3b4d3bc7-2cc8-aee5-17c4-5bb9cb6c92d8.png)

登録が終わったら、「保存」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/f4bd0eee-863d-4da0-590f-5f81e92100d0.png)

##### 2-3-6. 対話モデルのビルド
最後にビルドをして終了です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/6828f382-8252-1052-c595-cefdd5f87c96.png)


### 3. 対話モデルとサイコロAPIを結ぶゲートウェイフローの作成
ではいよいよ、最初に作ったサイコロAPIと、3つの対話モデルをつなげていきます。
基本的に対話モデルとバックエンドのやりとりはJSONでやりとりが行われています。

どんなJSONが対話モデルから送られ、またどんなJSONをバックエンドから返してあげる必要があるのかは、各ドキュメントを参照したり、シミュレーターのテスト結果から調べることができます。
このJSONを、Microsoft Flowで解析し、サイコロAPIの呼び出しを含むフローを作っていきます。

3プラットフォームとも、基本的なフローはほぼ同じなので、まずAlexa用にまずフローを作り、Google Assistant用/Clova用はそれを複製して微修正する、という流れでクロスプラットフォーム対応していきます。

#### 3-1. Alexa
まずはAlexaです。

##### 3-1-1. HTTPトリガーの作成
サイコロAPIと同様、HTTPトリガーで動くフローを作っていきます。
Azureポータルのダッシュボードより「リソースの作成」からLogic Appを作成します（「Web」などの中にある）。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/b9003321-85f2-3049-73b3-a5061dd3f5c1.png)

Logic Appの名前（'dice-roller-alexa-gateway'とした）、サブスクリプション、リソースグループ（さきほど作った`dice-roller`を選択）、場所を設定し「作成」をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/e00f4184-f5c7-1b34-e99c-1e4a38d85def.png)

デプロイが完了したらリソースに移動し、サイコロAPIと同じくテンプレートで「HTTP要求と応答」というものがあるので、これを選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/91cc510f-15e1-cd0f-cbe1-b2cd308625b7.png)

「このテンプレートを使用する」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/2170a53a-6936-9cea-055a-d855abcefb0b.png)

「要求本文のJSONスキーマ」の下にある「サンプルのペイロードを使用してスキーマを生成する」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/a3a8ff2f-de4d-1d52-3db4-dcfe823b30a3.png)


以下のJSONを入力します。
これはリファレンスの[IntentRequestの例](https://developer.amazon.com/ja/docs/custom-skills/request-types-reference.html#intentrequest-example)を参考に、Slot名だけ今回作った「diceCount」に変更したのです。
※リファレンスではカンマがひとつ足りないので注意

```json
{
  "version": "1.0",
  "session": {
    "new": false,
    "sessionId": "amzn1.echo-api.session.0000000-0000-0000-0000-00000000000",
    "application": {
      "applicationId": "amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebe"
    },
    "attributes": {
      "supportedHoroscopePeriods": {
        "daily": true,
        "weekly": false,
        "monthly": false
      }
    },
    "user": {
      "userId": "amzn1.account.AM3B00000000000000000000000"
    }
  },
  "context": {
    "System": {
      "application": {
        "applicationId": "amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebe"
      },
      "user": {
        "userId": "amzn1.account.AM3B00000000000000000000000"
      },
      "device": {
        "supportedInterfaces": {
          "AudioPlayer": {}
        }
      }
    },
    "AudioPlayer": {
      "offsetInMilliseconds": 0,
      "playerActivity": "IDLE"
    }
  },
  "request": {
    "type": "IntentRequest",
    "requestId": " amzn1.echo-api.request.0000000-0000-0000-0000-00000000000",
    "timestamp": "2015-05-13T12:34:56Z",
    "dialogState": "COMPLETED",
    "locale": "string",
    "intent": {
      "name": "GetZodiacHoroscopeIntent",
      "confirmationStatus": "NONE",
      "slots": {
        "diceCount": {
          "name": "diceCount",
          "value": "virgo",
          "confirmationStatus": "NONE"
        }
      }
    }
  }
}
```

入力してOKを押すと、JSONスキーマが登録されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/2b9745c4-76b9-93fc-19fd-e3345477f8e6.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/a955c3d1-a69c-d790-d7ea-4ac21bc45b55.png)

##### 3-1-2. リクエストタイプによる分岐の作成
「HTTP要求の受信時」の下にアクションを追加し、「Built-in」→「制御」→「条件」と選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/7bc60d5b-35f3-ef0f-f10c-2236427222d4.png)

条件には、動的なコンテンツより「type」、`次の値に等しい`、`LaunchRequest`を入力します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/78ad72b1-3fe4-8faa-5bc9-464404a99b8b.png)

これにより、true側が起動リクエスト（LaunchRequest）の場合の処理、false側がそれ以外、となります。

false側ではさらにインテントリクエスト（IntentRequest）かどうかを識別したいので、さらに条件を追加します。
すると、分岐はこうなります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/e7602281-0984-0965-cfa9-56aeec4e1502.png)

今回は起動とインテントリクエスト以外のリクエストに対する処理は省略します。
何もしないfalse-falseの部分に、空の応答をさせるため、もともとあった「Response」をドラッグ＆ドロップで移動しておきます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/92a42339-fd64-2144-783a-2c09a82fef41.png)

それでは以下で起動/インテントリクエストに対する処理を埋めていきます。

##### 3-1-3. 起動リクエストに対するレスポンスの作成
最初の条件の「true」の中に「応答」のアクションを追加します。

ヘッダーにはこれまでと同じように、以下の内容を追加します。

`Content-Type` - `application/json;charset=utf-8`

本文には以下のJSONをセットします（Alexaのドキュメントを参考にしました）。
スキル起動時に「サイコロをいくつ投げますか？」としゃべらせるためのレスポンスです。

```json
{
  "response": {
    "outputSpeech": {
      "text": "サイコロをいくつ投げますか？",
      "type": "PlainText"
    },
    "reprompt": {
      "outputSpeech": {
        "text": "サイコロをいくつ投げますか？",
        "type": "PlainText"
      }
    },
    "shouldEndSession": false
  },
  "version": "1.0"
}
```

##### 3-1-4. インテントリクエストに対するレスポンスの作成
false-trueのブロックでは、リクエストされたインテントに対応する処理を作ります。
ここでインテント名に基づく条件分岐を作る必要があります。

ここでは対話モデルに作った「ThrowDiceIntent」の1種類に対応する処理のみ作っていきます（本来はカスタムインテントが1つでも、ガイド（ヘルプ）などデフォルトのインテントに対応する処理を作る必要がありますが、ここでは割愛します）。

「条件」を追加し、動的なコンテンツから「name」、`次の値に等しい`、`ThrowDiceIntent`と入力します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/f8d4bfce-09df-f274-6e29-ee3589e9aa97.png)
「name」は2つあるうちの上のほう（入力後マウスオーバーで「triggerBody()?['request']?['intent']?['name']」と表示されるほう）です。


falseのほうには、起動リクエストと同じ「応答」を入れておきます（何を聞かれても「サイコロをいくつ投げますか？」と言ってもらう）。

trueのほうはサイコロを振る処理なので、サイコロAPIの呼び出しを行います。
サイコロAPIはHTTPのリクエストで動くフローなので、HTTP呼び出しをそのまま作ってもよいですが、Logic App同士の呼び出しはもっと簡単に行うことができます。

「アクションの追加」で「Built-in」→「Azure Logic Apps」を選択し、「dice-api」を選びます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/d82342fc-9815-62db-d020-50905becc80d.png)

さらに「request」をクリックすると、呼び出しパラメータの設定ができるようになります。

「count」には、Alexaのリクエストに含まれるスロット「diceCount」の値を渡します。
数値型でないと渡せないようになっているので、ここでもintとcoalesceを使って空を0に変換します（ここはAPIとどちらかで済むようにすればよかったかもしれません）。

「式」で変換関数の「int」、操作（もっと見る）の「coalesce」を順にクリックし、動的なコンテンツの「value」を選択後、`,0`と入力します。
「fx」内が`triggerBody()?['request']?['intent']?['slots']?['diceCount']?['value']`となればOKです。

ブロックはこうなります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/a5c35a38-ea1e-2178-e808-72e4de89c255.png)

続けて、dice-apiからのレスポンスを解析する処理を作ります。
「アクションの追加」で「Built-in」→「データ操作」→「JSONの解析」を選びます。

「コンテンツ」にはdice-apiの「本文」を入れ、スキーマは「サンプルのペイロードを～」から以下のJSON（dice-apiからのレスポンス想定）を入力して作ります。

```json
{
  "result": "結果は1,1,1で、合計は3でした。"
}
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/9f7372ca-9f1e-74f4-8618-f8f071167c56.png)

最後に「応答」を作ります。

ここでは解析結果の「result」を返すことと、アシスタントとの対話を終わりにするため、セッションを終了させるよう`shouldEndSession`をtrueにするようなレスポンスを作ります。
本文に入れるJSONは以下のようになります。

```json
{
  "response": {
    "outputSpeech": {
      "text": "[result]",
      "type": "PlainText"
    },
    "shouldEndSession": true
  },
  "version": "1.0"
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/89f23e55-aaaf-1d22-53fc-32c50cb985a8.png)

これでAlexa用のゲートウェイは完成です。「保存」を押します。

##### 3-1-5. Alexaとの接続
Alexa用のゲートウェイのLogic Appを保存後、一番上の「HTTP要求の受信時」に表示されるURLの右のボタンを押し、URLをコピーします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/ca6b35a1-7a2d-1d0d-8131-caf3b9e744ad.png)

alexa developer consoleに戻り、「エンドポイント」を開きます。
「HTTPS」を選択し、コピーしたURLを貼り付けます。証明書に関する選択肢は、2つ目を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/2ecdd0cd-6770-d6ff-8b88-0909f0bc31e0.png)

上にある「エンドポイントの保存」を押せば、Alexa→ゲートウェイ→サイコロAPIの接続が完了です。

##### 3-1-6. シミュレーターでの動作確認
「テスト」タブに移り、「非公開」から「開発中」に変更します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/8e8378bc-6183-ea41-f448-c3c64a7a1f60.png)

左側で、会話の確認ができます。
テキストで入力することも、マイクで話しかけることもできます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/d68796b3-7a97-8543-af70-49c870b319c0.png)

「4つ」とテキスト入力するとスロットをうまく認識してくれず、マイクで「五個」というと認識してくれました（漢数字になる）。

うまくつなげられたようなので、Alexaはこれで完成です！

#### 3-2. Googleアシスタント
ここから先はもうラクチンです。

##### 3-2-1. Alexa用のLogic Appを複製
Alexa用に作ったLogic Appをコピーして、それを微修正して完成させていきます。

まず、さきほどのAlexa用のLogic Appを開き、「複製」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/db0d629d-6892-8421-2821-9ff5fe829774.png)

名前は`dice-roller-google-gateway`とし、作成をクリックします。

<img src="https://qiita-image-store.s3.amazonaws.com/0/194664/66f86247-402c-8186-6e55-96305a3c43c8.png" width="300px">

##### 3-2-2. Fulfillmentの設定
デプロイが終わったらリソースへ移動し、「編集」からデザイナーへ移動します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/22d2d20f-2616-07f0-90c9-be4a915351bc.png)

一番上にある「HTTP要求の受信時」からURLを先ほどと同じようにコピーします。

Dialogflowの画面へ行き、「Fulfillment」の「Webhook」を有効（ENABLED）にし、コピーしたURLを貼り付けます。

設定したら、画面一番下の「SAVE」をクリックしてください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/13edc2fd-2cc1-4d30-93f9-94b2ad45bea7.png)

次に「Intents」を開き、「Default Welcome Intent」と「ThrowDiceIntent」のそれぞれでFulfillmentを有効化します。
各インテントを開き、一番下で「ENABLE FULFILLMENT」をクリックして以下のように設定してください（設定後、一番上の「SAVE」を押して保存する）。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/41e591fc-b800-ce83-f29c-2b2b67691eff.png)


##### 3-2-3. JSONスキーマ定義の更新
Fulfillmentの設定ができたら、右端にある「Try it now」に`サイコロを3つ投げて`など発話を入力しEnterを押します。
すると、実際に発話のインテント/エンティティの解析とバックエンドへのリクエストが実行されます。
バックエンドはまだAlexaのものを複製しただけなので当然うまくいきませんが、ここでリクエストのJSONを得ることができます。

テスト結果の一番下の「DIAGNOSTIC INFO」をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/96d55989-b195-bffb-39dc-72c973565669.png)

「FULFILLMENT REQUEST」でリクエスト本文が確認できるので、「COPY RAW RESPONSE」でその内容をコピーします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/0ded6706-384a-852d-83f5-29ed738df268.png)

コピーしたJSONを、Logic App（Google用）の一番上の「サンプルのペイロード～」から貼り付け、スキーマをGoogle Assistant用に変えます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/61e63f29-4422-be6f-45ba-c65b9008a25b.png)

##### 3-2-4. 動的なコンテンツ等の入れ直し
リクエストのスキーマ定義が変わったので、それに伴いフロー中で使っていた動的なコンテンツ等を入れ直していきます。

**①1つ目の「条件」**
動的なコンテンツ「displayName」、`次の値に等しい`、`Default Welcome Intent`に変更します。

**②falseの中の「条件２」の上に、そのなかのtrueにある「条件３」を移動**
ドラッグ＆ドロップで移動させます。

**③「条件２」を削除**
不要なので、ブロックの右側にある「…」から「削除」をします。

**④「条件３」を変更**
最初の動的なコンテンツ「name」を、同じく動的なコンテンツ「displayName」にします。

**⑤「条件３」trueの場合のdice-apiのパラメータ**
「count」の式を、`triggerBody()?['request']?['intent']?['slots']?['diceCount']?['value']`の部分を削除し、動的なコンテンツ「diceCount」を入れ更新。
式が`int(coalesce(triggerBody()?['queryResult']?['parameters']?['diceCount'],0))`となっていればOKです。

**⑥レスポンス本文の変更**
「応答」（左端）と「応答２」（右端）は以下。

```json
{
  "fulfillmentText": "サイコロをいくつ投げますか？"
}
```
「応答３」（真ん中）は以下を設定します。

```json
{
  "payload": {
    "google": {
      "expectUserResponse": false,
      "richResponse": {
        "items": [
          {
            "simpleResponse": {
              "textToSpeech": "[result]"
            }
          }
        ]
      }
    }
  }
}
```

「result」は動的なコンテンツです。

以上で変更は終了です。
保存をして、シミュレーターで動作確認をします。

##### 3-2-5. シミュレーターでの動作確認
Actions on Googleの「Simulater」から動作確認できます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/566b01a7-1df4-15b8-08fa-a3bf86e25d7a.png)

このようになれば成功です！

#### 3-3. Clova
##### 3-3-1. Alexa用のLogic Appを複製
最後にClovaです。こちらも全く同じ要領でAlexa用のものを複製して変更していきます。
ClovaはGoogle AssistantよりもAlexaに似ているので、さきほどより楽です。

`dice-roller-clova-gateway`という名前でLogic Appを複製しましょう。

##### 3-3-2. CEKエンドポイントの設定
複製できたら、先ほどと同じくURLをコピーし、CEK側に設定します。

Clova Developer Centerで、「開発設定」からURLを設定します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/2ad528f7-8cff-a7ca-b0fc-2c44a611153e.png)

その後、必要事項がいくつか聞かれるので、適当な値を設定していきます。
※アイコンが必須なので、いらすとやさんからいただいた画像を使ってしのぎます。
<img src="https://qiita-image-store.s3.amazonaws.com/0/194664/d6d14432-878f-6dd1-5890-11037c3bef3a.png" width="200px">

##### 3-3-3. JSONスキーマ定義の更新
Google Assistantのときと同様、JSONスキーマ定義を変更します。
今回はドキュメントを参考にJSONを用意します。以下のJSONを「サンプルのペイロード～」に貼り付けましょう。

```json
{
  "version": "1.0",
  "session": {
    "new": false,
    "sessionAttributes": {},
    "sessionId": "a29cfead-c5ba-474d-8745-6c1a6625f0c5",
    "user": {
      "userId": "U399a1e08a8d474521fc4bbd8c7b4148f",
      "accessToken": "XHapQasdfsdfFsdfasdflQQ7"
    }
  },
  "context": {
    "System": {
      "application": {
        "applicationId": "com.example.extension.pizzabot"
      },
      "user": {
        "userId": "U399a1e08a8d474521fc4bbd8c7b4148f",
        "accessToken": "XHapQasdfsdfFsdfasdflQQ7"
      },
      "device": {
        "deviceId": "096e6b27-1717-33e9-b0a7-510a48658a9b",
        "display": {
          "size": "l100",
          "orientation": "landscape",
          "dpi": 96,
          "contentLayer": {
            "width": 640,
            "height": 360
          }
        }
      }
    }
  },
  "request": {
    "type": "IntentRequest",
    "intent": {
      "name": "OrderPizza",
      "slots": {
        "diceCount": {
          "name": "pizzaType",
          "value": "ペパロニ"
        }
      }
    }
  }
}
```
スロット名だけ、今回用に変更しています。Alexaのときと同じですね。

##### 3-3-4. 動的なコンテンツ等の入れ直し
実は動的なコンテンツは入れ直しの必要がありません（定義がほぼ同じため）。

各応答は変更が必要なので以下のように変えてください。

「応答１」「応答２」

```json
{
  "version": "1.0",
  "sessionAttributes": {},
  "response": {
    "outputSpeech": {
      "type": "SimpleSpeech",
      "values": {
        "type": "PlainText",
        "lang": "ja",
        "value": "サイコロをいくつ投げますか？"
      }
    },
    "card": {},
    "directives": [],
    "shouldEndSession": false
  }
}
```

「応答３」

```json
{
  "version": "1.0",
  "sessionAttributes": {},
  "response": {
    "outputSpeech": {
      "type": "SimpleSpeech",
      "values": {
        "type": "PlainText",
        "lang": "ja",
        "value": "[result]"
      }
    },
    "card": {},
    "directives": [],
    "shouldEndSession": true
  }
}
```

「result」は動的なコンテンツです。
shouldEndSessionをtrueにするのを忘れずに。

以上で終了です。保存し、シミュレーターで動作確認していきます。

##### 3-3-5. シミュレーターでの動作確認
さきほどの開発設定を終えた画面で、「テスト」が表示されているので、そこで確認します。

「シナリオテスト」に切り替えると起動からの一連の流れをテストすることができます。
「○○を起動して」のボタンを押せばワンクリックで起動リクエストが投げられます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/194664/697799da-50a3-5fad-2650-b8e2d1a6dab7.png)


このようになれば成功です！

以上で、クロスプラットフォーム対応のスキル開発は完了です。

### 4. 実機での動作確認
#### 4-1. Alexa
特になにもせず、実機で動作確認ができます。

#### 4-2. Googleアシスタント
Alexa同様、特になにもせず実機で動作確認ができます。

#### 4-3. Clova
スマートフォンのClovaアプリの「スキルストア」より開発中のスキルの有効化を行うことで実機で動作させることができます。

## 実運用する場合の注意
今回は省略しましたが、Logic Appへのアクセスが本当にAlexaやGoogle Assistant、Clovaからのアクセスかどうかのリクエスト検証をしたほうがよいでしょう。
上記どちらも、各アシスタントからのリクエストを受けるゲートウェイのフローで対応することになります（実装方法はドキュメントを参考にしてください。余裕があれば追記するかも）。

## まとめ
複雑なフローもあり、もともとスマートスピーカー向けのツールというわけではないため、誰でも簡単！とはいいきれませんが、ノンコーディングでスキルを作ることができました。
Azure Logic Appsは他サービスとの連携に長けているので、プログラミングなしに魅力的なスキルを作成できる可能性を秘めています。

ぜひ、プログラミングを普段行わない方にもスキル開発に挑戦してほしいなと思います。