Lambda関数の作成はじめにこんにちは。データサイエンスチームのmotchieです。Kitでしりとりスキルを作成していきます。SDK)を使い、アレクサとしりとりが出来るようにLambda関数を設定し、テストシミュレーターを使ってスキルをテストしてみます。SDKに関して、ステートハンドラによるインテント制御、セッションアトリビュートによる情報の保持、ElicitSlotディレクトリによる単一スロットのみの発話の認識、スロット値の取得、などの方法を見ていきます。形態素解析器kuromoji.jsによる品詞判定や読み仮名取得の方法や、Lambdaで実行する際の注意点も見ていきたいと思います。前提この記事は2になります。アカウント作成~対話モデルの設定まで手順はこちらの記事をご覧ください。Node.jsデプロイパッケージの作成node.jsのプロジェクト用にディレクトリを作り、必要なファイルを作成していきます。最終的な関数パッケージの中身は以下のようになります。npmによるパッケージの取得まず、必要なnode.jsのパッケージのインストールしていきます。node.jsをこれからインストールする場合は、node.jsのバージョン管理が容易なnvmでインストールするのがオススメです。versionsパッケージのインストールにはnpmを用います。SDKとkuromoji.jsのパッケージを取得します。パッケージ定義の作成。パッケージのインストール作成されたpackage.jsonは以下のような内容になっているかと思います。エンドポイントの作成アプリのメイン部分になるエントリポイントを作成していきます。index.jsを作成し、以下の内容を貼り付けます。"しりとりスキルへようこそ。"ゲームを始めるには、まず、「しりとり」と言ってみてください。"聞き取れませんでした。"続ける場合は「はい」、やめる場合は「いいえ」、と言ってください。"しりとりを終了します。"返せる言葉がありません。"しりとりを再開します。"次の単語を入力してください。"単語が取得できませんでした。"違う単語を試してみてください。"、は使えない言葉です。名詞一単語で答えてください。"単語の読みがなが取得できません。"違う単語を試してみてください。"は既に使われた単語です。入力単語が「ん」で終わる場合。"は、「ん」で終わる単語ですね。"しりとりは私の勝ちです。返せる単語がない場合。SDKの使い方については、こちらの記事を参考にさせていただきました。SDKの使い方について見ていきたいと思います。ステートハンドラによるインテントの制御アレクサとユーザーとの会話が複数回にわたるスキルでは、会話の段階によって呼び出せるインテントを制御する仕組みが必要になります。しりとりスキルでも、スキル開始時はしりとりゲーム中のインテントSiritoriIntentは呼び出せないようにし、ヘルプが呼び出された時はAmazon.YesIntentでしりとりを終了する、などといったインテント制御を行っています。SDKではステートという仕組みを用います。ステートごとにステートハンドラを定義し、会話が特定の段階(ステート)の場合に呼び出せるインテントを、ステートハンドラごとに定義します。ステートハンドラの実装については、こちらを参考にさせていただきました。"_HELPMODE",};しりとりスキルではステートとして、しりとりスタート時のSTARTMODE、しりとりゲーム中のSIRITORIMODE、ヘルプが呼び出された際のHELPMODEを定義しました。{起動時は何もステートを持たないため、newSessionHandlersのハンドラのインテントが呼ばれます。this.handler.stateにステートの値を代入することで、そのステートに紐付くステートハンドラのインテントが呼び出されるようになります。ステートハンドラは、Alexa.CreateStateHandlerメソッドでステートとハンドラを設定して作成します。helpStateHandlers);また、ステートハンドラは、通常のハンドラと同じように、alexa.registerHandlersメソッドで登録します。セッションアトリビュートによる情報の保持アレクサとユーザーとの会話が複数回にわたるスキルでは、ユーザーから入力された情報を保存しておき、後で参照できる仕組みが必要です。SDKではセッションアトリビュートによって、会話(セッション)をまたいで情報を保持することが出来ます。previousWords;しりとりスキルでは、セッションアトリビュートの値として既出単語の配列を保持しています。しりとり処理ごとに、this.attributesの要素から参照、配列に新しい単語を加えて更新し、this.attributesの要素に代入し直しています。レスポンスアクションによる複数回のやりとりアレクサがレスポンスを返した後、セッションを維持してユーザーから次の返答を待つか、返答を待たずにスキルを終了するか、2種類のアクションが考えられます。これらのアクションは、emitメソッドの引数で指定します。SURRENDER_MESSAGE);:tellを指定し、単発のレスポンスを返します。発話が終わるとセッションが終了し、スキルが終わります。speechOutput);:askを指定すると、レスポンスを返した後、ユーザーからの応答を待ち、セッションを維持します。複数回の会話を行う際には、基本的にこの:askを指定します。answer);:elicitSlotを指定することで、レスポンスを返した後、セッションを維持して、特定のスロット値に関するユーザーの返答を待つことができます。通常は、単一スロット値のみの発話は認識できません。ElicitSlotディレクティブを使うことで、単一のスロット値のみの発話を認識してインテントを呼び出す事が出来ます。しりとりスキルでは、しりとり単語(SiritoriWordスロット)のみの発話を認識するため、:elicitSlotを多用しています。:elicitSlotでは、emitメソッドの引数として、引き出すスロット名SiritoriWordを指定します。this.event.request.intent.slots.SiritoriWord.value;スロット名SiritoriWordを指定して、ユーザーが入力した言葉を取得します。対話モデルでのインテント・スロットの設定については、前回の記事をご覧ください。スロットの値として取得される単語は、SiritoriWordのスロットタイプSiritoriWordType作成時に追加した単語に偏重されますが、それ以外の単語でも認識されます。kuromoji.jsによる単語の品詞判定と読み仮名取得スロットから取得した言葉は、既に漢字変換などの処理が行われているため、しりとり処理で使うためには読み仮名へと変換する必要があります。入力された言葉がちゃんと名詞一単語であるか、チェックする必要があります。今回は、JavaScriptの形態素解析器kuromoji.jsを使い、入力された単語の読み仮名の取得と、入力が1つの名詞からなる単語かどうかの判定を行います。]例えば、「西瓜」をkuromoji.jsで形態素変換した結果は上のようになります。読み仮名はtok[0].readingといった形で取得できます。{今回、Promiseを用いて同期処理を設定することで、形態素変換が終わるのを待ってから、以降のしりとり処理が行われるようにしました。tokenizer.tokenize(String(inputWord))で形態素変換した結果をresolveの引数で渡し、then節の中でのしりとり処理で使っています。undefinedというエラーが出るため、Stringにキャストする必要があります。強制的にガベージコレクションを開始するgc();複数回のやりとりをしていくうちに、Lambdaのメモリ使用量が増えていってエラーになる問題に直面しました。形態素変換で確保したメモリが開放されずに残っているのかもしれないと思い、強制的にガベージコレクションを実行することで、エラーを回避しています。Lambdaにおけるnode.jsのメモリリークに関しては、こちらの記事に記述がありました。"単語の読みがなが取得できません。"違う単語を試してみてください。speechOutput);}また、形態素変換の結果、読み仮名(reading)要素を持たない形態素が得られることもあるため、上のように処理を分けています。アレクサ用の単語辞書を作成アレクサがしりとりで使える単語の連想配列を作成します。プロジェクトのディレクトリにalexaVocab.jsonを作成し、以下の内容を貼り付けます。valueにしりとり単語の配列をそれぞれカタカナで入力します。上記の単語配列の要素を増やしていくことで、アレクサが使える単語を増やしていくことが出来ます。今回はまたしても力尽きたので極めて少ないボキャブラリーしか設定していませんが、最強のしりとりスキルを目指して、アレクサに使わせてみたい単語をぜひ色々追加してみてください。カスタムスロットタイプや単語の追加に関しては、次回の記事で詳しく扱う予定です。package.jsonここまでの手順が完了すると、ディレクトリ内は上のようになっているかと思います。-rプロジェクトのディレクトに移り、これらのファイルをzipに圧縮します。ここまでがLambda関数パッケージの作成でした。次はこのパッケージをAWS上にアップロードしていきます。Lambda関数の作成AWSマネジメントコンソールAWSにログインし、Lambda関数を作成していきます。画面左上からサービス一覧を開き、「Lambda」をクリックします。左側のタブで「関数」を選択し、「関数の作成」をクリックします。リージョンは東京で作成します。「一から作成」を選択します。今回、関数の名前は「alexa-siritori」としました。CloudWatchログ権限を持つロールを選択します。既存のロールがない場合は、「カスタムロールの作成」を選択し、設定項目はそのままで「許可」ボタンをクリックしてロールを作成します。「関数の作成」をクリックします。トリガーの追加アレクサからLambda関数を呼び出せるように、アクセス許可を追加します。Kit」を選んで「追加」をクリックします。右上のボタンで変更を保存します。手順1で作成したLambda関数パッケージをアップロードします。alexa-siritoriの関数を選択します。コードエントリタイプとして「.ZIPファイルをアップロード」を選択し、「アップロード」のボタンをクリックして関数パッケージをアップロードします。形態素変換の処理にメモリと時間が必要になるため、メモリとタイムアウトの設定を変更します。ページを下にスクロールしていくと基本設定の項目があります。今回は、メモリを768MB、タイムアウトを10秒に設定してみます。メモリ不足でエラーになる場合は、こちらの設定を増やしてみてください。ページ右上のボタンをクリックし、ここまでの変更を保存します。手順3で必要なので、ARNの値をコピーしておきます。以上まででLambda関数の設定は終了です。次はAmazon開発者コンソールに戻り、スキルとLambdaの接続設定を行います。スキルとLambdaの接続Amazon開発者コンソールのスキル開発に戻ります。左側のタブの上から三つ目の「設定」をクリックします。LambdaのARN」を選びます。デフォルトの枠に先ほどでコピーしたLambdaのARNの値を貼り付けます。他の設定は既定値のまま「保存」をクリックし、「次へ」をクリックします。スキルのテストテストを「有効」にし、しりとりスキルをテストできるようにします。これで、お持ちのアレクサデバイスでしりとりスキルがテストできるようになりました。アレクサアプリにスキルが表示されない場合は、開発者コンソールにログインしているAmazonアカウントとアレクサアプリに設定したAmazonアカウントが同じであるか確認してみてください。Amazon.co.jpのアカウントとAmazon.comのアカウントは別物なので注意してください。アレクサデバイスがなくても、テストシミュレーターを使ってスキルのテストを行うことが出来ます。Simulator」をクリックし、テストシミュレーターを開きます。テキストまたは音声を入力して、スキルのテストが行えます。「しりとりスキルを開いて」と入力してスキルを起動し、しりとりをテストしてみましょう。注意点ですが、執筆時点(12/22)では、Amazon.co.jpに紐づく開発者アカウントではスキルの起動に失敗します。本記事では、Amazon.comに紐づくアカウントで実行確認を行いました。テストシミュレーターに関しては、こちらの記事を参考にさせていただきました。Kitでしりとりスキルを作ってみた手順になります。みなさんもぜひ好きな単語を追加して、オリジナルのしりとりスキルを作ってみてください。Kitによるスキル作成のうち、Node.jsデプロイパッケージの作成、Lambda関数の作成、スキルとLambda関数の接続、スキルのテストまでを行いました。SDKに関して、ステートハンドラによるインテント制御、セッションアトリビュートによる情報の保持、ElicitSlotディレクトリによる単一スロットの発話の認識・スロット値の取得、などの方法を見ていきました。kuromoji.jsの使い方、Lambdaで使う際の注意点を見ていきました。テストシミュレーターを使ってスキルのテストを行いました。Lambdamotchie2017年4月、NHNテコラスに新卒入社。データサイエンスチームに所属し、AWSを活用したデータ分析サービスの設計開発を担当。注力分野は自然言語処理、好きなAWSサービスはEMR、SageMaker。