LoginSignup
1
3

簡易ヘルプデスクボットの作成

Posted at

はじめに

Amazon Connect、Lambda、Lex、DynamoDBを使って、ヘルプデスクボットを作成してみました。

完成イメージ

スクリーンショット 2023-11-13 120029.png

Work1: コンタクトフロー作成

Step 1: LambdaとDynamoDBによるサーバーレスアプリの構築

1. DynamoDBの作成

①AWS コンソール から Amazon DynamoDB を選択し、テーブルの作成を選択します。
②テーブルの作成ページで、テーブル名を connectDemo、パーティションキーを phoneNumber 文字列に設定します。
スクリーンショット 2023-11-13 092644.png
③その他のオプションはデフォルトのまま、テーブルの作成を選択します。
connectDemo テーブルは正常に作成されました。が表示されれば成功です。

2. 新しい IAM ロールの作成

①AWS コンソール から IAM を選択し、アクセス管理セクションのロールを選択し、ロールを作成を選択します。
②信頼されたエンティティタイプはAWS のサービスを、ユースケースはLambda
を選択します。
③ポリシーのフィルタ欄で AWSLambdaBasicExecutionRole と入力して Enter キーを押し、表示されたポリシーを選択状態にします。
スクリーンショット 2023-11-13 093247.png
④フィルターをクリアし、前の手順と同様に AmazonDynamoDBFullAccess と入力して Enter キーを押し、表示されたポリシーを選択します。次へを選択します。
スクリーンショット 2023-11-13 093520.png
⑤ロール名を ws-LambdaDynamoRole と入力します。ここまでの手順で設定した内容が正しいことを確認し、ロールの作成を選択します。
スクリーンショット 2023-11-13 093731.png
ロール ws-LambdaDynamoRole が作成されました。と表示されれば成功です。

3. Lambda 関数の作成

①AWS コンソール から、AWS Lambda を選択し、関数の作成を選択します。
②一から作成を選択し、関数名に dbDemoを入力します。ランタイムはNode.js 16.x を選択します。
スクリーンショット 2023-11-13 094128.png
デフォルトの実行ロールの変更を展開し、既存のロールを使用するを選択します。既存のロールドロップダウンリストで、上記の IAM で作成したロールを選択し、関数の作成を選択します。
スクリーンショット 2023-11-13 094348.png
④下記の Javascript サンプルコード をコピーし、コードセクションの Lambda コードに貼り付けます。Deploy を選択し、関数を保存します。

Javascript サンプルコード
/*
MIT No Attribution

Copyright 2021 Amazon Web Services, Inc. or its affiliates. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

// Get the AWS SDK and Dynamo SDKs ready
var AWS = require("aws-sdk");
var docClient = new AWS.DynamoDB.DocumentClient();

//Sets the timezone environment variable for the Lambda function
process.env.TZ = "Asia/Tokyo";

exports.handler = (event, context, callback) => {
    // set the options for the date format
    var dateOptions = {
        weekday: "short",
        year: "numeric",
        month: "short",
        day: "numeric"
    };

    // set the variables to record the current local date and time
    var currentShortDate = new Date().toLocaleDateString();
    var currentLongDate = new Date().toLocaleDateString("ja-JP", dateOptions);
    var currentTime = new Date().toLocaleTimeString("ja-JP");
    var currentTimeStamp = new Date().toString();

    //log the incoming event from Amazon Connect for troubleshooting purposes
    console.log("Received event from Amazon Connect at: " + currentTimeStamp);
    console.log("Amazon Connect Event Details: " + JSON.stringify(event));

    //set the variables for the customer ANI and unique contact ID
    var sourcePhoneNumber = event.Details.ContactData.CustomerEndpoint.Address;
    var currentContactId = event.Details.ContactData.ContactId;

    //set up the database query to be used to lookup customer information from DynamoDB
    var paramsQuery = {
        //DynamoDB Table Name.  Replace with your table name
        TableName: 'connectDemo',
        KeyConditionExpression: "phoneNumber = :varNumber",

        ExpressionAttributeValues: {
            ":varNumber": sourcePhoneNumber
        }
    };

    //set up the database query to be used to update the customer information record in DynamoDB
    var paramsUpdate = {
        //DynamoDB Table Name.  Replace with your table name
        TableName: 'connectDemo',
        Key: {
            "phoneNumber": sourcePhoneNumber
        },

        ExpressionAttributeValues: {
            ":var1": currentTimeStamp,
            ":var2": currentLongDate,
            ":var3": currentTime,
            ":var4": currentContactId,
        },

        UpdateExpression: "SET lastCalledTimeStamp = :var1, lastCalledDate = :var2, lastCalledTime = :var3, lastCalledCallId = :var4"
    };

    //use the lookup query (paramsQuery) we set up to lookup the customer data based on the source phone number from DynamoDB 
    docClient.query(paramsQuery, function (err, dbResults) {
        //check to make sure the query executed correctly, if so continue, if not error out the lambda function
        if (err) {
            console.log(err); // an error occurred
            context.fail(buildResponseFailed);
        }
        //if no error occured, proceed to process the resutls that came back from DynamoDB
        else {
            //log the results from the DynamoDB query
            console.log("DynamoDB Query Results:" + JSON.stringify(dbResults));

            //check to ensure only 1 record came back for the customer phone number
            if (dbResults.Items.length === 1) {

                //set variables for the pertinet information from the returned database record:
                var lastCalledDate = dbResults.Items[0].lastCalledDate;
                var lastCalledTime = dbResults.Items[0].lastCalledTime;
                var customerFirstName = dbResults.Items[0].firstName;
                var customerLastName = dbResults.Items[0].lastName;

                //check to see if there is a record of a previous call, and set the previous call variable accordingly
                var customerFirstCall = true;
                if (lastCalledDate) {
                    customerFirstCall = false
                }

                //update the customer record in the database with the new call information using the paramsUpdate query we setup above:
                docClient.update(paramsUpdate, function (err, data) {
                    if (err) console.log("Unable to update item. Error: ", JSON.stringify(err, null, 2));

                    else console.log("Updated item succeeded: ", JSON.stringify(data, null, 2));

                });

                callback(null, buildResponseNumberFound(customerFirstName, customerLastName, lastCalledDate, lastCalledTime, customerFirstCall));
            } else {
                customerFirstCall = true;
                docClient.update(paramsUpdate, function (err, data) {
                    if (err) console.log("Unable to update item. Error: ", JSON.stringify(err, null, 2));

                    else console.log("Updated item succeeded: ", JSON.stringify(data, null, 2));

                });

                callback(null, buildResponseNumberNotFound(customerFirstCall));
            }

        }
    });
};


//This is the function that will be called on a successful callback if we find the phone number in our database
function buildResponseNumberFound(customerFirstName, customerLastName, lastCalledDate, lastCalledTime, customerFirstCall) {
    var results = {
        firstName: customerFirstName,
        lastName: customerLastName,
        lastCalledDate: lastCalledDate,
        lastCalledTime: lastCalledTime,
        firstCall: customerFirstCall,
        phoneNumberFound: true,
        lambdaResult: "Success"
    };
    console.log("Lambda's Response to Amazon Connect is: " + JSON.stringify(results));
    return results;
}


//This is the function that will be called on a successful callback if we don't find the phone number in our database
function buildResponseNumberNotFound(customerFirstCall) {
    var results = {
        firstCall: customerFirstCall,
        phoneNumberFound: false,
        lambdaResult: "Success"
    };
    console.log("Lambda's Response to Amazon Connect is: " + JSON.stringify(results));
    return results;
}

//This is the function that will be called on an error
function buildResponseFailed() {
    var results = {
        lambdaResult: "Error"
    };
    console.log("Lambda's Response to Amazon Connect is: " + JSON.stringify(results));
    return results;
}

スクリーンショット 2023-11-13 094641.png

⑤設定セクションで一般設定に移動し、編集を選択します。
⑥タイムアウト 0分 8秒 に変更し、保存を選択します。
スクリーンショット 2023-11-13 095543.png

Step 2: AWS Lambda 統合

1. Amazon Connect インスタンスにAWS Lambda関数を追加する

①AWS コンソール から、Amazon Connect を開きます。
②インスタンスエイリアス欄から、事前に作成していたインスタンス名を押下します。
③ナビゲーションペインで、問い合わせフローを選択し、AWS Lambda セクションまでスクロールダウンします。Lambda 関数 ドロップダウンを選択し、dbDemoを選択します。Add Lambda Function を選択します。
④Lambda 関数のリストに 登録した Lambda 関数が表示されることを確認します。
スクリーンショット 2023-11-13 100314.png

Step 3: Amazon Connect ルーティングの設定

1. 新しいユーザーの追加

①Amazon Connect インスタンスにログインします。ナビゲーションバーのユーザーからユーザー管理を選択します。
新しいユーザーの追加を選択し、ユーザーを手動で追加が選択されていることを確認します。
スクリーンショット 2023-11-13 100718.png
③ユーザー情報に新規ユーザーの認証情報で、すべての必須フィールドを規則に従って入力します。
スクリーンショット 2023-11-13 101334.png
④ルーティングプロファイルで Basic Routing Profile を、セキュリティプロファイルで Agent を選択します。
スクリーンショット 2023-11-13 101540.png
⑤完了したら画面右上の保存を選択します。

2. キューの追加

①ナビゲーションバーからルーティングを選択し、キューを選択します。
キューを追加を選択します。
③名前に Customer Support と入力し、オペレーション時間は、Basic Hours を選択します。
スクリーンショット 2023-11-13 102114.png
保存を選択します。
⑤前のステップを繰り返して、Password Resetのキューを追加します。※設定値は同じです。
スクリーンショット 2023-11-13 102330.png

3. ルーティングプロファイルの編集

①ナビゲーションバーからユーザーを選択し、ルーティングプロファイルを選択
Basic Routing Profile を選択します。
③キューセクションで、キューを追加を選択します。
スクリーンショット 2023-11-13 102548.png
④追加したキューのドロップダウンリストで、Customer Support キューを選択します。

  • 優先度を 1 に設定します。
  • 遅延を 0 に設定します。

⑤再度キューを追加を選択し、同じ手順で Password Reset キューを追加します。

  • 優先度を 1 に設定します。
  • 遅延を 0 に設定します。

⑥画面右上の保存を選択します。

4. コンタクトフローのインポート

⓪以下の手順を行う前に、こちらをダウンロードしてください
AWS_Demo_Flow_Main_J
①ナビゲーションバーからルーティングを選択し、フローを選択します。
フローの作成を選択します。
③画面右上の保存の横にあるドロップダウンリストから、フローのインポート(ベータ) を選択します。
AWS_Demo_Flow_Main_J.json ファイルを選択し、インポート を選択します。
すると、フロー図が自動で生成されました。
スクリーンショット 2023-11-13 103723.png
⑤画面右上の公開`を選択してコンタクトフローを保存・公開します。

Step 4: コンタクトフローのテスト

1. 電話番号をコンタクトフローに設定

①Amazon Connect のダッシュボードのナビゲーションバーから、 チャネル > 電話番号 を選択します。
②取得済みの電話番号を選択します。ドロップダウンリストから AWS_Demo_Flow_Main_J コンタクトフローを選択し、保存を選択します。
スクリーンショット 2023-11-13 104642.png
③取得済みの電話番号にテストコールを行います。
コールすると、 お客様の電話番号が弊社の記録にありませんでしたので、今後のためにデータベースに追加しました。初めてお電話いただきました。ありがとうございます。 というメッセージが再生され、切断されます。

2. DynamoDB テーブルの更新

①AWS コンソール から、Amazon DynamoDB を開きます。
②画面左側のナビゲーションメニューの テーブル > 項目を探索 を選択し、リストから connectDemo テーブルを選択します。テストコールで使用した電話番号を選択します。
③項目の編集画面が開きます。

  • 新しい属性の追加 > 文字列 を選択します。属性名 firstName を追加します。値に任意の名前を入力します。
  • 新しい属性の追加 > 文字列 を選択します。属性名 lastName を追加します。値に任意の姓を入力します。
  • 保存して閉じるを選択します。

スクリーンショット 2023-11-13 105843.png
④取得済みの電話番号に再度テストコールを行います。このとき、Amazon Connect はデータベースのテーブルからテストに使用した電話番号を認識し、前の手順で設定した名前と、最後に電話をかけた時間を音声で再生します。
「Shohei Otani様、お電話ありがとうございます。」と応答が来ました!

Work2: ヘルプデスク Lex ボットの作成

Step 1: Lex ボットのインポート

Lex ボットのインポート

⓪以下の手順を行う前に、こちらをダウンロードしてください
HelpDesk-Lex_v2_Bot_J.zip
①AWS コンソール から、Amazon Lexを開きます。
②ボットセクションのアクション > インポートを選択します。
③ボットをインポート画面でボット名に HelpDesk と入力します。ファイルを参照を選択し、前の手順でダウンロードした HelpDesk-Lex_v2_Bot_J.zip を選択します。
スクリーンショット 2023-11-13 110542.png
④以下の情報を設定します。:

  • IAM アクセス許可:基本的な Amazon Lex 権限を持つロールを作成します。 を選択
  • 児童オンラインプライバシー保護法 (COPPA):いいえを選択
  • アイドルセッションタイムアウト:5 分を設定

インポートを選択します。
⑥インポートが成功した通知を確認し、HelpDesk ボットを選択します。
スクリーンショット 2023-11-13 111134.png
⑦画面左側のナビゲーションメニューで 日本語 (JP) を選択します。画面上のセクションでBuildを選択して、インポートしたボットの構築処理を開始します。
ボット (日本語 (JP)) で言語 HelpDesk が正常に構築されましたが表示されれば成功です。

Step 2: Amazon Connect インスタンスへ Amazon Lex ボットを追加

1. Amazon Connectインスタンスへ Amazon Lex ボットを追加

①AWS コンソール から、Amazon Connect へ移動します。選択したリージョンが、Amazon Lex ボットを構築したリージョンと同じであることを確認します。
②インスタンスエイリアスの欄からワークショップに使用するインスタンスの名前を選択します。
③ナビゲーションペインで、問い合わせフローを選択し、Amazon Lex セクションまでスクロールダウンします。

  • ボットドロップダウンから HelpDesk を選択します。
  • エイリアスは TestBotAlias を選択します。
  • + Amazon Lex ボットを追加を選択して、Amazon Connect のボットリストに追加します。

④Amazon Lex ボットセクションに、ボットが追加されたことを確認します。
スクリーンショット 2023-11-13 112206.png

2. ヘルプデスクのデモ用フローのインポート

⓪以下の手順を行う前に、こちらをダウンロードしてください
AWS_Demo_Flow_Main_HD_J
①Amazon Connect ダッシュボードに移動します。
②画面左側のナビゲーションバーから、ルーティング > フローを選択します。
③画面右上のフローの作成 を選択します。
④画面右上の保存の横にあるドロップダウンリストから フローのインポート (ベータ) を選択します。
⑤前の手順でダウンロードした AWS_Demo_Flow_HD_J.json ファイルを選択し、インポートを選択します。
スクリーンショット 2023-11-13 113531.png
フロー図が自動で生成されました。

⑥画面右上の保存を選択して、コンタクトフローを保存します。

3. コンタクトフローブロックの更新

①コンタクトフロー内の顧客の入力を取得するブロックを開きます。 Amazon Lex セクションまでスクロールします。

  • Lexボットを選択 を選択します。
  • 名前ドロップダウンリストから、前の手順で作成した HelpDesk ボットを選択します。
  • エイリアスドロップダウンリストで TestBotAlias を選択します。
  • 保存 を選択します。

スクリーンショット 2023-11-13 114028.png

②3つ並んでいる作業キューの選択ブロックのうち、一番上のブロックを開きます。 Customer Support キューを選択し、保存を選択します。
③前の手順を繰り返し、上から2番目の作業キューの選択ブロックに Password Reset キューを、上から3番目の作業キューの選択ブロックに BasicQueue キューを選択します。
④画面右上の 公開 を選択し、コンタクトフローを公開します。

4. コンタクトフローに電話番号を割り当てテストする

①Amazon Connect ダッシュボードで、画面左側のナビゲーションバーから チャネル > 電話番号を選択します。
②取得した電話番号を選択し、 AWS_Demo_Flow_HD_J コンタクトフローを割り当て、保存を選択します。
スクリーンショット 2023-11-13 114422.png
③コンタクトフローの動作を確認するために、取得した電話番号にテストコールをかけます。質問に対し、以下の選択をテストします:

  • "PCが起動しません" と言うと、Customer Support キューにルーティングされます。
  • "パスワードを忘れました" と言うと、Password Reset キューにルーティングされます。

まとめ

"パスワードを忘れました" などと言うと、自動音声が対応してくれました。
ただしフロー作成に用いたファイルは複雑で時間がかかりそうだったので、AWS Workshop studioのファイルそのまま使いました。
このファイルをもっと編集するとおもしろそうなのですが、前回の簡易コールセンターに比べてややこしそうなので、今回はここで留めておきます。
データをDynamoDBに保存するのは流用できそうだなと思いました。

参照

AWS Workshop studio

1
3
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
1
3