技術全体を見るCTOの視点、ビジネス全体を見るプロジェクトマネージャーの視点、その両方で世の中のトレンド、ニュースを見る

Amazon Echo と IoT を連携したオフィスハックを実践してみました

»

Alexa, ask yumemi-eggs, how many eggs are there?

Amazon Echoは、このブログでも以前触れましたが、Amazonがリリースしたデバイスで、音声で話しかけると処理をした上で音声で回答をしてくれるという音声アシスタントです。

これを使ったオフィスハックの仕組みを作りました。卵の数(なぜ卵?というのは動画にて)をIoTデバイスが数えて、Echoに聞くと教えてくれるようになっています。全体の概要を動画にてご説明しておりますので、ご覧ください。

Echoとの連携は非常に簡単です。この部分に絞って、今回の取り組みについてさらにご説明をしたいと思います。

Alexa Skillを作ろう

Echoから送られてきた音声を処理する部分をAlexa Skillといいます。今回作ったスキルは、実はRailsサーバへのつなぎ込みも含めても1時間くらいで出来てしまいました。この簡単さがAlexaのスゴイところです。だからこそ、どんどん対応サービスが増えていくんですね。この簡単さは、現段階ですとGoogle HomeやSiriでは全く太刀打ちができない部分です。

Alexa関連の処理で、作るべき部分は2つあります。Echoから呼び出されるAlexa Skillと、その中身の実処理を担当するLambdaファンクションです。

Alexa Skillは、Amazon(US)のデベロッパーページからWeb上で簡単に作ることが出来ます。

amazon alexa developer page

AlexaのSkilは、Intentという単位で処理を作成します。1回話しかけると、1個のIntentが起動されます。今回は、機能としては「卵の数を聞いたら答えてくれる」だけでいいので、Intentは1個だけあれば足ります。では、これを GetNumberOfEggsIntent という名前にしましょう。

ここで作るのは、「Intent自体の定義」と、「Intentの呼び出し方」の2つです。

Intentを作ろう

まずはIntent自体の定義です。これは Intent Schema と呼ばれます。今回はこんな形で作りました。

{
    "intents": [
        {
             "intent": "GetNumberOfEggsIntent",
             "slots": [
                {
                    "name": "Place",
                    "type": "LIST_OF_PLACES"
                }
            ]
        }
    ]
}

説明が必要そうなところは slots くらいですね。これは、Echoへの問いかけの中で、プログラム的に取得したい部分を指しています。先にIntentの呼び出し方を見たほうが、理解しやすいと思うので、まずそちらを見てみましょう。 Sample Utterances といいます。今回はこのようにしました。

GetNumberOfEggsIntent How many eggs are there in {Place}
GetNumberOfEggsIntent Are there any eggs in {Place}
GetNumberOfEggsIntent In {Place}

ここには、4つの要素があります。まず1つ1つの行、これが、話しかけ方の「例」を示します。ただし、ここに書かれている話しかけ方じゃなきゃダメだということではなく、言い方が違っていたとしても、裏でDeep Learningを使って話しての意図(まさにIntentですね!)を推測してくれます。(らしいです)

そして、行の最初に書かれているのが、「Intent名」です。今回はIntentが1個しかないので、どの行も同じIntent名が書いてあります。

スペースを空けて、そこから先が、実際の話し方になります。1行目であれば、「How many eggs are there in {Place}」ですねここで、 slot が出てきます。先程の中の「{Place}」の部分ですね。この中括弧で囲まれている部分が、 slot です。実際に人間が話しかけるときには、例えば "How many eggs are there in Tokyo office?" というように聞きます。そうすると、"Tokyo office" の部分が、Place として抜き出され、後からプログラムで使えるようになります。先程のIntent Schemaを見てみましょう。

 "slots": [
    {
        "name": "Place",
        "type": "LIST_OF_PLACES"
    }
]

ここが、「Placeっていうスロットを用意するので、後からプログラムで使いますよ」という宣言になっているわけです。typeというのは、それがどういう情報かというもので、単に文字列なのか、日付なのか、数字なのか、というのを区別しています。こちらのページに定義済みの型の情報があります。今回は、Placeにオフィスの場所を入れて欲しいと思っていまして、特定のもののリストを用意しまして、それが LIST_OF_PLACES です。

Alexa Skillとしては、設定しなければいけないのはほぼこれだけです。あとはLambdaファンクションを作って、Lambdaファンクションはこれを使いますよ、という設定をすればOKです。

Lambda ファンクションを作ろう

あとは、LambdaのファンクションをAWSの管理ページから作成します。新規作成のときに、Alexa系の雛形がいくつかあるので、それをベースにすると比較的簡単に作れます。

aws lambda blueprints

今回作ったもののメイン部分は下記の1ファイルのみです(APIのURLなど一部伏せております。)。今回はNode.jsで開発しました。ライブラリはnpmで導入する必要があります。

/* eslint-disable  func-names */
/* eslint quote-props: ["error", "consistent"]*/
/**
 * This sample demonstrates a simple skill built with the Amazon Alexa Skills
 * nodejs skill development kit.
 * This sample supports multiple lauguages. (en-US, en-GB, de-DE).
 * The Intent Schema, Custom Slots and Sample Utterances for this skill, as well
 * as testing instructions are located at https://github.com/alexa/skill-sample-nodejs-fact
 **/

'use strict';

const Alexa = require('alexa-sdk');
const request = require('sync-request');

const APP_ID = 'amzn1.ask.skill.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';

const languageStrings = {
    'en-GB': {
        translation: {
            EGG_NUM_NULL: 'There seems to be no machine in ',
            EGG_NUM_ZERO: 'There is no egg in ',
            EGG_NUM_ONE: 'There is one egg in ',
            EGG_NUM_POLY: 'There are %%NUM%% eggs in ',
            EGG_NUM_ERROR: 'Oops! Error. ',
        },
    },
    'en-US': {
        translation: {
            EGG_NUM_NULL: 'There seems to be no machine in ',
            EGG_NUM_ZERO: 'There is no egg in ',
            EGG_NUM_ONE: 'There is one egg in ',
            EGG_NUM_POLY: 'There are %%NUM%% eggs in ',
            EGG_NUM_ERROR: 'Oops! Error. ',
        },
    },
    'de-DE': {
        translation: {
            EGG_NUM_NULL: 'There seems to be no machine in ',
            EGG_NUM_ZERO: 'There is no egg in ',
            EGG_NUM_ONE: 'There is one egg in ',
            EGG_NUM_POLY: 'There are %%NUM%% eggs in ',
            EGG_NUM_ERROR: 'Oops! Error. ',
        },
    },
};

const handlers = {

    'GetNumberOfEggsIntent': function () {
        // Get a random space fact from the space facts list
        // Use this.t() to get corresponding language data

        const place = this.event.request.intent.slots.Place.value;
        const url = 'http://example.com/path_to_api/?place=' + place;

        var response = request('GET', url);
        var body = response.getBody('utf8');

        // Create speech output
        var speechOutput;
        if (response.statusCode == 200) {
            if (body === 'ERROR') {
                speechOutput = this.t('EGG_NUM_ERROR') + place;
            } else if (body === 'NULL') {
                speechOutput = this.t('EGG_NUM_NULL') + place;
            } else if (body === '0') {
                speechOutput = this.t('EGG_NUM_ZERO') + place;
            } else if (body === '1') {
                speechOutput = this.t('EGG_NUM_ONE') + place;
            } else if (!isNaN(body)) {
                speechOutput = this.t('EGG_NUM_POLY').replace('%%NUM%%', body) + place;
            } else {
                speechOutput = 'No!';
            }
        } else {
            speechOutput = this.t('EGG_NUM_ERROR') + response.statusCode;
        }

        this.emit(':tell', speechOutput);
    },
};

exports.handler = (event, context) => {
    const alexa = Alexa.handler(event, context);
    alexa.APP_ID = APP_ID;
    alexa.resources = languageStrings;
    alexa.registerHandlers(handlers);
    alexa.execute();
};

前半は、返す文言のパターンを定義しています。0個、1個、複数個で文言を切り替える必要があるので、このようにしています。プログラムをシンプルにするために無理に言い方のパターンを統一するよりも、ソースは複雑になってしまいますが、自然な言語で返してあげる方が、ボイスユーザインタフェースとしては正しいと思います。

最後の7行は、Alexa SDKへのつなぎ込み部分で、これは雛形そのままです。

その間が、処理のメイン部分で、APIから卵の個数を取得し、数によって文言を切り替えている部分です。

長さも短いですし、トータル1時間で出来たよ!というのもご納得いただけるのではないでしょうか。

Alexa Skill に Lambda ファクションをつなごう

あとは、Alexa Skill と Lambda ファンクションを関連付ければ、Echo に話しかけて Lambda が起動し、声で返答するように出来ます。Lambda ファンクションには、ARN (Amazon Resource Name) というものがありますので、これを Alexa Skill の管理画面から設定すれば OK です。

configuring alexa skill

Comment(0)

コメント

コメントを投稿する