ちょっと話題の記事

Alexaの知識がないところからスキルを作ってみた

2018.01.19

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

モバイルアプリサービス部の中安です。

自分の手元に echo dot が届いてからというもの、すっかりラジオプレーヤーになり果てております(苦笑)

でも、せっかくなので「カスタムスキルとやらを作ってみようじゃないか」と、見切り発車でほぼ無知識の中ほそぼそと作りはじめることにしました。そして、初心忘るべからずという意味も込めて、作っていく中で感じた感想やハマりどころなどを開発日記としてブログに書くことにしました。

そんなノリの開発日記なので、高度なAlexaの技術記事を求めてここに来られた方はすいません、ここまでです。(;´∀`)

もし今、自分と同じように「スキル作ってみようかなー」と思っていて、「でも、よくわからないなぁ」「何から始めたらいいのかなぁ」と思っている方にとっての参考になればと思います。

あかうんと

スキル開発を始めるにあたって、意外と躓きやすいのがアカウントらしいです。

うまくいかなくてこんな状態(↑)にならないように、最初の最初ですが慎重にやっていったほうがよさそうです。

アカウントは3種類要る

スキルを開発するために取得しておくべきアカウントは3種類あるそうです。ふむふむ

AmazonWebServices(AWS)アカウント

スキルはAWSサービスである「Lambda」と、Alexaスキル開発のためのキット「AlexaSkillsKit」との組み合わせによって作られるとのこと。へぇ。

なので、AWSのアカウントが必要です。持ってない人は取得すべし。 (以降もLambdaの他にも色々なAWSサービスが絡んできます)

AmazonDeveloperアカウント

スキル自体の登録はAWSではなく、AmazonDeveloperConsole というところで行うそうです。ふむふむなるほど。

「AWSの中でやるんじゃないの?」と勘違いしてる人も多そう。違うんですね、これが

Amazonアカウント

上記の2アカウントあればスキルの開発はできるらしいですが、echoなどでスキルを試す場合には、AmazonDeveloperアカウントと同じメールアドレスで作られたAmazonのアカウントがあるとよいとのことです。へぇー。

Amazonアカウントとは、ほんとにあの買い物サイトのAmazonのアカウントのことなのですが、このアカウントをもってAlexaのデバイスの管理を行えちゃいます。

で、ここでアカウントに紐付いたechoなどのAlexaデバイスと、AmazonDeveloperアカウントがええ感じで紐付いて動作確認がしやすくなるとのこと。すごいですね。

Amazon.com と Amazon.co.jp 問題

重要なことは、Amazon.com のアカウントと、Amazon.co.jp のアカウントを決して混ぜないこと だそうです。

そう、

Amazon.com のアカウントと、Amazon.co.jp のアカウントを決して混ぜないこと!!!!

大事なことなので太文字で2回言いました。つまり、日本語スキルを作りたい場合は Amazon.co.jpのみに存在するアカウントであるべしとのことです。

素晴らしいことに弊ブログにて先人の方がアカウントの取り方についてブログにしたためてくれています。

失敗しないAlexa開発者アカウントの作り方

居住国選択が日本でなかったせいなのか、はたまた違う理由なのか、Amazon.co.jp のアカウントでAlexaの管理画面にログインしたのにドメインが Amazon.com になってしまうなど自分も危うく色々ハマりかけました。

どうも躓いてしまうという方は、上記のブログ通りにやってみるといいかと思います。

つくる

「Alexa スキル 開発」でGoogle検索してみると、「Alexaスキル開発トレーニング」というなんとも親切なAlexa公式サイトが上位に登場します。

↑ おっ、このコンテンツを作ってるのはクラスメソッドという会社じゃないか! (ステマ)

自分はもう基本の基本からって感じだったので、第1回をじっくり読んでまずはこの通りやってみることにしました。

(・・・こまかい手順はトレーニングの通りなので、そちらを参照ください。省略・・・)

以下、やってみたことのまとめと所感です。

スキルの呼び出し名

案外迷って、そのあげく「おためし」というスキルの呼び出し名にしました。最初ですからね。

「アレクサ、おためしを開いて」

って感じになるイメージです。

実際に声に発するものなので、大声で言って恥ずかしくない名前にしましょうね。

サンプルのnode.jsは読みやすい

トレーニングの中でLambdaにのっけるサンプルソースをダウンロードできます。(自分は何故か見落としてしまって、アレ?ってなりました。注意深く文章を見ましょうね)

中には色々と入っていますが、とりあえず index.js だけを開いて見ればよさそう。

'use strict';
var Alexa = require('alexa-sdk');

//=========================================================================================================================================
//TODO: このコメント行より下の項目に注目してください。
//=========================================================================================================================================

//Replace with your app ID (OPTIONAL).  You can find this value at the top of your skill's page on http://developer.amazon.com.  
//Make sure to enclose your value in quotes, like this: var APP_ID = "amzn1.ask.skill.bb4045e6-b3e8-4133-b650-72923c5980f1";
var APP_ID = undefined;

var SKILL_NAME = "豆知識";
var GET_FACT_MESSAGE = "知ってましたか?";
var HELP_MESSAGE = "豆知識を聞きたい時は「豆知識」と、終わりたい時は「おしまい」と言ってください。どうしますか?";
var HELP_REPROMPT = "どうしますか?";
var STOP_MESSAGE = "さようなら";

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

//=========================================================================================================================================
//この行から下のコードに変更を加えると、スキルが動作しなくなるかもしれません。わかる人のみ変更を加えてください。  
//=========================================================================================================================================
exports.handler = function(event, context, callback) {
    var alexa = Alexa.handler(event, context);
    alexa.APP_ID = APP_ID;
    alexa.registerHandlers(handlers);
    alexa.execute();
};

var handlers = {
    'LaunchRequest': function () {
        this.emit('GetNewFactIntent');
    },
    'GetNewFactIntent': function () {
        var factArr = data;
        var factIndex = Math.floor(Math.random() * factArr.length);
        var randomFact = factArr[factIndex];
        var speechOutput = GET_FACT_MESSAGE + randomFact;
        this.emit(':tellWithCard', speechOutput, SKILL_NAME, randomFact)
    },
    'AMAZON.HelpIntent': function () {
        var speechOutput = HELP_MESSAGE;
        var reprompt = HELP_REPROMPT;
        this.emit(':ask', speechOutput, reprompt);
    },
    'AMAZON.CancelIntent': function () {
        this.emit(':tell', STOP_MESSAGE);
    },
    'AMAZON.StopIntent': function () {
        this.emit(':tell', STOP_MESSAGE);
    }
};

node.jsを触ったことある/ない、そもそもエンジニアさんなのか、そうでないのかに関わらず、このソースコードを見ただけで何をしたら何が変わりそうかというのが分かりやすいサンプルだと思いました。

GetNewFactIntent というインテント(Alexaへの命令名みたいなもの)が一つだけあり、そのハンドラで何をやってるかが書かれています。(50行目)

とりあえず、ここに自分が喋らせたいことを書いてみるところからはじめました。

他のインテント(AMAZON.CancelIntent)を参考に emit というメソッドに':tell'を与えて、文字列を定義してみます。

    'GetNewFactIntent': function () {
        this.emit(':tell', "おい、焼きそばパン買ってこいや");
    },

文字列書くだけでちゃんとしたイントネーションで話しだすので、すごいですよね。

書きかえたら、node_modulesというディレクトリも併せて落としてきた形と同じになるようにZIP圧縮します。

$ cd (サンプルのZIP解凍先パス)
$ zip -r ../lambda.zip node_modules index.js

できあがった lambda.zip(名前は任意) を、Lambda のコンソール画面でアップロードすればデプロイ完了です。 (このあたりはトレーニングにも載っていますね)

インテントと発話をいじる

トレーニングではとりあえずコピペしろと書かれている「インテントスキーマ」と「サンプル発話」も、せっかくだからカスタマイズしてみました。

{ "intents": [
  { "intent": "GetNewFactIntent" },
  { "intent": "AMAZON.HelpIntent" },
  { "intent": "AMAZON.StopIntent" },
  { "intent": "AMAZON.CancelIntent" }
]}
GetNewFactIntent 豆知識
GetNewFactIntent 豆知識を教えて
GetNewFactIntent 他の豆知識
GetNewFactIntent 雑学
GetNewFactIntent 雑学を教えて
GetNewFactIntent 他の雑学
GetNewFactIntent 知識
GetNewFactIntent 何か
GetNewFactIntent 何か教えて

サンプルは豆知識を言ってくれるスキルなので上記のように定義されていますが、「焼きそばパンを買ってこい」と言ってくるスキルに変えたので

{ "intents": [
  { "intent": "YakisobaPanIntent" },
  { "intent": "AMAZON.HelpIntent" },
  { "intent": "AMAZON.StopIntent" },
  { "intent": "AMAZON.CancelIntent" }
]}
YakisobaPanIntent おなかすいた
YakisobaPanIntent おなかすきました
YakisobaPanIntent はらへった
YakisobaPanIntent はらがへった
YakisobaPanIntent 何か食べたい

と、変えてみました。

これに対応するLambda側のハンドラも

    'YakisobaPanIntent': function () {
        this.emit(':tell', "おい、焼きそばパン買ってこいや");
    },

このように変えてデプロイしてやりました。

動作確認

さぁ、実機確認!

ということで、iOSアプリ開発してる人間としては、ここでEchoに対して「ビルド&ラン」でもしてやらないといけないのかなと思うところなのですが・・・

Amazonアカウントの話の際に書いたとおり、同じメールアドレスで開発アカウントと紐付いてる場合は、なんと何もしなくてもEchoに開発中のスキルが入っている状態になるようです。びっくり。

なので、この状態で「アレクサ、おためしでおなかすいた」と語りかけてやると、「おい、焼きそばパン買ってこいや」と音声で返してくれるようになりました。すごい。

※ ほんとうはその模様を動画に撮って貼り付けようと思ったのですが、諸事情により割愛します。

まとめ

というわけで、まだまだ話しかけると決まった言葉が返ってくるだけの簡単なスキルですが、形には一応なりました。

ここまでのまとめとしては

  • 最初のアカウント作りは気をつけよう
  • 読めばまずはド素人でも形にできる優しいトレーニング
  • おなかすいたのに焼きそばパン購入を命令されるってどういうこと?

の3つです。

で、次はもう少し複雑なことをさせたいなぁと思っています。

といっても一歩一歩少しずつ。順番に下記のようなことをしたいと思っております。

  • Alexaから問いかけられるようにしたい
  • DynamoDBもからませたい
  • 焼きそばパン買ってくる

また空いた時間に色々ためして「その2」が書けるように頑張ります。

以上です。