## 預測式外呼
>[info] **功能說明**
> 預測式外呼是一種基于數據分析和機器學習的外呼方式,它通過預測客戶接通電話的概率和坐席的空閑狀態,自動發起外呼,并將接通的電話自動分配給座席,以提高工作效率。
> 2:這種外呼方式可以有效地過濾無效號碼,避免座席撥打無效號碼的浪費時間。
* **名詞解釋**
* 隊列:預測式外呼中所使用的隊列是“fifo隊列”,是一個“生產者一一消費者”的模式,即來話或去話相當于生產者,而座席則相當于消費者,它對來話進行服務即相當于“消費”生產者生產的內容。fifo是先入先出模式,即最先進入隊列的客戶電話,最先被座席接聽,也就相當于生活中的排隊模式。
* offhook座席:座席的SIP電話,呼入到隊列并等待(隊列會給座席放等候音樂),座席一直不掛機,當客戶應答后客戶電話轉入到隊列,隊列會自動把客戶電話(生產者)平均分配給已經在隊列中等待的座席(消費者),座席這種接聽電話的方式就叫:offhook座席。“offhook座席”在繁忙的通話場景中能更迅速地為客戶提供更快速的服務。
* 簽入:座席(消費者角色)進入隊列,在"offhook座席"場景中,"offhook座席"呼入到隊列就是簽入。
* 簽出:已經進入隊列的座席(消費者角色)出隊列,在"offhook座席"場景中,"offhook座席"掛機是簽出。
* 排隊時長:客戶電話在隊列中等待座席接聽的時長(預測式外呼需要盡量減少該時長,越小越好)。
* 通話時長:客戶與座席的通話時長,不包含在隊列中排隊的時長。
* **工作流程**
1. 業務系統調用軟交換的API,給客戶撥打電話;
2. 軟交換開始呼叫客戶;
3. 客戶接聽電話后,軟交換將接聽的通話轉入到fifo隊列;
4. 隊列將電話轉給簽入并且空閑的座席。
如圖所示:

* **后端接口**
**獲取隊列狀態接口:**
預測式外呼最重要的工作是需要知道隊列中有多少簽入并且空閑的座席,后端獲取隊列狀態有兩種方式:
1:主動查詢軟交換;
2:通過前端傳會的事件(座席簽入,簽出,和客戶通話橋接,和客戶通話斷開)。
主動查詢軟交換獲取隊列狀態API請求地址:
```
{base_url}pbxapi/{api_version}/fifoCount
```
* **請求參數**
| 參數 | 是否必選 | 類型 | 描述 |
| --- | --- | --- | --- |
| fifoName | 否 | string | 隊列名稱,如果不傳或值為空則表示查詢所有隊列 |
* **響應參數**
| 參數 | 類型 | 描述 |
| --- | --- | --- |
| status | string | 請求結果:success:成功,failed:失敗。|
| data | array | 隊列當前實時狀態。 |
| data. fifo_name | string | 隊列名稱 |
| data. consumer_count | int | 簽入座席的合計數量(即消費者),空閑與通話的都算 |
| data.waiting_caller | int | 正在排隊的客戶數量,已經與座席通話的不算 |
| data. idle_consumer | int | 空閑的座席數量 |
| msg | string | 如果返回failed,對失敗原因的描述。|
* **響應示例**
```
{
"status": "success",
"data": [{
"fifo_name": "6501",
"consumer_count": "1",
"waiting_caller": "0",
"idle_consumer": "1"
}, {
"fifo_name": "6500",
"consumer_count": "0",
"waiting_caller": "0",
"idle_consumer": "0"
}],
"msg": "查詢成功"
}
```
提交外呼數據接口:
```
{base_url}pbxapi/{api_version}/predictive
```
* **請求參數**
| 參數 | 是否必選 | 類型 | 描述 |
| --- | --- | --- | --- |
| fifoName | 是 | string | 隊列名稱 |
| callto | 是 | string | 被叫號碼,即客戶的電話號碼 ,如果是多個電話號碼,使用逗號分隔 |
| trunkName | 否 | string | 中繼名稱,如果服務器上接入了多個運營商的中繼,可以選擇使用哪個運營商的中繼線路撥打電話。 |
| trunkNumber | 否 | string | 出局號碼,即透傳號碼,但該功能必須運營商支持透傳號碼才能生效。 |
| callPrefix | 否 | string | 外呼前綴,如果運營商要求號碼加前綴,則需要提交該數據。 |
| customerId | 否 | string | 客戶編號,與點擊外呼相同 |
| UID | 否 | string | 與點擊外呼相同 |
| relationID | 否 | string | 與點擊外呼相同 |
| callbackData | 否 | string | json字符串格式,本次通話的客戶數據,如客戶ID,案件ID等等,在通話完畢回調時會原樣回調,與點擊外呼相同。 |
| callbackDomain | 否 | string | 回調地址,與點擊外呼相同 |
* **響應參數**
| 參數 | 類型 | 描述 |
| --- | --- | --- |
| status | string | 請求結果:success:成功,failed:失敗。|
| msg | string | 如果返回failed,對失敗原因的描述。 |
* **響應示例**
```
{
"status": "success",
"msg": "預測外呼數據提交成功"
}
```
* **前端接口**
前端使用webrtc,此處僅描述與點擊外呼webrtc不同的地方(會提供預測外呼的webrtc的demo)
1:增加全局變量
在js中增加全局變量window.session,如:

在通話建立時,給window.session復制,如:

在通話結束后,將window.session設置為:undefined,如:

這樣做的目的是,座席可以對當前通話的session進行操作,如發送dtmf等,以下會用到。
1:簽入
簽入其實就是使用webrtc撥打隊列號碼,但是注意,需要加前綴:fifo-,如隊列名詞是:6500,那么webtrc撥打的號碼就是:fifo-6500,隊列名稱需要從后端獲取。
~~~
$('#btn_call').click(function() {
var telnum = 'fifo-6500';//隊列號碼,從后端獲取
var session = phone.call(telnum);
});
~~~
簽入與點擊外呼基本相同,只是簽入每次呼的號碼都是固定的。
2:簽出
簽出其實就是掛機,與點擊外呼掛機一樣
3:掛斷客戶電話
如果客戶主動掛機,則座席無需操作,如果客戶不掛機,座席則可以向服務器發送dtmf的方式掛斷本次通話,掛斷或座席還在隊列,沒有簽出。
~~~
$('#btn_dtmf').click(function() {
if (window.session) {
window.session.sendDTMF('*');//發送dtmf給服務器,服務器掛斷電話
}
});
~~~
* **前端事件**
當有事件產生,服務器會給前端webrtc發送事件,事件有:
| 序號 | 事件名稱 | 描述 |
| --- | --- | --- |
| 1| consumer_start | 座席簽入|
| 2 | consumer_stop | 座席簽出|
| 3| bridge-caller-start | 座席開始與客戶通話|
| 3 | bridge-caller-stop | 座席與客戶通話斷開|
前端上的狀態或計時,都可以根據以上事件開發。
**座席簽入事件格式:**
```
{
"action": "consumer_start",
"sipNumber": "90000002",
"fifoName": "6501"
}
```
**座席簽出事件格式:**
```
{
"action": "consumer_stop",
"sipNumber": "90000002",
"fifoName": "6501"
}
```
**座席開始與客戶通話事件格式:**
```
{
"action": "bridge-caller-start",
"trunkName": "GSM",
"fifoName": "6500",
"callfrom": "90000002",
"callto": "18600118300",
"trunkNumber": "18600647467",
"customerId": "111",
"UID": "222",
"relationID": "444",
"type": "predictive"
}
```
**座席與客戶通話斷開事件格式:**
```
{
"action": "bridge-caller-stop",
"trunkName": "GSM",
"fifoName": "6500",
"callfrom": "90000002",
"callto": "18600118300",
"trunkNumber": "18600647467",
"customerId": "111",
"UID": "222",
"relationID": "444",
"type": "predictive"
}
```