Twilio Flexの始め方（GoogleSpreadsheet連携編）

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

# はじめに

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

[Twilio Flex Advent Calendar 2021](https://qiita.com/advent-calendar/2021/twilio-flex) 7日目の記事となります。
[前回の記事](https://qiita.com/mobilebiz/private/4906a2d37607e1082808)では、Twilio Studioを使ったIVRの実装についてご紹介しました。その中で、ユーザーの要件を発話させ、音声認識した結果をエージェントの本来顧客名を出すところに表示する方法を紹介しましたが、今回の記事では、発信者の電話番号からGoogleSpreadsheet上に登録されている顧客名を検索し、それを顧客名として表示させてみたいと思います。

完成すると、このような形で顧客の名前が表示されるようになります。
![スクリーンショット 2021-12-10 9.19.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/1439a2b5-8d68-d18f-1d22-a10959eefd96.png)

# 準備

本記事を実行するための準備について説明します。
すでにFlexのセットアップが完了しているものとします。

## Google Spreadsheet

Google Spreadsheetに以下のような簡単な顧客リストを作成してください。
![スクリーンショット 2021-12-09 12.07.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/26c36cdc-d2bd-e537-9e19-0842168faae1.png)


一行目が項目名になります。A列を「顧客名」、B列を「電話番号」という名前にしておきます。
電話番号は、0から始まるため、そのまま登録してしまうと数値として先頭の0がカットされてしまいます。なので、0の前にシングルコーテーションをつけて、文字列として登録しておきましょう。
また、シート名（画面下側にあります）を、「sheet1」（すべて小文字+数字の１）に変更しておいてください。

シートが作成できたら、シートのURLをメモ帳に控えておきます。

## Stein

今回は、GAS（Google Apps Script）ではなく、[Stein](https://steinhq.com/)というサービスを使ってデータにアクセスします。Steinは、Google Spreadsheetを簡単にAPI化してくれるサービスで、読み込みだけでなく、書き込みにも対応しています。

Steinのアカウントを、事前に[こちら](https://steinhq.com/)から作成しておいてください。
アカウントの作成が終わると、利用方法のウィザードが始まり、途中で先程控えておいた Google SpreadSheetのURLを聞かれます。

ウィザードが終了すると、以下のようにAPIが完成しています。

![スクリーンショット 2021-12-09 15.10.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/bb8a9ef5-6d55-2a5e-e0a2-efe4cd55118e.png)

右側の矢印を押すと、このAPIの詳細画面が表示されます。
![スクリーンショット 2021-12-09 15.11.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/54796a31-16c1-4506-71a3-fa6b84b0e25f.png)

後ほど使うので、API URLをメモ帳などに控えておいてください。

# 顧客名を検索するプログラムを作る

では実際にSpreadsheetを検索するプログラムを作りましょう。
今回は、Twilio Functions内にコードを作成していきます。

- Twilio管理コンソールにログインします。
- 左側のスライドメニューから**Functions**を選択します。
![スクリーンショット 2021-12-09 15.18.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/f4094119-d0e0-4813-3217-e5c418ba5686.png)

- **Service**メニューを選択し、**Create Service**ボタンを押します。
![スクリーンショット 2021-12-09 15.19.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/e5bf3d4f-d2eb-d55f-1dda-8dcecdb91c91.png)

- **Service Name**欄に「Flex」と入力して、**Next**ボタンを押します。
![スクリーンショット 2021-12-09 15.21.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/7e324378-796e-37f3-955f-21397a25e0b6.png)

- **Add**ボタンを押すと、リストメニューが開くので**Add Function**を選択します。
![スクリーンショット 2021-12-09 15.22.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/19a93408-8d8c-50ab-8454-8cb0a3fc29f1.png)

- FunctionのPathには、「get-customer」と指定をしておきます。
- 以下のようなテンプレートプログラムが表示されます。
![スクリーンショット 2021-12-09 15.26.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/5504089f-eada-87af-f231-36fadcad5b2e.png)

## Dependenciesの設定

次に、SteinのJavaScriptライブラリを利用できるようにしていきます。

- **Settings**の**Dependencies**を選択します。
![スクリーンショット 2021-12-09 15.29.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/05f864a1-a441-c6de-3c3e-25c208cbc8d6.png)

- **MODULE**と**VERSION**に以下の内容を指定します。

MODULE|VERSION
:--|:--
stein-js-client|0.0.2

- **Add**ボタンを押します。

## Environment Variablesの設定

次にSteinのAPI URLを環境変数として指定していきましょう。

- **Settings**の**Environment Variables**を選択します。
![スクリーンショット 2021-12-09 15.32.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/a13c2d93-0c7e-5f95-bbe5-ed0cdabe9319.png)

- **KEY**と**VALUE**を以下のように指定します。

KEY|VALUE
:--|:--
STEIN_API|Steinで払い出されたAPIのURL（https://api.steinhq.com/v1/storages/xxxxxxxxxxxxxxx）

- **Add**ボタンを押します。

## コードを作成する

では最後に、Spreadsheetを検索するコードを作成します。

- **Functions**の中から、先程作成した「/get-customer」を選択します。
![スクリーンショット 2021-12-09 15.34.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/370250d3-a799-4891-45c1-235bed767a41.png)

- 右側のコード欄に書かれている既存のコードをすべて削除し、以下のコードに置き換えます。

```javascript
const SteinStore = require('stein-js-client');

exports.handler = async function(context, event, callback) {
  try {
    const number = event.From.replace(/\+81/, '0'); // E.164->0ABJ
    const store = new SteinStore(context.STEIN_API);
    const data = await store.read("sheet1", { search: { '電話番号': number }});
    console.log(`data: ${data}`);
    return callback(null, data.length > 0 ? data[0]['顧客名'] : number);
  } catch(err) {
    console.error(`ERROR: ${err}`);
    return callback(err);
  }
};
```

- **Save**ボタンを押します。
- 続いて**Deploy All**ボタンを押します。デプロイにはしばらく時間がかかります。
- 以下のように、Functionsの「/get-customer」に緑色のアイコンが表示されれば完成です。
![スクリーンショット 2021-12-09 15.43.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/63d9b8a6-ada3-fc8e-2368-1091d9a5ccf5.png)

### コードの解説

- 1行目は、SteinのJavaScriptの読み込みを行っています。先程のDependenciesで設定しておく必要があります。
- 5行目は、電話番号の変換をしています。Twilio内では、電話番号はすべてE.164形式（日本なら+81から始まる番号）で扱われるため、シート内に設定した0ABJ（0から始まる電話番号）と一致させるために必要です。
- 6〜7行目が、実際にSpreadsheetを検索するコードです。ここでは、シート名（`sheet1`）と項目名（`電話番号`）を指定しています。Spreadsheet側の名前が違うとうまく検索できませんので気をつけてください。
- 9行目で検索結果を返却する準備をしています。該当するデータが存在する場合は顧客名を返し、該当するデータがない場合は0ABJの電話番号を返却するようにしています。

なお、今回はFunctionsを**Protected**として作成したため、認証情報がないと外部からこのFunctionを呼び出すことはできません。一方で、Studio内部からは認証情報がなくても呼び出しが可能です。

# IVR側でFunctionsを呼び出す

では次に、IVR側から今作成したFunctionsを呼び出すようにStudioフローを作成していきましょう。

- 管理コンソールの左側のスライドメニューから、**Studio**を選択します。
![スクリーンショット 2021-12-09 15.48.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/5add5a30-95d3-b051-3fc4-c6a6d5d4e53e.png)

- すでに作成してある**Voice IVR**の**Duplicate Flow**をクリックして複製します。
![スクリーンショット 2021-12-09 15.50.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/5cf86931-73b5-edb5-0458-a2f8d2ffa508.png)

- **Trigger**ウィジェットを選択し、設定パネルの**FLOW NAME**を「Voice IVR Customer」に変更します。
- **Save**ボタンを押します。

前回の記事通りに作業をしている方は、**GetQuestion**ウィジェットが表示されていると思いますが、今回はこちらのウィジェットは不要なので、削除します。

- **GetQuestion**ウィジェットを選択します。
![スクリーンショット 2021-12-09 15.54.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/c12489af-714c-fb50-c25e-8090e5897052.png)

- 右下のゴミ箱アイコンをクリックします。
- 削除の確認ダイアログが表示されるので、**Yes**ボタンを押して削除してください。

![スクリーンショット 2021-12-09 15.56.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/79e9597b-6792-009a-05a3-0b5b134c8ea3.png)

- 右側の**WIDGET LIBRARY**から、**Run Function**ウィジェットをキャンパス上にドラッグして配置します。
- 配置したウィジェットを選択すると、設定パネルが表示されます。
![スクリーンショット 2021-12-09 17.22.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/15a8075a-2784-f7fc-4bd7-a98d6f2e72c6.png)

- **WIDGET NAME**欄に「getCustomer」と入力します。
- **SERVICE**のプルダウンリストから「Flex」を選択します。
- **ENVIRONMENT**のプルダウンリストから「ui」を選択します。
- **FUNCTION**のプルダウンリストから「/get-customer」を選択します。
- **FUNCTION URL**は自動的に入力されます。
- **Function Parameter**の右側の＋ボタンを押します。
![スクリーンショット 2021-12-09 17.37.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/f1ccc738-fce4-4a9a-69e7-170fdc8d6128.png)

- 以下のように値を設定します。

KEY|VALUE
:--|:--
From|{{trigger.call.From}}

- **Save**ボタンを押します。

では、それぞれのウィジェットを接続しましょう。

![スクリーンショット 2021-12-09 17.26.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/40dfc8ff-2bd3-81d9-0314-3680b28be306.png)

- **Trigger**ウィジェットの**Incoming Call**と書かれた線を、**getCustomer**ウィジェットの左上の黒丸につなげます。
- **getCustomer**ウィジェットの**Success**と書かれた線を、**SendCallToAgent**ウィジェットの左上の黒丸につなげます。

では最後にTaskRouterへ受け渡す属性に、Functionsの結果を入れましょう。

- **SendCallToAgent**ウィジェットを選択して、設定パネルを開きます。
![スクリーンショット 2021-12-10 8.39.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/305e3d3a-394a-d9fb-f76f-2c987542049f.png)

- **ATTRIBUTES**欄を以下の内容に書き換えます。

```json
{ "type": "inbound", "name": "{{widgets.getCustomer.body}}" }
```

- **Save**ボタンを押します。
- 最後に画面上部の**Publish**ボタンを押します。
![スクリーンショット 2021-12-09 17.32.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/19d45823-daaf-2a48-3054-3934926a682a.png)

確認ダイアログが表示されるので、**Publish**ボタンを押します。

## 電話番号にフローを割り当てる

では最後に、今作成したStudioフローを着信番号に割り当てましょう。

- 管理コンソールの左側のスライドメニューから、**Phone Numbers**を選択します。
- **番号の管理**の中の**アクティブな電話番号**を選択します。
- すでに購入済みの電話番号がリストされているはずなので、その番号を選択します。
![スクリーンショット 2021-12-10 9.09.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/026f0ed0-78f4-749e-f069-af3f12a5b358.png)

- **Voice & Fax**の設定の中にある**A CALL COMES IN**のプルダウンから、先程作成した「Voice IVR Customer」を選びます。
- **Save**ボタンを押して、設定を保存します。

以上で設定はすべて完了です。

# テスト

では早速テストをしてみましょう。
事前にGoogleSpreadsheetsに、発信する電話番号と自分の名前を入れておくことを忘れないようにしてください。
準備ができたら、Flexを起動して、エージェントを待ち受け状態にしておきます。

登録した電話機から先程のフローを割り当てた番号に電話をかけると、着信画面上に正しく名前が表示されれば成功です。
![スクリーンショット 2021-12-10 8.38.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/156a2b29-6726-9c93-c5af-f259147885ee.png)

もし着信しない場合は、Studio内でFunctionsの呼び出しが失敗している可能性があります。
管理コンソールから**Debugger**を選択するとエラーの内容が確認できます。

# まとめ

本日の記事では発信者の電話番号から顧客の名前を表示させる方法をご紹介しました。今回はGoogleSpreadsheetを利用しましたが、もしAPIが利用できるサービスであれば同様の方法で顧客を検索することが可能です。担当するオペレーターが決まっているような場合であれば、その情報をTaskRouterに引き渡すことで、直接担当者につなぐことも可能です。

次回からはいよいよTwilio Flexの中心機能であるTaskRouterについて説明していきたいと思います。

★次の記事
[Twilio Flexの始め方（TaskRouter基礎編）](https://qiita.com/mobilebiz/items/2af0d9fd09cff1040878)

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

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

自己紹介|　
:--|:--
<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