Flask-AskでAlexaのカスタムスキルを作成
はじめに
昨年末にAmazon Echo Dotを購入したので、カスタムスキルを作ろうと思い、その方法を備忘としてまとめます。
Alexaのカスタムスキルは以前作ったことがあり、そのときに使用したFlask-Askを使用して実装したいと思います。
Flask-Askをインストールする際の注意点はこちらの記事にまとめています。
環境構築
DockerでPython環境の構築
今回は作ったプログラムと環境をHerokuにデプロイするので、コンテナをそのままデプロイ出来るようDockerで環境を作ります。
まずは簡単に以下のようなDockerfileを作ります。
FROM python:3.7.1-alpine3.8 ADD . /app WORKDIR /app RUN apk update && apk add git vim
以下コマンドでDockerコンテナを起動します。
$ docker build . -t alexa_env $ docker run -it -v $PWD:/app -p 8000:8000 alexa_env /bin/ash
今回はalpineのDocker imageを使用しているので、/bin/bash
ではなくbin/ash
であることに注意。
Dockerコンテナに入ったら入ったら、flask
とgunicorn
インストールします。
/app $ pip install flask gunicorn
動作確認のためのapp.py
を作成します。
from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World!" if __name__ == "__main__": app.run()
gunicornを起動します。
/app $ gunicorn app:app -b 0.0.0.0:8000
ブラウザからhttp://localhost:8000
を開いて"Hello World!"が表示されればOKです。
Herokuにデプロイ
続いてDockerfileを編集してHerokuにデプロイ出来る環境を作っていきます。
事前にコンテナ内でpip freeze > requirements.txt
を実行しrequirement.txt
を作成しておきます。
また前回の記事にて実施したFlask-Askのパッケージのローカルへのダウンロードと編集したパッケージを/src
配下に準備するとともに、build-base
,libffi-dev
,openssl-dev
のインストールを追記しておきます。
最終的なDockerfileは以下の通り。
FROM python:3.7.2-alpine3.8 ADD . /app WORKDIR /app RUN apk update && \ apk add git vim build-base libffi-dev openssl-dev && \ pip install --upgrade pip && \ pip install -r requirements.txt && \ pip install src/Flask-Ask-0.9.8.tar.gz EXPOSE 8000 ENV PORT 8000 CMD gunicorn app:app -b 0.0.0.0:$PORT
以前の記事に書いたように、以下コマンドでherokuにデプロイします。
$ heroku login # herokuにログイン $ heroku container:login # Heroku 上の Container Registry へログイン $ heroku create alexacustomskil # Heorkuアプリの作成 $ heroku container:push web --app yourappname $ heroku container:release web --app yourappname
これでHerokuにデプロイされ、デプロイされたURLにアクセスし先ほどと同様"hello World!"が表示されればOKです。
スキル作成
いよいよここからはカスタムスキルを作成していきます。
基本的にはこちらの開発ブログに掲載されているチュートリアルに従って実装していきます。
Flask-Ask: A New Python Framework for Rapid Alexa Skills Kit Development : Alexa Blogs
こちらのチュートリアルでは、数字が3つ読み上げられるのでその数字を覚えて逆から読むというゲームを作っています。
Alexa Developer Console上での設定と、Flask-Askでのサーバ側の処理実装が必要になります。
Amazon Developper Consoleで設定
チュートリアルとは少し画面構成が違いますが、Console上で設定するものは以下のものです。
- スキルの作成
- スキルの名前を設定 「アレクサ、〇〇を開いて」のときの名前
- スキルのインテントを設定
インテントとはユーザーがアレクサに対して応答する言葉のカテゴリのようなもの
そのユーザー応答が何を意味するのかを定義します。
今回登録するのは以下の2つ- YesIntent ゲーム開始時に「始めてもいいですか?」の問に対して、ユーザーがOKを場合の発話を定義
- AnswerIntent 出された問題に対してユーザーが解答する場合の発話を定義
- それぞれのインテントのスロットを設定 インテントにて定義する発話の中で使用する、変数の器のようなもの 今回のAnswerIntentでは発話の中で数字を読み上げるので、固定値で発話パターンを定義出来ないので、変数としてスロットを定義したうえで発話を定義します。
まずはAlexa Developer ConsoleにAmazonアカウントでログインします。
開発者アカウントにするために追加で情報入力が必要な際は入力します。
https://developer.amazon.com/alexa/console/ask
開発者コンソールが開いたらスキルの作成をクリックします。
新しいスキルの登録画面で、カスタムスキルを作成します。
必要情報を入力すると、スキル編集画面にきます。
まずはインテントを登録します。
今回は上で説明したとおり、以下の2つを登録します。
- YesIntent ゲーム開始時に「始めてもいいですか?」の問に対して、ユーザーがOKを場合の発話を定義
- AnswerIntent 出された問題に対してユーザーが解答する場合の発話を定義
まずはYesIntentを登録します。
また、YesIntentのサンプルを登録し、このIntentがどういった発話パターンを取りうるのかAlexaに知ってもらいます。
次にAnswerIntentを登録します。
AnserIntentについては、発話パターンのサンプルを登録する前に、発話パターンの中で使用されるスロット(変数、器のようなもの)を登録します。
今回は3つの数字のスロットを使用しますので、それぞれfirst、second、thirdの3個を登録します。 スロットのタイプはAMAZON.numberとします。
次にこのスロットを使用してAnswerIntentの発話パターンを登録します。 今回は以下の2パターンを登録しました。
次に、このスキルを呼び出した際にそれを処理するサーバーのURLを設定します。 先程デプロイしたherokuのURLを設定します。
最後に今回のスキルを呼び出すためのスキル名を設定します。 設定を保存し、ビルドします。
これで開発コンソールでの設定は完了です。
左メニューのJSONエディター上は以下のような表示になります。
このJSONをそのまま編集してもOKです。
{ "interactionModel": { "languageModel": { "invocationName": "メモリーゲーム", "intents": [ { "name": "AMAZON.CancelIntent", "samples": [] }, { "name": "AMAZON.HelpIntent", "samples": [] }, { "name": "AMAZON.StopIntent", "samples": [] }, { "name": "AMAZON.NavigateHomeIntent", "samples": [] }, { "name": "YesIntent", "slots": [], "samples": [ "うん", "はい", "もちろん", "OKです", "OK", "了解" ] }, { "name": "AnswerIntent", "slots": [ { "name": "first", "type": "AMAZON.NUMBER" }, { "name": "second", "type": "AMAZON.NUMBER" }, { "name": "third", "type": "AMAZON.NUMBER" } ], "samples": [ "{first} と {second} と {third}", "{first} {second} {third}" ] } ], "types": [] } } }
Flask-ASKで実装
サーバ側の処理はFlask-Askで実装していきます。
Welcome to Flask-Ask — Flask-Ask documentation
チュートリアルの通り、app.pyを以下のように書き換えます。
import logging from random import randint from flask import Flask, render_template from flask_ask import Ask, statement, question, session app = Flask(__name__) ask = Ask(app, "/") logging.getLogger("flask_ask").setLevel(logging.DEBUG) @ask.launch ``def new_game(): welcome_msg = render_template('welcome') return question(welcome_msg) @ask.intent("YesIntent") def next_round(): numbers = [randint(0, 9) for _ in range(3)] round_msg = render_template('round', numbers=numbers) session.attributes['numbers'] = numbers[::-1] # reverse return question(round_msg) @ask.intent("AnswerIntent", convert={'first': int, 'second': int, 'third': int}) def answer(first, second, third): winning_numbers = session.attributes['numbers'] if [first, second, third] == winning_numbers: msg = render_template('win') else: msg = render_template('lose') return statement(msg) if __name__ == '__main__': app.run(debug=True)
templateファイルの中にはAlexaが話すセリフを記載します。
welcome: メモリーゲームへようこそ! これから5つの数字を読み上げるので、アタナはその数字を逆の順番で答えてください。準備はいいですか? round: 今回の数字は {{ numbers|join(", ") }} です。反対の順番で読み上げてください。 win: 正解です! lose: 不正解です。
サーバー側の処理はこれでOKなので、再度Herokuにデプロイします。
そして開発用アカウントに紐づけたEcho端末や、アレクサシミュレーターで「アレクサ、メモリーゲームを開いて」と話しかけてゲームがスタートすれば成功です。
が、返事が返ってきません。
Herokuのログを確認すると以下のようなエラーが出ていました。
2019-01-24T15:02:16.836079+00:00 app[web.1]: File "/usr/local/lib/python3.7/site-packages/OpenSSL/crypto.py", line 740, in _subjectAltNameString 2019-01-24T15:02:16.836081+00:00 app[web.1]: method = _lib.X509V3_EXT_get(self._extension) 2019-01-24T15:02:16.836082+00:00 app[web.1]: AttributeError: module 'lib' has no attribute 'X509V3_EXT_get'
調べてみるとpyOpenSSLを再インストールする必要があるようです。
記事を参考にDockerfileを以下のように修正します。
FROM python:3.7.2-alpine3.8 ADD . /app WORKDIR /app RUN apk update && \ apk add git vim build-base libffi-dev openssl-dev && \ pip install --upgrade pip && \ pip install -r requirements.txt && \ pip install src/Flask-Ask-0.9.8.tar.gz && \ pip uninstall --yes pyOpenSSL && \ yes | pip install pyOpenSSL EXPOSE 8000 ENV PORT 8000 CMD gunicorn app:app -b 0.0.0.0:$PORT
再度Herokuにデプロイすると無事動作するようになりました。
まとめ
前回の続きで、Flask-Askを使用してAlexaのカスタムスキルを作成してみました。
Flaskを使って簡単に実装できるので、アイデア次第でいろんなスキルが作れそうです。