Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Alexa Hostedおさらい&Blueprintsでスキルリリースしてみた / Alexa Hosted & Blueprints review

Alexa Hostedおさらい&Blueprintsでスキルリリースしてみた / Alexa Hosted & Blueprints review

【大阪】スマートスピーカーミーティング 2019/02/28(https://osaka-driven-dev.connpass.com/event/117481/) のLTの資料です

Kuniaki Shimizu

February 28, 2019
Tweet

More Decks by Kuniaki Shimizu

Other Decks in Technology

Transcript

  1. JAWS DAYS 2019に行ってきました。 - コンテナ人気すごい。でもAlexa関連も良かったです。 - Alexaハンズオン最高。資料はQiitaで公開されてます。オススメ。 →「Qiita: CodeStar+Twilio PayでAlexa経由の電話決済を実装する」

     (by 岡本さん) - パブリックスペースでの導入事例を作りたい - 導入事例(商店街・ホテル)の現地レポをブログ載せてます。 - Alexa居酒屋、池袋パルコ、名古屋松坂屋、行きたい、、、
  2. 自分向けまとめ • スキル開発に慣れてくるといろいろやりたくなる。 ◦ 静的ファイル、セッション、 、などなど ◦ ここが最初のハードル • いろいろ調べるけど、情報が多すぎる。

    ◦ リソース使う前提のものが多い ◦ でそれできるんだっけ? • 楽したい ◦ 使う場合に特化した情報がほしい ◦ コード頻繁に書かないので、コピペで済ませたい • とはいうものの、 ◦ まあ一応 も知って起きたいよね。 ◦ 違いを把握しておけばよい 完全にLGTMなまとめです!
  3. 静的ファイル(これまで) S3でホストが一般的 リージョン選択可能、東京リージョンが一般的 バケットにCORS設定必要 オブジェクトにパブリックアクセス権を付与 コードからは画像、音声、動画それぞれのやり方で呼び出す const imageUrl = 'https://s3-ap-northeast-1.amazonaws.com/xxxxxx/sample.png';

    const myImage = new Alexa.ImageHelper() .addImageInstance(imageUrl) .getImage(); const url = 'https://s3-ap-northeast-1.amazonaws.com/xxxxxx/sample.mp4'; return handlerInput.responseBuilder .speak(speechText) .addVideoAppLaunchDirective(url, 'title', 'subtitle') .getResponse();
  4. 静的ファイル( ) Alexa Hosted専用のS3でホスト。スキルごとにバケットが用意される。 リージョンは米国東部(バージニア北部)のみ。 → レイテンシー注意 設定変更一切不可(アクセス権付与、バージョニング、暗号化)。 → 逆に言うと何も気にせずアップロードだけで良い

    コードからは署名付きURLで呼び出す必要があり。 → 有効時間60秒固定、変更不可。問題になるケースがあるかも? const Util = require('util.js'); ... handle(handlerInput){ const pictureUrl = Util.getS3PreSignedUrl("Media/picture.jpg"); return handlerInput.responseBuilder .speak('画像付きのハローワールドです ') .withStandardCard('card title', 'card text', pictureUrl) .getResponse(); }
  5. 静的ファイル( ) const AWS = require('aws-sdk'); const s3SigV4Client = new

    AWS.S3({ signatureVersion: 'v4' }); module.exports.getS3PreSignedUrl = function getS3PreSignedUrl(s3ObjectKey) { const bucketName = process.env.S3_PERSISTENCE_BUCKET; const s3PreSignedUrl = s3SigV4Client.getSignedUrl('getObject', { Bucket: bucketName, Key: s3ObjectKey, Expires: 60*1 // the Expires is capped for 1 minute }); console.log(`Util.s3PreSignedUrl: ${s3ObjectKey} URL ${s3PreSignedUrl}`); return s3PreSignedUrl; }
  6. 静的ファイル( ) const AWS = require('aws-sdk'); const s3SigV4Client = new

    AWS.S3({ signatureVersion: 'v4' }); module.exports.getS3PreSignedUrl = function getS3PreSignedUrl(s3ObjectKey) { const bucketName = process.env.S3_PERSISTENCE_BUCKET; const s3PreSignedUrl = s3SigV4Client.getSignedUrl('getObject', { Bucket: bucketName, Key: s3ObjectKey, Expires: 60*1 // the Expires is capped for 1 minute }); console.log(`Util.s3PreSignedUrl: ${s3ObjectKey} URL ${s3PreSignedUrl}`); return s3PreSignedUrl; } ・util.jsでaws-sdkを使っている ・よいところ   - 環境変数からS3のバケット名を とってきている - Github等でコードを公開する場合、 このほうが都合が良い - 普通にLambda使う場合でもこのほう がいいんでは?
  7. セッション(これまで) 3種類 Request attributes (1回のリクエスト中) Session attributes (1回のセッション中) Persistent attributes

    (セッション跨ぎ) Persistent attributes DynamoDBが一般的(S3でもできなくはない) LambdaのIAMロールにDynamoDBアクセス権付与 DynamoDBPersistentAdapterを使う SkillBuilders内でテーブル名を指定 テーブル自動作成も可(要権限) 読み書きする
  8. セッション(これまで) const Alexa = require('ask-sdk'); ・・・ exports.handler = Alexa.SkillBuilders.standard() .addRequestHandlers(

    ・・・ .withTableName("sampleTableName") .withAutoCreateTable(true) .lambda(); const Alexa = require('ask-sdk-core'); const Adapter = require('ask-sdk-dynamodb-persistence-adapter'); exports.handler = Alexa.SkillBuilders.custom() .addRequestHandlers( ・・・ .withPersistenceAdapter( new Adapter.DynamoDbPersistenceAdapter( {tableName: 'sampleTableName', createTable: true })) .lambda(); (全部入り) を使う場合 (ミニマム) を使う場合
  9. セッション(これまで) async handle(handlerInput) { ・・・ const attr = await handlerInput.attributesManager.getPersistentAttributes();

    const info = attr.info; ・・・ } async handle(handlerInput) { ・・・ const attr = await handlerInput.attributesManager.getPersistentAttributes(); attr.info = "foo"; handlerInput.attributesManager.setPersistentAttributes(attr); await handlerInput.attributesManager.savePersistentAttributes(); ・・・ } 読み 書き
  10. セッション( ) • Persistent attributes ◦ DynamoDBは使えない、S3のみ ◦ S3-persistence-adapterを使う ▪

    パッケージ追加必須 ▪ バケット名を指定する必要がない ▪ バケット内にユーザIDごとのファイルが作成 される
  11. セッション( ) const Alexa = require('ask-sdk-core'); const persistenceAdapter = require('ask-sdk-s3-persistence-adapter');

    ・・・ exports.handler = Alexa.SkillBuilders.custom() .addRequestHandlers( ・・・ .withPersistenceAdapter( new persistenceAdapter.S3PersistenceAdapter( {bucketName:process.env.S3_PERSISTENCE_BUCKET})) .lambda(); .lambda(); 読み書きは 使う場合と同じ
  12. セッション( ) const Alexa = require('ask-sdk-core'); const persistenceAdapter = require('ask-sdk-s3-persistence-adapter');

    ・・・ exports.handler = Alexa.SkillBuilders.custom() .addRequestHandlers( ・・・ .withPersistenceAdapter( new persistenceAdapter.S3PersistenceAdapter( {bucketName:process.env.S3_PERSISTENCE_BUCKET})) .lambda(); .lambda(); 読み書きは 使う場合と同じ ・util.jsを思い出してほしい ・環境変数からS3のバケット名を とってきている
  13. セッション( ) exports.handler = Alexa.SkillBuilders.custom() .addRequestHandlers( ・・・ .withPersistenceAdapter( .withPersistenceAdapter( new

    persistenceAdapter.S3PersistenceAdapter( {bucketName:process.env.S3_PERSISTENCE_BUCKET, objectKeyGenerator: deviceIdKeyGenerator})) .lambda(); function deviceIdKeyGenerator(requestEnvelope) { if (requestEnvelope && requestEnvelope.context && requestEnvelope.context.System && requestEnvelope.context.System.device && requestEnvelope.context.System.device.deviceId) { return requestEnvelope.context.System.device.deviceId; } throw 'Cannot retrieve device id from request envelope!'; } デバイスごとにセッションを保存したい場合
  14. セッション( ) exports.handler = Alexa.SkillBuilders.custom() .addRequestHandlers( ・・・ .withPersistenceAdapter( .withPersistenceAdapter( new

    persistenceAdapter.S3PersistenceAdapter( {bucketName:process.env.S3_PERSISTENCE_BUCKET, objectKeyGenerator: deviceIdKeyGenerator})) .lambda(); function deviceIdKeyGenerator(requestEnvelope) { if (requestEnvelope && requestEnvelope.context && requestEnvelope.context.System && requestEnvelope.context.System.device && requestEnvelope.context.System.device.deviceId) { return requestEnvelope.context.System.device.deviceId; } throw 'Cannot retrieve device id from request envelope!'; } デバイスごとにセッションを保存したい場合 objectKeyGeneratorにIDを生成する 関数を指定する デバイスIDの場合
  15. セッション( ) • Persistent attributes ◦ DynamoDBは使えない、S3のみ → 結果整合性には注意かも ◦

    S3-persistence-adapterを使う ▪ パッケージ追加必須 ▪ バケット名を指定する必要がない → 環境変数も勝手に設定されるので便利 → コード内に書く必要がなくて便利 ▪ バケット内にユーザIDごとのファイルが作成 される → デバイスIDも可能、いろいろできる 再掲 DynamoDB高いので普通に Lambda 使う場合でもS3でやればいいという声 もあり
  16. 無料枠( ) AWS Lambda - スキルの利用頻度 (時間&回数) リクエスト100万件/月 コンピューティング時間 320万秒/月

    AWS CodeCommit - コードのサイズと更新頻度 ストレージ 50 GB Gitリクエスト 10,000件/月 ほとんど問題ないと思うけど、音声・動画ファイルを使う場合と永続 セッションを使う場合は気をつけたほうが良いかも。 Amazon S3 - スキル内からのファイル の利用頻度 ストレージ容量 5GB GETリクエスト 20,000件/月 PUTリクエスト 2,000件/月 データ転送量 15 GB/月
  17. • 予め用意されたテンプレートから、必要な値だけを変更 して、スキルを作成する。 • テンプレートいろいろ ◦ クイズ ◦ ◦ トリビア

    ◦ フラッシュブリーフィング ◦ などなど、現在 種類以上 • 現時点( 年 月末) オンリー ◦ アカウントでしか作れない ◦ スキルしかリリースできない
  18. • 超かんたん! ◦ テンプレベースだからバグることがない ◦ 本当の意味でスキルの中身に集中できる ◦ テンプレの種類が豊富、ありがちなものはほぼカバー ▪ よくある案内スキルとかならすぐできる

    ◦ 審査リジェクトの可能性は低い • デメリット ◦ 日本ではまだ使えない(そのうち使えるようになるはず) ◦ 多言語もできない ◦ 凝ったことはできない ◦ 統計情報へのアクセスができない • その他 ◦ テンプレを作って公開できるといいな