AmazonConnectとLambdaの連携と拡張


#はじめに
こんにちは，僕はエンジニア歴1年目のユウジロウと申します．
僕は大学院生の最後の半年間，株式会社ノベルワークスでインターンし，その際にAmazon Connectを使って音声ボットシステムの開発に携わりました．
その時に感じたあれこれや，備忘録を残しておきたいと思います．
難易度としては，ちょっとConnectを触ってみてこれからサービスを作る人向けの内容になっています．

#Amazon Connect とは
Amazon Connectとは顧客対応する音声システムを簡単に作れる，AWSサービスの１つです．AWSのLambdaやKinesis Video Streams（KVS）と組み合わせて拡張ができます．

体感とても簡単です．直感的なUIと機能が理解しやすくサクサク開発ができます．
また料金も従量課金制なので，使った分だけ請求されます．

大変だった点は様々な拡張機能に関する技術ブログや，公式ページの説明が薄かった点です．調べてもなかなかわからないことが多くありました．また拡張方法も充実しているのですが，LambdaやKVSを使うとその分料金が発生し，「本当に要求されている機能に対してこの設計でいいのか？」を何度も練り直しました．

Connectの設計次第で，運用費用が大きく変わるので突き詰める必要があります．

##読み方の拡張
Amazon Connectには指定した文字の読み上げに，SSMLタグを使用し読み方を拡張できます．
まず［プロンプトの再生］ブロックのテキストの読み上げの中で拡張したいテキストを<speak>〜</speak>で囲みます．

［解釈する］をSSMLに設定し，準備完了です．
⚠︎段落は考慮されません．また間違えたタグはそのまま読まれてしまいます．
<img width="500" alt="スクリーンショット 2021-03-05 17.37.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/225231ba-2bd3-e14f-4507-9159ed01f73d.png">

###一時停止，breakタグ
最大10秒間一時停止できます．
この間にバックエンドの処理を走らせるという使い方をしました．
<img width="500" alt="スクリーンショット 2021-03-05 17.45.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/70ddd22a-c55b-9728-8d02-6743a2d3625d.png">


###その他の読み上げタグ
色々読み方の拡張があったのですが <break>タグ以外は結局使用しませんでした．
読み上げスピードの変更や
使えそうなタグに<lang>タグがありましたが，日本語対応していないみたいです．
<lang>タグは，タグで囲まれた語句を指定言語で読み上げます．Connectの日本語の読み上げは完璧ではなく，「HP」を「エイチピー」とカタカナで読むため「ホームページ」と指定する必要があります．簡単な英単語の読み上げができないので，<lang>タグが機能すればかなり便利だと思います．
その他の使用できるタグは，AWSの公式の[詳しいタグ一覧](https://docs.aws.amazon.com/ja_jp/polly/latest/dg/supportedtags.html#prosody-tag)で参照できます．

##通話時間，オペーレーター数による制御
例えば入電からの通話時間で分岐させたい時は「キューの状態を確認する」ブロックを使用します．
また転送先のオペレーターの数が足りない時，待機してもらうには「人員の確認」ブロックを使用します．

<img width="500" alt="スクリーンショット 2021-03-13 21.17.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/4ce44c28-8ece-a831-98f0-187a0c4fbb84.png">


##営業時間に応じた反応の変化
サービスにオペレータ機能がある場合，営業時間内のみ転送でき，時間外はシステムが受け答えすることが理想的です．
これは「オペレーション時間を確認する」ブロックで実現可能です．
しかし，この方法ではオペレーション可能時間をConnectに登録しなければなりません．
営業時間外の変更や急な休業などの際に，Connectで一々管理しないといけないので，建設的ではありません．

そこでLambdaを呼び出し，Dynamoを参照することで営業時間に応じたフローを実現できます．
この後の［動的な読み上げ設計］の［Lambdaで変数を設定］で説明します．

<img width="500" alt="スクリーンショット 2021-03-13 21.19.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/17fa29bc-5373-a790-8e77-ee085d59624f.png">

<img width="500" alt="スクリーンショット 2021-03-14 21.38.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/20e0ab82-b1e2-0cdf-ac74-d725f09dd088.png">

##動的な読み上げ設計
Connectを使っていると動的な読み上げ機能が欲しくなります．
動的な読み上げを実現するには２パターンあります．

###顧客入力（IVR）と分岐で動的な読み上げインタラクション
よく音声案内サービで「新規お申し込みの方は１を，契約済の方は２を，その他のお問い合わせの方は３を押してください」というインタラクションがあると思います．Amazon Connectでは「顧客の入力を取得する」ブロックが用意されており，IVR入力によりフロー分岐させることが可能です．

まず「顧客の入力を取得する」ブロックを設置します．
<img width="500" alt="スクリーンショット 2021-03-14 18.39.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/bba07a23-6962-58c2-83d6-8f73e8d5c5ff.png">

次にブロック内に読み上げるテキストを入力します．
<img width="500" alt="スクリーンショット 2021-03-14 18.43.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/9e0c6584-1b3f-b821-4b36-7497be2df5d4.png">

ブロック内のDTMFを設定します．
タイムアウト時間は入力がなかった時の反応で，最小1秒，最大10秒設定できます．
「別の条件の追加」でオプションを増やします．
オプションにはIVRで入力する１から４の数字を入れます．これにより入力に応じた分岐を作れます．

<img width="500" alt="スクリーンショット 2021-03-14 19.14.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/a9a8022b-a18f-0eb4-b2a7-ffdef1d5f365.png">


全体的にはこのようになります．
急ぎ１〜急ぎ４は１から４の入力に応じた分岐です．
「デフォルト」は１〜４以外の想定されていない入力があった時の分岐です．
その時はもう一度入力して欲しいので，IVRに戻るようにフローを作ります．
しかし，ブロックが自分自身を指定できないので，「プロンプトの再生」や「問い合わせ属性の設定」ブロックなど適当なブロックを挟みましょう．
「もう一度聞きたい方」向けにもこの方法で戻れるようにしましょう．
![スクリーンショット 2021-03-14 19.26.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/bd4bd0af-6df4-9810-5201-a88aa54145a9.png)


###Lambdaで変数を設定
Connectから呼び出したLambdaで指定した変数を読み上げることができます．
またLambdaで設定した変数を使って，分岐やループも可能です．
Lambdaとの連携により，電話番号からデータベースの検索や，ユーザによって対応を変えるコールbotの作成も可能です．
![スクリーンショット 2021-03-05 19.58.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/d53ba5c0-35d6-a015-1e71-2d47d5b052dc.png)


Lambdaの作成
Connectから呼び出すLambdaを作成し，読み上げたい文字列を変数に格納，returnする．
ここで営業時間内外を判断したり，挨拶を時間によって変更したり，データベースを参照し，電話をかけてきているユーザの会員情報を参照することができます．
スクショはNode.js 14xで書かれています．
![スクリーンショット 2021-03-05 19.10.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/3606ba8b-e7b3-5ce2-4bb6-3b8273662266.png)

Connectのコンソールではなく，AWS側のConnectコンソールで使用するLambdaを追加します．

![スクリーンショット 2021-03-05 18.47.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/07969a48-363b-658f-5615-d1820941aa5c.png)

Connectで［AWS Lambda 関数を呼び出す］ブロックを設置します．
ここで上の「AWS側のConnectコンソールで使用するLambdaを追加」をしていないとLambdaを呼び出せないので，忘れずにしましょう

［問い合わせ属性の設定］ブロックでLambdaからの返り値を固定します．
これにより，Connectで使える変数を定義できます．
**このブロックを［AWS Lambda 関数を呼び出す］ブロックの直後に設置しないと，返り値を保存できません．**
![スクリーンショット 2021-03-14 22.22.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/686e373c-f176-a196-ed9e-e46a47999e00.png)


↓［問い合わせ属性の設定］ブロック内の設定
<img width="500" alt="スクリーンショット 2021-03-05 19.16.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/dbb31777-c6d7-aff2-21af-022c7f825218.png">

プロンプトの再生でこのように記述します．
これにより，問い合わせ属性で設定した値を読み上げることが可能です．
今回の場合は「おはようございます．アマゾンコネクトです．」と読み上げられます．
「Attributes」の部分はおまじないのようなものです．なので「$.Attributes.」以降で変数を指定してください．

<img width="500" alt="スクリーンショット 2021-03-05 20.30.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/76e5dc51-1c1b-e7c7-f43b-2383401d9f6c.png">

全体設計はこのようになります．
このLambdaとConnect，Connect内の分岐を使えば，営業時間内外のフローの分岐も実現可能です．
とても便利でできることかなり増えるので，この連携はおすすめです．
![スクリーンショット 2021-03-05 20.16.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605275/5e33021f-75fe-e632-a9fb-5bb7441f7ad3.png)


#総評
とても扱いやすく，拡張方法も工夫次第で多いのですが，まだまだできないことも多くあります．
例えばリアルタイムの文字起こしの機能はまだなく，外部のAPIを使用しないと実現できません．
AWS Transcribeの日本語対応も2019年11月に実装されたのですが，リアルタイムではなく通話終了後の処理のみとなっています．

しかし日々細かなアップデートもきてるみたいで，見る度にコンソール画面が少し変わっています．
まだまだ機能を追加してくれる雰囲気があるので，今後に期待です．
個人的には**Contact Lens**という機能が楽しみです．
リアルタイムで会話の文字起こし，自然言語分析，感情分析をしてくれるらしいです．
話しているユーザが不快感に感じていないかどうかなどもわかるみたいです．
現在（2021年3月）は日本語対応しておらず，実装が楽しみです．