search
LoginSignup
1

More than 1 year has passed since last update.

posted at

updated at

Amazon Lexで簡単なボットを作成してみた

はじめに

この記事はLexの勉強用として試したことをまとめたものです。
書籍「AWSでつくる-AIプログラミング入門」を参考にして対話ボットを作成してみました。

Amazon Lexについて

  • 対話型インターフェイスを作成することができるAIサービスである。
  • 会話ボットを簡単に構築することができる。
  • Amazon Alexaで使われている深層学習技術と同じ技術を使用している。
  • 現時点で日本語未対応である。

IAMロールを作成

ボットを作成

インテントを作成

スロットタイプの作成

ボットを構築

  • 「Build」ボタンを押下して、ボットを作成する。
  • 以下のように設定してみた。 sampleボット.png

Lambdaを作成

  • 以下スクリプトを作成する。
import json
import datetime
import time
import os
import dateutil.parser
import logging

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

# --- Main ---
def lambda_handler(event, context):
    print(event)
    return dispatch(event)

# --- Input Check ---
def try_ex(func):
    try:
        return func()
    except KeyError:
        return None

# --- Intent Check ---
def dispatch(intent_request):

    logger.debug('dispatch userId={}, intentName={}'.format(intent_request['userId'], intent_request['currentIntent']['name']))

    intent_name = intent_request['currentIntent']['name']

    if intent_name == 'OrderIntent':
        return ice_cream_order(intent_request)

# --- Intent Request ---
def ice_cream_order(intent_request):

    Container = try_ex(lambda: intent_request['currentIntent']['slots']['Container'])
    Flavor = try_ex(lambda: intent_request['currentIntent']['slots']['Flavor'])
    session_attributes = intent_request['sessionAttributes'] if intent_request['sessionAttributes'] is not None else {}
    print(session_attributes)

    if intent_request['invocationSource'] == 'DialogCodeHook':
        # Validate any slots which have been specified.  If any are invalid, re-elicit for their value
        validation_result = validate_order(intent_request['currentIntent']['slots'])
        if not validation_result['isValid']:
            slots = intent_request['currentIntent']['slots']
            slots[validation_result['violatedSlot']] = None

            return elicit_slot(
                session_attributes,
                intent_request['currentIntent']['name'],
                slots,
                validation_result['violatedSlot'],
                validation_result['message']
            )

    print(Container)
    print(Flavor)
    msg = "OK, {} ice cream in {}".format(Flavor, Container)

    print("json : " + str(msg))
    return close(
        session_attributes,
        'Fulfilled',
        {
            'contentType': 'PlainText',
            'content': msg
        }
    )
  • Lexへ返すための関数を定義する。
    • ElicitSlot・・・ユーザーがレスポンスでスロット値を提供するよう予期されていることをLexに伝える。
    • Close・・・ユーザーからのレスポンスを予期しないようにLexに伝える。レスポンス不要である。
# --- Validate Check ---
def validate_order(slots):
    Container = try_ex(lambda: slots['Container'])
    Flavor = try_ex(lambda: slots['Flavor'])

    if Container is None:
        return build_validation_result(
            False,
            'Container',
            'corn or cup ?'
        )

    if Flavor is None:
        return build_validation_result(
            False,
            'Flavor',
            'vanilla, chocolate or strawberry ?'
        )

    return {'isValid': True}

# --- Validate Result ---
def build_validation_result(isvalid, violated_slot, message_content):
    return {
        'isValid': isvalid,
        'violatedSlot': violated_slot,
        'message': {'contentType': 'PlainText', 'content': message_content}
    }

# --- Responses Build ---
def elicit_slot(session_attributes, intent_name, slots, slot_to_elicit, message):
    return {
        'sessionAttributes': session_attributes,
        'dialogAction': {
            'type': 'ElicitSlot',
            'intentName': intent_name,
            'slots': slots,
            'slotToElicit': slot_to_elicit,
            'message': message
        }
    }

# --- Responses Close ---
def close(session_attributes, fulfillment_state, message):
    response = {
        'sessionAttributes': session_attributes,
        'dialogAction': {
            'type': 'Close',
            'fulfillmentState': fulfillment_state,
            'message': message
        }
    }
    print("Res : " + str(response))
    return response

会話のテスト

  • コンソール画面からテストができるので試してみる。
  • 「ice cream order」とLexを呼び出してみると会話が始まる。
    sample会話_OK.png

  • 登録されていないインテントでLexを呼び出してみると「Please try again.」と返ってくる。
    (Error handlingでインテントに入らなかった時にどう返すか定義しているため。)
    sample会話_NG.png

まとめ

  • Lexへ返すための形式に苦労したが一度作成してしまえば色々と応用できそう。
  • 日本語対応が待ち遠しい。

参考

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
What you can do with signing up
1