LoginSignup
8
3

More than 5 years have passed since last update.

Alexa for Businessのスキルを作成してみた

Last updated at Posted at 2017-12-04

Alexa for Businessのスキルを作成してみました。
リージョンを指定するとそのリージョンで発生中のCloudwatchAlarmを答えるスキルです。

必要なもの

  • AWSアカウント
  • Amazon Developerアカウント
  • Alexa Skills Kit Command Line Interface (ASK CLI)

作業概要

  1. スキル用のLambdaの作成
  2. スキルの作成とテスト
  3. プライベートスキルの設定
  4. 公開情報とプライバシーとコンプライアンスの設定
  5. 申請とスキルの有効化

1. スキル用のLambdaの作成

以下AWSマネジメントコンソールにログインして作業します。

1. Lambda用のIAMロールを作成する

以下ポリシーを持ったIAMロールを作成します。
Lambda用のベースのポリシーにCloudwatchアラームへのアクセス許可を追加しています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Effect": "Allow",
            "Action": "cloudwatch:DescribeAlarms",
            "Resource": "*"
        }
    ]
}

 
2. blueprintsで[alexa-skills-kit-color-expert-python]を選択・編集しLambdaを作成する

blueprintはpython2.7用ですが、python3.6用にしています。

# -*- coding: utf-8 -*-
import boto3


# --------------- Helpers that build all of the responses ----------------------

def build_speechlet_response(title, output, reprompt_text, should_end_session):
    return {
        'outputSpeech': {
            'type': 'PlainText',
            'text': output
        },
        'card': {
            'type': 'Simple',
            'title': "SessionSpeechlet - " + title,
            'content': "SessionSpeechlet - " + output
        },
        'reprompt': {
            'outputSpeech': {
                'type': 'PlainText',
                'text': reprompt_text
            }
        },
        'shouldEndSession': should_end_session
    }


def build_response(session_attributes, speechlet_response):
    return {
        'version': '1.0',
        'sessionAttributes': session_attributes,
        'response': speechlet_response
    }


# --------------- Functions that control the skill's behavior ------------------

def get_welcome_response():
    session_attributes = {}
    card_title = "Welcome"
    speech_output = "こんにちは。AWSのアラート状況をお知らせするスキルです。 " \
                    "例えば次のように質問して下さい。 " \
                    "東京リージョンの状況は"
    reprompt_text = "例えば次のように質問して下さい。 " \
                    "東京リージョンの状況は"
    should_end_session = False
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))


def handle_session_end_request():
    card_title = "Session Ended"
    speech_output = "Thank you for trying the Alexa Skills Kit sample. " \
                    "Have a nice day! "
    # Setting this to true ends the session and exits the skill.
    should_end_session = True
    return build_response({}, build_speechlet_response(
        card_title, speech_output, None, should_end_session))


def get_alarms(region):
    cloudwatch = boto3.client('cloudwatch', region_name=region)
    try:
        response = cloudwatch.describe_alarms(StateValue='ALARM')
        alarms = [alarm['AlarmName'] for alarm in response['MetricAlarms']]
        print(alarms)
        return alarms
    except Exception as e:
        print(e)
        raise e


def response_alarms(intent, session):
    card_title = intent['name']
    session_attributes = {}
    should_end_session = False
    region_dic = {
        '東京':'ap-northeast-1',
        'バージニア':'us-east-1',
        'シドニー':'ap-southeast-2'
    }

    if 'Region' in intent['slots'] \
    and intent['slots']['Region']['value'] in region_dic:
        region_jp = intent['slots']['Region']['value']
        region = region_dic[region_jp]
        alarms = get_alarms(region)
        if len(alarms) == 0:
            speech_output = "現在" + \
                            region_jp + \
                            "リージョンにアラートはありません。 "
        else:
            speech_output = "現在" + \
                            region_jp + \
                            "リージョンに" + \
                            str(len(alarms)) + \
                            "件アラートが発生しています。" + \
                            "アラート名は" + \
                            "と".join(alarms) + \
                            "です。"
        reprompt_text = None
        should_end_session = True
    else:
        speech_output = "リージョン名がわかりませんでした。" \
                        "もう一度お願いします。"
        reprompt_text = "リージョン名がわかりませんでした。 " \
                        "もう一度お願いします。"
        should_end_session = False
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))


# --------------- Events ------------------

def on_session_started(session_started_request, session):
    print("on_session_started requestId=" + session_started_request['requestId']
          + ", sessionId=" + session['sessionId'])


def on_launch(launch_request, session):
    print("on_launch requestId=" + launch_request['requestId'] +
          ", sessionId=" + session['sessionId'])
    return get_welcome_response()


def on_intent(intent_request, session):
    print("on_intent requestId=" + intent_request['requestId'] +
          ", sessionId=" + session['sessionId'])

    intent = intent_request['intent']
    intent_name = intent_request['intent']['name']

    if intent_name == "MyAwsAlarmsIntent":
        return response_alarms(intent, session)
    elif intent_name == "AMAZON.HelpIntent":
        return get_welcome_response()
    elif intent_name == "AMAZON.CancelIntent" or intent_name == "AMAZON.StopIntent":
        return handle_session_end_request()
    else:
        raise ValueError("Invalid intent")


def on_session_ended(session_ended_request, session):
    print("on_session_ended requestId=" + session_ended_request['requestId'] +
          ", sessionId=" + session['sessionId'])



# --------------- Main handler ------------------

def lambda_handler(event, context):
    """ Route the incoming request based on type (LaunchRequest, IntentRequest,
    etc.) The JSON body of the request is provided in the event parameter.
    """
    print("event.session.application.applicationId=" +
          event['session']['application']['applicationId'])

    """
    Uncomment this if statement and populate with your skill's application ID to
    prevent someone else from configuring a skill that sends requests to this
    function.
    """
    # if (event['session']['application']['applicationId'] !=
    #         "amzn1.echo-sdk-ams.app.[unique-value-here]"):
    #     raise ValueError("Invalid Application ID")

    if event['session']['new']:
        on_session_started({'requestId': event['request']['requestId']},
                           event['session'])

    if event['request']['type'] == "LaunchRequest":
        return on_launch(event['request'], event['session'])
    elif event['request']['type'] == "IntentRequest":
        return on_intent(event['request'], event['session'])
    elif event['request']['type'] == "SessionEndedRequest":
        return on_session_ended(event['request'], event['session'])

2. スキルの作成とテスト

以下Amazon開発者コンソールにログインして作業します。

1. スキル情報を設定する

  • スキルの種類:Custom
  • 言語:Japanese
  • スキル名:AWSアラート状況
  • 呼び出し名:awsアラート状況

他はデフォルト
 
2. 対話モデルを設定する

  • インテントスキーマ
{
  "intents": [
    {
      "slots": [
        {
          "name": "Region",
          "type": "LIST_OF_REGIONS"
        }
      ],
      "intent": "MyAwsAlarmsIntent"
    },
    {
      "intent": "AMAZON.HelpIntent"
    },
    {
      "intent": "AMAZON.StopIntent"
    },
    {
      "intent": "AMAZON.CancelIntent"
    }
  ]
}
  • カスタムスロットタイプ

    • タイプ:LIST_OF_REGIONS
    • 値:
      • 東京
      • バージニア
      • シドニー
  • サンプル発話

    • MyAwsAlarmsIntent {Region} は
    • MyAwsAlarmsIntent {Region} の状況は
    • MyAwsAlarmsIntent {Region} のアラート状況は

 
3. 「設定」を設定する

  • サービスエンドポイントのタイプ:AWS Lambda の ARN
    • 作成したLambdaのARNを指定する

他はデフォルト

 
4. テストする

4-1. あらかじめ、バージニアリージョンに3件Cloudwatchアラームが発生している状態にしておきます。

4-2. 発話を入力してください欄に「バージニアは」と入力してテストすると

4-3. サービスレスポンスに下記が返ってきます。

{
  "version": "1.0",
  "response": {
    "outputSpeech": {
      "text": "現在バージニアリージョンに3件アラートが発生しています。アラート名はalarm_1とalarm_2とalarm_3です。",
      "type": "PlainText"
    },
    "card": {
      "content": "SessionSpeechlet - 現在バージニアリージョンに3件アラートが発生しています。アラート名はalarm_1とalarm_2とalarm_3です。",
      "title": "SessionSpeechlet - MyAwsAlarmsIntent"
    },
    "reprompt": {
      "outputSpeech": {
        "type": "PlainText"
      }
    },
    "speechletResponse": {
      "outputSpeech": {
        "text": "現在バージニアリージョンに3件アラートが発生しています。アラート名はalarm_1とalarm_2とalarm_3です。"
      },
      "card": {
        "content": "SessionSpeechlet - 現在バージニアリージョンに3件アラートが発生しています。アラート名はalarm_1とalarm_2とalarm_3です。",
        "title": "SessionSpeechlet - MyAwsAlarmsIntent"
      },
      "reprompt": {
        "outputSpeech": {}
      },
      "shouldEndSession": true
    }
  },
  "sessionAttributes": {}
}

3. プライベートスキルの設定

1. alexa Skills Kit Command Line Interface (ASK CLI)をインストールする

下記URLを参考にインストールします。
https://developer.amazon.com/docs/smapi/quick-start-alexa-skills-kit-command-line-interface.html
 
2. プライベートスキルの設定をする

下記URLを参考にプライベートスキルの設定をします。
http://docs.aws.amazon.com/a4b/latest/ag/private-skills.html

スキルのIDは、スキル情報に表示されます。

$ skill_id=<スキルのID>
$ ask api get-skill -s ${skill_id} > skill.json
$ vi skill.json

"distributionMode": "PRIVATE"を1行追加する

skill.json
{
  "skillManifest": {
    "publishingInformation": {
      "locales": {
        "ja-JP": {
          "name": "AWSアラート状況"
        }
      },
      "isAvailableWorldwide": true,
      "distributionMode": "PRIVATE"
    },
    "apis": {
      "custom": {
        "endpoint": {
          "uri": "<LambdaのARN>"
        }
      }
    },
    "manifestVersion": "1.0"
  }
}
$ ask api update-skill -s ${skill_id} -f skill.json

4. 公開情報とプライバシーとコンプライアンスの設定

以下Amazon開発者コンソールで作業します。

ちょっと面倒ですが、小アイコン(108x108)と大アイコン(512x512)を用意してアップロードし
他記入できるところを全て記入します。

5. 申請とスキルの有効化

1. 申請する

$ ask api submit -s ${skill_id}

 
2. ステータスがLiveになるまで、数時間待つ
 
3. Alexa for Businessオーガナイゼーションに配布する

$ account_id=arn:aws:iam::<AWSアカウントID>:root
$ ask api add-private-distribution-account -s ${skill_id} --stage live --account-id ${account_id}

 
4. スキルを有効にする

AWSマネジメントコンソール:Alexa for Businessのprivate skillsの一覧にスキルが表示されます。

skill.png

[Review]をクリックして[Enable]を選択しスキルを有効にします。
 
5. ここまで
東京リージョンではまだ利用できないので、残念ながらここまでです。
2017/12/5追記 英語でよければ、利用できるそうです。

雑感

Alexa for Businessの何でもできちゃいそう感がすごい。
Re:Inventのキーノートを見たら「ちょっといい会議システム」みたいなものと勘違いしちゃいそうですが、もっと全然奥が深そう。
自分の中では2017年のRe:Inventの2番目の目玉です。
早く東京リージョンにこないかな。

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3