Amazon Lex でサンプルbotを試した

Amazon Lex

Lexがついに一般公開されました。
Alexa Voice Serviceで色々と頑張らなくても手軽にAlexaを使えそうです。

サンプルbotのモデル

公式ドキュメントのExercise2を通して、Lexの使い方を学んでいきたいと思います。

Pizza Ordering Bot

早速作っていきましょう。
※Lexはus-east-1(バージニア北部)のみで利用可能です。

1. lambda関数の用意

1-1: IAMロールの作成

マネジメントコンソールからIAMを選択し、サイドバーのロールから新しいロールの作成に進みましょう。
ロールタイプはAWSサービスロールのlambdaを選んでください。
ポリシーのアタッチ画面で検索窓に lex と入力し、
AmazonLexRunBotsOnlyを選択してロールを作成します。

スクリーンショット 2017-04-23 9.31.06.png

1-2: 関数の作成

ここを参考に作れば問題ないです。

ざっくり言うと lambda→ブランク関数→Node.js v4.3 を選択し、ドキュメントのコードをそのまま貼り付ければ問題ないです。
ロールについては、既存のロールを選択より先程作成したものをアタッチしてください。

2. Lex botの作成

コンソールの LexBotsCreate からbotを作成します。
名前は適当に(e.g. PizzaOrderingBot)、好きな声を選んで、Session timeout は5分で。Child-DirectedNo で大丈夫です。

3. SlotTypeとIntentの設定

3-1: Slotの追加

EditorタブのサイドバーからSlot typesにある+ボタンより新しいスロットを追加。
今回は以下のように追加します

  • Crusts というslotを作成し、valueに thickthin
  • Sizes というslotを作成し、valueに small, medium, large
  • PizzaKind というslotを作成し、valueに cheeseveg

※↓ではPizzaSizeになってますが、SizesでもPizzaSizeでも好きな名前をつけてください
スクリーンショット 2017-04-23 8.58.28.png

※ Slotとは

Alexaの質問に対して答えるべき単語のまとまり、といった感じです。
(Alexaが回答として期待している単語のまとまりと言うべきか。)
主要な都市や日時、空港や俳優などAmazonが用意しているものも利用可能です。
Amazonが用意したBuilt-in SlotはAMAZON.xxxで定義されており、インストールなどの必要もありません。

3-2: Intentの追加

EditorタブのサイドバーからIntentにある+ボタン、Create New Intentより作成しましょう。

3-2-1: Sample utterancesの編集

ここに入れた文章でAlexaに呼びかけると、反応して処理を開始します。
以下のような文章を追加します。

  • I want to order pizza please
  • I want to order a pizza
  • I want to order a {pizzaKind} pizza
  • I want to order a {size} {pizzaKind} pizza
  • I want a {size} {crust} crust {pizzaKind} pizza
  • Can I get a pizza please
  • Can I get a {pizzaKind} pizza
  • Can I get a {size} {pizzaKind} pizza
3-2-2: Slotsの編集

作成したslotを追加していきます。
Nameで登録した名前は、上のutterancesの文章や、lambdaの処理で利用する際のkeyとなります。
Slot typeは先程作成したものを選択、PromptにはAlexaから投げられる質問を入れます。
また、Requiredにはすべてチェックを入れましょう。

※ Promptの例
– pizzaKind: Do you want a cheese or veg pizza?
– size: What size pizza?
– crust: Thick or thin crust?

スクリーンショット 2017-04-23 9.37.54.png

3-3: その他設定

FulfillmentでAWS Lambda functionを選択し、先程作ったlambda関数を選択します。
Lambda initialization and validationConfirmation promptはとりあえずそのまま空白で問題ありません。

※ Intentとは

utterancesに追加した文章で我々が呼びかけるとAlexaが質問を投げかけてくるので、それに対してslotに入ってる単語で回答。また、promptでAlexaは別の質問を行いデータをさらに集める。それらのデータを用いてAlexaが回答、またはlambdaに処理が投げられる。
このような一連の流れをIntentとしてまとめています。

4. テスト

早速テストしましょう。画面上部の Build ボタンよりビルド完了後、画面右下のチャット欄からチェックできます。

スクリーンショット 2017-04-23 9.49.23.png

ビルド後はIntentが保存されて編集できなくなるのですが、画面上部でversionをLatestに変更すると再び編集が可能になります。

スクリーンショット 2017-04-23 9.37.39.png

5. おつかれさまでした😌

lambda関数の動きについては触れていませんが、今後何か書くかもしれません。
あとは音声入力などについても調べたいと思います。
(Alexa Voice ServiceのSkill Kitに追加できないのかしら…)

続きを読む

Amazon Dash ButtonをHackするのはJust do itでしょ、と思って手を出したら落とし穴にどハマった件

Exective Summary

そもそもやりたかったこと:

Amazon Dash Buttonを押して、AWS上の全EC2を停止する。
(利用料が個人レベルでない上に、お小遣いが少ないもので…)

前提・制約:

(甲) 我が家にはWindows10マシンしかない(Linuxマシンはない、という意味)。
(乙) 一方、AWS Dash ButoonをHackするツールとしては、Linux/OS X向けNode.js系ツールが主流らしい([1],[3],[5],[9])。
⇒Amazon Dash Buttonは、ボタンを押すとARPリクエストを送出(ブロードキャスト)する。それを同じLANで待ち受けて検知できるのがDasher。その検知をトリガーにして任意の処理(WebAPIを呼び出す、等)を起動できる。
(丙) 我が家にはAWS Dash Buttonが2つある。それは、購入商品の指定/設定を、
  (A) 意図的に途中でやめてあるモノ
  (B) 無邪気に最期まで完了した(知らずに済ませてしまった)モノ
  の2種類だ。
(丁) 呼び出されたら「全EC2を停止する」というAPIは、AWS IoT/API Gateway/Lambdaのサーバレスアーキで作成済み。
⇒世間の情報も豊富だし、小1時間程度でできるっしょーとたかをくくる。

俺的に考え得た・試した選択肢

①Windows10+Dasher・・・×
②Windows10+Bash on Windows+Dasher・・・×
③Windows10+Cygwin+Dasher・・・×
④Windows10+win-node-dash-button・・・×
⑤Windows10+Vagrant+VirtualBox+Ubuntu+Dasher・・・○
⑥Windows10+Docker-Machine+VirtualBox+Boot2Docker+Dasher・・・×
⑦Windows10+Docker-Machine+VirtualBox+Boot2Docker+Docker+Ubuntu+Dasher・・・未

紆余曲折の結果が…コレだ…ワン・ツー・スリー…

⑤Windows10+Vagrant+VirtualBox+Ubuntu+Dasher

学べる(学べた)コト

・Git
・node.js/npm/node-gyp/node_pcap
・python/pip
・Bash on Windows/Cygwin/Ubuntu
・Docker-Machine/Vagrant/VirtualBox
・Wireshark/tcpdump
・NW/ARP/DNS

嵐の後の所感

やってみた結果として、Amazon Dash Buttonは幅広く技術を体験するのに良いテーマだったという実感。
(「フェルマーの最終定理」と同じ構図?定理の意味の理解はトリビアルだが、その証明を理解するには色々な数学的知識が必要!)
次は『Dash Button(丙)-(B)』のHackを試みる…(方向性としては『DNSサーバをポジティブに偽装する』)
…まあ、AWS IoT Buttonが日本でも発売されたら、それを使うけどね…

俺が落ちた落とし穴の各論

以下、詳細:(細々と続く)

参考情報

[1] Amazon Dash ButtonをただのIoTボタンとして使う
[2] node-dash-button@GitHub
[3] Amazon Dashボタンのハックにおける期待と落胆(Wi-Fi編)
[4] dasher@GitHub
[5] Amazon Dash Buttonを(正しくない方向で)使ってみた
[6] Dash Button for Node@GitHub
[7] node_pcap
[8] node_pcapのWindows7対応Folk
[9] win-node-dash-button
[10] Windowsでnpm installしてnode-gypでつまずいた時対処方法
[11] これはすごい!分解とパケット解析で分かったAmazon Dash Buttonの「本気度」
[12] これはすごい!Amazon Dash Buttonをプレゼンに使う
[13] これはすごい!Amazon Dash Buttonでツイートできた

続きを読む

Mastodonのrake mastodon:dailyをLambdaで定期実行する

ドキュメント
https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Production-guide.md
これやらないとこういうことが起きるので大事。
http://cryks.hateblo.jp/entry/2017/04/18/125351
まさに自分のサーバーで起きて大変だった…。

環境

前回のAWS EC2 Container Service
http://qiita.com/kawax/items/5307b58e549dd9cc3928

これでcronはどうやるんだろうと調べたけど結構簡単だった。

ECSタスク

aws-daily.yml

version: '2'
services:
  web:
    image: {image}
    env_file: .env.production
    command: bundle exec rake mastodon:daily
    mem_limit: 536870912
    ports:
      - "3000"
ecs-cli compose -f aws-daily.yml --project-name mastodon-daily create

Lambda

ランタイム:Node.js 6.10
ブランク関数で新規に作っていく。

トリガーで CloudWatch イベント - スケジュール を選択。
ルール名やルールの説明は適当なものを。
スケジュール式は rate(1 day)

ロールはカスタムロールの作成から新規ロールを作った後で
管理ポリシーAmazonEC2ContainerServiceFullAccessを付ける。
インラインポリシーoneClick_lambda_basic_executionも付いてるはず。
この辺は後でLambda 関数が実行できるポリシーを付ける。

コード

clusterとtaskDefinitionを自分のものに書き換える。

var AWS = require('aws-sdk');
var ecs = new AWS.ECS();

exports.handler = (event, context, callback) => {
    var params = {
        cluster: "mastodon", 
        taskDefinition: "ecscompose-mastodon-daily"
    };
    ecs.runTask(params, function(err, data) {
        if (err) console.log(err, err.stack); // an error occurred
        else     console.log(data);           // successful response
    });
};

テストしてみてエラーが出てなければトリガーを有効化して終わり。
エラーが出てる場合はロールを確認する。

続きを読む

AWS Lambdaを利用してChatWorkにメッセージ送信

環境

AWS Lambda

  • Node.js 6.10
  • Lambdaの実行権限だけつけて、No VPC環境で実行(単にめんどくさかった。)

ChatWorkでやること

この辺はChatWorkのドキュメント見てください・・・

実装

外部モジュールは使わない。

index.handler
var https = require ('https');
exports.handler = function(event, context) {
    var body = 'body=' + event.message;

    var options = {
        host: 'api.chatwork.com',
        path: '/v2/rooms/'+ event.room_id +'/messages',
        method: 'POST',
        headers: {
            'X-ChatWorkToken': process.env.TOKEN,
            'Content-Type': 'application/x-www-form-urlencoded',
            'Content-Length': body.length
        }
    };


    var req = https.request(options, function (res) {
        res.on('data', function (chunk) {
            // console.log('--- on  ' + (+new Date() * 0.0001) + ' ---');
            // console.log(chunk.toString());
        }).on('error', function (e) {
            // console.log('--- err ' + (+new Date() * 0.0001) + ' ---');
            // console.log('ERROR:' + e.stack);
        });
    });

    // console.log('--- req ' + (+new Date() * 0.0001) + ' ---');
    req.write(body);

    // console.log('--- end ' + (+new Date() * 0.0001) + ' ---');
    req.end();
};

event

event
{
    "room_id" : "{ChatWorkの送信対象のチャンネル}",
    "message" : "投稿するメッセージ"
}

Lambda環境変数

  • TOKEN

    • 自分のAPIキー

TODO

  • API Gateway経由してWebhookをする。
  • Jenkinsから通知
  • GitHubから通知
  • JIRAから通知
  • 日時レポート的なやつの発行

経緯

SlackからChatWorkを使わざるをえなくなったためWebhookを移行するために泣く泣く調べてる最中なう。
ということで、サーバレスにしようということでAWS Lambdaで環境構築メモを残しておけば誰かの役に立つかもしれないと(いないか。。。)

参考

Tattin’s App History – node.jsでhttpのPOSTリクエスト

続きを読む

AWS Lambdaの初回起動が遅い問題を解決する魔法の設定

たまーにしか実行しないようなプログラムこそ、サーバーレスで実行したいですよね。

ところがサーバーレスの代表格であるAWS Lamdaで、ライブラリを含んたzipをアップロードすると初回実行が非常に遅いのです。
Lambdaは一定時間実行されないと、アンロードされてしまうので、たまーにしか実行しないようなケースでは毎回遅い初回実行になってしまいます。

特にAPI Gatewayを通してLambdaを実行する場合はタイムアウトが上限30秒なので、PhantomJs等、重い処理が入っている場合は、初期化や処理中にタイムアウトしてしまいます。

色々試した結果、以下の方法で解決しました。

解決方法

Lambda関数のトリガにCloudWatchイベントスケジュールで五分毎の実行を入れるだけ!

image

※魔法の設定とか書いてごめんなさい

手順(要らないかもしれないけど念のため)

1.Lamda関数のトリガを開く

image

2.トリガ追加をクリック

image

3.トリガーを追加でClundWatchイベント – スケジュールを選択

image

4.ルール名を適当に入れて、スケジュール式を「rate(5 minute)」を指定して、送信ボタン

image

5.こんな感じになればOK

image

6.関数側はパラメータ無しの場合、空振りするようにしておくと良い

ソースはnode.jsであれば以下のような感じ。

index.js
exports.handler = (event, context, callback) => {

    // パラメータがない場合、空振りさせる(判定方法は適宜変更)
    if (event.sampleParam === undefined) {
        console.log(`exec by timer.`);
        callback(null, {"result":`NOP`});
        return;
    }

    console.log(`exec by api.`);
    // ☆☆☆ APIの処理 ☆☆☆
    // ☆☆☆ APIの処理 ☆☆☆
    // ☆☆☆ APIの処理 ☆☆☆
    callback(null, {"result":`OK`});

};

補足

  • 同時実行が必要な場合は複数のスケジュールを入れてキープおくと良いです
  • コストについては、五分毎の場合、一日288回増なので気にしなくて良さそうです
  • 五分毎でキープしてますが何分まで伸ばしてもアンロードされないかは調べてません

続きを読む

lammaで始める等身大のAWS Lambda

(https://medium.com/@ayemos/lamma%E3%81%A7%E5%A7%8B%E3%82%81%E3%82%8B%E7%AD%89%E8%BA%AB%E5%A4%A7%E3%81%AEaws-lambda-d032addc5f4d より転載)

TL;DR

AWS Lambda

Amazon S3上にcsvファイルがアップロードされたら、その集計データをS3上の別のcsvファイルに保存したい

毎週金曜日の21:00に特定のタグがついたEc2インスタンスの過去数時間のCPUUtilization値をチェックして、アイドル状態にあるものは自動的にシャットダウンしたい

などなど、AWS上に構築されたインフラシステムにおいて、あるトリガーが発生したときに、ちょっとしたロジックと実装でもって処理を継続したい、というシチュエーションに最適なサービスがAWS Lambdaです。

AWS Lambdaで予め用意された計算環境(python, Node.jsなどの言語環境と、 AWS SDKの各言語実装などが含まれる)を利用することで、EC2上に計算環境をプロビジョンする手間が省けたり、実行回数とその長さに基づいた課金システムで、非常に安価に利用できるなどの利点があります。

しかし、計算機環境の構築と付き合わなくなった一方で、実装された関数のLambda上でのバージョンコントロールやデプロイ/ロールバックが面倒であるという現状があり、実際apexやlamveryなど、Lambdaのマネジメントツールが開発されています。

lamma

https://github.co/ayemos/lamma
ruby製のAWS Lambdaのマネジメントツール。

すでにあるツールとの差別化という意味で「IoT、ChatBotなどの目的でAWS Lambdaをなるべく手軽に今すぐ使いたい」という人をターゲットに作っているつもりです。

$ gem install lamma
$ lamma init my_function --runtime=python2.7
Looks like you didn't specified role arn for the function.
Do you want me to create default IAM role and configure it (my_function-lamma-role)? (y/n) y
I, [2017-04-06T22:28:53.952278 #5027]  INFO -- : Creating role my_function-lamma-role
I, [2017-04-06T22:28:54.863304 #5027]  INFO -- : Checking attached role policies for my_function-lamma-role
I, [2017-04-06T22:28:55.243400 #5027]  INFO -- : Could not find AWSLambdaBasicExecutionRole policy. Attatching.
I, [2017-04-06T22:28:55.243449 #5027]  INFO -- : Attaching minimal policy (AWSLambdaBasicExecutionRole) to my_function-lamma-role
I, [2017-04-06T22:28:55.466092 #5027]  INFO -- : Done
      create  /workspace/my_function/lambda_function.py
      create  /workspace/my_function/lamma.yml
I, [2017-04-06T22:28:55.468021 #5027]  INFO -- : Initializing git repo in /workspace/my_function
$ ls
total 16
drwxr-xr-x   5 yuichiro-someya  staff  170  4  6 22:28 ./
drwxr-xr-x   3 yuichiro-someya  staff  102  4  6 22:28 ../
drwxr-xr-x  10 yuichiro-someya  staff  340  4  6 22:28 .git/
-rw-r--r--   1 yuichiro-someya  staff  357  4  6 22:28 lambda_function.py
-rw-r--r--   1 yuichiro-someya  staff  207  4  6 22:28 lamma.yml
$ lamma deploy -a production
Function my_function doesn't seem to be exist on remote.
Do you want me to create it? (y/n) y
I, [2017-04-06T22:29:14.113561 #9209]  INFO -- : Creating new function my_function...
I, [2017-04-06T22:29:14.123244 #9209]  INFO -- : Saved the build: /var/folders/kd/_chs6sw13jvg01hlq6nd50k00000gp/T/lamma/05f92074cf833092343cd5414754efef
I, [2017-04-06T22:29:14.448724 #9209]  INFO -- : Created new function arn:aws:lambda:ap-northeast-1::function:my_function
I, [2017-04-06T22:29:14.448780 #9209]  INFO -- : Publishing...
I, [2017-04-06T22:29:14.605540 #9209]  INFO -- : Published $LATEST version as version 1 of funtion: arn:aws:lambda:ap-northeast-1::function:my_function:1
Function alias PRODUCTION doesn't seem to be exist on remote.
Do you want me to create it? (y/n) y

とまあこんな感じに、
shell-session
gem install lamma

して、

lamma init my_function --runtime=python2.7

して、 lambda_function.py 編集して

lamma deploy -a production

とすると、my_functionとPRODUCTIONエイリアスがクラウド上に生成されます。便利。

一方で、init時に生成されたlamma.ymlは次のように設定値がまるっとはいってます。

$ cat lamma.yml
function:
  name: my_function
  role_arn: arn:aws:iam:::role/my_function-lamma-role
  description: Hello, world.
  timeout: 3
  memory_size: 128
  runtime: python2.7
  region: ap-northeast-1

また、複数回デプロイした後は、

lamma rollback -a production

でエイリアスを指定して(デプロイごとに1回のみ)ロールバックすることが出来ます。
(deploy時にエイリアス毎に古いバージョンに向けたエイリアス(LAST)を用意することで実現している。)

lammaの紹介は以上。issueを上げてもらえると開発頑張れます。

続きを読む

初めての Scrapy+LINE BOT+AWS lambda

ポプテピピックの最新話を通知してくれるLINE BOTを作ったよ!
ここから実際に使えます

ソースコードはGithubにあります。

※私が勝手に作った非公式botです。竹書房様、大川ぶくぶ先生は無関係です。
※もし問題があればすぐに停止します。

目次

  1. 何を作ったか?
  2. どうして作ろうと思ったか?
  3. どうやって作ったか?
  4. 参考にさせていただいた記事
  5. 今後の展望

何を作ったか?

  1. Scrapy Hubで更新情報をゲット → dynamodbに格納 → lambdaからLINE BOT APIを叩く
  2. Webhookでユーザのメッセージを受信 → AWS API Gateway → lambdaでランダム返信を作成 → LINE BOT APIを叩く

どうして作ろうと思ったか?

  • AWSとLINE BOT APIを使ってみたかった。
  • 会社の勉強会でScrapyを教わったので、復習がしたかった。
  • ポプテピピックの最新話がいつ更新されているのか分からなかったので、通知システムが欲しかった。

どうやって作ったか?

アーキテクチャーはこんな感じです。

1.更新通知機能
0406.PPTP_architecture01.png

2.ランダム返信機能
0406.PPTP_architecture02.png

苦労したところ

  • つなぎが大変
    Scrapyからdyanamodb, lambdaからLINE BOT APIなどなど…
    偉大な先人のQiitaと、github/gistで見つかったコードの切れ端に大いに助けられました。
     -> つなぎ込みの処理だけgithubにアップしている人もいる!まずは探して、可能なら拝借しよう!

  • 初めてのnode.jsが大変
    非同期処理、コールバック、アロー関数…
    普段使わない概念がたくさん出てきて大変。でも勉強になりました。

  • テストが大変
    疎通確認をするのにもインターネット経由(bot作りのの宿命…?)
    毎回統合テストちっくなので、バグ混在箇所を探すのが大変
    -> まずはcurlを使おう!

参考にさせていただいた記事

今後の展望

いずれLINE BOTでもクリエーターズスタンプを使えるようになるのかしら…?
その暁にはこのBOTからポプテピのスタンプを送りたい所存。

続きを読む