SMSを送信するAlexaスキルを作る（ASK SDK v2 for Node.js対応）

# はじめに
Alexaは、『声』という直感的なインターフェイスを使って様々なサービスを利用することができます。
利用するサービスは自分で『スキル』を構築することにより拡張でき、オリジナルのサービスをAlexaを通して利用することができます。
ここでは、Twilioを使ってSMSを送信するAlexaスキルの作り方を紹介します。

## 前提
この記事では以下を前提としています。

- Alexa 開発者アカウントを持っている（https://developer.amazon.com/ja/alexa からサインインできる）
- AWSアカウントを持っている
- Lambda（Node.js v8）の開発環境を持っている（Lambda 関数デプロイパッケージを作成し、パッケージをアップロードできる）
- Twilioアカウントを持っている
 - もしTwilioアカウントをもっていない場合は、[https://jp.twilio.com/try-twilio/kddi-web](https://jp.twilio.com/try-twilio/kddi-web)からサインアップしてください。

## 目次
1. SMS送信用の電話番号を取る
2. Alexaスキルを作る
3. スキルの呼び出し名、インテントを設定する
4. LambdaでSMS送信処理部分をつくる
5. AlexaスキルとLambdaをつなぎこむ
6. テスト

### 1. SMS送信用の電話番号を取る
Twilioコンソールに[こちら](https://jp.twilio.com/console)からログインします。

左のメニューから『Phone Numbers』を選択し、『番号の管理』から『番号を購入』（+ボタン）を選択します。

<img src="https://vigorous-crush-3355.twil.io/assets/phone_number_menu.png">

Twilioでは、SMSの送信は日本の番号からはできません。アメリカ番号（+1で始まる番号）を購入する必要があります。そのため、『COUNTRY』では『United States』を選択し、『機能』で『SMS』にチェックを入れて検索してください。

<img src="https://vigorous-crush-3355.twil.io/assets/phone_number_search.png">


検索結果に表示された番号の中から好きなものを選び、『購入』ボタンをクリックして購入してください。

<img src="https://vigorous-crush-3355.twil.io/assets/phone_number_purchase.png">

### 2. Alexaスキルを作る
Alexaデベロッパーコンソールに[こちら](https://developer.amazon.com/ja/alexa)からサインインします。
『スキルを作成』ボタンをクリックし、スキル作成画面に遷移します。

<img width="1336" alt="skill_create.png" src="https://qiita-image-store.s3.amazonaws.com/0/268190/01e82ef3-b26f-e3c0-edfa-61cf4acf61ce.png">


スキル名、デフォルトの言語（日本語）、スキルに追加するモデル（カスタム）を選択し、『スキルを作成』ボタンをクリックすると、新しいスキルが作成できます。

<img width="1342" alt="skill_create_finish.png" src="https://qiita-image-store.s3.amazonaws.com/0/268190/d22e1433-68ac-b5a9-e914-9cbd3644bbd1.png">


### 3. スキルの呼び出し名、インテントを設定する
スキルの管理画面で、左のメニューから『呼び出し名』を選択します。

<img width="1340" alt="skill_call_name.png" src="https://qiita-image-store.s3.amazonaws.com/0/268190/93a4fabf-17d1-df83-2551-454e7f6ec558.png">

呼び出し名は、『アレクサ、〇〇で■■して』とAlexaに話しかけたときの『〇〇』にあたる部分です。
好きな名前を入力してください（今回は『おくるくん』とします）。入力したら、『モデルを保存』ボタンで入力値を保存します。

<img src="https://vigorous-crush-3355.twil.io/assets/skill_call_name_finish.png">


次に、左メニューのインテントで『追加』をクリックします。

<img src="https://vigorous-crush-3355.twil.io/assets/skill_intent_add.png">

インテントは、『アレクサ、〇〇で■■して』とユーザーからリクエストを受けたあと、そのリクエストに対応して行われる処理のことを指します（詳細については、[こちら](https://developer.amazon.com/ja/docs/custom-skills/understanding-how-users-invoke-custom-skills.html)をご参照ください）。

『追加』をクリックすると、インテントの名前入力欄が表示されます。インテントの名前はこの後作成するTwilio Function上コードでも使用しますので、アルファベットの大文字、小文字、アンダースコアのみを使い、わかりやすい名前をつけてください（今回は『SendSms』とします）。
名前の入力後、『カスタムインテントを作成』をクリックします。

<img src="https://vigorous-crush-3355.twil.io/assets/skill_intent_create.png">

カスタムインテントの作成後、そのインテントの詳細設定画面に遷移します。ここでは『サンプル発話』を入力します。
サンプル発話は、『アレクサ、〇〇で■■して』の『■■して』の部分にあたります。サンプル発話に登録した内容がAlexaにリクエストされると、サンプル発話が登録されているインテントが実行されます。
ここではサンプル発話を一つ入力します（実際にAlexaスキルを作成する場合は、表記ゆれを考慮し複数のパターンの発話を登録する必要があります）。
サンプル発話を入力したら、エンターキーで登録ができます。登録後、『モデルを保存』ボタンで入力値を保存します。

<img src="https://vigorous-crush-3355.twil.io/assets/skill_intent_create_finish.png">


### 4. LambdaでSMS送信処理部分をつくる
次に、AWSコンソールにサインインし、『Lambda』コンソールに移動します。
Lambdaコンソールで『関数の作成』をクリックします。

<img src="https://vigorous-crush-3355.twil.io/assets/lambda_create.png">

関数の作成では『一から作成』、ランタイムはNode.js 8.10を選択します。

『基本的な情報』では『名前』に好きな関数名、『ロール』は『テンプレートから新しいロールを作成』、『ロール名』にはわかりやすいロール名を入力し、ロールのテンプレートは『シンプルなマイクロサービスのアクセス権限』を選択します。入力が終わったら『関数の作成』をクリックします。


関数が作成されたら、以下のコードでデプロイパッケージを作成し、コンソールまたは CLI を使用してパッケージをアップロードしてください。

- index.js

```javascript
'use strict';

const Alexa = require('ask-sdk');
const Twilio = require('twilio');

const TWILIO_ACCOUNT_SID = process.env.TWILIO_ACCOUNT_SID;
const TWILIO_ACCESS_TOKEN = process.env.TWILIO_ACCESS_TOKEN;
const TWILIO_SMS_FROM_NUMBER = process.env.TWILIO_SMS_FROM_NUMBER;
const TWILIO_SMS_TO_NUMBER = process.env.TWILIO_SMS_TO_NUMBER;

const HELP_MESSAGE = 'エスエムエスを送信できます。おくるくん、エスエムエスを送ってと言ってみてください';
const MESSAGE_BODY = 'こんにちは！ AlexaからのSMSです';
const SENT_MESSAGE = 'エスエムエスを送信しました。';
const STOP_MESSAGE = 'さようなら';


const LaunchRequestHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
    },
    handle(handlerInput) {
        const speechText = HELP_MESSAGE;

        return handlerInput.responseBuilder
            .speak(speechText)
            .getResponse();
    }
}

const SendSmsIntentHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest'
            && handlerInput.requestEnvelope.request.intent.name === 'SendSms';
    },
    handle(handlerInput) {
        const client = new Twilio(TWILIO_ACCOUNT_SID, TWILIO_ACCESS_TOKEN);
        return client.messages
        .create({
            body: MESSAGE_BODY,
            from: TWILIO_SMS_FROM_NUMBER,
            to: TWILIO_SMS_TO_NUMBER
       })
      .then(message => {
	    const speechText = SENT_MESSAGE;
        return handlerInput.responseBuilder
            .speak(speechText)

            .getResponse();
      })
    }
};

const HelpIntentHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest'
            && handlerInput.requestEnvelope.request.intent.name === 'AMAZON.HelpIntent';
    },
    handle(handlerInput) {
        const speechText = HELP_MESSAGE;

        return handlerInput.responseBuilder
            .speak(speechText)
            .getResponse();
    }
};

const CancelAndStopIntentHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest'
            && (handlerInput.requestEnvelope.request.intent.name === 'AMAZON.CancelIntent'
                || handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StopIntent');
    },
    handle(handlerInput) {
        const speechText = STOP_MESSAGE;

        return handlerInput.responseBuilder
            .speak(speechText)
            .getResponse();
    }
};

const SessionEndedRequestHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest';
    },
    handle(handlerInput) {
        return handlerInput.responseBuilder.getResponse();
    }
};

const ErrorHandler = {
    canHandle(handlerInput) {
        return true;
    },
    handle(handlerInput) {
        return handlerInput.responseBuilder.speak('正常に処理できませんでした。')
        .getResponse();
    }
};

let skill;

exports.handler = async function (event, context) {
  console.log(`REQUEST++++${JSON.stringify(event)}`);
  if (!skill) {
    skill = Alexa.SkillBuilders.custom()
      .addRequestHandlers(
        LaunchRequestHandler,
        SendSmsIntentHandler,
        HelpIntentHandler,
        CancelAndStopIntentHandler,
        SessionEndedRequestHandler,
      )
      .addErrorHandlers(ErrorHandler)
      .create();
  }

  return skill.invoke(event,context);
}
```

- package.json

```json
{
  "name": "sms-sender",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "dependencies" : {
      "ask-sdk": "^2.0.7",
      "twilio": "^3.17.4"
  }
}
```
（index.jsの'SendSms'が、手順3で作成したインテントと対応する処理です。）

パッケージのアップロードが終わったら、関数のコンソールからトリガーを追加します。
トリガーの追加の一覧から『Alexa Skills Kit』を選択します。

<img src="https://vigorous-crush-3355.twil.io/assets/lambda_trigger.png">

下の『トリガーの設定』で『スキルID設定』を『有効』、『スキルID』に作成したAlexaスキルIDを入力します（スキルIDは、AlexaデベロッパーコンソールのAlexaスキル一覧画面で『スキルIDの表示』から取得できます）。

<img src="https://vigorous-crush-3355.twil.io/assets/skill_list.png">

入力が終わったら『保存』をクリックします。

<img src="https://vigorous-crush-3355.twil.io/assets/lambda_trigger_finish.png">

次に、関数の環境変数を入力します。入力するキーと値は以下の4つです。

- TWILIO_ACCOUNT_SID

Twilioコンソールダッシュボードで確認できる、TwilioのアカウントSIDを入力します。
- TWILIO_ACCESS_TOKEN

Twilioコンソールダッシュボードで確認できる、TwilioのAUTH TOKENを入力します。
- TWILIO_SMS_FROM_NUMBER

手順1で取得したTwilioのSMS送信用電話番号を入力します。
なお、このとき電話番号は[E.164形式](https://ja.wikipedia.org/wiki/E.164)で入力します。E.164形式の電話番号は、Twilioコンソールで『Phone Numbers』>『番号の管理』で該当番号をクリックし、表示される詳細画面の『電話番号』で確認できます。

- TWILIO_SMS_TO_NUMBER

SMSの送信先の電話番号です。同じくE.164形式で入力します。例えば、080-1234-5678に送信したいときは、+818012345678と入力します。
また、Twilioアカウントがトライアルアカウントの場合、SMS送信先に指定できるのはTwilioアカウント作成時に入力した電話番号だけです。

環境変数の入力が終わったら、『保存』ボタンをクリックします。

<img width="1195" alt="lambda_env.png" src="https://qiita-image-store.s3.amazonaws.com/0/268190/9027a3fc-585e-046f-56b2-80a9be3c6c92.png">


### 5. AlexaスキルとLambdaをつなぎこむ
Alexaデベロッパーコンソールで左メニューの『エンドポイント』を選択します。

『サービスのエンドポイントの種類』で『AWS LambdaのARN』を選択し、『デフォルトの地域』に手順4で作成したLambdaのARNを入力します（LambdaのARNは、関数のコンソールで確認できます）。
入力が終わったら『エンドポイントを保存』ボタンで入力値を保存します。

<img src="https://vigorous-crush-3355.twil.io/assets/alexa_lambda_endpoint.png">

### 6. テスト
Alexaデベロッパーコンソールの上部メニューで『ビルド』を選択し、『モデルをビルド』をクリックします。

<img src="https://vigorous-crush-3355.twil.io/assets/alexa_skill_build.png">

ビルド完了までには数分かかり、完了したらそのメッセージが表示されます。
ビルドが完了したら『テスト』を選択します。もしスキルのテストが無効になっていた場合は有効化します。
入力欄に『アレクサ、{呼び出し名}で{サンプル発話}』と入力します。例えば、『呼び出し名』に『おくるくん』、『サンプル発話』に『エスエムエスを送って』と入力していたら、『アレクサ、おくるくんでエスエムエスを送って』と入力します。
すると処理が実行され、SMSが送信されてきます。

<img src="https://vigorous-crush-3355.twil.io/assets/alexa_test.png">

<img src="https://vigorous-crush-3355.twil.io/assets/sms.png">

これでSMSを送信するAlexaスキルの作成は完了です。

## Twilio SDKについて
今回、Lambda関数ではTwilioモジュールを使い、TwilioのSDKを利用してSMSを送信しています。
TwilioSDKでは、SMS以外にも『電話をかける』『LINEやFacebook Messangerにメッセージを送る』『プッシュ通知』『Faxを送る』など様々な機能を簡単に利用することができます。

Alexaスキル開発にTwilioを利用し、様々なコミュニケーション機能を組み込んでみてください。