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

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

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

- Alexa 開発者アカウントを持っている（https://developer.amazon.com/ja/alexa からサインインできる）
- Twilioアカウントを持っている
 - もしTwilioアカウントをもっていない場合は、[https://jp.twilio.com/try-twilio/kddi-web](https://jp.twilio.com/try-twilio/kddi-web)からサインアップしてください。

## 目次
1. SMS送信用の電話番号を取る
2. Alexaスキルを作る
3. スキルの呼び出し名、インテントを設定する
4. Twilio FunctionsでSMS送信処理部分をつくる
5. AlexaスキルとFunctionsをつなぎこむ
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. FunctionsでSMS送信処理部分をつくる
Twilioの管理コンソールにログインし、スライドメニューから**Runtime**の**Configure**を選択します。
**Credentials**の**Enable ACCOUNT_SID and AUTH_TOKEN**のチェックを入れます。

<img width="336" alt="スクリーンショット 2018-08-07 18.26.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/268190/dc4bdeea-12cb-66f1-ee48-19fa51eee984.png">

**Environmental Variables**の下にある赤い+アイコンを2回クリックして、枠を2行作ります。
今作成した2行に、以下の内容を追加します。

|KEY|VALUE|
|:--|:--|
|SMS_FROM_NUMBER|先程購入したUS番号|
|SMS_TO_NUMBER|SMSを送信したい携帯番号（E.164形式）|

**Dependencies**の中の赤い+アイコンを押して、枠を一つ追加します。
**NAME**欄に、「ask-sdk」、**VERSION**欄に「2.0.7」と入力します。

<img width="753" alt="スクリーンショット 2018-08-07 17.14.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/268190/fdb55300-401f-bc06-9f3b-0b9ec2da8d09.png">

画面下部にある**Save**ボタンを押して、設定を保存します。

左側のメニューの**Functions**の**Manage**を選択します。
赤い+アイコンを押すか、**Create a new Function**ボタンを押して新しいFunctionを作ります。
**New Function**ダイアログが開くので、**Blank**を選択してから**Create**ボタンを押します。
**FUNCTION NAME**に「SendSmsV2」と入力し、**PATH**欄には、「/send-sms-v2」と入力します。

<img width="595" alt="スクリーンショット 2018-08-07 17.18.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/268190/0c921d25-02c4-ab5a-965b-4f1326b748a2.png">

**CODE**欄に予め書かれているコードをすべて削除し、以下のコードを貼り付けます。

```javascript

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

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

let twilioContext;

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

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

const SendSmsIntentHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest'
            && handlerInput.requestEnvelope.request.intent.name === 'SendSms';
    },
    handle(handlerInput) {
        const client = twilioContext.getTwilioClient();
        return client.messages
        .create({
            body: MESSAGE_BODY,
            from: twilioContext.SMS_FROM_NUMBER,
            to: twilioContext.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)
            .reprompt(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 = function (context, event, callback) {
  console.log(`REQUEST++++${JSON.stringify(event)}`);
  twilioContext = context;  // Twilioの環境変数参照用
  if (!skill) {
    skill = Alexa.SkillBuilders.custom()
      .addRequestHandlers(
        LaunchRequestHandler,
        SendSmsIntentHandler,
        HelpIntentHandler,
        CancelAndStopIntentHandler,
        SessionEndedRequestHandler,
      )
      .addErrorHandlers(ErrorHandler)
      .create();
  }

  return skill.invoke(event,context)
  .then((res) => {
    callback(null, res);
  })
  .catch((error) => {
    callback(error);
  });
};

```

**Save**ボタンを押して、デプロイが完了するまでしばらく待ちます。
**PATH**欄の右側にあるコピーアイコンをクリックし、FunctionsのURLをクリップボードにコピーしておきます。

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

『サービスのエンドポイントの種類』で『HTTPS』を選択し、『デフォルトの地域』に手順4で作成したFunctionsのURLを入力します。
証明書については、『開発用のエンドポイントは、証明機関が発行したワイルドカード証明書をもつドメインのサブドメインです』を選択します。
入力が終わったら『エンドポイントを保存』ボタンで入力値を保存します。

### 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について
今回のように、Twilio Functionsを利用することで、Lambdaを利用せずにスキルの開発可能になりました。
TwilioSDKでは、SMS以外にも『電話をかける』『LINEやFacebook Messangerにメッセージを送る』『プッシュ通知』『Faxを送る』など様々な機能を簡単に利用することができます。

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