サンタさんのプレゼント受付窓口のボットを作ってみた – Amazon Connect アドベントカレンダー 2022

I wish you a merry Christmas!サンタさんのためにプレゼント受付窓口のボットを作りました
2022.12.24

こんにちは、洲崎です。
Amazon Connect アドベントカレンダー 2022、24日目の記事です!
クラスメソッドとギークフィードさんの有志が募ってチャレンジしている企画になります。
(アドベントカレンダーのカレンダー一覧はこちら↓)

今日はクリスマスイブということで、サンタさんのプレゼント受付窓口のボットを作ってみました。

実装画面

Amazon Connect Chatを埋め込んだシンプルなWebページです。

チャットで「配達希望日」と「欲しいもの」を伝えます。

チャットが終了したら、Amazon SNSで登録したサンタさんのプレゼント受付窓口宛に「配達希望日」と「欲しいもの」をEメールで連絡する仕組みです。

構成図

Amazon CloudFront × Amazon S3でチャットページを用意します。
裏側はAmazon Lex→AWS Lambda→Amazon SNSでプレゼント受付窓口にEメールで連絡します。
Amazon LexはAWS Lambdaからのreturn値も必要になるため、Lex↔︎Lambda間は交互に指してます。

やってみる

Amazon Lex

Amazon Lexのボットを作成します。
ボットは分かる名前と説明を入力し、IAMロールは自動作成、他はデフォルトです。

インテントでプレゼント窓口のフローを作成します。
インテントは、”サンプル発話”、”スロット”、”Confirmation”、”フルフィルメント”、”応答を閉じる”の箇所を設定します。

サンプル発話


サンプル発話にはトリガーとなる発話をいれます。「プレゼントが欲しい」や「サンタさんにお願いしたい」を入れました。

スロット


チャットで連絡してきた情報をスロットとして保存します。
今回はdelivery(スロットタイプ:AMAZON.Date)で「いつお届けしますか?」に対する回答と、iwant(カスタムスロットタイプ:want)で「何が欲しいですか?」の2つを設定しました。
スロットタイプのAMAZON.Dateは組み込みで用意されているのでそのまま利用できます。
AMAZON.Dateは「today」、「now」、または「12月24日」等の連絡を、2022-12-24として変換する機能です。
今日だけでなく、「来週」や「先週」等も変換可能です。詳しくは下記ドキュメントを参照ください。

カスタムスロットタイプは、組み込みスロットにない情報を保存したい時に使う機能です。別で作成する必要があります。
ボットの”スロットタイプ”から、”スロットタイプを追加”→”空のスロットタイプを追加”でスロットタイプを追加で作成します。
スロットタイプ値のところで、「入力されそうなワード」をいくつか入力します。
今回は「スイッチ」、「カービィのゲーム」、「マリオのゲーム」、「くまのぬいぐるみ」を登録しました。

これ以外の発話だとLexが認識しない為、事前にリサーチして入力しそうな単語を入れるようにします。
(Lexはフリーワードをスロットとして登録する手法がないと思ってますが、もっと良い方法があるよ!という方はブログのコメント欄か、Twitter等で連絡いただけると嬉しいです。)

Confirmation

Confirmationでスロットの内容の確認を簡単に行うことができます。
スロットを指定したい場合はスロットのプロンプトを{}で囲みます。
{delivery}{iwant}を希望でよろしいですか?」と入力します。

フルフィルメント


Lambda関数を設定する項目は、Lambdaを作成する前に設定してテストを行うとエラーが起きてしまうので、テスト後に設定します。
フルフィルメントが成功した場合は「サンタさんにお伝えします」、失敗した場合は「エラーが発生しました」と入力します。

応答を閉じる


チャットを終了する時のメッセージを入力します。
設定が終わったら、右下の”インテントを保存”をクリックし、右上のBuildをクリックします。

Lexのテスト

ここで一旦、Lexの流れをテストします。
右上のTestボタンをクリックし、一連の流れを通して確認します。
”検査”ボタンをクリックすることで、JSONの入力/出力の内容を確認できます。
(マネジメントコンソールがダークモードだとちょっと見づらいですね。。)

最後の”応答”のところのJSONをコピーします。(あとでLambda関数を作成する時に参考にします)
私の場合は、こんな形で出力されていました。

{
 "messages": [
  {
   "content": "サンタさんにお伝えします。",
   "contentType": "PlainText"
  },
  {
   "content": "いい子にして待っててね。",
   "contentType": "PlainText"
  }
 ],
 "sessionState": {
  "dialogAction": {
   "type": "Close"
  },
  "intent": {
   "name": "present",
   "slots": {
    "delivery": {
     "value": {
      "originalValue": "12/25",
      "interpretedValue": "2022-12-25",
      "resolvedValues": [
       "2022-12-25"
      ]
     }
    },
    "iwant": {
     "value": {
      "originalValue": "くまのぬいぐるみ",
      "interpretedValue": "くまのぬいぐるみ",
      "resolvedValues": [
       "くまのぬいぐるみ"
      ]
     }
    }
   },
   "state": "Fulfilled",
   "confirmationState": "Confirmed"
  },
  "sessionAttributes": {},
  "originatingRequestId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
 },
 "interpretations": [
  {
   "nluConfidence": {
    "score": 1
   },
   "intent": {
    "name": "present",
    "slots": {
     "delivery": {
      "value": {
       "originalValue": "12/25",
       "interpretedValue": "2022-12-25",
       "resolvedValues": [
        "2022-12-25"
       ]
      }
     },
     "iwant": {
      "value": {
       "originalValue": "くまのぬいぐるみ",
       "interpretedValue": "くまのぬいぐるみ",
       "resolvedValues": [
        "くまのぬいぐるみ"
       ]
      }
     }
    },
    "state": "Fulfilled",
    "confirmationState": "Confirmed"
   }
  },
  {
   "intent": {
    "name": "FallbackIntent",
    "slots": {}
   }
  }
 ],
 "requestAttributes": {},
 "sessionId": "xxxxxxxxxxxxxxx"
}

この中でresolvedValues2022-12-25くまのぬいぐるみをLambdaで取り出してSNSに連携できれば、メールで内容を送れそうだなということがわかります。

フルフィルメントのLambda設定


テストが終わったら詳細オプションを開き、”フルフィルメントにLambda関数を使用”にチェックを入れます。

最後に右上のBuildをもう1度クリックします。

Amazon SNS

Amazon SNSのトピック作成方法は下記ブログをご確認ください。(数クリックで終了します)

作成できたらSNSのARNを控えておきます。

AWS Lambda

LexからSNSに情報を渡してメールを飛ばすLambdaを作成します。
Python3.9で作成しました。

import boto3

def lambda_handler(event, context):
    topic_arn = "arn:aws:sns:ap-northeast-1:xxxxxxxxxxxxx:lex-to-email"
    subject = "【サンタさんのプレゼント受付窓口】申し込みのお知らせ"

    sns = boto3.resource('sns')
    date = event.get('interpretations',{})[0].get('intent',{}).get('slots',{}).get('delivery',{}).get('value',{}).get('resolvedValues',{})[0]
    iwant = event.get('interpretations',{})[0].get('intent',{}).get('slots',{}).get('iwant',{}).get('value',{}).get('resolvedValues',{})[0]

    platform_endpoint = sns.PlatformEndpoint(topic_arn)

    msg = """
    チャットからプレゼントを受け付けました。\n
    配達希望日: {date}\n
    欲しいもの: {iwant}\n
    """.format(date=date, iwant=iwant)

    response = platform_endpoint.publish(
        Message = msg,
        Subject = subject
    )

    return {
        'sessionState': {
            'dialogAction': {
                'type': 'Close'
            },
            'intent': {
                'name': 'present',
                'state': 'Fulfilled'
        }
    }
 }

topic_arnのところに、控えたSNSのトピックARNを貼り付けます。
datewantはテスト時にJSONで吐き出した値を抽出しています。
dateの場合は今回でいうと2022-12-25、wantはくまのぬいぐるみです。
最後にreturnでLambdaからLexに値を返しています。
今回はAmazon Lex V2のドキュメントに書いてある必須項目のsessionState,dialogAction,intentをreturnで返しました。

LexにLambdaを設定

Lambda関数をデプロイできたら、Lexに対象のLambdaを設定します。
場所はボットのサイドメニューから、エイリアス→言語のJapanese(Japan)→エイリアス言語のサポートです。
ソースとバージョンまたはエイリアスを指定して、保存をクリックします。

Amazon Connect

Amazon Lex、AWS Lambda、Amazon SNSと設定できたので、最後はAmazon Connectを設定します。
マネジメントコンソールの問い合わせフローに飛んで、Amazon Lexの部分で作成したボットとエイリアスを指定して、”Amazon Lex ボットを追加”をクリックします。

Amazon Connectコンソールに入り、フローを作成します。(ほぼLexに任せてるのでかなりシンプルです)

”顧客の入力を取得する”ブロックでLexを設定します。
アナウンスはテキスト読み上げで「サンタさんのプレゼント受付窓口です。プレゼントが欲しいと送信してください。」と入力し、追加したLexボットを指定します。

これで、Amazon Connect、Amazon Lex、AWS Lambda、Amazon SNSを連携することができました!

Amazon Connect Chat

こちらは、下の記事で構築手順を載せてますので割愛します。

作成したAmazon Connectのフローを紐づけてもらえれば、チャットで一連の動作の確認が可能です。

最後に

クリスマスイブということで、サンタさんのプレゼント受付のボットを作ってみました!
実際作ってみようと思うと、Lambdaはどう書くのだろうとか、Lexはどう設定したらいいのだろう等、色々考えることがあり勉強になりました。
これからも”何か作ってみよう”の気持ちを忘れずに、色々試していきたいと思います。

いよいよ、明日はAmazon Connect Advent Calendar 2022の最終日です!(あっという間ですね)
ギークフィード 西山さんが執筆予定です。ぜひ楽しみにしてください!

ではまた!コンサルティング部の洲崎でした。