第５回 キューを実装して完成！ - TwilioとRailsでミニマムコールセンターを作ろう

`別サイトで2014/4/30に投稿した記事です。別サイト閉鎖につき、移転しました。情報が古い可能性があるので、ご注意ください。`

## やること
前回で見た目はミニマムコールセンターが完成したように見えますが、指定されたエージェント（Agent1とAgent2）がログインしていないと、お客さんの電話に応答できません。

ではどうすればいいのでしょうか。

解決策はキューです。キューは、コールセンターにとって作業グループのようなものです。キューを作っておくと、エージェントがログインしていなくても、そのキューにコールをためておけます。エージェントが電話に応答可能になり、キューに接続すると、キューに溜まっていたお客さんの電話が着信します。

今回は、エージェントが接続するキューを実装します。これでミニマムコールセンターは完成です！

## 流れ

* 2名のエージェントが「カスタマーサービス」と「受注」のキューにそれぞれ接続する
* 顧客がコールセンターに電話をする
* 「お問い合わせの場合は１、注文の場合は２を押してください」というアナウンスが流れて、
* １を選ぶと、「カスタマーサービス」キューに接続しているエージェントに着信し、２（1以外）を選ぶと、「受注」キューのエージェントに着信する
* 顧客が用件を済ませて、電話を切る

## Ruby on Railsで実装してみよう
### 前回のプロジェクトに追加していく
前回使ったプロジェクトに機能追加していきましょう。
今回から始めたい方は、 [https://github.com/fuji3zpg/twilio-collect-digit](https://github.com/fuji3zpg/twilio-collect-digit) のリポジトリをダウンロードしてください。

    git clone git@github.com:fuji3zpg/twilio-collect-digit.git
    cd twilio-agent-browser/
    rails server

[http://localhost:3000/call/client](http://localhost:3000/call/client)で前回までの状態になるはずです。

＊ただし、まだTwilioアカウントを取得していなかったり、環境変数が設定されていないと動きません。
その場合は、[第4回](/article/twilio_rails_callcenter_4)以前の手順に沿って、やってみてください。

### 環境変数を追加

電話発信用に環境変数を1つ追加します。

    export TWILIO_DEMO_APP_SID_QUEUE=xxx

.bash_profile 辺りに上記の環境変数を設定しておくと便利です。

設定後、

    source ~/.bash_profile

コマンドを実行して、追加した環境変数を有効にするのをお忘れなく。

### エージェントのブラウザをキュー対応に

call_controller.rbのclientメソッドに、

    capability.allow_client_outgoing ENV['TWILIO_DEMO_APP_SID_QUEUE']

を追加して、電話発信できるようにします。この値は、[TwiML APPS](https://jp.twilio.com/user/account/apps/)として作ったアプリのSIDを設定します。

```
def client
  # パラメータ"client"でクライアント名を設定する。未設定の場合は、デフォルトのエージェント名を使用する
  @client_name = params[:client]

  if @client_name.nil?
    @client_name = default_client
  end

  # 以下、エージェント用クライアントが使える機能を設定する
  account_sid = ENV['TWILIO_SID']
  auth_token = ENV['TWILIO_TOKEN']

  capability = Twilio::Util::Capability.new account_sid, auth_token
  capability.allow_client_incoming @client_name # 電話応答機能を有効に
  capability.allow_client_outgoing ENV['TWILIO_DEMO_APP_SID_QUEUE'] # 電話発信機能を使うために必要。TwiML APPSとして作ったアプリのSIDを設定する。
  @token = capability.generate # エージェント用クライアントに設定するトークン
end
```

ブラウザ側も設定しましょう。views/call/client.html.erbにキューを指定する欄とキューに接続するボタンを設置します。

```
<button class="call" onclick="queue();">キューに接続</button>

<input type="text" id="queue" nume="queue" placeholder="キュー名： 例）Customer Support" />
```

「キューに接続」ボタンを押した時に呼び出されるJavaScriptも追加します。

```
function queue() {
  params = {"Queue": $("#queue").val()};
  console.log("#queue: " + $("#queue").val());
  Twilio.Device.connect(params);
}
```

### エージェントがキューに接続するためのTwiMLを追加する

#### エージェントがキューに接続するために
エージェントが指定したキューに接続するために、call_controller.rbに「queue」メソッドを追加します。

```
def queue
  response = Twilio::TwiML::Response.new do |r|
    queue_name = params[:Queue] || default_queue
    r.Say "#{queue_name}のキューに接続しました。", voice: 'woman', language: 'ja-JP'

    r.Dial do |d|
      d.Queue queue_name
    end
  end

  render xml: response.text
end
```
#### ルーティングの設定
config/routes.rb に「queue」メソッドのルーティングを設定します。

```
post "call/queue"
```

CSRFエラーを防ぐために、protect_from_forgeryメソッドに「queue」を追加します。

```
class CallController < ApplicationController
  # collect_digit・receiveメソッドなどへのCSRFチェックをオフにする。collect_digitメソッドにPOSTメソッドを送る時に、オフにしておかないとエラーが発生する。
  protect_from_forgery except: [:voice, :collect_digit, :receive, :queue]
```

    curl -X POST http://localhost:3000/call/queue -d "Queue=カスタマーサービス"

を実行して、動作確認してみましょう。

### 顧客の電話をキューで扱えるようにTwiMLを追加する

#### キューに顧客のコールを入れるTwiMLを作成
call_controller.rbに「enqueue」メソッドを追加します。

```
def enqueue
  response = Twilio::TwiML::Response.new do |r|
    params[:Digits] == "1" ? queue_name = "カスタマーサービス" : queue_name = default_queue

    r.Say "コールが#{queue_name}キューにはいりました。", voice: 'woman', language: 'ja-JP'
    r.Enqueue queue_name
  end

  render xml: response.text
end
```

#### ルーティングの設定
config/routes.rb に「enqueue」メソッドのルーティングを設定します。

```
post "call/enqueue"
```

CSRFエラーを防ぐために、protect_from_forgeryメソッドに「enqueue」を追加します。

```
class CallController < ApplicationController
  # collect_digit・receiveメソッドなどへのCSRFチェックをオフにする。collect_digitメソッドにPOSTメソッドを送る時に、オフにしておかないとエラーが発生する。
  protect_from_forgery except: [:voice, :collect_digit, :receive, :queue, :enqueue]
```

curl -X POST http://localhost:3000/call/enqueue -d ""

を実行して、動作確認してみましょう。


### 顧客の入力を得たら、「enqueue」メソッドを呼び出す

collect_digitメソッドの「Redirect」先をenqueueメソッドに設定します。
これで、顧客の入力が終わったら、「enqueue」メソッドを呼び出して、担当エージェントにつなぐことができます。

```
def collect_digit
  base_url = request.protocol + request.host_with_port

  response = Twilio::TwiML::Response.new do |r|
    # 1桁の数字を取得し（numDigits）、actionのTwiMLに渡す。タイムアウトは10秒。
    r.Gather(action: call_enqueue_path, numDigits: 1, timeout: 10) do
      r.Say('お問い合わせの場合は１、注文の場合は２を押してください', voice: 'woman', language: 'ja-JP')
    end

    # タイムアウト時の処理
    r.Say('何も入力されませんでした', voice: 'woman', language: 'ja-JP')
    r.Redirect base_url + "/call/enqueue"
  end

  render xml: response.text
end
```

### Twilioの管理画面で設定

#### インターネットからアクセス
作成したRailsプロジェクトをインターネットのサーバにアップしてください。
Twilioからそのプロジェクトにアクセスします。

#### TWIMLアプリの設定
ブラウザでTwilioを使うために、[TWIML APPS](https://jp.twilio.com/user/account/apps)を作成し、このSIDを使っています。
作成したTWIMLアプリの詳細画面を開いて、音声通話のRequest URLに" http://example.com/call/queue "に「POST」メソッドでアクセスするように設定します。

#### Twilioで取得した電話番号で設定
[取得した電話番号の一覧ページ](https://jp.twilio.com/user/account/phone-numbers/incoming)を開いて、詳細画面に進みます。
音声通話のRequest URLに" http://example.com/call/collect_digit "、"POST"メソッドでアクセスするように設定します。

### 通しで動作確認
設定がすべて完了したので、最後に通しで動作確認をしてみましょう！

手順は以下の通りです。

* Agent1が「 http://example.com/call/client?client=Agent1 」にアクセスして、キュー名に「カスタマーサービス」を設定。「キューに接続」ボタンを押す
* Agent2が「 http://example.com/call/client?client=Agent2 」にアクセスして、キュー名に「受注」を設定。「キューに接続」ボタンを押す
* 顧客がTwilioの電話番号に電話する
* 「お問い合わせの場合は１、注文の場合は２を押してください」というアナウンスが流れる
* 顧客が１を選ぶと、「カスタマーサービス」キューに接続している「Agent1」に着信する
* 顧客とAgent1が通話できていることを確認して、顧客が電話を切る

＊顧客が２（1以外）を選ぶと、「受注」キューのAgent2に着信するケースも確認しましょう。

## まとめ

長くなりましたが、ついにミニマムコールセンターが完成しました！

動作確認のところでは書きませんでしたが、キューにどのエージェントも接続していない状態で、顧客が電話するとどうなるのでしょうか？そうです。キューに待っている間、音楽が流れます。そして、エージェントがキューに接続すると、そのエージェントにつながります。日常生活でも、こういった経験があると思います。

実際のコールセンターは、スクリーンポップアップ・転送・3者通話・コール統計・通話録音など、いろいろな機能が要求されます。この連載を基礎にして、それぞれ必要な機能を学習していただけたら幸いです。

お疲れ様でした！

（完）

## サンプルコードのダウンロード
上記のサンプルコードは、Githubよりダウンロードできます。

[https://github.com/fuji3zpg/twilio-queue](https://github.com/fuji3zpg/twilio-queue)

## 参考資料
[TwiMLTM 音声通話 : Queue](https://jp.twilio.com/docs/api/twiml/queue)
[TwiMLTM 音声通話 : Enqueue](https://jp.twilio.com/docs/api/twiml/enqueue)

## 関連するページ
* [第4回 用件選択アナウンスを流し、顧客入力番号を取得](http://qiita.com/fuji3zpg/items/a5250bdea5f2af6ac278)