0
0

More than 3 years have passed since last update.

AWSでAIサービスを使ってみる〜第9回lex編〜

Last updated at Posted at 2021-09-15

Lexとは

AWSのbotのAIサービス。Amazon Lex を使うと、すべてのデベロッパーが Amazon Alexa に採用されている深層学習技術と同じ技術を利用できるため、自然言語での高度な対話ボット (チャットボット) を短時間で簡単に構築できます。

今回はlexを用いてアイスクリームのフレーバーや容器について答えるボットを作成して行きます。
コードの量があるので順番に解説して行きます。

ボット作成ファイルの全体像

lex_create_bot.py
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とサービスクライアント作成

lex_create_bot.py
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のサービスクライアントを作成

②スロットタイプ作成

スロットとはユーザーから聞き出す必要のあるパラメーターです。
今回はフレーバーと容器をスロットに設定しています。

lex_create_bot.py
#フレーバーのスロットタイプ
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について

lex_create_bot.py
#インテントの作成
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

lex_create_bot.py
 #発話例
  sampleUtterances=[
    'I want {Flavor} ice cream in {Container}',
    '{Flavor} ice cream {Container}',
    'ice create'
  ],

引数sampleUtterancesはインテントに対するユーザーの発話例です。
{スロット名}でスロットを表します。{Flavor}の部分にはフレーバー(chocolate,strawberry,vanilla)が入り、{Container}には(cupなど)が入ります。
今回ユーザーの発話を見ることはなさそうですね。

引数conclusionStatement

lex_create_bot.py
 #完了時のセリフ
  conclusionStatement={
      'messages': [{
          'contentType': 'PlainText',
          'content': 'OK, {Flavor} ice cream in {Container}'
      }],
  },

引数conclusionStatementはボットがユーザーから必要なスロットの情報を聞き出すことができて、インテントが完了したときのセリフです。辞書型の項目として引数slotsのvalueElicitationPromptに指定する辞書の項目と同じです。

引数fulfillmentActivity

lex_create_bot.py
  #完了の動作
  fulfillmentActivity={'type': 'ReturnIntent'},
  createVersion=True)
print('intent:',intent['name'])

引数fulfillmentActivityはインテントが完了したときの動作です。
引数にはキー'type'を含む辞書を指定します。

typeの種類
ReruenIntent:呼び出し元のプログラムにインテントの情報を返します。
CodeHook:Lambda呼び出してLambdaに登録されたプログラムを実行します。

④botの作成

最後にボットとボットエイリアスを作成します。Lexでbotを公開するにはボットエイリアスを作成する必要があります。

lex_create_bot.py
#ボットの作成
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'に指定します。

作成時の進捗時間表示

lex_create_bot.py
#ボット作成の進捗表示
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プログラミング入門

0
0
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
0
0