[Amazon Connect] 自動発信(Automated Outbound Calling)を利用したサンプル(その2)〜キャンペーン案内の電話を自動でコールして、顧客の都合が良いときだけエージェントにつなぐ〜

1 はじめに

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

Amazon Connect(以下、Connect)では、自動発信が可能になっています。

前回は、このOutboundを使って下記のサンプルを作成してみました。
[Amazon Connect] 自動発信(Automated Outbound Calling)を利用したサンプル(その2)〜キャンペーン案内の電話を自動でコールして、顧客の都合が良いときだけエージェントにつなぐ〜

今回は、自動発信の後、エージェントにつなぐ形のサンプルを作成してみたいと思います。

最初に、顧客の電話に着信しているようすをご確認下さい。今すぐ、エージェントと話することを希望(1を選択)すると、エージェントの電話が着信しているのが分かります。 ちょっと不注意でしたが、エージェントがソフト フォンを取った時点でハウリングしてしまってます。m(.)m

2 キャンペーン案内の電話を自動でコールして、顧客の都合が良いときだけエージェントにつなぐ

「顧客リストをもとに、キャンペーン案内の電話をかける」という作業があった場合、せっかく電話をしても、不在で電話にでてくれなかったり、タイミングが悪く、今、話を聞けないと言って断られてしまう可能性は充分に考えられます。

都合の良い顧客に電話が繋がって、実際に案内が始まるまでのこのような手順は、ちょっと勿体無い感じです。

今回のサンプルは、これを避けるために、次のような仕組みになっています。

  1. 顧客リストに従って、自動で発信する
  2. IVRで顧客の都合を伺う
  3. 都合が良い場合は、エージェントに転送される
  4. エージェントが顧客と通話(キャンペーン案内)をする

なお、3.の転送のタイミングは、いわゆる顧客の待ち状態になってしまうので、エージェントが直ちに対応できるように、1.の自動発信は、対応可能なエージェントの人数分だけ、進めるようになっています。

3 顧客DB

顧客のリストは、前回と同じで下記のようなものになっています。簡単になるように電話番号がキーになっています。

  • phoneNumber: 顧客の電話番号 (キー)
  • name: 顧客の名前
  • canpaign_2018_12: キャンペーン情報 顧客DBには、キャンペーン情報のカラムがあり、その状態を保持しています。

キャンペーン情報につては、最初に、すべてのデータを -1 に設定しておき、順次に自動で電話をかけ、処理した内容を記録していきます。

自動電話に対する顧客の応答で、「今すぐ話しを聞きたい」ということでエージェントに接続した場合は、当該カラムが1、「後日、再度の連絡を希望」の場合は2、「メールでの案内を希望」の場合3、「興味なし」の場合は、0となります。(不在の場合は、-2となります)

4 問い合わせフロー

顧客が電話に出た場合に、対応する問い合わせフローは以下のようになっています。

最初に「顧客の入力を保存する」で、入力を取得し、Lambdaに渡します。また、エージェントへの接続を希望した場合は、キューに接続されます。

Lambdaのコードは、以下のとおりです。選択にしたがって、メッセージを生成し、顧客の電話番号をキーにして顧客DBを書き換えます。

なお、1を選択された場合だけ、disconnectのフラグがfalseとなり、事後のフローでキューに向かいます。

Timeoutを処理しているのは、顧客が電話にでない(留守番電話に入ってしまう)などの場合を想定しており、後で分かるように -2 を設定しています。

const aws = require('aws-sdk');
const dbClient = new aws.DynamoDB.DocumentClient({region: 'ap-southeast-2'});
const tableName = 'outbound-sample-001';
const campaign = "campaign_2018_12"; // 対象キャンペーン

exports.handler = async function(event, context) {
  console.log(JSON.stringify(event));
  // 顧客の電話番号
  const phoneNumber = event.Details.ContactData.CustomerEndpoint.Address; 
  // 顧客が選択した番号
  const inputData = event.Details.Parameters.inputData;

  let message = '<speak>';
  let disconnect = true; // この電話を切断するかどうか
  let flg = -1; // キャンペーンフラグ
  if(inputData == 'Timeout') { // 番号選択なし(留守番電話など)
    message = '番号選択を認識できませんでした。<p/>もし、このキャンペーンに興味がございましたら、0120-000-0000にお電話下さい。';
    flg = -2;
  } else if(inputData == '1') { // 今すぐ話しを聞く(エージェントとの接続)
    message += 'ありがとうございます。<p/>そのままお待ち下さい。';
    disconnect = false; // falseの場合は、キューに入れる
    flg = 1;
  } else if(inputData == '2') { // 後日、改めて連絡を希望
    message += 'ありがとうございます。<p/>後日、改めてご連絡申し上げます。';
    flg = 2;
  } else if(inputData == '3') { // メールでの連絡を希望
    message += 'ありがとうございます。<p/>メールでご案内を送らせて頂きます。';
    flg = 2;
  } else { // 案内は、必要ない場合
    message += 'ありがとうございます。<p/>今後とも、クラスメソッドを宜しくお願い申し上げます。';
    flg = 0;
  }
  message += '</speak>';

  var param = {
    TableName : tableName,
    KeyConditionExpression : "#k = :val",
    ExpressionAttributeValues : {":val" : phoneNumber},
    ExpressionAttributeNames  : {"#k" : "phoneNumber"}
  };
  let data = await dbClient.query(param).promise();
  if(data.Items && 0 < data.Items.length){
    data.Items[0][campaign] = flg;
    const r = await dbClient.put( { "TableName": tableName, "Item": data.Items[0]}).promise();
  }
  return {message:message, disconnect:disconnect};
}

5 自動発信

顧客DBを元に、順次発信するコードは、前回のものとほとんど同じです。

一部違うのは、今回は、発信するだけでなく、状況によってはエージェントの対応が必要なため、対応可能なエージェント数以下となるように発信を調整している点です。

対応するキューに紐付いたエージェントの状態は、getCurrentMetricDataで取得が可能です。 このAPIを使用して、ステータスがAVAILABLEになっているエージェントをカウントし、0以上の場合に、次の発信に進むようになっています。

const aws = require('aws-sdk');
const connect = new aws.Connect({region:'ap-southeast-2'});
const dynamo = new aws.DynamoDB({region: 'ap-southeast-2'});

// ConnectのインスタンスID
const instanceId ='d091242f-xxxx-xxxx-xxxx-f9545cf8f8ef';
// 応答する問い合わせフローのID
const contactFlowId = '3191af9e-xxxx-xxxx-xxxx-79081b2e2b13';
// 対象キューのID
const queueId = 'a14070c7-xxxx-xxxx-xxxx-abf124301180';
// 発信電話番号(Connectインスタンスで確保している番号)
const sourcePhoeNumber = '+81507771111';

const tableName = 'outbound-sample-001';

const sleep = msec => new Promise(resolve => setTimeout(resolve, msec));

async function job(){
  const data = await dynamo.scan({"TableName": tableName}).promise();
  if(data){
    data.Items.forEach( async item => {

      // エージェントが空くまで待機する
      while(true){
        //対応可能なエージェント数を取得する
        if(0 < await getNumberOfAgent()){
          break;
        }
        console.log("Agend Busy.")
        await sleep(5000); 
      }

      // 顧客DBから電話番号を取得  
      const destinationPhoneNumber = item.phoneNumber;
      const params = {
        ContactFlowId: contactFlowId,
        DestinationPhoneNumber: destinationPhoneNumber.S,
        InstanceId: instanceId,
        SourcePhoneNumber: sourcePhoeNumber
      };
      // 自動発信
      const result = await connect.startOutboundVoiceContact(params).promise();
      console.log(JSON.stringify(result));
      }
    })
  }
}

// 対応可能なエージェント数を取得する
async function getNumberOfAgent() {

  var params = {
    CurrentMetrics: [
      { Name: 'AGENTS_AVAILABLE', Unit: 'COUNT' }
    ],
    Filters: { 
      Channels: ['VOICE'],
      Queues: [ queueId ]
    },
    InstanceId: instanceId,
  };

  const data = await connect.getCurrentMetricData(params).promise();

  let count = 0;
  data.MetricResults.forEach( result => {
    result.Collections.forEach( collection => {
      if(collection.Metric.Name == 'AGENTS_AVAILABLE') {
        count = collection.Value;
      }
    })
  })
  return count;
}

6 最後に

今回は、Outboundの機能を利用した「キャンペン案内の電話を自動でコールして、顧客の都合が良いときだけエージェントにつなぐ」サンプルを作成してみました。

getCurrentMetricDataで、エージェントの状況を確認することで、更に、startOutboundVoiceContactの応用が広がりそうです。

弊社では、音声を利用した各種ソリューションの導入支援を行っております。お気軽にお問い合わせください。
チャットボット開発支援
クラウド型コンタクトセンターサービス導入支援

7 参考にさせて頂いたリンク


LINE Botにお願いしてAmazon Connect APIから電話をかけてもらう
Amazon Connect Outbound ContactのPreview版を試してみる

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