Lexとは
AWSのbotのAIサービス。Amazon Lex を使うと、すべてのデベロッパーが Amazon Alexa に採用されている深層学習技術と同じ技術を利用できるため、自然言語での高度な対話ボット (チャットボット) を短時間で簡単に構築できます。
今回はlexを用いてアイスクリームのフレーバーや容器について答えるボットを作成して行きます。
コードの量があるので順番に解説して行きます。
ボット作成ファイルの全体像
import boto3
import time
iam = boto3.client('iam')
iam.create_service_linked_role(AWSServiceName='lex.amazonaws.com')
lex = boto3.client('lex-models', 'us-east-1')
#フレーバーのスロットタイプの作成
flavor_slot_type = lex.put_slot_type(
name='FlavorSlotType',
enumerationValues=[
{'value': 'vanilla'},
{'value': 'chocolate', 'synonyms': ['choc']},
{'value': 'strawberry', 'synonyms': ['berry']}
],
valueSelectionStrategy='TOP_RESOLUTION',
createVersion=True)
print('slot type:', flavor_slot_type['name'])
#容器のスロットタイプを作成
container_slot_type = lex.put_slot_type(
name='ContainerSlotType',
enumerationValues=[
{'value': 'corn'},
{'value': 'cup'}
],
valueSelectionStrategy='TOP_RESOLUTION',
createVersion=True)
print('slot type:', container_slot_type['name'])
#インテントの作成
intent = lex.put_intent(
name='OrderIntent',
#インテント内のスロット
slots=[
{
'name': 'Flavor',
'slotConstraint':'Required',
'slotType':'FlavorSlotType',
'slotTypeVersion': '1',
'valueElicitationPrompt': {
'messages': [{
'contentType': 'PlainText',
'content': 'Vanilla, chocolate or strawberry?'
}],
'maxAttempts': 3
}
},
{
'name': 'Container',
'slotConstraint': 'Required',
'slotType': 'ContainerSlotType',
'slotTypeVersion': '1',
'valueElicitationPrompt': {
'messages': [{
'contentType': 'PlainText',
'content': 'Corn or cup?'
}],
'maxAttempts': 3
}
}
],
#発話例
sampleUtterances=[
'I want {Flavor} ice cream in {Container}',
'{Flavor} ice cream {Container}',
'ice create'
],
#完了時のセリフ
conclusionStatement={
'messages': [{
'contentType': 'PlainText',
'content': 'OK, {Flavor} ice cream in {Container}'
}],
},
#完了の動作
fulfillmentActivity={'type': 'ReturnIntent'},
createVersion=True)
print('intent:',intent['name'])
#ボットの作成
bot = lex.put_bot(
name ='MyBot', locale='en-US', childDirected=False,
#インテント
intents=[
{
'intentName': 'OrderIntent',
'intentVersion': '1'
}
],
#中止時のセリフ
abortStatement={
'messages':[
{
'contentType': 'PlainText',
'content': 'Please try again.'
}
]
},
voiceId='Joanna',
createVersion=True)
print('bot:', bot['name'])
#ボット作成の進捗表示
start = time.time()
status = ''
while status not in ['READY', 'FAILED']:
#ボットを取得
status = lex.get_bot(name='MyBot', versionOrAlias='1')['status']
time.sleep(10)
print('{:7.2f} {}'.format(time.time()-start, status))
#作成に失敗した場合は理由を表示
if status == 'FAILED':
print(lex.get_bot(
name='Mybot', versionOrAlias='1')['failureReason'])
#ボットエイリアスを作成
bot_alias = lex.put_bot_alias(
name='MyBotAlias', botName='MyBot', botVersion='1')
print('bot alias:', bot_alias['name'])
①importとサービスクライアント作成
import boto3
import time
iam = boto3.client('iam')
iam.create_service_linked_role(AWSServiceName='lex.amazonaws.com')
lex = boto3.client('lex-models', 'us-east-1')
boto3とtimeのインポートとiamのロールとlexのサービスクライアントを作成
②スロットタイプ作成
スロットとはユーザーから聞き出す必要のあるパラメーターです。
今回はフレーバーと容器をスロットに設定しています。
#フレーバーのスロットタイプ
flavor_slot_type = lex.put_slot_type(
name='FlavorSlotType',
enumerationValues=[
{'value': 'vanilla'},
{'value': 'chocolate', 'synonyms': ['choc']},
{'value': 'strawberry', 'synonyms': ['berry']}
],
valueSelectionStrategy='TOP_RESOLUTION',
createVersion=True)
print('slot type:', flavor_slot_type['name'])
#容器のスロットタイプ
container_slot_type = lex.put_slot_type(
name='ContainerSlotType',
enumerationValues=[
{'value': 'corn'},
{'value': 'cup'}
],
valueSelectionStrategy='TOP_RESOLUTION',
createVersion=True)
print('slot type:', container_slot_type['name'])
put_slot_typeメソッドでスロットを作成します。
enumerationValuesでスロットが取りうる値を辞書型で指定
valueSelectionStrategyの'TOP_RESOLUTION'はスロットタイプの中からユーザーの言葉に近いものを返します。今回でいえばchocoと入力すると本来の値のchocolateが返ってくる。
③インテントの作成
intentとは意思や意図という意味がありますが、lexの中ではユーザーと会話する台本のイメージになります。
今回をアイスクリーム注文するコマンドを受け取るインテントを作成します。パラメーターとしてアイスクリームのフレーバーと容器を受け取リます。
put_intentメソッドでインテントを作成します。
引数slotsについて
#インテントの作成
intent = lex.put_intent(
name='OrderIntent',
#インテント内のスロット
slots=[
{
'name': 'Flavor',
'slotConstraint':'Required',
'slotType':'FlavorSlotType',
'slotTypeVersion': '1',
'valueElicitationPrompt': {
'messages': [{
'contentType': 'PlainText',
'content': 'Vanilla, chocolate or strawberry?'
}],
'maxAttempts': 3
}
},
{
'name': 'Container',
'slotConstraint': 'Required',
'slotType': 'ContainerSlotType',
'slotTypeVersion': '1',
'valueElicitationPrompt': {
'messages': [{
'contentType': 'PlainText',
'content': 'Corn or cup?'
}],
'maxAttempts': 3
}
}
],
引数slotsはインテント内にスロットを作成するために使います。
・slotConstraint:スロットの制約です。'Required'または'Optinal'で選択。
・slotTypeVersion:スロットのバージョン。最初はバージョン'1'
・valueElicitationPrompt:スロットの値をユーザーから促すためのセリフ
→valueElicitationPromptに指定する辞書の項目
・message:セリフを表す辞書リスト。その中にcontentTypeとcontentが含まれる
・maxAttempts:聞き返す回数の上限
→→messageに指定する辞書の項目
・contentType:セリフのタイプ。'PlainText','SSML','CustomPayload'から指定
・content:セリフの内容
引数sampleUtterances
#発話例
sampleUtterances=[
'I want {Flavor} ice cream in {Container}',
'{Flavor} ice cream {Container}',
'ice create'
],
引数sampleUtterancesはインテントに対するユーザーの発話例です。
{スロット名}でスロットを表します。{Flavor}の部分にはフレーバー(chocolate,strawberry,vanilla)が入り、{Container}には(cupなど)が入ります。
今回ユーザーの発話を見ることはなさそうですね。
引数conclusionStatement
#完了時のセリフ
conclusionStatement={
'messages': [{
'contentType': 'PlainText',
'content': 'OK, {Flavor} ice cream in {Container}'
}],
},
引数conclusionStatementはボットがユーザーから必要なスロットの情報を聞き出すことができて、インテントが完了したときのセリフです。辞書型の項目として引数slotsのvalueElicitationPromptに指定する辞書の項目と同じです。
引数fulfillmentActivity
#完了の動作
fulfillmentActivity={'type': 'ReturnIntent'},
createVersion=True)
print('intent:',intent['name'])
引数fulfillmentActivityはインテントが完了したときの動作です。
引数にはキー'type'を含む辞書を指定します。
typeの種類
ReruenIntent:呼び出し元のプログラムにインテントの情報を返します。
CodeHook:Lambda呼び出してLambdaに登録されたプログラムを実行します。
④botの作成
最後にボットとボットエイリアスを作成します。Lexでbotを公開するにはボットエイリアスを作成する必要があります。
#ボットの作成
bot = lex.put_bot(
name ='MyBot', locale='en-US', childDirected=False,
#インテント
intents=[
{
'intentName': 'OrderIntent',
'intentVersion': '1'
}
],
#中止時のセリフ
abortStatement={
'messages':[
{
'contentType': 'PlainText',
'content': 'Please try again.'
}
]
},
voiceId='Joanna',
createVersion=True)
print('bot:', bot['name'])
put_botメソッドを呼び出してボットを作成します。
引数のnameは名前、localeは今回'en-US'、childDirected(子供向け)は子供向けの場合にはTrue、子供向けではない場合はFalseに指定。
引数intentはnameとintentVersionを辞書型で渡します。
引数abortStatementには中止時のセリフを辞書型のリストにして指定します。
voiceIdは'en-US'の中から'Joanna'に指定します。
作成時の進捗時間表示
#ボット作成の進捗表示
start = time.time()
status = ''
while status not in ['READY', 'FAILED']:
#ボットを取得
status = lex.get_bot(name='MyBot', versionOrAlias='1')['status']
time.sleep(10)
print('{:7.2f} {}'.format(time.time()-start, status))
#作成に失敗した場合は理由を表示
if status == 'FAILED':
print(lex.get_bot(
name='Mybot', versionOrAlias='1')['failureReason'])
#ボットエイリアスを作成
bot_alias = lex.put_bot_alias(
name='MyBotAlias', botName='MyBot', botVersion='1')
print('bot alias:', bot_alias['name'])
get_botメソッドでボットの情報を取得しstatusへ、10秒間時間を待ち開始からに時間と取得したボットの情報をstatusに代入して表示します。
作成に失敗した場合は、失敗した理由を取得し表示。
put_bot_aliasメソッドでボットエイリアスを作成し、画面に表示します。
まとめ
ここまで長くなりましたが、lexでのbot作成のコードと解説でした。
次回はbotにテキストを与えて動かしてみます。
参考文献
この記事は以下の情報を参考にして執筆しました
AWSでつくるAIプログラミング入門