[Amazon Connect] Connect Streamsを使用して、ソフトフォンに発信履歴とリダイアルの機能を追加してみました。

1 はじめに

AIソリューション部の平内(SIN)です。

Amazon Connect(以下、Connect)では、amazon-connect-streamsを使用してCCPを拡張することができます。
aws/amazon-connect-streams

今回は。Connectのソフトフォンでは利用できないが、できれば欲しい機能として「発信履歴」と「リダイアル」を拡張として実装してみました。

最初に利用している様子です。

2 セットアップ

amazon-connect-streamsを使用するための一連の作業は、以下のとおりです。

  • make
  • html(JavaScript)からの利用
  • httpsへの配置
  • アプリケーション統合
  • ブラウザからの利用

(1) make

Connect Streamsは、githubで公開されています。
https://github.com/aws/amazon-connect-streams

amazon-connect-streamsは、最初にmakeが必要です。

makeを実行すると、connect-streams-${VERSION}.jsというファイルが生成されます。(2019.01.30現在、バージョンは、amazon-connect-1.3.jsとなっていました。)

$ git clone https://github.com/aws/amazon-connect-streams
$ cd amazon-connect-streams
$ make
$ ls -la amazon-connect-*.js 
-rw-r--r--  1 sin  staff  661541  1 30 09:20 amazon-connect-1.3.js

(2) html(JavaScript)からの利用

後は、html内のJavaScriptからamazon-connect-1.3.jsを読み込み、connect.core.initCCP()で初期化するだけCCPが利用可能です。

amazon-connect-streamsを利用する最低限(CCPを使用するだけ)のコードは、以下のようになります。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Extened CCP</title>
    <script type="text/javascript" src="amazon-connect-1.3.js"></script>
</head>

<body>
    <center>
        <div id="containerDiv" style="width: 320px; height: 465px"></div>
    </center>
</body>

<script type="text/javascript">
    var ccpUrl = "https://example.awsapps.com/connect/ccp#/";
    connect.core.initCCP(containerDiv, {
        ccpUrl:        ccpUrl,
        loginPopup:    true,
        softphone: {
            allowFramedSoftphone: true
        },
    });
</script>
</html>

(3) httpsへの配置

Connect Streamsを使用するためには、httpsでホストする必要があります。

今回は、必要ファイルを、S3上に置き、CloudFlontからアクセスすることにしました。

(4) アプリケーション統合

ConnectのインスタンスでConnect Streamsを利用するためには、アプリケーション統合が必要です。

下記では、配置したCloudFlontのDNS名を統合先として登録しています。

(5) ブラウザでの利用

ここまでの作業で、CloudFlontのDNS名をリクエストするとCCPを利用できることが確認できます。

3 履歴

amazon-connect-streamsでは、その機能を拡張できるように、各種のイベントにハンドラをセットすることができまます。

今回は、履歴を作成するために、「コンタクト開始」「コンタクト終了」「コンタクト接続」の3つのイベントを処理しました。

CCPでダイヤルすると「コンタクト開始 connect.contact()」となり、そのコンタクトが終了した時点で「コンタクト終了 onEnded()」がハンドルされます。また、相手と接続された時点で「コンタクト接続 onConnected()」となります。

「コンタク開始」から「コンタクト終了」までの間で、「コンタクト接続」のイベントがあった場合は、【通話】、無かった場合に【不在】と表示するようにしました。

各イベントを処理しているコードは、以下のようになります。1接続ごとに履歴用のオブジェクトを生成し、そこに各イベントを記録しています。また、コンタクト終了時に、蓄積された履歴用オブジェクトを使用して、表示を更新しています。

connect.contact(function(contact) {

    if (contact.getActiveInitialConnection() && contact.getActiveInitialConnection().getEndpoint()) {
        // 電話番後を取得
        const phoneNumber = contact.getActiveInitialConnection().getEndpoint().phoneNumber;

        // コンタクト開始(履歴用のオブジェクトを生成)
        currentContact = new Contact(phoneNumber);

        contact.onEnded(function(contact) {
            console.log("onEnded");
            if(contact.contactData == undefined){
                // コンタクト終了(履歴用のオブジェクトに終了を記録)
                currentContact.end(); 
                contacts.push(currentContact);
                // 履歴の表示更新
                refresh(contacts);
            }
        }); 

        contact.onConnected(function() {
            // コンタクト接続(履歴用のオブジェクトに接続を記録)
            currentContact.connected();
        });
    }
});

4 発信

履歴表示をクリックすると、対象オブジェクトから電話番号を取得して、下記のcall()が呼び出されます。

ここでは、エージェントオブジェクトで.connect()を使用して、発信を行っています。

ここで使用されているエージェントオブジェクトは、エージェントがログインした時点で予め、取得されています。

function call(n) {
    const phoneNumber = contacts[n]._phoneNumber

    var result = window.confirm(phoneNumber + 'に発信しますか?');

    if( result ) {
        // エンドポイントオブジェクトの生成
        var endpoint = connect.Endpoint.byPhoneNumber(phoneNumber);
        // 発信開始
        login_agent.connect(endpoint,{
            success: () => {
                console.log("Connect Success");
            },
            failure: () => {
                console.log("Connect Failed");
            }
        });
    }
}

5 コード

履歴オブジェクト(Contactクラス)を含む、全てのhtmlは以下です。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Extened CCP</title>
    <script type="text/javascript" src="//code.jquery.com/jquery-1.12.4.js"></script>
    <script type="text/javascript" src="amazon-connect-1.3.js"></script>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <center>
    <table>
        <tr>
        <td>
            <div id="containerDiv" style="width: 320px; height: 465px"></div>
        </td>
        <td valign="top">
            <ol></ol>
        </td>
        </tr>
    </table>
    </center>
</body>

<script type="text/javascript">
    var login_agent = undefined;
    var ccpUrl = "https://exsample.awsapps.com/connect/ccp#/";
    connect.core.initCCP(containerDiv, {
        ccpUrl:        ccpUrl,
        loginPopup:    true,
        softphone: {
            allowFramedSoftphone: true
        },

    });

    // 履歴オブジェクト
    let contacts = [];
    // 接続中のコンタクト情報
    let currentContact;

    connect.agent( agent => {
        login_agent = agent; //エージェントオブジェクトを取得
    });

    //コンタクトイベントのサブスクライブ設定
    connect.contact(function(contact) {

        if (contact.getActiveInitialConnection() && contact.getActiveInitialConnection().getEndpoint()) {
            //const conn = contact.getActiveInitialConnection();

            // 電話番後を取得
            const phoneNumber = contact.getActiveInitialConnection().getEndpoint().phoneNumber;
            //const contactId = contact.getContactId();

            // コンタクト開始(履歴用のオブジェクトを生成)
            currentContact = new Contact(phoneNumber);

            contact.onEnded(function(contact) {
                console.log("onEnded");
                if(contact.contactData == undefined){
                    // コンタクト終了(履歴用のオブジェクトに終了を記録)
                    currentContact.end(); 
                    contacts.push(currentContact);
                    // 履歴の表示更新
                    refresh(contacts);
                }
            }); 

            contact.onConnected(function() {
                // コンタクト接続(履歴用のオブジェクトに接続を記録)
                currentContact.connected();
            });
        }
    });

    // 履歴用オブジェク(1通話分)
    class Contact {
        // 発信開始でオブジェクトを生成する
        constructor(phoneNumber) {
            this._phoneNumber = phoneNumber.split(':')[1].split('@')[0];
            this._startTime = new Date(); 
        }

        end() {
            this._endTime = new Date();
        }

        connected() {
            this._connectedTime = new Date();
        }

        display() {
            const phone = this._phoneNumber;
            const day = this.parseDate(this._startTime);
            const start = this.parseTime(this._startTime);
            const end = this.parseTime(this._endTime);

            if(this._connectedTime) { // 接続された場合
                const connected = this.parseTime(this._connectedTime);
                return ' 【通話】 ' + phone + ' ' + day + ' ' + connected + ' - ' + end;
            }
            return '【不在】 ' + phone + ' ' + day + ' ' + start;
        }

        parseDate(dt) {
            const y = ('0000' + dt.getFullYear()).slice(-4);
            const m = ('00' + (dt.getMonth() + 1)).slice(-2);
            const d = ('00' + (dt.getDate() + 1)).slice(-2);
            return y + '/' + m + '/' + d; 
        }

        parseTime(dt) {
            const h = ('00' + (dt.getHours() + 1)).slice(-2);
            const m = ('00' + (dt.getMinutes() + 1)).slice(-2);
            const s = ('00' + (dt.getSeconds() + 1)).slice(-2);
            return h + ':' + m + ':' + s; 
        }
    }

   // 履歴オブジェクトによる表示更新
    function refresh(contacts) {
        $('ol').empty();
        for(var i=0; i<contacts.length; i++) {
            $('ol').append('<li onclick="call('+ i +')">' + contacts[i].display() + '</li>');
        }
    }

    // 発信
    function call(n) {
        const phoneNumber = contacts[n]._phoneNumber

        var result = window.confirm(phoneNumber + 'に発信しますか?');

        if( result ) {
            var endpoint = connect.Endpoint.byPhoneNumber(phoneNumber);
            login_agent.connect(endpoint,{
                success: () => {
                    console.log("Connect Success");
                },
                failure: () => {
                    console.log("Connect Failed");
                }
            });
        }
    }

</script>
</html>

6 最後に

Connect開発時には、CCPでを操作する機会が多くなりますが、発信履歴やリダイレクトが無いので、ちょっと手数を感じてました。

今後は、この拡張CCPで快適に開発を進められると思います。

弊社では、「Amazon Connect」の導入を検討している方を対象とした無料相談会を毎週開催中です。

また、音声を利用した各種ソリューションの導入支援を行っております。お気軽にお問い合わせください。
チャットボット開発支援

7 参考リンク


aws/amazon-connect-streams

コメントは受け付けていません。