はじめに
Lex 組み込みスロットタイプのAMAZON.TIMEを使用した際、
21時
と伝えると、聞き取ってくれますが、9時
だと、9:00 もしくは 21:00
の2通りあるため、Lexがどっちか分からず、エラーになります。
下記のドキュメントに記載されていました。
ただし、時間の発話の範囲が、9:00〜19:00の場合
、9時
と答えると、21時
ではないため、9時と認識してほしいものです。
その方法をまとめます。
事前構築
下記の記事を参考にしました。
Lexは、下記の通りにしました。
実際の発話
21時と答えた場合
LambdaのCloudWatchLogsからログを確認してみると、
interpretedValue(解釈した値)
は、21:00
となっていました。
{
"what_time": {
"shape": "Scalar",
"value": {
"originalValue": "21",
"resolvedValues": [
"21:00"
],
"interpretedValue": "21:00"
}
}
}
-
interpretedValue
Amazon Lex V2 がスロットについて決定する値。実際の値は、ボットの値を選択する設定によって異なります。
ユーザーが入力した値を使用できるか、Amazon Lex V2 に resolvedValues のリスト中の値を選ばせるかが行えます。 -
originalValue
スロットに対して入力されたユーザーからの発話のテキスト。
-
resolvedValues
スロットで認識された追加の値のリスト。
9時と答えた場合
9時と答えるとエラーになりました。
LambdaのCloudWatchLogsからログを確認してみると、
resolvedValues
内に、"09:00","21:00"
の2つがあることがわかります。
{
"what_time": {
"shape": "Scalar",
"value": {
"originalValue": "9",
"resolvedValues": [
"09:00",
"21:00"
]
}
}
}
interpretedValue(解釈した値)
は、ないことも分かりました。
対処方法
LexのLambdaは、以下のようにしました
import json
from decimal import Decimal
# json形式でログを出力するため、Decimalがある場合取り除く
def decimal_to_int(obj):
if isinstance(obj, Decimal):
return int(obj)
def elicit_slot(slot_to_elicit, intent_name, slots):
return {
'sessionState':{
'dialogAction': {
'type': 'ElicitSlot',
'slotToElicit': slot_to_elicit,
},
'intent':{
'name': intent_name,
'slots': slots,
'state': 'InProgress'
}
}
}
def validation_slot(slot_to_elicit, message_content, intent_name, slots):
return {
'messages': [{'contentType': 'PlainText', 'content': message_content}],
'sessionState':{
'dialogAction': {
'type': 'ElicitSlot',
'slotToElicit': slot_to_elicit,
},
'intent':{
'name': intent_name,
'slots': slots,
}
}
}
def confirm_intent(message_content, intent_name, slots):
return {
'messages': [{'contentType': 'PlainText', 'content': message_content}],
'sessionState':{
'dialogAction': {
'type': 'ConfirmIntent',
},
'intent':{
'name': intent_name,
'slots': slots,
'state': 'Fulfilled'
}
}
}
def input_slots_value(value):
return {
"shape": "Scalar",
"value": {
"originalValue": value,
"resolvedValues": [value],
"interpretedValue": value
}
}
def close(fulfillment_state, message_content, intent_name, slots):
return {
'messages': [{'contentType': 'PlainText', 'content': message_content}],
"sessionState": {
'dialogAction': {
'type': 'Close',
},
'intent':{
'name': intent_name,
'slots': slots,
'state': fulfillment_state
}
}
}
# "time"インテント
def time_reserve(intent_request):
print("Received event:" + json.dumps(intent_request, default=decimal_to_int, ensure_ascii=False))
intent_name = intent_request['sessionState']['intent']['name']
slots = intent_request['sessionState']['intent']['slots']
print('Received intent_name:' + json.dumps(intent_name, default=decimal_to_int, ensure_ascii=False))
print('Received slots:' + json.dumps(slots, default=decimal_to_int, ensure_ascii=False))
if slots['what_time'] is None:
return elicit_slot('what_time',intent_name,slots)
what_time_resolved = slots['what_time']['value']['resolvedValues']
counts = len(what_time_resolved)
# あいまいな時間を言った場合
for i in range(counts):
if "09:00" <= what_time_resolved[i] <= "19:00":
what_time = what_time_resolved[i]
slots['what_time']['value']['interpretedValue'] = what_time
break
try:
if "09:00" <= slots['what_time']['value']['interpretedValue'] <= "19:00":
what_time = slots['what_time']['value']['interpretedValue']
# 20時の場合
else:
return validation_slot('what_time',f"{what_time}ですか?時間は、9:00から19:00時の間でお伝え下さい。",intent_name,slots)
# 8時の場合
except KeyError:
return validation_slot('what_time',f"{what_time_resolved[0]}ですか?時間は、9:00から19:00時の間でお伝え下さい。",intent_name,slots)
confirmation_status = intent_request['sessionState']['intent']['confirmationState']
print(confirmation_status)
if confirmation_status == "Confirmed":
return close( "Fulfilled", '承知しました。', intent_name, slots)
elif confirmation_status == "Denied":
return close( "Failed", 'キャンセルしました。', intent_name, slots)
elif confirmation_status == "None":
return confirm_intent(
f"{what_time}ですね?よろしければ、はいと、そうでない場合、いいえとお伝え下さい。",
intent_name, slots)
# インテントのルーティング
def dispatch(intent_request):
# 他にインテントを使用する場合
intent_name = intent_request['sessionState']['intent']['name']
# "book"インテント
if intent_name == 'book':
return book_reserve(intent_request)
# "time"インテント
if intent_name == 'time':
return time_reserve(intent_request)
def lambda_handler(event, context):
return dispatch(event)
注意点ですが、時間を判定する際、時間は、"9:00"
ではなく、"09:00"
と0が必要です。
if what_time < "9:00" : # ✕
if what_time < "09:00" : # ◯
テスト
9時と答えた場合
9時と答えた場合、21:00
ではなく、9:00
と判断されました。
8時と答えた場合
9:00〜19:00
を答えた場合、拒否されます。
別の方法
今回時間範囲が9:00〜19:00
でしたが、時間範囲がない場合の対処法は、時間の前に午前・午後
をつけると聞き取ってくれます。
AMAZON.TIMEの発話リスト
他にも以下の伝え方だと、聞き取ってくれます。
発話 | 判定 |
---|---|
3時 | ✕(聞き取れない) |
15時 | 15:00 |
15時半 | 15:30 |
午後3時 | 15:00 |
午前12時 | 00:00 |
午後0時 | 00:00 |
午後12時 | 12:00 |
午後0時 | 12:00 |
今 | 現在の時刻 |