こんにちは。
前回は『アレクサ(Amazon Echo)で何ができるのか?』について記事にしました。 blog.wackwack.net
その中で「自分でAlexaスキルも作れる!」と紹介していまして、実際に自分でAlexaスキルを作ってみました。
と言うことで今回は、私が実際に作った『Alexaからツイッターに投稿するスキル』を例に、Alexaスキルの作り方をまとめます。
作成したスキル
今回作成したスキルは、
というシンプルなものです。
2018年1月18日 19時8分38秒 に帰ってきました。(Alexaスキルでつぶやいています)
— くおっと (@quo1987) 2018年1月18日
ついでにAlexaが「つぶやきました」と喋ります。
「ツイッター」での「ログ」ということで、『ツイログ』と名付けました。
- 「アレクサ、ツイログで行ってきます」
- 「アレクサ、ツイログでただいま」
と、不自然な発話をすることでツイートします。
なお開発用スキルであるため、公開申請はしていません。(というか今回の実装内容だと公開できない)
また今回のスキルは、TwitterAPIに必要なアカウント情報(ACCESS_TOKEN、ACCESS_TOKEN_SECRET)をプログラム中に埋め込むため、アプリ連携許可を飛ばして固定のTwitterアカウントでツイートされます。
全体イメージ
Alexaスキルのイメージはこんな感じです。
ユーザーがAmazon Echoに話しかけると、Amazon EchoはAlexaスキル(Alexa Skills Kit)を起動します。実際のスキルはAWS Lambda上に実装されており、AWS LambdaのプログラムはTwitterAPIを呼び出してツイートを行います。
参考資料
本家Amazonが全6回で「Alexaスキル開発トレーニング」が公開されています。
一日あれば全部学べるボリュームで、かつこれを見れば最低限のスキル開発ができるようになります。興味がある方はまずここから始めましょう。
Alexaスキルの開発
TwitterApplicationManagementの登録
まず初めに、外部からTwitterAPIを叩くための各種キーを取得します。
Twitter Application Managementへアクセスし、自分のTwitterアカウントでログインします。
次に右上の「Create New App」をクリックします。
(私の画面では登録済みのアプリケーションが表示されていますが、初利用時にはこの画面は空白です。)
登録するアプリケーションの入力フォームが出ます。
「Name」「Description」「Website」は必須入力項目です。適当な内容で入力します。
- Name:アプリケーションの登録名
- Description:アプリケーションの説明文
- Website:アプリケーションの問い合わせ先が分かるようなURLを入力します。私の場合はとりあえず当ブログのURLを登録しています。
- CallbackURL:今回は設定不要です。
入力したらページ最下部の「Create your application」をクリックします。
これでアプリケーションの登録が完了しました。
続いてAPIの利用に必要となるAccess Tokenの発行を行います。表示されたページのタブ「Keys And Access Tokens」から「Create my access token」をクリックします。
これで準備は完了です。ページに表示されている「Consumer Key」「Consumer Secret」「Access Token」「Access Token Secret」をプログラム内で利用します。
Amazon開発者コンソール
いよいよAlexaスキルを作成していきます。まずAmazon開発者コンソールにログインします。
上段メニュー「ALEXA」を選択して「Alexa Skills Kit」へ進みます。
右上の「新しいスキルを追加する」をクリックします。(下の画面には作成済みのスキル一覧が表示されていますが、初めての場合は何もありません。)
スキルの基本情報として「言語」「スキル名」「呼び出し名」を入力して保存、次へ進みます。
- 言語:スキルの対応言語。
- スキル名:このスキルの名前。ユーザーにはスキル名が表示される。
- 呼び出し名:スキルを呼び出す時のフレーズ。「アレクサ、◯◯を開いて」の「◯◯」の部分。
続いて対話モデルを設定します。ここがAlexaスキル開発のポイントです。「インテントスキーマ」と「サンプル発話」を設定します。
インテントスキーマ
インテントスキーマは「Alexaスキルで実行するアクションの種類」です。JSON形式で以下のように入力します。
{ "intents": [ { "intent": "GoOutTweet" }, { "intent": "ComeHomeTweet" }, { "intent": "AMAZON.HelpIntent" }, { "intent": "AMAZON.StopIntent" }, { "intent": "AMAZON.CancelIntent" } ] }
- GoOutTweet:「行ってきます」に対応するアクション。
- ComeHomeTweet:「ただいま」に対応するアクション。
- AMAZON.HelpIntent:「使い方」や「説明」に対応するアクション。
- AMAZON.StopIntent:「中止」「停止」に対応するアクション。
- AMAZON.Cancelntent:「キャンセル」に対応するアクション。
「AMAZON.~」と付いているインテントは、標準で用意されているこれを「標準インテント」です。インテントスキーマを定義するだけで使えるようになります。
一方で「GoOutTweet」「ComeHomeTweet」は今回作成するAlexaスキルのオリジナルアクションである「カスタムインテント」です。カスタムインテントは次に説明するサンプル発話でキーフレーズを設定する必要があります。
サンプル発話
サンプル発話ではカスタムインテントに対して「そのインテントがアクションを起こすためのキーフレーズ」を定義します。例えば「行ってきます」っぽいことを言えばGoOutTweetが、「ただいま」っぽいことを言えばComeHomeTweetが起動するイメージです。
今回はGoOutTweet、ComeHomeTweetに対して以下のように発話フレーズを設定します。
GoOutTweet 行く GoOutTweet 行って GoOutTweet 行きます GoOutTweet 出かける ComeHomeTweet ただいま ComeHomeTweet 帰った ComeHomeTweet 帰って ComeHomeTweet 戻った
入力が完了したら次に進みます。
AWS Lambda
ここで一度Amazon開発者コンソールを離れ、AWSにログインします。サーバーレスでプログラムを実行することができる『AWS Lambda』を通して、Alexaスキルを起動する仕組みです。
ログインしたらAWSサービスからLambdaを選択します。
右上の「関数の作成」を実行します。
作成フォームで「一から作成」を選択します。「名前」は任意の名前を入力し、「ランタイム」はNode.js 6.10を選択します。
続いてロールの項目から「カスタムロールの作成」を選択します。
ロールの作成画面が表示されます。全てそのままで「許可」をクリックします。
ここまでできたら右下の「関数の作成」をクリック。
実際に動かすプログラムを直接コーディングすることもできますが、今回はzipファイルをアップロードする形式を取ります。zipファイルとコードはgithub上にアップロードしています。
github.com
画面の中頃に「関数コード」という項目があるので、ここでコードエントリータイプ「.ZIPファイルをアップロード」を選択して、ファイル「skill.zip」をアップロードします。
プログラムの中身
skill.zipの内容について少しだけ触れておきます。index.jsがメインの実行プログラムです。Amazon開発者コンソールで定義したインテントごとにAlexaの振る舞いをコーディングします。
'use strict'; const Alexa = require('alexa-sdk'); const Twitter = require('twitter'); const APP_ID = undefined; // TODO replace with your app ID (OPTIONAL). const JSTOffset = 60 * 9 * 60 * 1000; // JST時間を求めるためのオフセット const ErrorMessage = 'ごめんなさい、 つぶやけませんでした。'; function calculateJSTTime() { var localdt = new Date(); // 実行サーバのローカル時間 var jsttime = localdt.getTime() + (localdt.getTimezoneOffset() * 60 * 1000) + JSTOffset; var dt = new Date(jsttime); return dt; } const handlers = { 'LaunchRequest': function () { this.emit('AMAZON.HelpIntent'); }, 'GoOutTweet' : function() { var dt = calculateJSTTime(); var stringTime = dt.getFullYear() + "年" + (dt.getMonth()+1) + "月" + dt.getDate() + "日 " + dt.getHours() + "時" + dt.getMinutes() + "分" + dt.getSeconds() + "秒 "; var message = stringTime + "に出かけました。(Alexaスキルでつぶやいています)"; Twitter.postTweet(message).then(()=>{ this.emit(':tell','つぶやきました。いってらっしゃい。 '); },(error)=>{ console.log(error); this.emit(':tell',ErrorMessage); }) }, 'ComeHomeTweet' : function() { var dt = calculateJSTTime(); var stringTime = dt.getFullYear() + "年" + (dt.getMonth()+1) + "月" + dt.getDate() + "日 " + dt.getHours() + "時" + dt.getMinutes() + "分" + dt.getSeconds() + "秒 "; var message = stringTime + "に帰ってきました。(Alexaスキルでつぶやいています)"; Twitter.postTweet(message).then(()=>{ this.emit(':tell','つぶやきました。おかえりなさい。 '); },(error)=>{ console.log(error); this.emit(':tell',ErrorMessage); }) }, 'AMAZON.HelpIntent': function () { const speechOutput = '「いってきます」「ただいま」 、とつぶやくと、その時間をツイートします。'; const reprompt = speechOutput; this.emit(':ask', speechOutput, reprompt); }, 'AMAZON.CancelIntent': function () { this.emit(':tell', this.t('STOP_MESSAGE')); }, 'AMAZON.StopIntent': function () { this.emit(':tell', this.t('STOP_MESSAGE')); }, }; 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.registerHandlers(handlers); alexa.execute(); };
Alexa.handlerオブジェクトのthis.emit
を実行することで、Alexaが喋ります。
ツイッターに投稿するTwitter.postTweet
の部分は同梱のtwitter.jsに自作のOAuthプログラムを実装しています。
"use strict"; const AWS = require('aws-sdk'); const https = require('https'); const request = require('request'); const crypto = require('crypto'); const url='https://api.twitter.com/1.1/statuses/update.json'; function postTweet(message) { return new Promise((resolve,reject) => { const include_entities = { status: message, // include_entities: true }; const params = { oauth_consumer_key: process.env.CONSUMER_KEY, oauth_token: process.env.ACCESS_TOKEN, oauth_signature_method: 'HMAC-SHA1', oauth_timestamp: (() => { const date = new Date(); return Math.floor(date.getTime() / 1000); })(), oauth_nonce: (() => { const date = new Date(); return date.getTime(); })(), oauth_version: '1.0' }; let auth_params = Object.assign(include_entities,params); let encoded_auth_params = Object.keys(auth_params).map(function(key){ return `${encodeURIComponent(key)}=${encodeURIComponent(this[key])}`; },auth_params); encoded_auth_params.sort((a,b) => { if(a < b) return -1; if(a > b) return 1; return 0; }); const sigunature_base = `${encodeURIComponent('POST')}&${encodeURIComponent(url)}&${encodeURIComponent(encoded_auth_params.join('&'))}`; const keyOfSign = `${encodeURIComponent(process.env.CONSUMER_SECRET)}&${encodeURIComponent(process.env.ACCESS_TOKEN_SECRET)}`; const signature = crypto.createHmac('sha1',keyOfSign).update(sigunature_base).digest('base64'); params.oauth_signature = signature; let authorization = Object.keys(params).map(function(key) { return `${encodeURIComponent(key)}="${encodeURIComponent(this[key])}"`; },params); authorization.sort((a,b) => { if(a < b) return -1; if(a > b) return 1; return 0; }); const headers = { Authorization: `OAuth ${authorization.join(', ')}` }; const options = { url: url+"?status="+encodeURIComponent(message), headers: headers }; request.post(options ,(error,response,body) => { if(error) { reject("reject:"+error); } else if(response.statusCode!=200) { reject("reject:statusCode="+response.statusCode); } else { resolve(); } }); }); }; module.exports.postTweet=postTweet;
const AWS = require('aws-sdk');
を実行することでprocess.env.CONSUMER_KEY
という形式で、後述するAWS lambdaに設定した環境変数を利用することができます。
続いて環境変数を設定します。「CONSUMER_KEY」「CONSUMER_SECRET」「ACCESS_TOKEN」「ACCESS_TOKEN_SECRET」をキーにとして、最初にTwitterApplicationManagementで取得したそれぞれの値を設定します。
次に画面上段のDesignerの「トリガーの追加」から「Alexa Skills Kit」を選択します。
画面最下部に「トリガーの追加」メニューが表示されるので「追加」を実行します。
最後に画面右上の「保存」を実行します。
ここまでで関数の作成は完了です。正常に関数が動作するかをテストします。
「テスト」をクリックすると子画面が表示されるので、「新しいイベントの作成」を選びイベントテンプレート「Alexa Start Session」を選択します。
すると何やらコードが表示されます。イベント名に適当な名前を入力し「作成」を実行します。
画面に戻り再び「テスト」を実行して「実行結果:成功」と表示されれば関数のテストは完了です。
最後に画面右上に表示された「ARN」をコピーしておきます。この後の設定に利用します。
Amazon開発者コンソールで仕上げとテスト
関数の作成が終わったらAmazon開発者コンソールに戻ります。
設定メニューの項目「エンドポイント」で「AWS LambdaのARN(Amazonリソースネーム)」を選択します。すると、下の方に「デフォルト」というフォームが表示されるので、先ほどコピーしたARNを貼り付けて次へ進みます。
テスト画面が表示されるので、ここで最終的な動作確認を行います。この画面では作成したAlexaスキルが起動した状態になっているため、発話サンプルで設定したキーフレーズを入力します。
フォームに「ただいま」と入力し、「ツイログを呼び出す」を実行します。
すると左側にはAlexaへ送信した入力情報、右側にはAlexaが情報を受け取りAWS Lambdaで実行された関数の結果が表示されます。右側の「outputSpeech」がAlexaが喋る内容です。ここに想定通りのセリフが表示されていればOKです!
AmazonEchoに導入
ここまででAlexaスキルの作成は全て完了です。最後は実機へ導入します。
次の画面へ進むと公開情報の設定になります。今回は本当に公開するわけではないので、適当に入力します。
最後にプライバシーとコンプライアンスの設定です。とりあえず「いいえ」と「輸出コンプライアンス」にチェックすればOKです。
保存を実行すると画面左側のメニューから「スキルのベータテスト」がクリックできるようになります。
「テスターのメールアドレス」に自分のアドレスを入力して追加します。他にも使ってもらいたい人がいれば最大500件まで登録できます。
最後に「テストを開始」を実行します。
自分のアドレスにメールが届くので、その中のリンクをクリックします。なお日本語環境では2番目の「JP customer~」リンクを選択します。
Alexaスキルのページ(アプリ画面)が表示されるので「スキルテスト」でスキルを有効化します。
Alexaスキル開発、骨は折れるが楽しいぞ!
以上、自作のAlexaスキルを開発して実機に導入するところまでを紹介しました。
Amazon DeveloperコンソールやAWS、必要に応じてアプリの認証も必要なので「手軽にできる!!」ものではありません。
しかしながら自分で作成したプログラムでAlexaが喋ってくれるは、なかなかに達成感があります。
暇な人、ガジェット好きな人、ぜひあなたのAlexaにオリジナルのスキルを装備させてみてください!
Amazon Echo (Newモデル)、チャコール (ファブリック)
- 出版社/メーカー: Amazon
- 発売日: 2017/11/15
- メディア: エレクトロニクス
- この商品を含むブログ (3件) を見る