[Amazon Connect] 着信時にCCP画面にお客様の名前を表示する (Amazon Connect Streams API)

電話を取る前にお客様の名前くらいは分かっておきたい・・・そんな要望に「CCP拡張」でお応えします。
2022.07.04

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

みなさん、こんにちは!
福岡オフィスの青柳です。

「Amazon Connect Streams API」を使うと、オペレーターが電話を受けたり掛けたりする時に使用する「CCP」(Contact Control Panel) をカスタマイズすることができます。

今回は、電話が着信した際にCCP画面に「お客様の名前」を表示するカスタマイズ方法をご紹介します。

Amazon Connect Streams API

「Amazon Connect Streams API」は、Amazon ConnectとWebアプリケーションを連係するためのAPIであり、AWSからオープンソースとして公開されています。

https://github.com/amazon-connect/amazon-connect-streams

Amazon Connect Streams APIはJavaScriptのライブラリであり、クライアントのWebブラウザで動作します。
(サーバー上で動作するものではありません)

クライアントで動作するものではありますが、ローカルディスクに置いたHTMLやJavaScriptを単にWebブラウザで開いただけでは動作しません。

Webサーバー上にHTMLやJavaScriptを配置した上で、クライアントのWebブラウザからアクセスすることで動作させることができます。
(Amazon Connectと連係させるためにWebサーバーのドメイン登録などの設定が必要となりますが、この手順については後ほど説明します)

今回作成するシステムの構成

今回構築するシステムは下図のようになります。

前章で説明した通り、Amazon Connect Streams APIを使ったWebページ (HTMLやJavaScriptで構成) はWebサーバー上に配置する必要があります。
サーバーサイドの処理は必要ありませんので、WebサーバーはCloudFrontとS3を使った「静的Webサイトホスティング」で用意することにします。

オペレーターは、まず、Webブラウザを使ってWebサーバー (CloudFront+S3) へアクセスします。
Webサーバー上のHTMLファイルにはCCPを表示するコンポーネントが埋め込まれており、WebブラウザはAmazon ConnectがホストするCCPへもアクセスします。

お客様から電話が着信した際、発信者電話番号を使ってお客様の名前を照会する必要があります。
この仕組みをAmazon ConnectのLambda連係機能を使って実装します。
電話番号とお客様の名前を登録するデータベースはDynamoDBで作成することにします。

Amazon Connect Streams APIはCCPを介してAmazon Connectから情報を取得することができます。
もちろんLambda連係によって照会したお客様の名前も取得の対象になります。
これによって、Webブラウザ上にお客様の名前を表示することができるという訳です。

システム構築手順

システムの構築は以下の流れで進めます。

  • 電話番号からお客様情報を照会する仕組みを作成する
    • 電話帳データベース (DynamoDB) を作成
    • Lambda関数を作成
  • Amazon Connectに必要な環境を作成する
    • Connectインスタンスを作成
    • ConnectインスタンスへLambda関数を登録
    • コンタクトフローを作成
    • 電話番号を取得してコンタクトフローへ割り当てる
    • オペレーターユーザーを作成
  • 動作を確認する (中間確認)
  • 静的Webサイトホスティングを用意する
    • S3バケットを作成
    • CloudFrontディストリビューションを作成
    • ConnectインスタンスへCloudFrontディストリビューションのドメイン名を登録
  • Amazon Connect Streams APIを使ったWebページを作成する
    • 各コンポーネントの説明
    • Webサイトへ各コンポーネントを配置
  • 動作を確認する
    • カスタマイズしたCCPを起動
    • 電話を掛けてみて動作を確認

電話番号からお客様情報を照会する仕組みを作成する

電話帳データベース (DynamoDB) を作成

今回はDynamoDBを使って「電話番号」と「お客様の名前」のみのデータを持つシンプルなデータベースを作成したいと思います。

電話番号でデータを検索する必要があるため、プライマリキーを「電話番号」(PhoneNumber) とします。
ソートキーは設定しません。

その他の設定はデフォルトのまま、テーブルを作成します。

テーブルを作成しましたら、データを登録します。

電話番号は「E.164」形式で登録します。

  • 最初に「国番号」を付ける (日本は+81)
  • 市外局番や携帯電話番号の先頭の「0」は外す (03-1234-XXXX+8131234XXXX)

お客様の名前のフィールドとして「CustomerName」を登録します。

これを必要な分だけ繰り返して、電話帳データベースを構築してください。

Lambda関数を作成

今回はPythonでLambda関数を記述したいと思います。

関数名とランタイムを指定して、その他の項目はデフォルトのまま、関数を作成します。

Lambda実行ロールはデフォルトの「基本的なLambdaアクセス権限で新しいロールを作成」を選択します。
(必要なアクセス権限を後で追加します)

関数が作成されましたら、「設定」タブの「アクセス権限」からLambda実行ロール (IAMロール) の画面へ遷移します。

Lambda関数からDynamoDBへのアクセスを可能とするために、許可ポリシーに「AmazonDynamoDBReadOnlyAccess」AWS管理ポリシーを追加します。
(今回はサンプルのため細かなアクセス権限の設定は行いませんが、本番システムではより厳密にIAMポリシーを設定しましょう)

「コード」タブに戻って、関数のコードを記述します。

lambda_function.py

import boto3
import json

def lambda_handler(event, context):
    table_name = 'PhoneBook'

    print(json.dumps(event))

    # Amazon Connectから受け取ったイベントから「発信者電話番号」を取り出す
    phone_number = event['Details']['ContactData']['CustomerEndpoint']['Address']

    # DynamoDBテーブルから「発信者電話番号」をキーに指定してレコードを抽出する
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table(table_name)

    response = table.get_item(
        Key={
            'PhoneNumber': phone_number
        }
    )

    print(json.dumps(response))

    # 抽出結果を元に関数の戻り値(マップ構造体)をセットする
    if 'Item' in response:
        # レコードが抽出できた場合:「お客様のお名前」を取り出して戻り値にセット
        result = {'CustomerName': response['Item'].get('CustomerName', '')}
    else:
        # レコードが抽出できなかった場合:「お客様の名前」は空白にして戻り値とする
        result = {'CustomerName': ''}

    return result

Amazon ConnectにおけるLambda連係では、Lambda関数はAmazon Connectから以下のようなイベント構造体を受け取ります。

{
    "Details": {
        "ContactData": {
            "Attributes": {},
            "Channel": "VOICE",
            "ContactId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
            "CustomerEndpoint": {
                "Address": "+81XXXXXXXXXX",
                "Type": "TELEPHONE_NUMBER"
            },
(後略)

発信者電話番号を取り出すにはphone_number = event['Details']['ContactData']['CustomerEndpoint']['Address']と記述すればよいことになります。

取り出した発信者電話番号をキーにしてDynamoDBから「お客様の名前」を取得します。

table.get_itemのレスポンスは以下のような内容となっています。

{
    "Item": {
        "PhoneNumber": "+81XXXXXXXXXX",
        "CustomerName": "彩木 あかり"
    },
    "ResponseMetadata": {
(中略)
    }
}

指定したキーのレコードが存在した場合、Itemにレコードの内容が入っています。
Itemからお客様の名前 (CustomerName) の値を取り出して、関数の戻り値として返します。

もし指定したキーのレコードが存在しない場合はレスポンスにItem自体が含まれません。
Itemの存在チェックを行い、存在しない場合は電話番号に該当するレコードが無かったと判断します。

レコードが無かった場合は、お客様の名前に「空の文字列」をセットして返します。

Amazon Connectに必要な環境を作成する

Connectインスタンスを作成

Amazon Connectインスタンスを作成します。

設定内容は全てデフォルトのままで構いません。
(作成画面は省略します)

ConnectインスタンスへLambda関数を登録

Amazon Connectインスタンスを作成しましたら、さきほど作成したLambda関数を登録しておきます。

インスタンスを選択して、左側のメニューより「問い合わせフロー」を選択します。

「Lambda関数」のプルダウンからさきほど作成したLambda関数の名前を選択して、「+Add Lambda Function」をクリックします。

Lambda関数が登録されたことを確認します。

これで、Lambda関数がインスタンスのコンタクトフローから利用できるようになりました。

コンタクトフローを作成

お客様から電話が着信した際の処理を行う「コンタクトフロー」を作成します。

配置する各ブロックについて、順に説明していきます。

(1) 「設定」-「ログ記録動作の設定」

コンタクトフローの動作確認 (デバッグ) のために、ログ記録を有効化しておきます。

(2) 「統合」-「AWS Lambda関数を呼び出す」

作成したLambda関数の名前を選択します。

(3) 「設定」-「コンタクト属性の設定」

Amazon Connect Streams APIがコンタクトフローから情報を取得する際には、「コンタクト属性」を介して取得します。

コンタクトフローから渡す情報として、以下のものをコンタクト属性として設定します。
(いずれも「ユーザー定義」の属性として設定する必要があります)

属性名 値の設定元
PhoneNumber 発信者電話番号
CustomerName Lambda関数の戻り値「CustomerName」

1つ目の属性「PhoneNumber」を以下のように設定します。

発信者電話番号は、システム属性「顧客電話番号」で参照することができます。

2つ目の属性「CustomerName」は以下のようになります。

Lambda関数からの戻り値はコンタクト属性のタイプ「外部」で参照することができます。

(4) 「設定」-「作業キューの設定」

転送先のキューを指定します。

(5) 「終了/転送」-「キューへ転送」

キューへ転送します。

コンタクトフローを作成しましたら、「保存」した後に、忘れずに「公開」を行いましょう。

電話番号を取得してコンタクトフローへ割り当てる

電話番号を取得して、作成したコンタクトフローへ割り当てます。
(設定画面は省略します)

オペレーターユーザーを作成

オペレーターがAmazon Connectコンソールへサインインするためのユーザーを作成しておきます。
セキュリティプロファイルとして「Agent」を指定します。
(作成画面は省略します)

動作を確認する (中間確認)

ここまでの設定が終わりましたら、一旦、動作を確認しましょう。

コンタクトフローに割り当てた電話番号へ電話を掛けてみます。
電話が繋がってオペレーター接続待ちの音楽が流れるところまで聞くことができたら、電話を切ります。
(オペレーターが応答する必要はありません)

コンタクトフローおよびLambda連係が期待通りに動作したかどうか確認するために、CloudWatch Logsに記録されたログを確認します。
(ログはロググループ/aws/connect/<Amazon Connectインスタンス名>に保存されています)

コンタクトフローの「ブロック」単位でログが記録されていますので、ContactFlowModuleTypeInvokeExternalResourceとなっているログを確認します。

{
    "ContactId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "ContactFlowId": "arn:aws:connect:ap-northeast-1:123456789012:instance/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/contact-flow/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "ContactFlowName": "Amazon Connect Streams Example Flow",
    "ContactFlowModuleType": "InvokeExternalResource",
    "Timestamp": "2022-07-02T12:01:40.015Z",
    "Parameters": {
        "FunctionArn": "arn:aws:lambda:ap-northeast-1:123456789012:function:SearchPhoneBook",
        "TimeLimit": "3000"
    },
    "ExternalResults": {
        "CustomerName": "彩木 あかり"
    }
}

Lambda関数の呼び出しが正しく行われたか、結果としてどのような値が戻って来たかを確認することができます。

「電話帳データベース」に存在する電話番号から電話を掛けた場合は、ExternalResultsCustomerNameに該当する名前が入っていると思います。

データベースに存在しない電話番号から掛けた場合や、「番号非通知」で電話を掛けた場合は、CustomerNameに空の文字列が入っているはずです。

Lambda関数呼び出しのログに続いて、ContactFlowModuleTypeSetAttributesとなっているログが2つ記録されていると思います。

{
    "ContactId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "ContactFlowId": "arn:aws:connect:ap-northeast-1:123456789012:instance/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/contact-flow/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "ContactFlowName": "Amazon Connect Streams Example Flow",
    "ContactFlowModuleType": "SetAttributes",
    "Timestamp": "2022-07-02T12:01:41.958Z",
    "Parameters": {
        "Key": "PhoneNumber",
        "Value": "+81XXXXXXXXXX"
    }
}

1つ目のログは、コンタクト属性「PhoneNumber」に発信者電話番号がセットされたことを示しています。

{
    "ContactId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "ContactFlowId": "arn:aws:connect:ap-northeast-1:123456789012:instance/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/contact-flow/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "ContactFlowName": "Amazon Connect Streams Example Flow",
    "ContactFlowModuleType": "SetAttributes",
    "Timestamp": "2022-07-02T12:01:41.959Z",
    "Parameters": {
        "Key": "CustomerName",
        "Value": "彩木 あかり"
    }
}

2つ目のログは、コンタクト属性「CustomerName」にLambda関数から返された「名前」がセットされたことを示しています。

これらのログが期待した通りの内容となっていることが確認できましたら、次へ進みましょう。

静的Webサイトホスティングを用意する

S3バケットを作成

CloudFrontのオリジンとなるS3バケットを作成します。

バケット名は任意の名前で構いません。

CloudFrontからS3オリジンに対するアクセス許可は「OAI」(Origin Access Identity) を使って行いますので、S3バケットはパブリックアクセスを全てブロックする設定にします。

その他の設定 (バージョニング、暗号化など) は任意で設定してください。

CloudFrontディストリビューションを作成

続いて、CloudFrontのディストリビューションを作成します。

オリジンとして、さきほど作成したS3バケットを指定します。

S3バケットアクセスの設定は「はい、OAIを使用します」を選択します。
「新しいOAIを作成」をクリックして作成したOAIを選択します。

バケットポリシーは「はい、バケットポリシーを自動で更新します」を選択します。

ビューワーの設定で、ビューワープロトコルポリシーは「Redirect HTTP to HTTPS」を選択します。

これら以外の設定はデフォルトのままで構いません。

CloudFrontディストリビューションを作成しましたら、エッジロケーションへのデプロイに少し時間がかかりますが、その間に次の手順に進みましょう。

ConnectインスタンスへCloudFrontディストリビューションのドメイン名を登録

Amazon Connect Streams APIを使って作成したWebサイトをAmazon Connectと連係して動作させるためには、Amazon Connectインスタンスの「承認済みオリジン」(承認済みドメイン) としてWebサイトのドメイン名を登録しておく必要があります。
(いわゆるCORSのための設定です)

マネジメントコンソールのAmazon Connect画面でインスタンスを選択して、左側のメニューより「承認済みオリジン」を選択します。

「ドメインを追加」をクリックします。

CloudFrontディストリビューションの「ディストリビューションドメイン名」をコピーして入力します。

「ドメイン」と表記されていますが、正確には「オリジン」の形式 (<スキーム>://<ドメイン>:<ポート>) である必要があります。
ただし、ポートはHTTPS標準の「443」であれば省略可能です。

承認済みオリジンの一覧に登録されたことを確認します。

Amazon Connect Streams APIを使ったWebページを作成する

ここからは、いよいよAmazon Connect Streams APIを使ったWebページを作成していきます。

今回作成するWebページの構成ファイルは以下の4つです。

  • index.html
  • custom-ccp.html
  • custom-ccp.ccs
  • custom-ccp.js

順に内容を説明します。

各コンポーネントの説明

まず、クライアントのWebブラウザで最初にアクセスする「index.html」ページを作成します。

index.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
</head>

<body>
    <p><a href="javascript:void(0)" onClick="window.open('custom-ccp.html', '_blank', 'width=328,height=650');">カスタムCCP起動</a></p>
</body>

</html>

内容としては、単にJavaScriptのonClickで新しいWebページをポップアップしているだけです。

続いて、index.htmlからポップアップで開かれる「custom-ccp.html」を作成します。

custom-ccp.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" href="custom-ccp.css">
    <script type="text/javascript" src="connect-streams-min.js"></script>
    <script type="text/javascript" src="custom-ccp.js"></script>
    <title>Amazon Connect Contact Control Panel</title>
</head>

<body onload="init()">
    <div class="parent">
        <div class="caption" id="name-cap">名前</div>
        <div class="content" id="name"></div>
        <div class="caption" id="phone-cap">電話番号</div>
        <div class="content" id="phone"></div>
        <div class="ccp" id="ccp"></div>
    </div>
</body>

</html>

まず、HTMLヘッダーでCCSファイルとJavaScriptファイルを指定しています。

「custom-ccp.css」と「custom-ccp.js」は、この後に作成するCSSファイルとJavaScriptファイルです。

「connect-streams-min.js」は、Amazon Connect Streams APIのファイルです。
このファイルの入手方法は後ほど説明します。

HTMLボディには、画面を構成する5つのパーツを<div>タグで定義しています。

div id 説明
name-cap 「名前」表示欄のキャプション
name 「名前」表示欄
phone-cap 「電話番号」表示欄のキャプション
phone 「電話番号」表示欄
ccp CCPを埋め込むコンテナ

キャプションを除いて、<div>タグの中身は後述するJavaScriptで設定することになります。

次に、custom-ccp.htmlの見た目を定義する「custom-ccp.css」を作成します。

custom-ccp.css

body {
    margin: 2px;
    padding: 0;
}

.parent {
    display: grid;
    grid-template-columns: 100px auto;
    grid-template-rows: 50px 50px auto;
    grid-gap: 2px;
    margin: auto;
}

.caption {
    padding: 15px;
    text-align: center;
    vertical-align: middle;
    color: white;
    background-color: royalblue;
}

.content {
    padding: 15px;
    text-align: left;
    vertical-align: middle;
    color: black;
    background-color: aliceblue;
}

.ccp {
    grid-column: 1/3;
    width: 326px;
    height: 540px;
}

特筆するとすれば、各パーツを配置するために「グリッドレイアウト」を使っていることくらいで、後は大したことはしていません。
(私はWebページのデザインについては素人ですので、皆さんが作成する時にはもっとデザインを工夫してみてください)

最後に、Amazon Connect Streams APIを使った処理を記述する「custom-ccp.js」を作成します。

custom-ccp.js

// Amazon Connect Streams APIの初期化処理
function init() {
    // CCPのURL (Connectインスタンス名の部分を御自身のものに置き換えてください)
    var instanceURL = "https://<Connectインスタンス名>.my.connect.aws/ccp-v2";

    var ccpDiv = document.getElementById("ccp");
    var nameDiv = document.getElementById("name");
    var phoneDiv = document.getElementById("phone");

    // CCPの初期化
    connect.core.initCCP(ccpDiv, {
        ccpUrl: instanceURL,          // CCPのURLを指定 (必須項目)
        loginPopup: true,             // 必要時にログインダイアログを自動的にポップアップする
        loginPopupAutoClose: true,    // ログイン後にログインダイアログを自動的に閉じる
        loginOptions: {               // ログインダイアログをポップアップする際の設定
            autoClose: true,
            height: 750,
            width: 400,
            top: 0,
            left: 0
        },
        softphone: {                      // ソフトフォンの設定
            allowFramedSoftphone: true    // ソフトフォンのコンポーネントをiframeで埋め込むことを許可する
        }
    });

    // イベントサブスクリプション
    // Contactイベント
    connect.contact(function (contact) {
        // 着信または発信が発生した時のイベント
        contact.onConnecting(function (contact) {
            // 着信時の場合のみ
            if (contact.isInbound()) {
                console.log('通話着信: contactId =' + contact.getContactId() + '\n');
                // コンタクト属性から「名前」「電話番号」の値を取得する
                var attributeMap = contact.getAttributes();
                var customerName = attributeMap["CustomerName"]["value"];
                var phoneNumber = attributeMap["PhoneNumber"]["value"];
                console.log('コンタクト属性を取得: customerName = \"' + customerName + '\"\n');
                console.log('コンタクト属性を取得: phoneNumber = \"' + phoneNumber + '\"\n');
                // 名前・電話番号の表示欄に値を表示する
                if (phoneNumber == 'anonymous' || phoneNumber == '') {
                    nameDiv.innerHTML = '(番号非通知)'
                    phoneDiv.innerHTML = '―'
                } else if (customerName == '') {
                    nameDiv.innerHTML = '(登録されていません)'
                    phoneDiv.innerHTML = phoneNumber
                } else {
                    nameDiv.innerHTML = customerName
                    phoneDiv.innerHTML = phoneNumber
                }
            }
        });

        // 通話を切断した時のイベント
        contact.onEnded(function (contact) {
            console.log('通話切断: contactId =' + contact.getContactId() + '\n');
            // 名前・電話番号の表示欄をクリアする
            nameDiv.innerHTML = ''
            phoneDiv.innerHTML = ''
        });
    });
}

JavaScriptファイルの全体が、HTMLファイルの<body>が読み込まれた時に実行されるinit()関数で構成されています。

関数の処理内容を順に説明します。

まず、4行目で「CCP」のURLを指定します。

    var instanceURL = "https://<Connectインスタンス名>.my.connect.aws/ccp-v2";

Amazon ConnectインスタンスのURL形式には以下の2通りがありますので、お使いのインスタンスのURLに合わせて記述してください。

  • https://<Connectインスタンス名>.my.connect.aws (最近の形式)
  • https://<Connectインスタンス名>.awsapps.com/connect/ (古い形式)

10行目からは、Amazon Connect Streams APIのconnect.core.initCCP()メソッドを使ってCCPの初期化を行います。

    // CCPの初期化
    connect.core.initCCP(ccpDiv, {
        ccpUrl: instanceURL,          // CCPのURLを指定 (必須項目)
        loginPopup: true,             // 必要時にログインダイアログを自動的にポップアップする
        loginPopupAutoClose: true,    // ログイン後にログインダイアログを自動的に閉じる
        loginOptions: {               // ログインダイアログをポップアップする際の設定
            autoClose: true,
            height: 750,
            width: 400,
            top: 0,
            left: 0
        },
        softphone: {                      // ソフトフォンの設定
            allowFramedSoftphone: true    // ソフトフォンのコンポーネントをiframeで埋め込むことを許可する
        }
    });

initCCPメソッドの第1引数は、CCPを埋め込む対象となる「div要素」を指定します。

第2引数は、CCP初期化時の各種パラメーターを構造体形式で指定します。
今回は最低限のパラメーターのみ設定していますが、そのほかのパラメーターについては下記リンク先を参照してください。
https://github.com/amazon-connect/amazon-connect-streams/blob/master/Documentation.md#connectcoreinitccp

27行目からは、CCPで発生する各種「イベント」の処理を記述します。

    // イベントサブスクリプション
    // Contactイベント
    connect.contact(function (contact) {
        ・・・

イベントサブスクリプションにはいくつかの種類がありますが、今回はCCPが電話を受信したり発信したりした時のイベントを扱うconnect.contact()のみを使用します。

更に、connect.contact()にはいくつかのイベントが含まれますが、今回は以下の2つのイベントに対して処理を記述します。

  • contact.onConnecting(): 着信または発信が発生した時のイベント
  • contact.onEnded() :通話を切断した時のイベント

まず、contact.onConnecting()で「着信または発信が発生した時のイベント」が発生した時の処理を記述します。

        // 着信または発信が発生した時のイベント
        contact.onConnecting(function (contact) {
            // 着信時の場合のみ
            if (contact.isInbound()) {
                ・・・

contact.onConnecting()が発生した時点では、それが着信時なのか発信時なのか分かりませんので、contact.isInbound()メソッドを使って着信時のイベントであることを判定して、着信時の場合のみ処理を行うようにします。

                // コンタクト属性から「名前」「電話番号」の値を取得する
                var attributeMap = contact.getAttributes();
                var customerName = attributeMap["CustomerName"]["value"];
                var phoneNumber = attributeMap["PhoneNumber"]["value"];

コンタクトフローで「コンタクト属性」に「発信者電話番号」と「お客様の名前」をセットしましたが、それらの値をAmazon Connect Streams APIを使って取得します。

まず、contact.getAttributes()メソッドを使って、全てのコンタクト属性が格納されたマップ形式の構造体を取得します。

そこから、「CustomerName」「PhoneNumber」の各コンタクト属性の値を参照して変数に代入しておきます。

                // 名前・電話番号の表示欄に値を表示する
                if (phoneNumber == 'anonymous' || phoneNumber == '') {
                    nameDiv.innerHTML = '(番号非通知)'
                    phoneDiv.innerHTML = '―'
                } else if (customerName == '') {
                    nameDiv.innerHTML = '(登録されていません)'
                    phoneDiv.innerHTML = phoneNumber
                } else {
                    nameDiv.innerHTML = customerName
                    phoneDiv.innerHTML = phoneNumber
                }
            }
        });

名前と電話番号が取得できましたので、それらをWebページの画面上に表示します。

この時、掛かってきた電話の電話番号は、以下のいずれかのパターンとなります:

  • 発信者電話番号が通知されている
    • 電話帳データベースに電話番号が登録されている
    • 電話帳データベースに電話番号が登録されていない
  • 発信者電話番号が通知されていない (番号非通知)

これらを判別して、それぞれ適切な表示を行うようにします。

まず、「番号非通知」の場合、Amazon Connectでは「発信者電話番号」にanonymousという文字列がセットされることになっています。
この場合は「番号非通知」と判定して、そのように画面に表示することにします。
(念のため「発信者電話番号」に何も入っていない場合も「番号非通知」の扱いにしています)

発信者電話番号が通知されている場合、データベースに電話番号が登録されているお客様であれば「名前」がセットされているはずです。

もし「名前」に空の文字列が入っている場合は、データベースに登録されていない電話番号ですので、その旨を表示することにしましょう。

ここまでで「着信または発信が発生した時のイベント」が発生した時の処理を全て記述しました。

続いて、もう一つのイベント「通話を切断した時のイベント」が発生した時の処理を記述します。

        // 通話を切断した時のイベント
        contact.onEnded(function (contact) {
            console.log('通話切断: contactId =' + contact.getContactId() + '\n');
            // 名前・電話番号の表示欄をクリアする
            nameDiv.innerHTML = ''
            phoneDiv.innerHTML = ''
        });

通話を切断した時には、電話が着信した時に「名前」「電話番号」の各表示欄にセットした値をクリアする処理のみを記述しています。

これで、全てのWebページのコンポーネントを作成しました。

Webサイトへ各コンポーネントを配置

作成したWebサイトのコンポーネント (ファイル) を、CloudFront+S3バケットで構成した静的Webサイトホスティングへ配置します。

その前に、Amazon Connect Streams APIのライブラリファイルである「connect-streams-min.js」を入手する必要があります。

ライブラリファイルを用意する方法としては「GitHubからソースを入手してビルドする」「npmを使ってインストールする」という方法もありますが、今回はGitHubに用意されているビルド済みのファイルをダウンロードすることにします。

下記のリンク先からダウンロードしてください。
https://github.com/amazon-connect/amazon-connect-streams/blob/master/release/connect-streams-min.js

入手したライブラリファイルと、前の手順で作成した各コンポーネントのファイルを合わせて、S3バケットへアップロードします。

  • connect-streams-min.js
  • index.html
  • custom-ccp.html
  • custom-ccp.ccs
  • custom-ccp.js

全てのファイルを合わせてもファイルサイズは小さいため、初回のアップロードであれば、すぐに反映されると思います。

2回目以降のアップロードの場合は、キャッシュされている可能性があるため、反映されるのに少し時間を要するかもしれません。

(検証用途であれば、CloudFrontディストリビューションのビヘイビアの設定で、キャッシュポリシーを「CachingDisabled」に設定しておくとよいでしょう)

動作を確認する

さて、これで全ての準備が完了しましたので、動作を確認してみましょう。

カスタマイズしたCCPを起動

まず、WebブラウザでCloudFrontでホストされているWebサイトのURLへアクセスします。

https://XXXXXXXXXXXXXX.cloudfront.net

Webページが表示されましたら「カスタムCCP起動」のリンクをクリックします。

すると、下図のような画面がポップアップすると思います。

画面の下部がエラーのような表示となっていますが、これはCCPへのサインインが行われていないためです。

しばらくすると、CCP (あるいはAmazon Connectコンソール) のサインイン画面がポップアップされます。

Amazon Connectのユーザーでサインインを行ってください。

場合によっては、初回のみ下図のようなダイアログが表示されるかもしれません。

その場合は「ポップアップを許可する」を指定してください。

また、これも初回のみですが、下図のようなダイアログが表示される場合があります。

この場合は、マイクの使用を「許可」してください。

ここまでの操作で、下図のような画面が表示されると思います。

これから電話を掛けるテストを行いますので、エージェントのステータスを「Offiline」から「Available」へ変更しておきましょう。

これで「カスタマイズしたCCP」の準備は完了です。

電話を掛けてみて動作を確認

実際に電話を掛けて動作を確認してみます。

まず、「電話帳データベース」に登録されている電話番号から掛けた場合です。

このように「名前」欄に登録された名前が表示されると思います。

次に、データベースに登録されていない電話番号から掛けた場合です。

この場合は「名前」欄に「(登録されていません)」と表示されるはずです。

最後に、番号非通知で掛けた場合です。
(電話番号の頭に「184」を付けると番号非通知になります)

ちゃんと「(番号非通知)」と表示されれば成功です。

お疲れ様でした!
これで全ての作業が終わりました。

どうですか? 動作確認まで問題無く終わりましたでしょうか?

もし期待通りの動作をしなかった場合は、各ステップの手順をもう一度見直してみてください。

原因を調べるために、CloudWatch LogsのコンタクトフローログやLambda関数ログを確認したり、Webブラウザの「開発者ツール」でコンソールに出力されたログを確認したりするのも有用だと思います。

おわりに

今回は「Amazon Connect Streams API」を使ってCCPをカスタマイズするパターンの一つとして、デフォルトのCCP画面を少しだけ拡張して「お客様の名前」を表示する方法を紹介しました。

「Amazon Connect Streams API」を使うと、既存の業務Webシステムの画面にCCPを組み込んで複雑な連係を行ったりすることもできるのですが、今回のようにデフォルトのCCPを「ちょっと」拡張するのであれば比較的少ないコード量で実現することができます。

今回はお客様の「名前」のみを表示するようにしましたが、データベースに登録されている情報であれば基本的にどのようなものでも表示できます。
電話を掛けて来られたお客様のいろいろな情報を表示することで、オペレーターがお客様に合わせてより良い対応や提案ができるようになると良いのではないかと思います。