FJCT_ニフクラ mobile backend(mBaaS)お役立ちブログ

スマホアプリ開発にニフクラ mobile backend(mBaaS)。アプリ開発に役立つ情報をおとどけ!

Amazon Echoからプッシュ通知を送る

f:id:mbaasdevrel:20180209175819p:plain

最近、スマートスピーカーが流行っていますね。Amazon Echo、Google Home、LINE Clova、HomePodなど多彩に出てきています。多くのスマートスピーカーは単なるBluetoothスピーカーではなく、音声認識とAIによって音声操作ができるようになっています。

今回はAmazon Echoを使ってプッシュ通知を送る仕組みを作ってみます。うまく使えばリモートにいる人に対して音声でプッシュ通知を送ることだってできるでしょう。

使うもの

  • Amazon Echo
  • AWS Lambda
  • Amazon S3
  • ニフクラ mobile backend

Lambdaの作成

Amazon Lambdaに音声をテキストにした後、コールされる関数を用意します。関数はalexa-skill-kit-sdk-factskillをベースにしています(設計図の中にあります)。

f:id:mbaasdevrel:20180209175608p:plain

Lambdaで関数を作った後、Alexa Skills Kitを追加します。AlexaのスキルIDを登録するので、ここで一旦待ちます。

f:id:mbaasdevrel:20180209175634p:plain

スキルの作成

次にスキルを作成します。アマゾンアプリ開発者ポータルでAlexaのスキルを作成します(Alexa Skills Kitを選択します)。呼び出し名は日本語で読み上げるものになるので分かりやすいものがいいでしょう。NCMBではほとんど認識されませんでしたので、プッシュ通知としています。

f:id:mbaasdevrel:20180209175648p:plain

対話モデルですが、インテントスキーマは次のようになっています。intentで指定したのがLambdaで呼ばれるイベントになります。プッシュ通知を送る時間であるSENDTIMEと送信するメッセージのMESSAGEという二つの変数(スロット)を定義しています。執筆時点では日本語では文章を送れないのでMESSAGEというタイプを定義しています。

{
  "intents": [
    {
      "slots": [
        {
          "name": "SENDTIME",
          "type": "AMAZON.TIME"
        },
        {
          "name": "MESSAGE",
          "type": "MESSAGE"
        }
      ],
      "intent": "PUSH"
    }
  ]
}

MESSAGEというタイプはカスタムスロットタイプで指定します。例えば以下のようになります。

こんにちは
今から帰ります
楽しかった
ごめんなさい
開始時間です
休憩終了

そしてサンプル発話は次のようにしてあります。最初のPUSHが呼ばれるインテント(イベント)後は文章に変数(スロット)を埋め込んだテンプレートになります。

PUSH プッシュ通知 を {SENDTIME} に {MESSAGE} って送って

そしてLambdaのaimを指定するところがありますので、先ほど作成したLambdaのものを設定します。逆にスキルができあがったらIDが付与されますので、それをLambda側に設定します。

f:id:mbaasdevrel:20180209175746p:plain

Lambdaのコードについて

LambdaはNode.jsなのでJavaScript SDKが利用できます。一旦、テンプレートで生成されたコードをすべてダウンロードし、npmでncmbを追加します。

npm i ncmb -S

そして index.js を修正します。テンプレートからほとんど修正していませんが、次のようになります。重要なのはPUSHとなっている関数です。

const Alexa = require('alexa-sdk');
const NCMB  = require('ncmb');
const applicationKey = 'YOUR_APPLICATION_KEY';
const clientKey = 'YOUR_CLIENT_KEY';
const ncmb  = new NCMB(applicationKey, clientKey);

const APP_ID = 'YOUR_SKILL_ID';  // TODO replace with your app ID (OPTIONAL).

// 日本語メッセージ
const languageStrings = {
    "ja": {
        translation: {
          ANSER_MESSAGE: "受け付けました",
          ERROR_MESSAGE: "エラーがおきました",
          GET_FACT_MESSAGE: "なんと送りますか?"
        }
    }
};

const handlers = {
    // 省略
    // プッシュ通知を開いて、というと呼ばれるイベント
    'GetFact': function () {
        // Get a random space fact from the space facts list
        // Use this.t() to get corresponding language data
        const factArr = this.t('FACTS');
        const factIndex = Math.floor(Math.random() * factArr.length);
        const randomFact = factArr[factIndex];

        // Create speech output
        const speechOutput = this.t('GET_FACT_MESSAGE');
        this.emit(':tellWithCard', speechOutput, this.t('SKILL_NAME'), randomFact);
    },
    // 省略
    // プッシュ通知を送る際に呼ばれるイベント
    'PUSH': function() {
      const message = this.event.request.intent.slots.MESSAGE.value || '送信します';
      const time = this.event.request.intent.slots.SENDTIME.value;
      const push = new ncmb.Push();
      push
        .set("message", message)
        .set("target", ["ios", "android"]);
      if (time) {
        const o = new Date();
        const d = new Date(`${o.getFullYear()}/${o.getMonth() + 1}/${o.getDate()} ${time}`);
        push.set('deliveryTime', d);
      } else {
        push.set("immediateDeliveryFlag", true);
      }
      push
        .send()
        .then(() => {
          // 送信設定したら、受付完了しましたとメッセージを読み上げます
          this.emit(':tell', this.t('ANSER_MESSAGE'));
        })
        .catch((err) => {
          // エラー時。エラー内容を読み上げます。
          this.emit(':tell', this.t('ERROR_MESSAGE') + JSON.stringify(err));
        });
    }
};

exports.handler = function (event, context) {
    const alexa = Alexa.handler(event, context);
    alexa.APP_ID = APP_ID;
    // To enable string internationalization (i18n) features, set a resources object.
    alexa.resources = languageStrings;
    alexa.registerHandlers(handlers);
    alexa.execute();
};

スキルで指定した SENDTIME や MESSAGE は this.event.request.intent.slots.SENDTIME.value や this.event.request.intent.slots.MESSAGE.value で取れます。後は普通のJavaScriptとして記述可能です。

スキルのベータテスティングに登録する

日本語版のAlexaでは実機テストをするためにはベータテスティングを使う必要があります。多少面倒ですが、公開情報やプライバシー、コンプライアンスなどの情報を登録すると使えるようになります。

f:id:mbaasdevrel:20180209175806p:plain

ベータテスティングを行ったら、Amazonアプリ開発者ポータルのAlexaの画面でスキルを有効にします(メールが来るのでそれに従います)。

f:id:mbaasdevrel:20180209175819p:plain

これで実機テストできる状態になります。

実機テスト

今回は「Alexa、プッシュ通知を開いて」ではなく「Alexa、プッシュ通知を14時にこんにちはって送って」といった指示の仕方をします。これだけで一連のコマンドとしてプッシュ通知が作成されます。

まとめ

ここまで書くと簡単に見えますが、最初は設定する値がどう関連してくるのか分からず悩むかも知れません。Lambdaを使わずにHTTPSのサーバを指定することもできるので、開発段階ではそちらの方がデバッグしやすいかと思います(ローカルコンピュータ環境をオンラインに公開するのは ngrok が良いでしょう)。

音声でデータを登録したり、検索できたりすると未来感があります。ぜひ試してみてください!

中津川 篤司

中津川 篤司

NCMBエヴァンジェリスト。プログラマ、エンジニアとしていくつかの企業で働き、28歳のときに独立。 2004年、まだ情報が少なかったオープンソースソフトの技術ブログ「MOONGIFT」を開設し、毎日情報を発信している。2013年に法人化、ビジネスとエンジニアを結ぶDXエージェンシー「DevRel」活動をスタート。