Microsoft Azure Functions ではじめる Alexaスキル開発チュートリアル

# 1. はじめに

---

## 参考文献
今回のMicrosoft Azure Functions ではじめる Alexaスキル開発チュートリアルは、以下のサイトを参考に、Microsoft Azure Functions環境（Node.js JavaScript）で、Alexa SDK V2（ask-sdk）を用いたAlexaスキル開発ができるよう、2019年1月時点の開発環境にアレンジし、まとめたものとなります。

- [AlexaアプリをAWS lambdaではなくAzure functionでつくった話](https://qiita.com/kino3/items/ede16f3468ce4101b40f)
- [RamjiP/alexa-skill-sdk-for-azure-function](https://github.com/RamjiP/alexa-skill-sdk-for-azure-function1)
- [Alexaスキルを Microsoft Azure Functions（Node.js）環境で開発する方法](https://qiita.com/zono_0/items/461b63aad3f9dd5c1a83)
 
---

## このスライドを見てできること
- Microsoft Azure Functions（Node.js JavaScript）を用いた、Alexaスキル開発の方法が理解できるようになる。

---

## 今回作成するAlexaスキル

- スキル名：宇宙の豆知識

※スキルテンプレートの[FACTスキル](https://github.com/alexa/skill-sample-nodejs-fact)をベースに、Microsoft Azure Functions環境でNode.js実行できるように変更を加えてあります。

```text:トークシナリオ
ユーザー：「アレクサ、＜宇宙の豆知識＞を開いて」
アレクサ：「知ってましたか、XXXXXXXX。」

※従量課金プランでAzure Functionsを利用している場合は、初回実行時に以下の応答となる場合があります。（おそらく、支払いプランを変更すると改善できると思います。）
アレクサ：「スキルからの応答に、予想以上の時間がかかっています。」

```

---

## 前提条件
- 今回の記事は、Windows10 ＋ Visual Studio Code ＋ コマンドプロンプト（cmd.exe）を想定した開発環境となります。
- Visual Studio Codeが利用できる開発環境であれば、環境依存しない想定です。

---

# 2. 事前準備・開発環境

---
## 事前準備（アカウント）
- [Amazon.co.jpアカウントの作成](https://dev.classmethod.jp/voice-assistant/how-to-safety-create-alexa-developers-account/)
- [Amazon Developerアカウントの登録](https://dev.classmethod.jp/voice-assistant/how-to-safety-create-alexa-developers-account/)
- [Microsoft Azureアカウントの作成](https://azure.microsoft.com/ja-jp/free/)

---

## 事前準備（ソフトウェア）
- [Visual Studio Codeのインストール](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-create-first-function-vs-code#prerequisites)
- [Visual Studio Code 用 Azure Functions 拡張機能のインストール](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-create-first-function-vs-code#install-the-azure-function-extension)
- [.NET Core 2.1のインストール（.NET Core SDK）](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-run-local#install-the-azure-functions-core-tools)
- [Node.jsのインストール](https://nodejs.org/ja/download/)

- [azure-functions-core-toolsのインストール](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-run-local#install-the-azure-functions-core-tools)

```shell:コマンドライン
> npm install -g azure-functions-core-tools

```

---

## 必要なソフトウェア

- ブラウザ：Google Chrome（推奨）
- エディタ：Visual Studio Code（推奨）

---

## 必要な開発環境

- マイク＆スピーカが利用できるパソコン
- インターネット（Wi-Fi）

---

# 3. AzureFunctionsプロジェクトの作成

---

## プロジェクトフォルダの新規作成
- 任意のフォルダ内に、プロジェクトフォルダを新規作成します。
- 今回は、C:\Work\Azure配下に、functions-project-alexa-fact-skillフォルダを新規作成しました。

![プロジェクトフォルダの作成.png](https://qiita-image-store.s3.amazonaws.com/0/240522/ebcc05ba-3e66-7488-38c2-b288cc8f6fff.png)

---

## AzureFunctions領域の表示

1. Visula Studio Code を起動する。
2. アクティビティバーのAzureアイコンを、クリックする。

- Azureアイコンが表示されていない場合は、[Visual Studio Code 用 Azure Functions 拡張機能](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-create-first-function-vs-code#install-the-azure-function-extension)をインストールし、Visual Studio Code を再起動する必要があります。

![AzureFunctions領域の表示.png](https://qiita-image-store.s3.amazonaws.com/0/240522/73bca5e1-ef26-b620-1e42-53a55465b201.png)

---

## AzureFunctionsプロジェクトの作成

1. 「新しいプロジェクトの作成]アイコンを、クリックする。
2. 先ほど新規作成した「プロジェクトフォルダ」を選択し、「Select（選択）」ボタンをクリックする。

![プロジェクト作成.png](https://qiita-image-store.s3.amazonaws.com/0/240522/b1319912-2f2c-25b9-fa81-2927b35d0f1d.png)

---

## プロジェクト言語の選択

1. プロジェクト言語の選択から、「JavaScript」をクリックする。

- このタイミングで、プロジェクトフォルダ内にAzureFunctionsで必要なファイルが自動作成されます。

![プロジェクト言語選択.png](https://qiita-image-store.s3.amazonaws.com/0/240522/7fedc6af-e197-37d4-6db6-475f76cb584c.png)

---

## ワークスペースに追加

1. 「Add to workspace（ワークスペースに追加）」 をクリックする。

![ワークスペースへの追加.png](https://qiita-image-store.s3.amazonaws.com/0/240522/372ae7e4-42c4-aae2-f17e-63fc93c5b1ab.png)

---

# 4. HTTPトリガー関数の作成

---

## HTTPトリガー関数作成の対象フォルダ選択

1. 「Create Function（関数の作成）]アイコンを、クリックする。
2. 先ほど新規作成したプロジェクトフォルダ（任意名：functions-project-alexa-fact-skill）をクリックする。

- うまくこの画面がでずに、次のページの関数作成選択が表示されることがあるかもしれません、その時は、HTTPトリガー関数作成をもう一度試すとよいと思います。

![関数フォルダ選択.png](https://qiita-image-store.s3.amazonaws.com/0/240522/b906ae52-eea4-81e7-6d03-d02f9a18f33c.png)

---

## HTTPトリガー関数の作成

1. 「HTTP trigger（HTTPトリガー関数テンプレート）]を、クリックする。

![トリガー関数作成2.png](https://qiita-image-store.s3.amazonaws.com/0/240522/97b51405-b687-632a-4d6b-976c57c313c9.png)

---

## HTTPトリガー関数名の決定

1. HTTPトリガー名（任意名：HttpTrigger）を入力し、エンターキーを入力する。

![関数名の決定.png](https://qiita-image-store.s3.amazonaws.com/0/240522/0a729922-35cc-3e9a-457d-8edd589dbe77.png)

---

## HTTPトリガー関数の認証選択

1. 「匿名認証（Anonymous）」を選択し、クリックする。

- このタイミングで、プロジェクトフォルダ内に「HttpTrigger」フォルダが作成され、HttpTriggerフォルダ内に、「Node.jsプログラム（index.js）」が作成されます。
- Alexaプログラム本体は、作成されたindex.jsファイルとなります。

![認証選択.png](https://qiita-image-store.s3.amazonaws.com/0/240522/6e52d3c3-4c2e-0f41-d8c9-50d73219f0e7.png)

---

## HTTPトリガー関数作成直後のindex.js

- 初期状態として、HTTPトリガー関数（index.js）の中身が表示されると思います。

1. この状態で、「F5キー」押下またはメニューから「デバッグ→デバッグの開始」を選択すると、HTTPトリガー関数（URLアクセス可能なWebAPI）が実行されます。
2. 実行すると、画面下部に、「ターミナル」ウィンドウが表示されますので、ターミナル内に表示されたURLをクリックしてみてください。WebAPIとして機能し、ブラウザ上に文字列が表示されると思います。
3. 終了する場合は、Visual Studio Codeの画面上部の「切断」アイコンをクリックしてください。

![関数初期状態.png](https://qiita-image-store.s3.amazonaws.com/0/240522/580c5e5b-db66-338f-579e-27cb410b41ff.png)
ログラム本体は、作成されたindex.jsファイルとなります。

```text:ターミナルに出力されるURL
Application started. Press Ctrl+C to shut down.

Http Functions:

        HttpTrigger: [GET,POST] http://localhost:7071/api/HttpTrigger

```

```text:ブラウザに表示される文字列
Please pass a name on the query string or in the request body

```

---

# 5. Alexaプログラムの作成

---

## index.jsの修正

1. 「エクスプローラ」アイコンをクリックし、プロジェクト内のファイルを表示する。
2. 「index.js」ファイルをクリックし、表示する。
3. Alexaプログラム（index.js）の内容をコピーし、index.jsファイルへペーストする（プログラムの内容をすべて書き換える）。

- 今回、Microsoft Azure Functionsの関数引数パラメータ（res）と、AWS Lambdaの関数引数パラメータ（event）との差分を、イベント関数（event）を用意し用いることで解消しています。

![indexの修正.png](https://qiita-image-store.s3.amazonaws.com/0/240522/de219660-f3ce-9d71-29c7-b5a720ba0651.png)

---

## Alexaプログラム（index.js）の内容

```javascript:index.js
/* eslint-disable  func-names */
/* eslint-disable  no-console */
'use strict';


/**
 * モジュール参照
 * 
 */ 
const Alexa = require('ask-sdk-core');


/**
 * 定数
 * 
 */ 
const SKILL_NAME = "宇宙の豆知識";
const GET_FACT_MESSAGE = "知ってましたか？";
const HELP_MESSAGE = "豆知識を聞きたい時は「豆知識」と、終わりたい時は「おしまい」と言ってください。どうしますか？";
const HELP_REPROMPT = "どうしますか？";
const ERROR_MESSAGE = '申し訳ありませんが、エラーが発生しました';
const STOP_MESSAGE = "さようなら";

const data = [
    "水星の一年はたった88日です。",
    "金星は水星と比べて太陽より遠くにありますが、気温は水星よりも高いです。",
    "金星は反時計回りに自転しています。過去に起こった隕石の衝突が原因と言われています。",
    "火星上から見ると、太陽の大きさは地球から見た場合の約半分に見えます。",
    "木星の<sub alias='いちにち'>1日</sub>は全惑星の中で一番短いです。",
    "天の川銀河は約50億年後にアンドロメダ星雲と衝突します。",
    "太陽の質量は全太陽系の質量の99.86%を占めます。",
    "太陽はほぼ完璧な円形です。",
    "皆既日食は一年から二年に一度しか発生しない珍しい出来事です。",
    "土星は自身が太陽から受けるエネルギーの2.5倍のエネルギーを宇宙に放出しています。",
    "太陽の内部温度は摂氏1500万度にも達します。",
    "月は毎年3.8cm地球から離れていっています。"
];


/**
 * ローンチリクエストハンドラ
 * 
 * ユーザ発話「アレクサ、＜スキル名＞を開いて」
 * まはた ユーザ発話「何か教えて。」
 */ 
const GetNewFactHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        return request.type === 'LaunchRequest'
            || (request.type === 'IntentRequest'
                 && request.intent.name === 'GetNewFactIntent');
    },
    handle(handlerInput) {
        var factArr = data;
        var factIndex = Math.floor(Math.random() * factArr.length);
        var randomFact = factArr[factIndex];

        // スピークアウトプットの設定（Alexa応答設定）
        var speakOutput = GET_FACT_MESSAGE + randomFact;

        // withSimpleCard（カード付きAlexa応答＆終了）
        return handlerInput.responseBuilder
            .speak(speakOutput)
            .withSimpleCard(SKILL_NAME, randomFact)
            .withShouldEndSession(true)
            .getResponse();
    },
};


/**
 * ヘルプハンドラ
 * 
 * ユーザ発話「ヘルプ。」
 */ 
const HelpHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        return request.type === 'IntentRequest'
            && request.intent.name === 'AMAZON.HelpIntent';
    },
    handle(handlerInput) {
        // スピークアウトプットの設定（Alexa応答設定）
        var speakOutput = HELP_MESSAGE;

        // リプロンプトの設定（聞き直し設定）
        var reprompt = HELP_REPROMPT;

        // ask（Alexa応答＋たずねる）
        return handlerInput.responseBuilder
            .speak(speakOutput)
            .reprompt(reprompt)
            .getResponse();
    },
};



/**
 * キャンセル＆ストップハンドラ
 * 
 * ユーザ発話「キャンセル。」
 * ユーザ発話「止めて。」
 */ 
const ExitHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        return request.type === 'IntentRequest'
            && (request.intent.name === 'AMAZON.CancelIntent'
                || request.intent.name === 'AMAZON.StopIntent');
    },
    handle(handlerInput) {
        // スピークアウトプットの設定（Alexa応答設定）
        var speakOutput = STOP_MESSAGE;

        // tell（Alexa応答＆終了）
        return handlerInput.responseBuilder
            .speak(speakOutput)
            .withShouldEndSession(true)
            .getResponse();
    },
};


/**
 * 予期せぬ終了
 * 
 * ユーザ発話「終了。」
 */ 
const SessionEndedRequestHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        return request.type === 'SessionEndedRequest';
    },
    handle(handlerInput) {
        console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`);
        return handlerInput.responseBuilder
            .withShouldEndSession(true)
            .getResponse();
    },
};


/**
 * エラーハンドラ
 * 
 */ 
const ErrorHandler = {
    canHandle() {
        return true;
    },
    handle(handlerInput, error) {
        console.log(`Error handled: ${error.message}`);
        console.log(`Error stack: ${error.stack}`);

        // スピークアウトプットの設定（Alexa応答設定）
        var speakOutput = ERROR_MESSAGE;

        return handlerInput.responseBuilder
            .speak(speakOutput)
            .reprompt(speakOutput)
            .getResponse();
    },
};


// ーーーー 追記ここから AzureFunctions対応 ーーーー
/**
 * イベント関数
 * 
 * Azureのreqパラメータを、AWS Lambdaのeventパラメータに変換
 */ 
let event = function (req) {
    let EventEmitter = require('events');
    let ee = new EventEmitter();
    for (let prop in req.body) {
        if(prop){
            ee[prop] = req.body[prop];
        }
    }
    return ee;
};


/**
 * プログラムの開始位置
 * 
 */ 
let skill;
module.exports = async function (context, req) {
    if(!skill){
        // ハンドラ設定
        skill = Alexa.SkillBuilders.custom()
            .addRequestHandlers(
                GetNewFactHandler,
                HelpHandler,
                ExitHandler,
                // FallbackHandler,
                SessionEndedRequestHandler,
            )
            .addErrorHandlers(ErrorHandler)
            .create();
    }

    // 処理実行＆Alexa応答
    return skill.invoke(event(req));
};
// ーーーー 追記ここまで AzureFunctions対応 ーーーー

```

---

## function.jsonの修正

1. 「function.json」ファイルをクリックし、表示する。
2. function.jsonの内容をコピーし、function.jsonファイルへペーストする（ファイルの内容をすべて書き換える）。

- "res"を"$return"に変更することで、HTTPトリガー関数の実行結果レスポンス内容を、index.jsプログラムのreturnの値（Response JSON）に変更しています。
- もし、Alexaプログラムを実行しても、レスポンス結果が空JOSN{}となる場合は、function.jsonが正しく修正されていない可能性があります。

```text:修正箇所
//修正前
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    }

// 修正後
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }

```

![functionsの修正.png](https://qiita-image-store.s3.amazonaws.com/0/240522/60fd767b-4a4c-e6dc-bac8-32fcbb1f22f9.png)

---

## function.jsonの内容

```JSON:function.json
{
  "disabled": false,
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
  ]
}

```

---

## package.jsonファイルの作成

1. コマンドプロンプト（cmd.exe）を開く。
2. cdコマンドで、プロジェクトフォルダ内に移動する。
3. npm initコマンドで、package.jsonファイルを新規生成する。

```text:コマンドプロンプト
//プロジェクトフォルダ内に移動
> cd C:\Work\Azure\functions-project-alexa-fact-skill

//package.jsonファイルの新規生成
> npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (functions-project-alexa-fact-skill)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to C:\Work\Azure\functions-project-alexa-fact-skill\package.json:

{
  "name": "functions-project-alexa-fact-skill",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Is this OK? (yes) yes

```

---

## 必要Nodeモジュールのインストール

1. コマンドプロンプト（cmd.exe）を開く。
2. cdコマンドで、プロジェクトフォルダ内に移動する。（package.jsonファイルが同一フォルダ内に存在していること。）
3. npm installコマンドで、必要Nodeモジュール（ask-sdk-model、ask-sdk-core）をインストールする。

```text:コマンドプロンプト

//ask-sdk-modelモジュールのインストール
> npm install --save ask-sdk-model
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN functions-project-alexa-fact-skill@1.0.0 No description
npm WARN functions-project-alexa-fact-skill@1.0.0 No repository field.

+ ask-sdk-model@1.11.2
added 1 package from 3 contributors and audited 1 package in 1.783s
found 0 vulnerabilities


//ask-sdk-coreモジュールのインストール
> npm install --save ask-sdk-core
npm WARN functions-project-alexa-fact-skill@1.0.0 No description
npm WARN functions-project-alexa-fact-skill@1.0.0 No repository field.

+ ask-sdk-core@2.3.0
added 2 packages from 3 contributors and audited 3 packages in 1.943s
found 0 vulnerabilities

```

---

## package.jsonファイルの内容

```JSON:package.json
{
  "name": "functions-project-alexa-fact-skill",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "ask-sdk-core": "^2.3.0",
    "ask-sdk-model": "^1.11.2"
  }
}

```

---

# 6. ローカル環境でのテスト実行

---

## Visual Studio Codeを用いたHTTPトリガーの実行

1. 「F5キー」押下またはメニューから「デバッグ→デバッグの開始」を選択し、HTTPトリガー関数（URLアクセス可能なWebAPI）を実行する。
2. 「ターミナル」に表示される「URL」を、コピーする。

![ローカルテスト.png](https://qiita-image-store.s3.amazonaws.com/0/240522/965e134b-0508-6ea3-b517-f843fe2a17b4.png)

---

## Requestの送信（ヘッダー部設定）

1. ローカル環境のURLに対しJSON Request をPOSTできるツールを用意する。（今回は、ChromeブラウザにChrome拡張機能の「[Advanced REST client](https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo?hl=ja)」をインストールし利用する。
2. リクエストのMethodに「POST」を選択する。
3. リクエストのURLに「先ほどコピーしたHTTPトリガーのURL」を、ペーストする。
4. リクエストのHeadersに「Content-Type」、「application/json」を設定する。

![ヘッダー部.png](https://qiita-image-store.s3.amazonaws.com/0/240522/45716f4b-15bd-ef4e-a9a4-2f072cd8020f.png)

---

## Requestの送信（ボディー部設定）

1. Request の Body部に、「application/json」、「Rqw input」を選択する。
2. Request の Body部に、Alexaスキルに送信したいリクエスト内容をセットする。
3. 「SEND」ボタンをクリックする。

![ボディー部2.png](https://qiita-image-store.s3.amazonaws.com/0/240522/062d950e-4eab-cccd-f714-c9b5a309c011.png)

---

## テスト用Request JSON（LaunchRequest）

```JSON
{
  "version": "1.0",
  "session": {
    "new": true,
    "sessionId": "session0001",
    "application": {
      "applicationId": "amzn1.echo-sdk-ams.app.0001"
    },
    "attributes": {},
    "user": {
      "userId": null
    }
  },
  "request": {
    "type": "LaunchRequest",
    "requestId": "request0001",
    "timestamp": "2018-08-11T13:04:56+0900"
  }
}

```

---

## Request送信結果の確認

1. 画面下部の実行結果を、確認する。
2. 実行結果が「200 OK」となっており、Response JSON内容が表示されていれば成功です。

![ローカルテスト結果.png](https://qiita-image-store.s3.amazonaws.com/0/240522/5ff35e64-a223-72ac-d865-3ff20fa74817.png)

---

# 7. Microsoft Azure Function App の作成

---

## Function Appの作成

1. [Azure](https://azure.microsoft.com/ja-jp/account/)にログインし、ポータルに移動する。
2. 「リソースの作成」を、クリックする。
3. 「Compute」を、クリックする。

![リソースの作成2.png](https://qiita-image-store.s3.amazonaws.com/0/240522/3dd00558-e54a-1e80-de75-e7aec42c81e2.png)

---

## Function Appの作成

1. 「Function App」を、クリックする。

![ファンクションズの選択.png](https://qiita-image-store.s3.amazonaws.com/0/240522/fc36b8ce-d1cb-7d8d-9f8b-cb4d57040bb0.png)

---

## Function Appの作成

1. アプリ名を入力する。（任意ですがURLの一部となるため、ユニークである必要があります。）
2. サブスクリプションを選択する。
3. リソースグループを選択する。
4. ホスティングプランを選択する。
5. 場所に、「東日本」を選択する。
6. ランタイムスタックに、「JavaScript」を選択する。
7. ストレージを選択する。
8. Application Insightsを選択する。（有効にするとログがとれるのだと思う。たぶん）
9. 「作成」ボタンをクリックする。

- サブスクリプションおよびホスティングプランは、各自の環境に合わせてください。
- ホスティングプランに「従量課金プラン」を選択した場合、HTTPトリガー関数の初回起動に時間がかかる場合があるかもしれません。

![作成設定.png](https://qiita-image-store.s3.amazonaws.com/0/240522/af5ba388-09d6-33d4-f9a7-daf55fc20e2e.png)

---
## Function App を開く

1. Function Appの作成まで、3分程度待つ。
2. 作成が完了するとポップアップが表示されるので、「リソースに移動」または「Function App」をクリックする。

![リソースに移動.png](https://qiita-image-store.s3.amazonaws.com/0/240522/107ef838-bab3-f8c5-7b82-cae11753bcc9.png)

---

## Function App を開く

1. Azure上に、Function Appが作成されていることを確認する。

- この時点ではまだ、関数が作成されていない状態（デプロイされていない状態）となります。

![ファンクションAPP.png](https://qiita-image-store.s3.amazonaws.com/0/240522/1862c8d6-6513-cc04-c7a1-b9c610abe0e1.png)

---

# 8. HTTPトリガーのデプロイ

---

## Visual Studio Code からHTTPトリガーをデプロイ

1. [Azureにサインイン](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-create-first-function-vs-code#sign-in-to-azure)する。
2. 「Azure」アイコンを、クリックする。
3. 「Deploy to Function App」アイコンを、クリックする。
4. 先ほど作成したAzureの「Function App 名」を、選択する。

![デプロイ2.png](https://qiita-image-store.s3.amazonaws.com/0/240522/6d556dd1-1191-ca56-3592-d7c77e3f98e0.png)

---

## Visual Studio Code からHTTPトリガーをデプロイ

1. 「Deploy（デプロイ）」ボタンをクリックし、ローカル環境で開発したプロジェクトを、クラウド環境のAzureへ、デプロイする。

- 初回のデプロイには、5分から10分程度時間がかかるかと思います。

![デプロイOK.png](https://qiita-image-store.s3.amazonaws.com/0/240522/54923777-ed72-9593-6289-e144aae2dafa.png)

---

# 9. Azure環境でのテスト実行

---

## HttpTriggerのテスト実行

1. デプロイが完了しており、「HttpTrigger」が反映されていることを確認する。
2. 「テスト」を、クリックする。

![Azureテスト.png](https://qiita-image-store.s3.amazonaws.com/0/240522/a3a0fc4c-9f04-e812-a55e-8a0f0de8661c.png)

---

## HttpTriggerのテスト実行

1. HTTPメソッドに、「POST」を選択する。
2. 要求本文に、「テスト用Request JSON（LaunchRequest）」をペーストする。
3. 「実行」ボタンを、クリックする。
4. 実行結果として、「出力」が画面右下に表示されればOKです。

![クラウドテスト.png](https://qiita-image-store.s3.amazonaws.com/0/240522/d5a92ec3-e59e-6995-10ee-c9f1313ed304.png)

---

# 10. 関数URLの取得

---

## 関数URLの取得

1. 「関数のURLの取得」から、URLをコピーしておく。

![関数URLの取得.png](https://qiita-image-store.s3.amazonaws.com/0/240522/88c6361a-41a1-6d3c-a441-ca62230e49cd.png)

---

# 11. Alexaスキルの作成

---

## Amazon Developer Consoleにアクセス

1. [Amazon Developer Console](https://developer.amazon.com/ja)を、開く。
2. 「管理者コンソール」を、クリックする。

![デベロッパーコンソールログイン1.png](https://qiita-image-store.s3.amazonaws.com/0/240522/001cc8a5-4913-f9c0-2782-5935f5a4cfe3.png)

---

## Amazon Developer Consoleにログイン

1. Alexaスキルを作成したいAmazon.co.jpアカウントで、ログインする。

- Alexaスキルは、アマゾンアカウントに紐づき、Alexaスキルが作成されます。

![デベロッパーコンソールログイン2.png](https://qiita-image-store.s3.amazonaws.com/0/240522/d573cb36-bb9a-a6e6-b888-f0ef57bdda24.png)

---

## Alexa Skills Kitの選択

1. 「Alexa」を、クリックする。
2. 「Alexa Skills Kit」を、クリックする。

![ASK.png](https://qiita-image-store.s3.amazonaws.com/0/240522/37789bee-eb66-7aaa-2202-d4b3a4ad505a.png)

---

## スキルの作成

1. 「スキルの作成」を、クリックする。

![スキルの作成.png](https://qiita-image-store.s3.amazonaws.com/0/240522/069b03cd-9820-364f-7ff4-adfc179499e9.png)

---

## スキルの作成

1. スキル名（任意名：宇宙の豆知識）を、入力する。
2. デフォルトの言語に、「日本語（日本）」を選択する。
3. 「カスタムスキル」を、選択する。
4. 「スキルを作成」ボタンを、クリックする。

![スキル名の設定.png](https://qiita-image-store.s3.amazonaws.com/0/240522/7f1ceef0-0a11-7c75-7a80-a5811b47232e.png)

---

## JSONエディターによるスキルの設定

1. 「JSONエディター」を、クリックする。

![JSONエディター.png](https://qiita-image-store.s3.amazonaws.com/0/240522/5124b8a5-94c0-a507-93ee-3633ddb2a5ff.png)

---

## JSONエディターによるスキルの設定

1. 「JSONエディター」内に、スキル設定JSONの内容を張り付ける。
2. 「モデルを保存」ボタンを、クリックする。

![モデルの保存.png](https://qiita-image-store.s3.amazonaws.com/0/240522/45d2df95-1008-f7a8-c240-8537d26f30cf.png)

---

## スキル設定JSON

```JSON:ja-JP.json
{
    "interactionModel": {
        "languageModel": {
            "invocationName": "宇宙の豆知識",
            "intents": [
                {
                    "name": "AMAZON.CancelIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.HelpIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.StopIntent",
                    "samples": []
                },
                {
                    "name": "GetNewFactIntent",
                    "slots": [],
                    "samples": [
                        "豆知識",
                        "教えて",
                        "話して",
                        "聞かせて",
                        "宇宙の豆知識",
                        "豆知識を教えて",
                        "宇宙の豆知識を教えて",
                        "豆知識を聞かせて",
                        "宇宙の豆知識を聞かせて",
                        "トリビア",
                        "宇宙のトリビア",
                        "トリビアを教えて",
                        "宇宙のトリビアを教えて",
                        "何か教えて",
                        "宇宙について教えて",
                        "なんか教えて",
                        "なんか言って"
                    ]
                },
                {
                    "name": "AMAZON.NavigateHomeIntent",
                    "samples": []
                }
            ],
            "types": []
        }
    }
}

```

---

## モデルをビルド

1. 「モデルをビルド」を、クリックする。

- Alexaスキルの構築（学習）が始まり、3分程度待ちます。

![モデルをビルド.png](https://qiita-image-store.s3.amazonaws.com/0/240522/696fa490-1644-5e8f-a1e9-b22df1c9fe76.png)

---

## エンドポイントの設定

1. 「エンドポイント」を、クリックする。
2. 「HTTPS」を、クリックする。
3. 「デフォルトの地域のURL」に、AzureのHttpTrrigerから取得した「関数のURL」をペーストする。
4. 「開発用のエンドポイントは、証明機関が発行したワイルドカード証明書をもつドメインのサブドメインです」を、選択する。
5. 「エンドポイントを保存」を、クリックする。

![エンドポイントの設定.png](https://qiita-image-store.s3.amazonaws.com/0/240522/3237c4d6-db40-5399-94e7-f802d01b3945.png)

---

## チェックリストの確認

1. 「スキルビルダーのチェックリスト」の「1から4」すべてが、オールグリーン（登録済み）であることを確認する。

- 登録漏れがある場合は、手順に漏れ（保存忘れ、ビルド忘れ）がありますので、確認してください。

![チェックリスト.png](https://qiita-image-store.s3.amazonaws.com/0/240522/72e1556c-1393-6ac5-8906-ad693d61b86b.png)

---

# 11. Alexaスキルの作成

---

## ブラウザテスト

1. 「テスト」を、クリックする。
2. 「開発中」を、選択する。
3. マイクアイコンを押したまま「＜（任意）スキル呼び出し名＞を開いて」と発話するか、もしくはキーボードを利用し「＜（任意）宇宙の豆知識＞を開いて」と入力後エンターキーを押下する。

![テスト.png](https://qiita-image-store.s3.amazonaws.com/0/240522/7c0da5c2-6a81-ad0d-6773-ea5547ed4d97.png)

---

## ブラウザテスト

1. アレクサ応答がスピーカから出力され、ブラウザ画面にも実行結果が表示されることを確認する。

- 開発アカウントと同じAmazon.co.jpアカウントに紐づくEcho実機デバイスからも、同様にテストすることができます。

![テスト結果.png](https://qiita-image-store.s3.amazonaws.com/0/240522/b60cb144-802f-0ee5-5e03-41029281ef12.png)

---

# 12. おわりに

---

## おわりに
みなさん、Microsoft Azure Functions ではじめる Alexaスキル開発チュートリアルはいかがでしたか？みなさんの環境でも、うまく実行できていれば幸いです。うまくいけば、4時間もあれば完成するかと思います。
Microsoft Azure Functions環境でのAlexaスキル開発がおこなえたことで、Microsoft Azure開発者にも、Alexaスキルを手軽に開発するきっかけになることを願っております。

2019/01/20 TAKAHIRO NISHIZONO

---

# 13. 補足

---

## Alexaスキル開発の基礎を学ぶには
- Alexaスキル開発の基礎を学ぶための、おすすめサイトをご紹介します。

- [Alexaスキル開発トレーニング](https://developer.amazon.com/ja/alexa-skills-kit/training/building-a-skill)
- [初めてのスキル開発](https://ask-sdk-for-nodejs.readthedocs.io/ja/latest/Developing-Your-First-Skill.html)
- [GitHub - alexa/alexa-skills-kit-sdk-for-nodejs](https://github.com/alexa/alexa-skills-kit-sdk-for-nodejs/blob/2.0.x/README.ja.md)

---

## 初回のAzure Functionsの起動が遅い？
- AWS Lambdaとくらべ、Azure Functionsで従量課金プランを選択した場合、初回実行にかかる時間が長いように感じます。
- 個人でAlexaスキルの申請（公開）を考えている場合、Azure Functionsの従量課金プランでは、Alexa仕様の「8秒以内にレスポンスを正常に返す」ことができず、リジェクト（申請否認）される可能性が考えられます。
- Azure Functionsで初回実行を早めるためには、「[App Service プラン](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-scale#app-service-plan)」の導入等の検討が必要かもしれません。

---

## Azure Functions のコールドスタンバイ対策
参考文献
- [スマートスピーカースキルのバックエンドをAzure Functionsで作ろう！～コールドスタート問題と向き合う～](https://qiita.com/himarin269/items/87b57cac400bfc2ff8ea)
- [スマートスピーカーのバックエンドとしての Azure Functions のコールドスタート対策](https://blog.okazuki.jp/entry/2019/03/10/111526)

---

## 従量課金プランの問題点
参考文献
- [Google Assistant アプリの開発のバックエンドに Azure Functions を使おう](https://blog.okazuki.jp/entry/2018/09/03/182959)

---

## 認証方式にFunctionを選ぶ場合
参考文献
- [認証キー](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-http-webhook#authorization-keys)
- [トリガー - 構成](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-http-webhook#trigger---configuration)
- [Azure Functions での App Service 認証/承認](https://blogs.msdn.microsoft.com/jpcie/?p=2445)

---

## Googleアシスタント音声アプリを開発するには？
参考文献
- [Azure Functions Node.jsでActions on Google Client Libraryを使う方法](https://www.eisbahn.jp/yoichiro/2019/01/aog_client_library_azure_function_nodejs.html)
- [Azure App ServiceでActions on Google Client Libraryを使う方法](https://www.eisbahn.jp/yoichiro/2019/01/aog_client_library_azure_app_service.html)
- [Actions on Google Client Library APIリファレンス](https://actions-on-google.github.io/actions-on-google-nodejs/index.html)

---

## マンガでわかるLINE Clova開発 第4話 Azure Functionsでバックエンドを作ろう
参考文献
- [マンガでわかるLINE Clova開発 第4話 Azure Functionsでバックエンドを作ろう](https://techplay.jp/column/455)

---

# end