はかせのラボ

私の頭の中を書いていく雑記ブログです

Alexa AWSLambdaを使ってハローワールドやってみる

あいさつ

どうも、はかせです。
前回までで大方公式のAlexaBlogの基礎トレが終わりました。

なので今回はAWSLambdaとの連携をやってみます。

準備

AmazonDeveloperアカウント作成
AWSアカウント作成

連携の理屈

・Alexaから入力
・入力内容をAWSに送り応答メッセージ作成してもらう

Alexaから入力

まずはいつもどおりスキルを作成します。
今回は最初に作ったハローワールドスキルでやってみます。
hakase0274.hatenablog.com

入力内容をAWSに送り応答メッセージ作成してもらう

スキルを作ったら今度はAWSの方で応答する関数を作ります。
まず最初にリージョン設定を東京にしてください。
f:id:hakase0274:20190810232205p:plain
f:id:hakase0274:20190810232222p:plain
(こうしないと後述のalexaのkitが出てきません)

リージョン設定が東京になったのを確認したら
コンソール画面の「関数の作成ボタン」をぽちっと押して
f:id:hakase0274:20190810231503p:plain

「Serverless Application Repositoryの参照」を選んで「alexa」で検索
f:id:hakase0274:20190810231350p:plain

そして出てきた「alexa-skills-kit-color-expert」をクリック
f:id:hakase0274:20190810231403p:plain

「アプリケーションの設定」のとこに好きな名前を入れて「デプロイ」
f:id:hakase0274:20190810231912p:plain
ちょっと待ったら関数が出来上がります。

関数ができたらそこに処理を追加します。
まずはランタイムを自分が使う言語のものに変えます。
私は参考サイトがpython3.6だったのでそれにします。
f:id:hakase0274:20190810232714p:plain

そしてデフォルトテンプレートだとjsのファイルしかないので
新たに「Test.py」を作成し、以下のコードを打ち込みます。

class BaseSpeech:
    """シンプルな、発話するレスポンスのベース"""

    def __init__(self, speech_text, should_end_session, session_attributes=None):
        """初期化処理

        引数:
            speech_text: Alexaに喋らせたいテキスト
            should_end_session: このやり取りでスキルを終了させる場合はTrue, 続けるならFalse
            session_attributes: 引き継ぎたいデータが入った辞書
        """
        if session_attributes is None:
            session_attributes = {}

        # 最終的に返却するレスポンス内容。これを各メソッドで上書き・修正していく
        self._response = {
            'version': '1.0', 
           'sessionAttributes': session_attributes,
            'response': {
                'outputSpeech': {
                    'type': 'PlainText',
                    'text': speech_text
                },
                'shouldEndSession': should_end_session,
            },
        }

        # 取り出しやすいよう、インスタンスの属性に
        self.speech_text = speech_text
        self.should_end_session = should_end_session
        self.session_attributes = session_attributes

    def simple_card(self, title, text=None):
        """シンプルなカードを追加する"""
        if text is None:
            text = self.speech_text
        card = {
            'type': 'Simple',
            'title': title,
            'content': text,
        }
        self._response['response']['card'] = card
        return self

    def build(self):
        """最後にこのメソッドを呼んでください..."""
        return self._response


class OneSpeech(BaseSpeech):
    """1度だけ発話する(ユーザーの返事は待たず、スキル終了)"""

    def __init__(self, speech_text, session_attributes=None):
        super().__init__(speech_text, True, session_attributes)


class QuestionSpeech(BaseSpeech):
    """発話し、ユーザーの返事を待つ"""

    def __init__(self, speech_text, session_attributes=None):
        super().__init__(speech_text, False, session_attributes)

    def reprompt(self, text):
        """リプロンプトを追加する"""
        reprompt = {
            'outputSpeech': {
                'type': 'PlainText',
                'text': text
            }
        }
        self._response['response']['reprompt'] = reprompt
        return self


def welcome():
    """ようこそと言って、ユーザーの返事を待つ"""
    return QuestionSpeech('ようこそ!').reprompt('よく聞こえませんでした').build()

def bye():
    """グッバーイといって終わる"""
    return OneSpeech('グッバーイ').simple_card('遊んでくれてありがとう!').build()

def HelloWorld():
    return OneSpeech('ハローワールド').build()

#渡されたものをそのまま発話する
def test(text):
    return OneSpeech(text).build()

def Test_handler(event, context):
    """最初に呼び出される関数"""
    # リクエストの種類を取得
    request = event['request']
    request_type = request['type']

    # LaunchRequestは、特定のインテントを提供することなく、ユーザーがスキルを呼び出すときに送信される...
    # つまり、「アレクサ、ハローワールドを開いて」のようなメッセージ
    # 「アレクサ、ハローワールドで挨拶しろ」と言うとこれはインテントを含むので、IntentRequestになる
    if request_type == 'LaunchRequest':
        return welcome()

    # 何らかのインテントだった場合
    elif request_type == 'IntentRequest':
        intent_name = request['intent']['name']
        
        if intent_name =='HelloWorldIntent':
            return HelloWorld()

        # 「ヘルプ」「どうすればいいの」「使い方を教えて」で呼ばれる、組み込みインテント
        elif intent_name == 'AMAZON.HelpIntent':
            return welcome()

        # 「キャンセル」「取り消し」「やっぱりやめる」等で呼び出される。組み込みのインテント
        elif intent_name == 'AMAZON.CancelIntent' or intent_name == 'AMAZON.StopIntent':
            return bye()

その後メッセージが来た時最初に呼ぶ関数をハンドラに登録します。
(要はプログラムのエントリポイントの設定ですね)

登録方法はハンドラの部分に
「ファイル名(拡張子抜き)」.「メソッド名」です。
(拡張子を入れてしまっていて数時間頭を悩ましてましたw)

今回ファイル名は「Test.py」なのでファイル名は「Test」
メソッド名は「Test_handler」
それらを上の構文に当てはめて
「Test.Test_handler」となります。
f:id:hakase0274:20190810232913p:plain

さてこれでAWS側でやることは終わりです。
あとはAlexaスキルにこの関数を登録します。
やり方は簡単でAWS関数の上の方にあるARNってのを
f:id:hakase0274:20190810233548p:plain
Alexaのエンドポイントに設定するだけです。
f:id:hakase0274:20190810233557p:plain

実行

長々とLambdaの設定が終わったので
Alexaに戻ってテストしてみましょう。
今回スキル名は「ラムダテスト」にしてみました。
f:id:hakase0274:20190810233832p:plain
成功しました\(^_^)/

あとがき

今回はAlexaとAWSLambdaの連携でした。
ここ最近で変わったのか私のやり方がなんかまずったのかはわかりませんが、
参考サイトであったような設定とかが無かったりして
とても手間取りましたが、終わってみればやり方は簡単になってましたね。

それでは今回はこの辺でノシ

参考

qiita.com