Slide 1

Slide 1 text

おさらい でスキル リリースしてみた

Slide 2

Slide 2 text

アジェンダ ● 自己紹介 ● おさらい ● おまけ) でスキルリリースしてみた

Slide 3

Slide 3 text

自己紹介

Slide 4

Slide 4 text

@kun432 通信事業者系ISPのインフラエンジニア 最近はWiFIのシステム開発・運用全般 - Twitter/Facebook/Github/はてなブログ/Alexa - ポートフォリオ: https://kun432.github.io/ I ❤

Slide 5

Slide 5 text

Alexa: 8 (JP:7, US:1) Google: 1 Clova: 1 今しがた一つリジェクトされました、、、 個までの道のりは長い、、、

Slide 6

Slide 6 text

JAWS DAYS 2019に行ってきました。 - コンテナ人気すごい。でもAlexa関連も良かったです。 - Alexaハンズオン最高。資料はQiitaで公開されてます。オススメ。 →「Qiita: CodeStar+Twilio PayでAlexa経由の電話決済を実装する」  (by 岡本さん) - パブリックスペースでの導入事例を作りたい - 導入事例(商店街・ホテル)の現地レポをブログ載せてます。 - Alexa居酒屋、池袋パルコ、名古屋松坂屋、行きたい、、、

Slide 7

Slide 7 text

おさらい

Slide 8

Slide 8 text

これまでの スキル開発 開発者コンソール 対話モデル設計 /エンドポイント 設定/公開申請 静的コンテンツ (画像/音声/動画) 永続データ等 アカウント アカウント バックエンド 実装 エラー時の 解析等 権限、ロー ルの管理

Slide 9

Slide 9 text

これまでの スキル開発 開発者コンソール 対話モデル設計 /エンドポイント 設定/公開申請 静的コンテンツ (画像/音声/動画) 永続データ等 アカウント アカウント バックエンド 実装 エラー時の 解析等 権限、ロー ルの管理

Slide 10

Slide 10 text

これまでの スキル開発 AmazonとAWSの両方のアカウントが必要。 Amazon.comのアカウント持っててハマる。 AmazonとAWSで画面行ったり来たり。 AWSのサービスごとに画面行ったり来たり。 AWSいろいろ知らなくていいことがたくさん出てくる。 - Lambdaでnpmパッケージ追加するならローカル環境必要。 - S3で静的ファイル扱うにはバケットのCORS設定が必要。 - S3、Alexaからはパブリックアクセス前提? - CloudWatch Logs見にくい。 - DynamoDB、RDBとは違う。 初心者にはやさしくない

Slide 11

Slide 11 text

そこで

Slide 12

Slide 12 text

スキルの作成、編集、公開がAlexa開発者コンソール で完結、ブラウザだけあればよい フロントエンド(対話モデル) バックエンド(Lambda相当) ファイルストレージ(S3相当) セッションストレージ(DynamoDB相当) ロギング(CloudWatch Logs相当) AWSアカウント不要、AmazonアカウントだけでOK 権限管理とかない(IAM) シンプル!

Slide 13

Slide 13 text

開発者 コンソール 相当 相当 相当 Amazon.co.jp アカウント

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

※カスタムスキルのみ ※ 分程度で作成される

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

必ず忘れないで実施!

Slide 19

Slide 19 text

これだけ

Slide 20

Slide 20 text

超簡単

Slide 21

Slide 21 text

さぁ、コードを 書こう!

Slide 22

Slide 22 text

その前に・・・

Slide 23

Slide 23 text

特有の やり方や制限がある

Slide 24

Slide 24 text

今日の本題

Slide 25

Slide 25 text

おさらい 自分向けまとめ

Slide 26

Slide 26 text

自分向けまとめ ● スキル開発に慣れてくるといろいろやりたくなる。 ○ 静的ファイル、セッション、 、などなど ○ ここが最初のハードル ● いろいろ調べるけど、情報が多すぎる。 ○ リソース使う前提のものが多い ○ でそれできるんだっけ? ● 楽したい ○ 使う場合に特化した情報がほしい ○ コード頻繁に書かないので、コピペで済ませたい ● とはいうものの、 ○ まあ一応 も知って起きたいよね。 ○ 違いを把握しておけばよい 完全にLGTMなまとめです!

Slide 27

Slide 27 text

画像、動画、音声、等 静的ファイル使いたい

Slide 28

Slide 28 text

静的ファイル(これまで) 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();

Slide 29

Slide 29 text

静的ファイル( ) 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(); }

Slide 30

Slide 30 text

静的ファイル( ) 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; }

Slide 31

Slide 31 text

静的ファイル( ) 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使う場合でもこのほう がいいんでは?

Slide 32

Slide 32 text

静的ファイル( )

Slide 33

Slide 33 text

静的ファイル( )

Slide 34

Slide 34 text

静的ファイル( )

Slide 35

Slide 35 text

静的ファイル( )

Slide 36

Slide 36 text

セッション使いたい

Slide 37

Slide 37 text

セッション(これまで) 3種類 Request attributes (1回のリクエスト中) Session attributes (1回のセッション中) Persistent attributes (セッション跨ぎ) Persistent attributes DynamoDBが一般的(S3でもできなくはない) LambdaのIAMロールにDynamoDBアクセス権付与 DynamoDBPersistentAdapterを使う SkillBuilders内でテーブル名を指定 テーブル自動作成も可(要権限) 読み書きする

Slide 38

Slide 38 text

セッション(これまで) 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(); (全部入り) を使う場合 (ミニマム) を使う場合

Slide 39

Slide 39 text

セッション(これまで) 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(); ・・・ } 読み 書き

Slide 40

Slide 40 text

セッション( ) ● Persistent attributes ○ DynamoDBは使えない、S3のみ ○ S3-persistence-adapterを使う ■ パッケージ追加必須 ■ バケット名を指定する必要がない ■ バケット内にユーザIDごとのファイルが作成 される

Slide 41

Slide 41 text

セッション( ) 必ず実施! npmパッケージを使いたい場合も同じです。

Slide 42

Slide 42 text

セッション( ) 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(); 読み書きは 使う場合と同じ

Slide 43

Slide 43 text

セッション( ) 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のバケット名を とってきている

Slide 44

Slide 44 text

セッション( )

Slide 45

Slide 45 text

セッション( )

Slide 46

Slide 46 text

セッション( ) “amzn1.ask.account.〜”というファイルが作成される ユーザID単位であることがわかる 中身を見たい場合はチェックしてダウンロード、テキストエディタ等 で見る(ブラウザからは見れない)

Slide 47

Slide 47 text

セッション( ) 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!'; } デバイスごとにセッションを保存したい場合

Slide 48

Slide 48 text

セッション( ) 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の場合

Slide 49

Slide 49 text

セッション( ) “amzn1.ask.device.〜”というファイルが作成される デバイスID単位であることがわかる

Slide 50

Slide 50 text

セッション( ) ● Persistent attributes ○ DynamoDBは使えない、S3のみ → 結果整合性には注意かも ○ S3-persistence-adapterを使う ■ パッケージ追加必須 ■ バケット名を指定する必要がない → 環境変数も勝手に設定されるので便利 → コード内に書く必要がなくて便利 ■ バケット内にユーザIDごとのファイルが作成 される → デバイスIDも可能、いろいろできる 再掲 DynamoDB高いので普通に Lambda 使う場合でもS3でやればいいという声 もあり

Slide 51

Slide 51 text

デバッグしたい

Slide 52

Slide 52 text

デバッグ( )

Slide 53

Slide 53 text

デバッグ( ) ここはそんなに変わらない。ロググループ探さなくてよいのは楽。

Slide 54

Slide 54 text

デバッグ( )※余談 ロググループの中を見ると、 codebuild のログが出てて、 AWSリソースがいろ いろいじられるさまが見えて面白い

Slide 55

Slide 55 text

無料枠について

Slide 56

Slide 56 text

無料枠( ) アカウントごとに適用 → スキル単位ではない → たくさんスキルを作る場合は注意! 超えた場合は1ヶ月の猶予期間内にAWSに要移行 → 事前に通知が来るらしい → エンドポイント変更が必要になるはず?再審査? 詳細は公式サイトを参照

Slide 57

Slide 57 text

無料枠( ) AWS Lambda - スキルの利用頻度 (時間&回数) リクエスト100万件/月 コンピューティング時間 320万秒/月 AWS CodeCommit - コードのサイズと更新頻度 ストレージ 50 GB Gitリクエスト 10,000件/月 ほとんど問題ないと思うけど、音声・動画ファイルを使う場合と永続 セッションを使う場合は気をつけたほうが良いかも。 Amazon S3 - スキル内からのファイル の利用頻度 ストレージ容量 5GB GETリクエスト 20,000件/月 PUTリクエスト 2,000件/月 データ転送量 15 GB/月

Slide 58

Slide 58 text

まとめ

Slide 59

Slide 59 text

まとめ AWSアカウント不要、開発者コンソールで完結する のでとても楽ちん ブラウザだけあればOK、ローカル環境構築不要 ハンズオンとかで良さげ 基本的なことはAlexa Hostedでも全部できる ハンズオンとかで良さげ ハンズオンとかで良さげ 個人レベル・小規模な開発なら問題なし それ以外はAWSで。

Slide 60

Slide 60 text

スキルを作って どんどん公開しよう!

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

No content

Slide 63

Slide 63 text

Any questions?

Slide 64

Slide 64 text

おまけ) でスキルリリースしてみた

Slide 65

Slide 65 text

No content

Slide 66

Slide 66 text

● 予め用意されたテンプレートから、必要な値だけを変更 して、スキルを作成する。 ● テンプレートいろいろ ○ クイズ ○ ○ トリビア ○ フラッシュブリーフィング ○ などなど、現在 種類以上 ● 現時点( 年 月末) オンリー ○ アカウントでしか作れない ○ スキルしかリリースできない

Slide 67

Slide 67 text

No content

Slide 68

Slide 68 text

● 超かんたん! ○ テンプレベースだからバグることがない ○ 本当の意味でスキルの中身に集中できる ○ テンプレの種類が豊富、ありがちなものはほぼカバー ■ よくある案内スキルとかならすぐできる ○ 審査リジェクトの可能性は低い ● デメリット ○ 日本ではまだ使えない(そのうち使えるようになるはず) ○ 多言語もできない ○ 凝ったことはできない ○ 統計情報へのアクセスができない ● その他 ○ テンプレを作って公開できるといいな

Slide 69

Slide 69 text

No content

Slide 70

Slide 70 text

※楽しかったので  超オススメ!

Slide 71

Slide 71 text

導入事例レポ

Slide 72

Slide 72 text

導入事例レポ

Slide 73

Slide 73 text

No content