Alexa 画面付きデバイス向けスキル公開 「カラーデコード」
去年の2018年後半から画面付きのAmazon Echoが続々発売されて、Fire TVもAlexa対応になりましたね。
んで この度、画面表示向けのAlexaスキルを作ってみたいと思い立ったのです。SpotもShowまだもってないんだけどね 🙄 。
スキル概要
今回つくったスキル「カラーデコード」は、16進数 6桁のカラーコードを言うと、画面にその色を表示するといういたってシンプルなスキルです。
でもふと口にしたカラーコードが色として目の前に現れるって素敵なことですよね。ファンタジーです。これまではカラーコードを言っても何も起きなかったのですから。
Alexa SDK for Node.js Ver2をつかってコーディングしてます。スキル作成の基本設定などは以下のブログの通りです。ご参照ください。
Alexa Developer Console
スキルの呼び出し名を設定
スキル名を「カラーデコード」としました。
インテントを追加
カラーコードが発話されると呼び出されるColorCodeインテントを作成します。
6桁のカラーコードを識別するために、{first} ~ {sixth}という6個のスロットを作りました。スロットタイプは以下のLIST_OF_NUMを作成して6つのスロットすべてに適用しました。
0~Fの16進数を検出します。
参考
6桁のカラーコード発話の認識として以下が大変参考になりました!
https://dev.classmethod.jp/cloud/4-digit-number-custom-slot/
Lambda Management Console
index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
/* eslint-disable func-names */ /* eslint-disable no-console */ const Alexa = require('ask-sdk'); //起動時 const GetNewFactHandler = { canHandle(handlerInput) { const request = handlerInput.requestEnvelope.request; return request.type === 'LaunchRequest' || (request.type === 'IntentRequest' && request.intent.name === 'GetNewFactIntent'); }, handle(handlerInput) { return handlerInput.responseBuilder .speak('ようこそカラーデコードへ。ディスプレイ表示したいカラーコード6桁をおっしゃってください') .reprompt('確認したいカラーコード6桁をおっしゃってください') .withSimpleCard('カラー de コード', '発話例) \n FF00FF など') .getResponse(); }, }; //ヘルプ const HelpHandler = { canHandle(handlerInput) { const request = handlerInput.requestEnvelope.request; return request.type === 'IntentRequest' && request.intent.name === 'AMAZON.HelpIntent'; }, handle(handlerInput) { return handlerInput.responseBuilder .speak('画面付きデバイス用のスキルです。6桁のカラーコードを言うと、その色を画面表示します。確認したいカラーコード6桁をおっしゃってください') .reprompt('確認したいカラーコード6桁をおっしゃってください') .getResponse(); }, }; //カラーコードインテント const ColorCodeHandler = { canHandle(handlerInput) { const request = handlerInput.requestEnvelope.request; return request.type === 'IntentRequest' && request.intent.name === 'ColorCode'; }, handle(handlerInput) { let value1 = handlerInput.requestEnvelope.request.intent.slots.first.resolutions.resolutionsPerAuthority[0].values[0].value.id; let value2 = handlerInput.requestEnvelope.request.intent.slots.second.resolutions.resolutionsPerAuthority[0].values[0].value.id; let value3 = handlerInput.requestEnvelope.request.intent.slots.third.resolutions.resolutionsPerAuthority[0].values[0].value.id; let value4 = handlerInput.requestEnvelope.request.intent.slots.fourth.resolutions.resolutionsPerAuthority[0].values[0].value.id; let value5 = handlerInput.requestEnvelope.request.intent.slots.fifth.resolutions.resolutionsPerAuthority[0].values[0].value.id; let value6 = handlerInput.requestEnvelope.request.intent.slots.sixth.resolutions.resolutionsPerAuthority[0].values[0].value.id; const colorCode = value1 + value2 + value3 + value4 + value5 + value6; const url = 'phpコードのあるサーバ/?code=' + colorCode; //ディスプレイ表示 if (supportsDisplay(handlerInput) ) { var speechText = 'カラーコード、' + value1 + '、' + value2 + '、' + value3 + '、' + value4 + '、' + value5 + '、' + value6 + 'の色を表示しています。' + '確認したいカラーコード6桁をおっしゃってください'; const myImage = new Alexa.ImageHelper() .addImageInstance(url) .getImage(); handlerInput.responseBuilder.addRenderTemplateDirective({ type: 'BodyTemplate1', token: 'string', backButton: 'HIDDEN', backgroundImage: myImage, title: '#' + colorCode, }); return handlerInput.responseBuilder .speak(speechText) .reprompt('確認したいカラーコード6桁をおっしゃってください') .getResponse(); }else{ speechText = 'カラーコードは' + value1 + '、' + value2 + '、' + value3 + '、' + value4 + '、' + value5 + '、' + value6 + 'ですが。画面の無いデバイスのため、色はお見せできません。' + '申し訳ございません。彩りあるいち日を'; return handlerInput.responseBuilder .speak(speechText) //.withSimpleCard('カラー de コード', 'カラーコードは') .getResponse(); } }, }; //キャンセル・停止時 const ExitHandler = { canHandle(handlerInput) { const request = handlerInput.requestEnvelope.request; return request.type === 'IntentRequest' && (request.intent.name === 'AMAZON.CancelIntent' || request.intent.name === 'AMAZON.StopIntent'); }, handle(handlerInput) { return handlerInput.responseBuilder .speak('ありがとうございました。彩りあるいち日を') .withShouldEndSession(true) .getResponse(); }, }; const SessionEndedRequestHandler = { canHandle(handlerInput) { const request = handlerInput.requestEnvelope.request; return request.type === 'SessionEndedRequest'; }, handle(handlerInput) { console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`); return handlerInput.responseBuilder.getResponse(); }, }; //エラー時 const ErrorHandler = { canHandle() { return true; }, handle(handlerInput, error) { console.log(`Error handled: ${error.message}`); return handlerInput.responseBuilder .speak('申し訳ございません。正しいカラーコードが聞き取れませんでした。もう一度お願いします') .reprompt('確認したいカラーコード6桁をおっしゃってください') .getResponse(); }, }; // スキルが画面付きデバイスで動作している時は true を返す。 function supportsDisplay(handlerInput) { var hasDisplay = handlerInput.requestEnvelope.context && handlerInput.requestEnvelope.context.System && handlerInput.requestEnvelope.context.System.device && handlerInput.requestEnvelope.context.System.device.supportedInterfaces && handlerInput.requestEnvelope.context.System.device.supportedInterfaces.Display return hasDisplay; } const skillBuilder = Alexa.SkillBuilders.standard(); exports.handler = skillBuilder .addRequestHandlers( GetNewFactHandler, ColorCodeHandler, HelpHandler, ExitHandler, SessionEndedRequestHandler ) .addErrorHandlers(ErrorHandler) .lambda(); |
起動時のインテント、エラーやキャンセル、ヘルプのインテント発動時の動作をそれぞれ記載しています。
supportsDisplay()でスキルが画面付きデバイスで動作しているかを判断しています。
ColorCodeインテントでカラーコードを識別して、phpで動的に1ドットの対応する色のpng画像を生成して、画面付きデバイスであれば画面に表示させます。
スロットタイプLIST_OF_NUMでスロットIDを追加しておいたのでカラーコードの文字列生成を容易にできました。
スキル停止時に画面表示を明確に切らないとダメですよと申請時にリジェクトされました。全然修正がわからなくてググりにググって以下を見つけました。
画面表示付きのskillを作成したが、対話が終了しても画面が消えない
こちらを参考にindex.jsの101行に .withShouldEndSession(true) を追加で、スキル停止時に画面表示も止まるようになりました。
index.php
1ドットの色画像を生成するphpコードです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?php // カラーコード $colorcode = $_GET['code']; $red = hexdec(substr($colorcode, 0, 2)); $green = hexdec(substr($colorcode, 2, 2)); $blue = hexdec(substr($colorcode, 4, 2)); //ヘッダーの設定 header("Content-type: image/png"); //指定した大きさの黒画像を生成 $img = imagecreatetruecolor(1, 1); //背景色の指定 $background_color = imagecolorallocate($img, $red, $green, $blue); //画像を背景色で塗る imagefilledrectangle($img, 0, 0, 300, 300, $background_color); //画像の出力 imagepng($img); //画像の消去(メモリの解放) imagedestroy($img); ?> |
参考
スキル動作検証
スキルの動作検証はAlexa DeveloperコンソールのAlexaシミュレータや
Fire TVで行いました。
Alexaスキル「カラーデコード」
こんな感じで動作します。Echo Spot持ってないのでFire TVで確認。 pic.twitter.com/R2Hp9MtjCT— HomeMadeGarbage (@H0meMadeGarbage) 2019年2月4日