TwilioのFunctionsを使ったサーバーレス受付電話システム

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

# Functions概要
2017/5/25 サンフランシスコで開催されたTwilioのイベント「SIGNAL 2017」で、Twilioのサーバーレスアーキテクチャー「Functions」が発表されました。
http://www.twilio.com/functions
![functions.jpg](https://qiita-image-store.s3.amazonaws.com/0/86046/aec4e24c-d459-7b39-3487-af7790e01a80.jpeg)


### Functionsとは
Functionsは、AWSのlambdaのように、Node（JavaScript）で書かれたプログラムをTwilioのサーバー上で実行することができるプラットフォームです。現在はパブリックベータなので、Twilioアカウントを持っていれば誰でも使えます。
また、Functionsと併せて、画像や音源データなどのコンテンツを保管するためのAssetsも発表されました。

### 料金
FunctionsとAssetsはともに、毎月10,000アクセスまでは無料で利用できます。10,000を超える場合は、１アクセスあたり、$0.0001（日本円では0.015円）が必要です。

# 何を作るか
今回は、同じくSIGNAL2017で発表された、Gatherの音声認識を使った受付電話システムを、Functionsを用いてサーバーレスで作成します。
具体的には、050の番号に着信すると担当者の名前を音声で受け付けて、該当する担当者の電話にリダイレクトさせます。

## 準備するもの

### Twilioアカウント
担当者に架電するためにTwilioのアカウントを取得してください。トライアルアカウントでは認証済み電話番号にしか架電ができないため、アップグレードされたアカウントが必要です。

### Twilio電話番号
着信用と発信用に少なくとも１つの050番号、もしくは0800番号を用意してください。
着信用と発信用は同じ番号でも、異なる番号でも構いません。

### 転送先電話番号
担当者につなぐため、各担当者の電話番号（固定電話でも可能）が必要です。担当者の数に制限はありませんが、同じ名前の担当者には対応していません。

# ハンズオン
以下の手順で作業を行います。
1. ソースコードのダウンロード
2. ソースコードを編集
3. Twilio管理コンソールでFunctionsを作成
4. Twilio管理コンソールで変数を設定
5. 着信用の電話番号を設定
6. テスト

### 1. ソースコードのダウンロード
以下のURLからサンプルプログラムのソースをダウンロードしてください。

```lang:github
$ git clone https://github.com/twilioforkwc/functionsSample.git
```

Gitが使えない場合は、以下のURLからZIPファイルとしてダウンロードも可能です。
https://github.com/twilioforkwc/functionsSample/archive/master.zip

### 2. ソースコードを編集
ダウンロードが成功すると、以下の4つのファイルが作成されます。
- README.md - 説明ファイル
- calling.js - 050番号に着信した時に実行されるプログラム
- redirect.js - Gatherの結果を処理するプログラム
- employee.js - 担当者のデータを管理するプログラム

コードを変更する必要があるのは、employee.jsのみです。
employee.jsをエディタで開き、担当者情報の部分を皆さんの環境に併せて修正してください。

```lang:employee.js（変更部分のみ抜粋）
const employeeList = {
  "高橋": "+81XXXXXXXXXX",
  "齋藤,斉藤,齊藤,斎藤": "+81XXXXXXXXXX",
  "青木": "+81XXXXXXXXXX",
  "伊藤,伊東": "+81XXXXXXXXXX",
  "金古,金子": "+81XXXXXXXXXX",
};
```

- 各行の先頭部分（Key部分）に担当者名を指定します。音声認識により、「斉藤」のような同じ読み方で別の漢字がある場合は、どの漢字に変換されるかがわからないため、なるべくすべての漢字をカンマで区切って記載してください。
- 各行の後半部分（Value部分）にはその担当者の電話番号をE.164形式で記載します。
- 行の制限はありませんが、同じ名前の人が複数いる場合には対応していません。

### 3. Twilio管理コンソールでFunctionsを作成

#### Calling

1. Twilioの管理コンソールにログインし、左側のスライドメニューからDeveloper Toolsの中のRuntimeのページを開きます。
2. 左のメニューからFunctionsを選択します。
3. 赤いプラスアイコンを押して、Functionsを新規作成します。
4. New Functionダイアログが開きますので、「Blank」を選択し、Createボタンを押します。
5. FUNCTION NAME欄に、「Calling」と入力します。
6. PATHの欄に、「/calling」と入力します。
7. ACCESS CONTROLのチェックを付けます。
8. EVENTは「Incoming Voice Calls」にします。
9. CODEの欄に、現在かかれている内容をすべて消去し、先程コーディングしたcalling.jsの内容をそのまま貼り付けます。
10. Saveボタンを押して登録します。

![スクリーンショット 2017-05-31 17.16.57.png](https://qiita-image-store.s3.amazonaws.com/0/86046/1ae85d4f-d8a1-7437-a015-1687a9c0f50f.png)

#### Redirect

1. 左側のメニューのRuntime - Functions - Manageを選択します。
2. 赤いプラスアイコンを押して、Functionsを新規作成します。
3. New Functionダイアログが開きますので、「Blank」を選択し、Createボタンを押します。
4. FUNCTION NAME欄に、「Redirect」と入力します。
5. PATHの欄に、「/redirect」と入力します。
6. ACCESS CONTROLのチェックを付けます。
7. EVENTは「Incoming Voice Calls」にします。
8. CODEの欄に、現在かかれている内容をすべて消去し、先程コーディングしたredirect.jsの内容をそのまま貼り付けます。
9. Saveボタンを押して登録します。

![スクリーンショット 2017-05-31 17.21.26.png](https://qiita-image-store.s3.amazonaws.com/0/86046/b1d768ce-b597-dd3d-570e-682045bf7e76.png)

#### Employee

1. 左側のメニューのRuntime - Functions - Manageを選択します。
2. 赤いプラスアイコンを押して、Functionsを新規作成します。
3. New Functionダイアログが開きますので、「Blank」を選択し、Createボタンを押します。
4. FUNCTION NAME欄に、「Employee」と入力します。
5. PATHの欄に、「/employee」と入力します。
6. **ACCESS CONTROLのチェックは外します。**
7. **EVENTは「Select...」にします。**
8. CODEの欄に、現在かかれている内容をすべて消去し、先程コーディングしたredirect.jsの内容をそのまま貼り付けます。
9. Saveボタンを押して登録します。

![FunctionsEmployee.png](https://qiita-image-store.s3.amazonaws.com/0/86046/1c85f61e-92e0-f37d-4470-f256daa91fc7.png)

### 4. Twilio管理コンソールで変数を設定

1. 左側のメニューのRuntime - Overview を選択します。
2. YOUR DOMAINにかかれているドメイン名をメモ帳にコピーしておきます。
3. 左側のメニューのRuntime - Functions - Configure を選択します。
4. 以下の２項目のEnvironmental Variablesを追加します。

| KEY       | VALUE |
|:---------:|:-------------------:|
| CALLER_ID | Twilioで購入した発信用電話番号（E.164形式） |
| DOMAIN    | 先程控えておいたドメイン名にhttps://を付与したもの |

### 5. 着信用の電話番号を設定

1. Twilio管理コンソールのボタンアイコンを押して、「電話番号」を選択します。
2. 準備した電話番号がリストに表示されることを確認し、その番号をクリックします。
3. フレンドリーネームに、「受付電話」と入力します（任意）。
4. ACCEPT INCOMINGが「Voice Calls」になっていることを確認します。
5. CONFIGURE WITHは、「Webhooks, or TwiML BIns or Functions」を選択します。
6. A CALL COMES INを、「Functions」に切り替え、リストから「Calling」を選択します。
7. 「保存」ボタンを押して、設定を保存します。

![Functions着信番号設定.png](https://qiita-image-store.s3.amazonaws.com/0/86046/a884bb5d-4264-e25e-6e8a-0bafc89081b4.png)

### 6. テスト

ここまで完了したら、最後にテストを行います。
着信用の050番号もしくは0800番号に電話を掛けます。「お繋ぎする担当者の名前を教えてください。」とアナウンスが流れるので、担当者名を発声します。「○○さんをお願いします」というようなフレーズでも大丈夫です。
しばらくすると、「○○にお繋ぎします。このまましばらくお待ち下さい」とアナウンスが流れ、担当者に電話がかかります。
担当者が取ることで、電話がつながります。

# 解説

calling.jsでは、050番号に着信した際のTwiMLを生成するコードが書かれています。この中でポイントになるのが、Gather動詞のinputパラメータです。今回音声認識をさせるために、inputパラメータに「speech」を設定しています。これによって、本来はDTMF（プッシュ信号）を受け付けるGatherが音声を受け付けるようになります。
音声を受け付ける場合のポイントとして、Timeoutパラメータがあります。これは、音声が切れてから何秒で音声認識に入るかを決めるためのものです。短すぎると話の途中で先に進んでしまう可能性がありますし、長すぎると次の処理までの間が空いてしまいます。最適な値は「2（秒）」です。

redirect.jsは、Gather動詞の飛び先になります。DTMFで受け付けた場合は、Digitsパラメータに押されたボタンの数字が入りますが、音声認識の場合はSpeechResultっていうパラメータに音声認識の結果が入ります。音声認識エンジンはGoogleが使われていますので、日本語もかなり正確に認識します。今回はさらに認識精度を上げるために、Gather動詞にHintsパラメータも指定しています。Hintsに指定した単語は認識されやすくなりますので、固有名詞などはなるべくHintsを使うとよいでしょう。

Functionsに関しては、AWSのlamｂdaとは違い、オリジナルのライブラリが使えません。ただ、幾つかのライブラリだけは利用できるようになっており、今回はその中のgotを使って担当者情報の取得などを行っています。
https://www.npmjs.com/package/got
gotライブラリは簡易なhttpライブラリで、外部のサーバーからコンテンツを取得するときなどに使えます。もちろん、Functionsで作成したプログラムを呼び出すこともできるので、今回は担当者情報だけを別のプログラム（Employee.js）に抜き出しています。
どのようなライブラリが用意されているかを知りたければ、以下のブログに目を通しておくことをおすすめします。
https://support.twilio.com/hc/en-us/articles/115007737928-building-apps-with-twilio-functions

また、Functionsでは環境変数のように、変数を外部で定義しておいて、それを読み込むことができます。今回はドメイン名と発信者番号を変数で定義しています。

# まとめ

Functionsは、AWSのlambdaに比べるとまだ機能もすくなく、ローカルでコーディングしたコードをAPI経由でデプロイすることができません。
ただ、今までは静的なTwiML Binsくらいしか利用できなかったサーバーレスの機能に、プログラムを記述することができるようになったことは大きな前進といえるでしょう。