naritoブログ

このブログはPython/DjangoとBootstrap4で作成されました
Githubのソースコード

Alexa Skills Kit入門②(Python、AWS Lambda使用)

約117日前 2018年2月27日15:56
プログラミング関連
Python Alexa Skills Kit
「Alexa Skills Kit入門シリーズ(Python、AWS Lambda使用)」の1つです。
https://torina.top/detail/441/

まずですが、AWSのアカウント登録が必要です。
https://aws.amazon.com/jp/

Lambdaしか使わなければ、公開してよほど人気にならない限りは無料で使えます(多分)
アカウントの登録がちょっと面倒です。クレジットカードが基本的に必須ですが、Vプリカでも登録はできるようです。なので、学生の方はコンビニでVプリカを購入すると良いでしょう。

AWS Lambdaを使わない方法もあるのですが、公開をするならばちょっと面倒です。サーバーを用意し、HTTPS対応が必須で、更にletsencryptではダメなようです。


実運用版のAlexaスキルは、接続の確立時に有効かつ信頼済みの証明書を提示し、対応する秘密鍵を所有している必要があります。

Amazon認定の認証局が署名した証明書をすでに持っているエンドポイントでウェブサービスをホスティングする場合は、新たにSSLのコンフィギュレーションを行う必要はありません。Amazon認定の証明書認証局には、こちらが含まれますが、https://letsencrypt.org/は含まれません。



しかし、そこさえクリアできれば開発自体はしやすいです。
flask-askといった既存のWebフレームワークを拡張した便利なものもありますし
https://github.com/johnwheeler/flask-ask

djangoバージョンも出てきているようです。
https://github.com/pycontribs/django-alexa

今回はAWS Lambdaですが、慣れるとそこまで苦ではありません。

AWSアカウントの取得ができれば、Lambdaサービスのページを開きましょう。右上の「関数の作成」ボタンを押します。




真ん中の「設計図」を押しましょう。




真ん中の入力欄に「alexa」と入力してエンターを押すと、Alexaに関連したものが絞り込まれます。「alexa-skills-kit-color-expert-python」を押して下さい。




名前は「helloworld」、ロールは「カスタムロールの作成」を選択すると新しい画面になります。その画面の右下に「許可」ボタンがあるので、それを押すと戻ってきます。




既存のロールを選択します。結果的に、以下の画像のようになると思います。




少し下に移動して、スキルID欄を入力します。これですが、スキル情報(呼び出し名)などを設定したページで確認できますので、それを入れてください。



終わったら、画面一番下の「関数の作成」ボタンを押します。


新しい画面に移りますが、とりあえず「ランライム」をPython3.6にしましょう。



既にコードがあります。これを見て勉強してもいいのですが、少し手を加えたコードを作りました。既存のコードを以下のコードにします。コードの内容は、④で説明します。もちろん、元々あったコードを元に改良してもいいですし、自分で作ってみるのも良いでしょう。
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 hello():
    """ハローと言っておわり"""
    return OneSpeech('ハロー、ハロー、ハロー').build()


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


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


def lambda_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 == 'Greet':
            return hello()

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

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



終わったら、画面右上の「保存」ボタンを押しましょう。そしてその上に「arn:aws - .....:function:helloworld」という文字列があるので、これをコピーしておいてください。