本記事はトレタアドベントカレンダー19日目の記事です。
こんにちは。リングフィットアドベンチャーを2週に1回のペースでプレイしているフロントエンドエンジニアの北川です。
私はトレタのコンタクトセンター事業(以下、トレタCC)のシステム開発全般を担っており、今年は基幹のCTI(電話機)をAmazonConnectへ入れ替えたので、その辺の話を本記事で紹介します。
トレタCCとは
トレタCCは、契約している飲食店の電話業務を代行するサービスです。
トレタって予約台帳なのになんでコンタクトセンターやってるの?と聞かれることがありますが、トレタは飲食店を支援することをミッションとしています。店舗にとっての電話業務とは、予約の電話に限らず当日の道案内や落し物の問い合わせなど、予約以外の多種多様な電話も時間問わずにかかってくるとても業務負荷の高いものです。トレタCCではそれらすべての電話を代行し、飲食店に電話がかかってこない環境をつくることで本来の業務にフォーカスしていただくためのサービスです。
トレタCCのシステムアーキテクチャ
トレタCCで使用するアプリケーションは、代行した店舗の電話をうけるCA(コールエージェント)が利用するシステムです。 トレタの予約台帳への予約の書き込みや、顧客台帳から電話口の顧客情報を表示したりします。また、前述の通り予約以外の電話もあるため、専用のDBヘ電話の対応履歴を登録したりします。
利用技術
- AmazonConnect
- Angular
- Lambda(Node.js)
- DynamoDB
クライアントはAngularで作られたWebアプリケーションになっており、AmazonConnectが提供しているCCP(ContactControlPanel)を埋め込み電話操作を行います。 サーバーサイドはAmazonConnectとの連携を考慮し、Lambdaを主軸にしたサーバーレス構成にしています。AngularへのAPIを提供や、AmazonConnectの問い合わせフロー(IVR)との連携を行います。DBはLambdaとの相性を考慮してDynamoDBを利用しています(先日LambdaにRDS Proxy機能が発表されたので、今ならRDBを使う選択肢もあると思います)。 また、serverlessフレームワークを利用しており、Lambdaのデプロイや、APIGatewayとDynamoDBをオフライン化した状態(serverless-offline, serverless-dynamodb-local)の開発環境を構築しています。
データ分析
AmazonConnectでは、履歴メトリクスとして通話履歴やエージェントの稼働状況の統計画面が標準で提供されています。データ出力も提供されており、トレタCCでの通話履歴とトレタ台帳の予約データを突合させるため、BigQueryでデータの一限管理を行なっています。
- AmazonKinesis
- GoogleBigQuery
AmazonConnectはAPIを提供していますが、通話履歴のAPIは提供されていないため、AmazonKinesisを設定することで、リアルタイムの通話履歴が取得できます。AmazonKinesisに設定されたLambdaが随時トリガーされ、渡される通話履歴データをBigQueryへ集約しています。また、音声ファイルは自動でS3へアップロードされ、通話履歴内にも音声ファイルのURLが含まれています。
AngularとAmazonConnectの連携
電話のインターフェースはAmazonConnectが提供しているCCPを使用しています。また、jsライブラリであるamazon-conect-streamsを使うことで、CCP上での受電などのイベント取得や発信を行うことが出来るようになります。
(AmazonConnectのCCP)
amazon-conect-streamsでは、エージェントのステータス変更イベントや通話のステータス変更イベントにコールバックが設定できるので、RxJsと組み合わてストリームにしてAngularで扱っています。
export class AmazonConnectAdapter { callStatus$ = new BehaviorSubject<CallStatus>(CallStatus.disconnect); agentStatus$ = new BehaviorSubject<AgentStatus>(AgentStatus.unavailable); availableQueues$ = new BehaviorSubject<Queue[]>([]); agentEndpoints$ = new BehaviorSubject<AgentEndpoint[]>([]); onInboundCallIncoming: EventEmitter<CallNumbers> = new EventEmitter(); onInboundCallAccepted: EventEmitter<CallNumbers> = new EventEmitter(); onOutboundCallConnected: EventEmitter<CallNumbers> = new EventEmitter(); initialize(ctiElement: ElementRef) { this.initCCP(ctiElement); this.openLogin(); connect.agent(agent => { this.onAgentCallback(agent); agent.onRoutable(() => { this.agentStatus$.next(AgentStatus.available); }); agent.onOffline(() => { this.agentStatus$.next(AgentStatus.unavailable); }); agent.onAfterCallWork(() => { this.agentStatus$.next(AgentStatus.unavailable); }); }); // ...
CCP内で行える機能はほぼamazon-conect-streamsから可能になっているため、今後は自前のUIに切り替える予定です。 逆にCCPではできないこともあり、発信時には発信元が設定できなかったりします。
(発信用インターフェースの例)
LambdaとAmazonConnectの連携
AmazonConnectはIVR機能である問い合わせフローを管理画面から設定することができ、フロー内でLambda関数を呼び出し、取得した値に応じたフローを書くことが可能です。
たとえば、コールセンターの業務時間の設定は標準機能である「オペレーション時間」の管理画面から設定することができますが、飲食店では祝日や祝前日は特別なオペレーションを行うことがあるため、自前のオペレーション時間設定をLambda関数から呼び出すことで柔軟に対応を行なっています。
今後の取り組み
AmazonConnectへの切り替えが終わり、現在はAmazonConnectを利用した自動音声応答(VoiceChatBot)に力を入れています。 AmazonConnectの問い合わせフローでの標準機能として、
- VideoStreamによるリアルタイムな音声データの抽出
- Lambda呼び出しによる動的なフロー作成
- AmazonPollyによる動的な文章読み上げ
が可能です。 これらを組み合わせることで、店舗にあった動的な自動応答が可能になります。 また、先日Amazon Transcribeの日本語対応が発表され、文字起こしがさらに容易に行えるようになりました。 テンプレ的な予約の受け答えはBot化し、人にしか対応できない部分はオペレーターが対応するハイブリッドな形を目指していこうと思っています。
おわりに
トレタCCでは、今までにない新しいコンタクトセンターを作っていく仲間を募集しています。 フロントエンドでAngularをゴリゴリやりたい方、Node.jsでサーバーレスをやりたい方、通話内容を分析して機械学習をやりたい方、などなど幅広く募集しております!
お次はインフラエンジニアのなぎらさんです。お楽しみに!