Twilio Flex で後処理中に通話録音を聞くプラグイン

:::note alert
2023年5月1日を持ちまして、株式会社KDDIウェブコミュニケーションズのTwilioリセール事業が終了したため、本記事に記載されている内容は正確ではないことを予めご了承ください。
:::

# はじめに

みなさん、こんにちは。
KDDIウェブコミュニケーションズ、Twilioエバンジェリストの高橋です。

今回は、Twilio Flex で後処理中に、今通話していた内容を聞くことができるプラグインについてご紹介します。
多くのコンタクトセンターでは、通話が終了したときに、問い合わせ内容を記録するための「後処理」と呼ばれる時間があります。この時間で、オペレーターは通話の内容を記録するのですが、そのときに通話内容がもう一度聞けると便利ですね。

プラグイン利用イメージ
![スクリーンショット 2022-05-23 8.39.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/4d4cc38b-174b-b441-86ca-816e93b0298d.png)

このプラグインを利用すると、上記のように「Record」というタブが用意されて、通話が録音するとこのタブの中にオーディオ再生ボタンが表示されるようになります。再生ボタンを押せば、通話内容が再生されます（Dual Channel Recording を利用しますので、オペレーターの声が右側、お客さんの声が左側から聞こえます）。

# セットアップ

セットアップ方法については、GitHub の README に書いてありますので、そちらに従ってください。

https://github.com/mobilebiz/plugin-listen-recording

# プログラムの解説

本プラグインの構成は以下の通りです。

```shell:構成
.
├── README.md
（省略）
├── src
│   ├── ListenRecordingPlugin.js
│   ├── components
│   │   ├── Record
│   │   │   ├── Record.Container.js
│   │   │   └── Record.jsx
│   │   └── __tests__
│   │       └── RecordComponent.spec.jsx
│   ├── i18n
│   │   └── JP.js
│   └── index.js
├── webpack.config.js
└── webpack.dev.js
```

## ListenRecordingPlugin.js

プラグインの中で最初に呼ばれる部分です。

```javascript:ListenRecordingPlugin.js
import React from 'react';
import { VERSION, Tab } from '@twilio/flex-ui';
import { FlexPlugin } from '@twilio/flex-plugin';
import japanese from './i18n/JP'; // 日本語サブセット

import RecordContainer from './components/Record/Record.Container';

const PLUGIN_NAME = 'ListenRecordingPlugin';

export default class ListenRecordingPlugin extends FlexPlugin {
  constructor() {
    super(PLUGIN_NAME);
  }

  /**
   * This code is run when your plugin is being started
   * Use this to modify any UI components or attach to the actions framework
   *
   * @param flex { typeof import('@twilio/flex-ui') }
   * @param manager { import('@twilio/flex-ui').Manager }
   */
  async init(flex, manager) {
    // 日本語コンソールへ切り替え
    manager.strings = { ...manager.strings, ...japanese };

    // 通録コンポーネントの配置
    flex.TaskCanvasTabs.Content.add(
      <Tab label='Record' key='record-tab'>
        <RecordContainer key='record-component' />
      </Tab>,
    );
  }
}
```

:::note info
このプログラムでは、Flex コンソールの日本語化を同時に行っています。もし、日本語化が不要な場合は、`import japanese　〜`の行と、`manager.strings = 〜`の行を削除してください。
:::

ここでは、タスクキャンバスコンポーネントに、新しく「Record」というタブを新設し、その中に RecordContainer コンポーネントを表示するようにしています。

## Record.Container.js

こちらが、RecordContainer コンポーネントになります。

```javascript:Record.Container.js
import React from 'react';
import { withTaskContext, TaskHelper } from '@twilio/flex-ui';
import Record from './Record';

const RecordContainer = (props) => {
  // Voiceチャンネル以外は処理しない
  if (!props.task || props.task.channelType !== 'voice') return null;

  // 後処理中かを確認する
  const taskHelper = new TaskHelper(props.task);
  if (!taskHelper.isInWrapupMode) return null;

  return <Record {...props} />;
};
export default withTaskContext(RecordContainer);
```

@twilio/flex-ui に含まれている`withTaskContext`を使ってコンポーネントをラップすることで、このコンポーネントに`task`オブジェクトをプロパティとして渡すことができます（最終行）。
そして、コンポーネントの内部で通話のタスクであるかの確認と、さらに現在のタスクの状態が後処理中であるかを確認しています。
タスクの状態が後処理中を調べるために、`TaskHelper`の`isInWrapupMode`を使っています。`TaskHelper`は便利なクラスなので、ぜひ覚えておきましょう。

https://assets.flex.twilio.com/releases/flex-ui/1.18.0/docs/TaskHelper.html

このコンポーネントの内部から、さらに`Record`コンポーネントを呼び出しています。

:::note info
`Record`コンポーネントの部分も一緒にコーディングすることも可能なのですが、そうするとテストコード（`RecordComponent.spec.jsx`）がエラーになる（Flexのテストでは、`@twilio/flex-ui`の`import`がエラーになる）ことがわかったので、今回は再生するコンポーネントだけをさらに抜き出すようにしています。
:::

## Record.jsx

こちらが実際に通話録音を再生するためのUIを提供しています。

```javaScript:Record.jsx
import React from 'react';
import { Box } from '@material-ui/core'
import AudioPlayer from 'react-h5-audio-player';
import 'react-h5-audio-player/lib/styles.css';

const Record = (props) => {
  if (!props.task) return null;

  // 録音データのURLはStudio Flowの中で設定されているはずなので、それを取得する
  const recordingUrl = `${props.task.attributes?.conversations?.media[0].url}.mp3`
    || '';
  if (!recordingUrl) return null;

  
  return (
    <Box width="100%" height="300px">
      <AudioPlayer
        className='audioPlayer'
        src={recordingUrl}
        preload='none'
        onPlay={(e) => console.log('onPlay')}
      />
    </Box>
  )
}

export default Record;
```

今回は、オーディオ再生用の React コンポーネントとして、`react-h5-audio-player`を利用しています。

https://github.com/lhz516/react-h5-audio-player

ポイントは、`preload`パラメータに、`none`を設定するところです。
Twilioの通話録音は、通話が終了した時点で生成が開始されるので、通話が終了したタイミングでは通録データはまだできていません。そのため、`preload`パラメータに`none`を指定しないと、コンポーネントが生成されたタイミングで先読みされてしまってデータが404になり再生されません。
本来は、録音をする際の`RecordingStatusCallback`を使って、通録データが完成したことを検知してから Flex コンソールに通知するのが望ましいのですが、これは相当にしんどそうだったので、今回は先読みをしないで対応するようにしてあります。

肝心の録音データのURLについては、こちらの記事に沿って通録を有効にすることで、タスクの`Attributes`に通録のURLが記載されるので、そちらをそのまま利用しています。

https://www.twilio.com/docs/flex/developer/insights/enable-dual-channel-recordings
# まとめ

ソースコードだけをみるととてもシンプルになっていますが、色々と試行錯誤をしたので、結果的に3日くらいかかってしまいました。
参考になれば幸いです。
なお、今回はタスクキャンパス上でタブを作っていますので、Salesforce Integration でも使えます。

---
### Twilio（トゥイリオ）とは

https://cloudapi.kddi-web.com
Twilio は音声通話、メッセージング（SMS /チャット）、ビデオなどの 様々なコミュニケーション手段をアプリケーションやビジネスへ容易に組み込むことのできるクラウド API サービスです。初期費用不要な従量課金制で、各種開発言語に対応しているため、多くのハッカソンイベントやスタートアップなどにも、ご利用いただいております。

Twilioに関するご相談などがございましたら、ぜひ毎週水曜日の午後に開催しております相談会をご利用ください。
[Twilio相談会（毎週水曜日）](https://cloudapi.kddi-web.com/contact/consultation?hsLang=ja-jp)

自己紹介|　
:--|:--
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/b51a8b88-abd5-ce5e-195a-de3564ba2ae6.png" height='200' width='150'/>|高橋克己（Katsumi Takahashi） 自称「<font color='red'>赤い芸人</font>」<br />グローバル・インターネット・ジャパン株式会社　代表取締役<br />株式会社KDDIウェブコミュニケーションズ　Twilio事業部エバンジェリスト<br /><br />2001年より大手通信事業者の法人サービスの教育に携わり、企業における電話のしくみや重要性を研究。2016年よりTwilio事業部にジョインし、Twilioを使ったスマートコミュニケーションの普及活動を精力的に行っている。<br />2015 Hall of Doers<br />2019 Twilio Champions