1. はじめに
- Alexaの音声アプリみたいなのを作ろうと思い、前回の記事「Amazon Nova Sonic を使ってみる 」では、「Amazon Nova Sonic」という、Speech to Speech タイプのLLMを使ったVoiceBotを作成した。
- 「Amazon Nova Sonic」は2025/7時点ではまだ日本語対応していないため、現時点で日本語のVoiceBotを作るにはやはり Amazon Lex なのかな?と思い、Amazon Lex を初めて使ってみる。
2. やったこと
3つのステップで構築、動作確認を行った。
- Step1 Lex(マネコン)に直接入出力
- Amazon Lex だけを用いて、簡単な対話ボット(星座占い)を作成する。
- マネコン上で文字入力、もしくは音声入力での対話ができることを確認する。
- Step2 LexにLambda処理を追加
- Lambdaを追加して、簡単な処理を行い、入力された内容に基づく回答ができるようにする。
- Step3 フロントエンドをWEB化
- マネコンではなく、ブラウザから対話できるようにする。
3. 構成図
4. 予習
4.1 チュートリアルの実施
- 公式ドキュメント「Amazon Lex V2 のコア概念」を見てから、「演習 1: 例からボットを作成する」を実施し、お花屋さんボットを作ることによって超基本概念を学習した。
- ここで学んだことメモ
- ボットの中で「インテント」を作成する。「インテント」は、対話を通じて達成したいこと。インテントの例としては「花を注文する」。
- 「インテント」を達成するための「スロット」を用意する。基本的には全てのスロットが埋まればインテントを完了できる。スロットの例としては「花の種類」「お届け日」「お届け時刻」
- 「スロットタイプ」で、スロットに入る値の型を規定できる。スロットタイプの例は以下。
- 「花の種類」:カスタム(ユリ、バラ、チューリップ)
- 「お届け日」:Date
- 「お届け時刻」:Time
4.2 builders.flashのLexの記事の実施
- builders.flashの記事「1 時間で Amazon Lex の掛け算九九練習ボットを作る」に、今回やりたいこと(Lambdaでの処理、マネコンではなくブラウザからの音声入力)の方法があったため、こちらをそのまま実施した。
- さすがに2021年の記事のため、マネコンの表示変更があったり、CloudFormationでいろいろエラーになったりして、結局完走するのに4時間くらいかかった。
5. 構築&動作確認
5.1 Step1 Lex(マネコン)に直接入出力
Step1では、チュートリアルのお花屋ボットと同レベルの、単純なボットを作成する。(中身としては、ユーザに星座を聞いて、「xx座ですね!」と言うだけのボット)
ボットの作成
まずはボットを作成し、対応言語として日本語を追加する。
「Lex > ボット > ボットを作成」から、新規にボットを作成する。
カスタムスロットの作成
続けてインテント作成の画面になるが、先にカスタムスロットを作成する。
-
ユーザに「あなたの星座を教えてください」と聞いた結果を入れるスロットには、「いて座」「かに座」などのあらかじめ定義した値のみを格納したい。そのため、まずカスタムスロットタイプを作成する。
-
「mksamba-holoscope > 中略 > スロットタイプ」から、「スロットタイプを追加 -> 空のスロットタイプを追加」する。タイプ名は zodiac_type とする。
-
スロットタイプ値を入力する。12星座それぞれに対して、「おひつじ座」「牡羊座」のように入力している。意図ととしては、ひらがなで入力されても漢字で入力されても同義として処理し、内部で処理するときは「おひつじ座」のようなひらがなの値で処理するようにしている。
- スロットタイプの値の入れ方は、こちらの記事「Amazon Lex カスタムスロットタイプの「値を展開」と「スロット値に制限」の違いをまとめみた」を参考にした。
インテントの作成
次にインテント(やりたいこと)を作成する。
- インテント名は「holoscope」とする。
- サンプル発話(このインテントを呼び出すフレーズ)として「星座占い」を設定する。
- 初期応答(インテント開始時のメッセージ)として、「星座占いを始めます!」を設定する。
- スロット(インテントを完了するのに必要な情報)として、「user_zodiac_type」を作成し、前の手順で作成したスロットタイプ(zodiac_type)を指定する。
- フルフィルメント(スロットの情報取得が完了)した際のメッセージとして、「あなたの星座はxx座ですね!」を登録する。
- 応答を閉じる際のメッセージとして、「終わりです」を登録する。
- インテントを保存し、「構築」を押してボットを作成する。
動作確認
「テスト」を使用して、マネコン上での動作確認が可能。
- まずはテキスト入力で動作確認を行う。
- サンプル発話に登録した「星座占い」を入力することで、インテントが開始される。
- 星座情報を得るまで問い合わせを行う。
- 「獅子座」のように漢字で入力されても、「しし座」のようにひらがなに変換して処理する。
- マイクのマークを押すことで、音声での入力も可能。音声で入力した場合、Kazuhaが音声で応答してくれる。
- 活舌が悪いとなかなか認識してもらえない。
- 入力欄左のマイクのマークを押して音声入力し、入力欄右のチェックボタンを押して入力を完了する。右のチェックボタンを押さないと音声入力が終わらず、音声認識が開始されない、、ということに気づくまで1時間かかった。
5.2 LexにLambda処理を追加
Step2では、フルフィルメントの完了時(=ユーザの星座のヒアリングができた時)にLambda関数を呼び出し、ユーザの入力した星座に応じた回答を作成し、結果をユーザに返答する。
Lambdaの作成
今回予習に用いた、builders.flashの記事「1 時間で Amazon Lex の掛け算九九練習ボットを作る」に、Lambdaのサンプルがあるため、Lexとの値の受け渡しの部分はそのまま使わせて頂き、星座ごとに回答を変える部分のロジックだけ作成する。
- 作成した Lambda関数は以下。ヘルパー関数などはそのままとし、星座ごとに別々の回答を作成するロジックだけを追加する。(おとめ座と、かに座だけ個別メッセージで他はまとめているが、、)
def get_slots(intent_request):
return intent_request['sessionState']['intent']['slots']
def get_slot(intent_request, slotName):
slots = get_slots(intent_request)
if slots is not None and slotName in slots and slots[slotName] is not None:
return slots[slotName]['value']['interpretedValue']
else:
return None
def get_session_attributes(intent_request):
sessionState = intent_request['sessionState']
if 'sessionAttributes' in sessionState:
return sessionState['sessionAttributes']
return {}
def close(intent_request, session_attributes, fulfillment_state, message):
intent_request['sessionState']['intent']['state'] = fulfillment_state
return {
'sessionState': {
'sessionAttributes': session_attributes,
'dialogAction': {
'type': 'Close'
},
'intent': intent_request['sessionState']['intent']
},
'messages': [message],
'sessionId': intent_request['sessionId'],
'requestAttributes': intent_request['requestAttributes'] if 'requestAttributes' in intent_request else None
}
def lambda_handler(event, context):
intent_name = event['sessionState']['intent']['name']
text = ''
zodiac_type = get_slot(event, 'user_zodiac_type')
print(zodiac_type)
if zodiac_type == 'おとめ座':
text = 'おとめ座だと、シャカさんと同じですね。六道輪廻!大吉です。'
elif zodiac_type == 'かに座':
text = 'かに座だと、デスマスクさんと同じですね。積尸気冥界波!小吉です。'
else:
text = f'{zodiac_type}ですか。興味深いですね。中吉です。'
message = {
'contentType': 'PlainText',
'content': text
}
fulfillment_state = "Fulfilled"
session_attributes = get_session_attributes(event)
return close(event, session_attributes, fulfillment_state, message)
ボット設定の修正
フルフィルメントが完了した際にLambdaを呼び出すようにインテントの設定を追加する。
- フルフィルメントの「詳細オプション」を開き、「フルフィルメントにLambda関数を使用」にチェックを入れる。
- ボットの「エイリアス」のところに、このボットで呼び出すLambda関数を指定する。
動作確認
Step1と同様、Lexのマネコンのテスト機能を用いて動作確認する。
5.3 フロントエンドをWEB化
Step2まではLex(マネコン画面)での入出力を行っていたが、それだと他の人に見せづらいため、フロントエンドをWEBに変更する(出来合いのCloudFormationテンプレートがあるのでそれを利用するだけ)。
CloudFormation によるCloudFront, S3の展開
今回予習に用いた、builders.flashの記事「1 時間で Amazon Lex の掛け算九九練習ボットを作る」に、CloudFrontでWEBインターフェースを作成する資材が紹介されているため、そのまま使用する(Githubはこちら)。
- スタックの作成画面で、以下の設定値を入力する。
- LexV2BotId: 自分のBotのID
- LexV2BotAliasId: 自分のBotのエイリアスのID
- LexV2BotLocaleId: ja_JP
- 機能的にはCognitoでのユーザ認証なども実装されているが、今回は使用しない。
動作確認
Cloudfrontにブラウザでアクセスして、ブラウザから文字入力および音声入力でのやりとりができることを確認する。
-
デフォルト設定のままデプロイしたので、タイトルがOrder Flowers、最初のメッセージが「『Buy flowers』で会話を始めましょう」になっていたり、完了時にgood/badを評価するボタンがあるが、そのあたりは修正可能。
-
文字入力は、Lexマネコンのテスト画面と同様に使用可能。
- 音声入力も、Lexマネコンのテスト画面と同様に使用可能(活舌がよい必要あり)。以下は「おとめ座」の発音がなかなかLexに認識してもらえないところ。Lexマネコンと同様、音声入力した場合、音声で回答してくれる。
6. 所感
- やっとLexデビューすることができた。生成AI(Bedrock)との連携ができるまで頑張りたい。