LoginSignup
3

More than 1 year has passed since last update.

Lex使用時、Lambdaでできるテクニック

Last updated at Posted at 2022-02-20

はじめに

LexとLambdaでできる応用テクニック?を書き留めます。

事前にこちらでLambdaとLexを設定しました。

LexとLambdaでできること色々

以下のスロット値の入力のコードについて、できることをまとめます。
フルのコードは、こちらです

Lexの流れは、以下の通りに聞かれます。
発話 → telephoneNumber(電話番号) → date(日付) → age(年齢) → 確認 → yes/no

if slots['telephoneNumber'] is None:
    return elicit_slot('telephoneNumber', intent_name, slots)

telephoneNumber = slots['telephoneNumber']['value']['interpretedValue']

if slots['date'] is None:
    return elicit_slot('date',intent_name, slots)

date = slots['date']['value']['interpretedValue']

if slots['age'] is None:
    return elicit_slot('age',intent_name, slots)

age = slots['age']['value']['interpretedValue']

if int(age) < 20:
    return validation_slot(
        'age',
        'ご利用は20歳以上とさせていただいております。\
        年齢を教えて下さい',
        intent_name,
        slots
        )

スロット値をすべてリセット

下記のようLambdaを設定すると、スロット値をすべてリセットできます。
年齢を聞かれた際、スロット値がリセットされ、
telephoneNumber→date→age(リセット)→telephoneNumber→date→age(リセット)→telephoneNumber ...とループします。

通常
発話 → telephoneNumber → date → age → 確認 → yes/no

年齢を聞かれた際に、リセット
発話 → telephoneNumber → date → age(リセット) → telephoneNumber → date → age(リセット)...

.py
return elicit_slot(
    'age',
    intent_name,
    {
        "date": None,
        "telephoneNumber": None,
        "age": None
    }
  )

Lambda側で1つのスロットに値を入れて、スロット値を聞かれないようにする

以下のようにすると、Lambda側でtelephoneNumberのスロット値に090を入れることができます。

通常
発話 → telephoneNumber → date → age → 確認 → yes/no

電話番号を事前に入力
発話 → date → age → 確認 → yes/no

return elicit_slot(
    'date',
    intent_name,
    {
        "date": None,
        "telephoneNumber": {
            "shape": "Scalar",
            "value": {
                "originalValue": "090",
                "resolvedValues": [
                    "090"
                ],
                "interpretedValue": "090"
            }
        },
        "age": None
    }
)

↓実際にコードを修正して書いてみます。
originalValueresolvedValuesinterpretedValueの3つに値を入れる必要があります。

telephoneNumber(聞かれない)→date→age→確認 という流れになります。

もちろんtelephoneNumberのスロット値には、090が入っています。

# if slots['telephoneNumber'] is None:
#     return elicit_slot('telephoneNumber', intent_name, slots)
# telephoneNumber = slots['telephoneNumber']['value']['interpretedValue']

if slots['date'] is None:
    return elicit_slot(
        'date',
        intent_name,
        {
            "date": None,
            "telephoneNumber": {
                "shape": "Scalar",
                "value": {
                    "originalValue": "090",
                    "resolvedValues": [
                        "090"
                    ],
                    "interpretedValue": "090"
                }
            },
            "age": None
        }
    )

date = slots['date']['value']['interpretedValue']

if slots['age'] is None:
    return elicit_slot(
        'age',
        intent_name,
        slots
    )

age = slots['age']['value']['interpretedValue']

if int(age) < 20:
    return validation_slot(
        'age',
        'ご利用は20歳以上とさせていただいております。\
        年齢を教えて下さい',
        intent_name,
        slots
        )

↓事前に入力しておく値をメソッド化してもいいですね。

def input_slots_value(value):
    return {
        "shape": "Scalar",
        "value": {
            "originalValue": value,
            "resolvedValues": [value],
            "interpretedValue": value
        }
    }

# 省略


# if slots['telephoneNumber'] is None:
#     return elicit_slot('telephoneNumber', intent_name, slots)
# telephoneNumber = slots['telephoneNumber']['value']['interpretedValue']

if slots['date'] is None:
    return elicit_slot(
        'date',
        intent_name,
        {
            "date": None,
            "telephoneNumber": input_slots_value(90),
            "age": None
        }
    )
date = slots['date']['value']['interpretedValue']
telephoneNumber = slots['telephoneNumber']['value']['interpretedValue']

if slots['age'] is None:
    return elicit_slot(
        'age',
        intent_name,
        slots
    )
age = slots['age']['value']['interpretedValue']

if int(age) < 20:
    return validation_slot(
        'age',
        'ご利用は20歳以上とさせていただいております。\
        年齢を教えて下さい',
        intent_name,
        slots
        )

Lambda側で2つのスロットに値を入れて、スロット値を聞かれないようにする

下記だと、telephoneNumber(聞かれない)→date→age(聞かれない)→確認 という流れになります。

通常
発話 → telephoneNumber → date → age → 確認 → yes/no

電話番号と年齢を事前に入力
発話 → date → 確認 → yes/no

# if slots['telephoneNumber'] is None:
#     return elicit_slot('telephoneNumber', intent_name, slots)
# else:
#     telephoneNumber = slots['telephoneNumber']['value']['interpretedValue']

if slots['date'] is None:
    return elicit_slot(
        'date',
        intent_name,
        {
            "date": None,
            "telephoneNumber": input_slots_value(90),
            "age": None,
        }
    )
date = slots['date']['value']['interpretedValue']
telephoneNumber = slots['telephoneNumber']['value']['interpretedValue']

if slots['age'] is None:

    # ageを入力し、確認プロンプトに移行する
    slots = {
        "date": input_slots_value(date),
        "telephoneNumber": input_slots_value(telephoneNumber),
        "age": input_slots_value(40)
        }
    return confirm_intent( intent_name, slots)

age = slots['age']['value']['interpretedValue']

# if int(age) < 20:
#     return validation_slot(
#         'age',
#         'ご利用は20歳以上とさせていただいております。\
#         年齢を教えて下さい',
#         intent_name,
#         slots
#         )

apiキーなどの英数字が混ざった文字列をスロット値に保存する

あるAPIとLex、Lambdaを連携する歳に、アクセスコード(予約コード)を(8j91dcf0rfje4bdaa7ik97c0d2e948pl)をスロット値に保存する必要があったため、書き留めます。
confirm_intent でreturnする際に、セッション属性値に値を渡すことができなかったため、スロット値に入れました。

通常
発話 → telephoneNumber → date → alpha(英数字の文字列) → 確認 → yes/no

電話番号とアクセスコードをLambda側で入力
発話 → date → 確認 → yes/no

スロットタイプから、組み込みスロットタイプを使用AMAZON.AlphaNumericを選択します。
スクリーンショット 2022-02-20 22.21.03.png
スクリーンショット 2022-02-20 22.21.32.png
スロットタイプ設定を以下の通りにします。これは、大文字と小文字を含めた英数字に対応します。
正規表現:[0-9][a-z][A-Z]
スクリーンショット 2022-02-20 22.21.50.png
APIキーのスロット値は、Lexの受け答えとして、使用しません。
こちらのageの箇所をスロット値alphaに変えます。
スクリーンショット 2022-02-20 22.22.51.png

APIキーなので、本来は、確認プロンプトに表示しませんが、以下のように、英数字をスロット値に入れることができました。
ちなみに、AMAZON.AlphaNumericは、100文字まで入れられます。
スクリーンショット 2022-02-20 22.30.47.png

#特定の条件で、強制終了させる(キャンセルさせる)
電話番号を聞かれた際、特定の番号の場合、強制終了させることができます。

下記だと、telephoneNumber(09)→強制終了 という流れになります。

通常
発話 → telephoneNumber → date → age → 確認 → yes/no

特定の条件で、強制終了させる
発話 → telephoneNumber(09) → no

close( "Failed",が必要になります。

スクリーンショット 2022-02-27 16.52.35.png

if slots['telephoneNumber'] is None:
    return elicit_slot('telephoneNumber', intent_name, slots)

telephoneNumber = slots['telephoneNumber']['value']['interpretedValue']

# 電話番号が09の場合、強制終了させる
if telephoneNumber == "09":
    return close( "Failed", '強制終了です。', intent_name, slots)

if slots['date'] is None:
    return elicit_slot(
        'date',
        intent_name,
        slots
    )

#省略

特定の条件で、予約完了させる

電話番号を聞かれた際、特定の番号の場合、予約完了させることができます。

下記だと、telephoneNumber(09)→ 予約完了 という流れになります。

通常
発話 → telephoneNumber → date → age → 確認 → yes/no

特定の条件で、予約完了させる
発話 → telephoneNumber(09) → yes

close( "Fulfilled",が必要になります。

スクリーンショット 2022-02-27 16.58.07.png

if slots['telephoneNumber'] is None:
    return elicit_slot('telephoneNumber', intent_name, slots)

telephoneNumber = slots['telephoneNumber']['value']['interpretedValue']

# 電話番号が09の場合、予約完了させる
if telephoneNumber == "09":
    slots = {
        "date": input_slots_value("2022-0227"),
        "telephoneNumber": input_slots_value(telephoneNumber),
        "age": input_slots_value("fmoeuweoiru93r3320io3wrjo32jr32jo32")
        }
    return close( "Fulfilled", '予約完了です。', intent_name, slots)

if slots['date'] is None:
    return elicit_slot(
        'date',
        intent_name,
        slots
    )

#省略

聞き取れなかった場合(解釈できない値)、強制的に予約失敗とする

通常
発話 → telephoneNumber → date → age → 確認 → yes/no

聞き取れなかった場合、強制的に予約失敗させる
発話 → telephoneNumber(09) → date(聞き取れない) → no

スクリーンショット 2022-02-27 17.25.04.png

if slots['telephoneNumber'] is None:
    return elicit_slot('telephoneNumber', intent_name, slots)

telephoneNumber = slots['telephoneNumber']['value']['interpretedValue']

if slots['date'] is None:
    return elicit_slot('date',intent_name,slots)

# 聞き取れなかった場合
if slots['date']['value']['resolvedValues'] == []:
    return close( "Failed",
                '聞き取れませんでした。最初からやり直してください。',
                intent_name,
                slots
                )

date = slots['date']['value']['interpretedValue']

if slots['age'] is None:

#省略

聞き取れなかった場合、lexからlambdaへのslots内のレスポンス

{
    "date": {
        "shape": "Scalar",
        "value": {
            "originalValue": "ttt",
            "resolvedValues": []
        }
    },
    "telephoneNumber": {
        "shape": "Scalar",
        "value": {
            "originalValue": "090",
            "resolvedValues": [
                "090"
            ],
            "interpretedValue": "090"
        }
    },
    "age": null
}

slots['date']['value']['resolvedValues'][]配列が空

slots['date']['value']['originalValue']lexが聞き取った言葉

slots['date']['value']['interpretedValue']なし 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
  3. You can use dark theme
What you can do with signing up
3