Asterisk權威指南/第十七章 交互式語音應答(IVR)

維基教科書,自由的教學讀本

在這一章中,我們將討論交互式語音應答(IVR)。如果你想了解自動接待,我們也為此寫了一個章節(第15章)。IVR一詞常被誤用來指代自動接待,但它們兩是完全不同的東西。

什麼是IVR[編輯]

交互式語音應答系統的意義是獲取呼叫者的輸入,並基於這個輸入執行動作(一般是在外部系統如一個資料庫中查找數據),然後返回結果給呼叫者。IVR系統在過去是複雜、昂貴的,實施起來很麻煩。Asterisk改變了這一切。

Asterisk模糊了傳統PBX和IVR系統的邊界。Asterisk撥號計劃的強大和靈活使得系統中幾乎每一個分機都可以視為傳統意義上的IVR。

IVR的內容[編輯]

IVR最基礎的元素和自動接待很相似,但目的是不同的。我們需要最少一個提示告訴呼叫者IVR希望他輸入的東西,一個從呼叫者處接受輸入的技術,邏輯驗證輸入值的回覆是否是有效輸入,邏輯確認IVR下一步幹嘛,最後,如果合適,還包括一個對於回應的存儲機制。我們可能會把IVR想成一個決策樹,儘管它不需要任何分支。例如,不管呼叫者做出什麼選擇,信息反饋可以向每個呼叫者呈現完全相同的提示集,並且所涉及的唯一路由邏輯是所給出的響應是否對於問題有效。

從呼叫者的角度來看,每個IVR需要從提示開始。這個初始提示將告訴呼叫者IVR是什麼,並要求呼叫者提供第一個輸入。 我們在第15章中討論了自動接待的提示。之後,我們將會創建一個撥號方案,讓你更好地管理多個語音提示。

第二個內容是IVR是一種用於從呼叫者接收輸入的方法。回想一下,在第15章中我們討論了用於接收新extension的Background()和WaitExten()應用程式。雖然你可以用Background()和WaitExten()創建IVR,但使用Read()應用程式通常更容易也更實用,該應用程式可以處理提示和捕獲相應。Read()應用程式專門設計用於IVR系統。 其語法如下:

Read(variable[,filename[&filename2...]][,maxdigits][,option][,attempts][,timeout])

參數在表17-1中列出:

Argument Purpose
variable

變量

存儲呼叫者的響應的變量。 最好的做法是給IVR中的每個變量賦予與該變量相關的提示類似的名稱。 這將有助於以後如果出於商業原因或易用性你需要重新排列IVR的步驟。 命名你的變量var1,var2等,在短期內可能看起來很容易,但是在你的生命周期中,它會使修復錯誤更加困難。
prompt

提示

為呼叫者播放的文件(或文件列表,用&字符連接在一起),用於請求輸入。文件名末尾省略格式擴展名。
maxdi gits

最大位數

允許輸入的最大字符數。 在面臨是/否問題和多項選擇時,最佳做法是將此值限制為1。如果長度較長,呼叫方可以通過按#鍵來終止輸入。
options

選項

s (skip)跳過

如果信道未回復立即退出

i (indication)指示

播放某種提示音(如撥號音)而不是播放提示

n (no answer)沒有回答

從呼叫者方讀取數字,即使線路尚未應答。

attempts嘗試

播放提示的次數。如果呼叫者沒有輸入任何內容,則Read()應用程式自動重新提示用戶。 默認是一次嘗試。

timeout超時

呼叫者輸入他的輸入的秒數。Asterisk中的默認值為10秒,可以使用此選項對單個提示進行更改,也可以使用dialplan函數TIMEOUT(response)為整個會話分配值。

收到輸入後,必須進行驗證。 如果你不驗證輸入,你很有可能發現呼叫者抱怨不穩定的應用程式。處理你預期的輸入是不夠的; 你還需要處理你預期之外的輸入。例如,呼叫者可能在IVR中會遇到困難並撥打0,在你的IVR中撥打0;你應該要很好地處理這個問題,讓他們連接到可以幫助他們的人,或提供一個有用的替代方法。精心設計的IVR(就像任何程序一樣)將嘗試預測每一個可能的輸入,並提供機制來適當處理該輸入。

輸入通過驗證後,你可以將其提交給外部資源進行處理。可以通過資料庫查詢,URI提交,AGI程序或其他的多種方式來完成。這個外部應用程式會產生一個結果,你要將它返回給呼叫者。它可能會是一個詳細的結果,例如「你的帳戶餘額是...」或簡單的確認,例如「你的帳戶已更新」。我們想不到現實世界中會存在呼叫者不需要返回的結果的情況。

有時IVR可能有多個步驟,因此結果可能包括來自呼叫者的請求更多信息,以便轉到IVR應用的下一步。

設計非常複雜的具有數十甚至數百個可能路徑的IVR系統也是可行的。我們在前面說過,我們還會再說一遍:人們不喜歡和你的手機系統通話,不管它是多麼聰明。讓你的IVR對呼叫者而言是簡單的,他們更有可能從中獲益。

一個絕贊的IVR

人們愛用的IVR的一個典例就是很多比薩送貨服務使用的IVR:當你打電話訂購時,IVR會查找你的呼叫ID,並說「如果你希望與上次完全一樣的訂單, 請按1。」

這就是它所做的所有工作,完美。

顯然,這些公司可以設計出大量複雜的IVR,讓你可以選擇每一個細節(「選擇放七粒穀物的麵包皮,請按7」),但是有多少醉酒的飢餓客戶能在早晨3點成功地應對導航?

最好的IVR是需要呼叫者輸入最少的IVR。 按下1,你的披薩就在路上!

IVR設計注意事項[編輯]

當設計你自己的IVR時,需要牢記一些重要事項。我們把這些在你的IVR中要做和不要做的事情列在一起。

  • 保持簡單
  • 有一個撥號選項可以連接到人工服務
  • 很好地處理錯誤

不要做

  • 認為IVR可以完全取代人類
  • 用你的IVR向人們展示你有多聰明
  • 嘗試用IVR複製你的網站。
  • 如果你不能輸入數字的話不要搭建IVR。沒有人想要在電話撥號面板上拼寫自己的名字
  • 強迫你的呼叫者聽廣告。記住,只要他們想,隨時都可以掛電話。

用於搭建IVR的Asterisk模塊[編輯]

可以在撥號計劃中處理IVR的「前端」(與呼叫者交互的部分)。僅僅使用撥號計劃來構建IVR系統(可能用astdb存儲和檢索數據)是可行的;然而,你通常需要與Asterisk外部的內容(IVR的「後端」)進行通信。

CURL[編輯]

Asterisk中的CURL()撥號計劃功能允許你使用單行撥號計劃代碼涵蓋整個Web應用程式。我們將在本章後面的示例IVR中使用它。雖然你會發現CURL()本身使用起來非常簡單,但Web應用程式的創建需要Web開發經驗。

func_odbc[編輯]

使用func_odbc,僅僅使用撥號計劃代碼和資料庫查找功能,在Asterisk中開發一個極其複雜的應用程式也是可行的。 如果你不是一個強大的程式設計師,但是非常擅長Asterisk的撥號計劃和資料庫,那麼你會喜歡func_odbc,就像我們一樣。 具體請看第16章。

AGI[編輯]

Asterisk網關接口是將外部應用與Asterisk集成在一起的重要組成部分,我們給它單獨分出一個章節。你可以在第21章找到更多信息。

AMI[編輯]

Asterisk Manager接口是一個套接字接口,你可以使用它來獲取配置和狀態信息,請求執行操作,並通知呼叫發生的事件。關於AMI我們也寫了一整個章節。 你可以在第20章找到更多信息。

使用CURL實現的一個簡單的IVR[編輯]

GNU / Linux程序cURL對於從URI檢索數據很有用。在Asterisk中,CURL()是一個撥號計劃功能。

接下來我們用CURL()實現一個非常簡單的IVR例子。我們將從http://www.whatismyip.org请求我们的外部IP地址。

實際上,大多數IVR應用將會變得更加複雜。 包括CURL()的大多數使用也會變得複雜,因為URI可以返回一個巨大而可變的數據量,而絕大多數數據對於Asterisk來說是無法理解的。重點在於IVR不僅僅是撥號計劃;它也非常關注由撥號計劃觸發的外部應用程式,它們正在進行IVR的真正工作。

在使用CURL()之前,必須確保它成功安裝。

安裝cURL模塊

安裝cURL很簡單。 當你上次編譯完Asterisk後它不在系統上,安裝cURL完畢後你需要重新編譯Asterisk,讓它找到cURL依賴項並編譯func_curl.so模塊。

在 RHEL:

$ sudo yum -y install libcurl-devel

在Ubuntu:

$ sudo apt-get install libcurl4-openssl-dev

撥號計劃

我們的示例IVR的撥號計劃非常簡單。CURL()函數將從http://www.whatismyip.org检索我们的IP地址,然后SayAlpha()将向呼叫者说出结果:

exten => *764,1,Verbose(2, Run CURL to get IP address from whatismyip.org)

same => n,Answer() same => n,Set(MyIPAddressIs=${CURL(http://www.whatismyip.org/)})

same => n,SayAlpha(${MyIPAddressIs})

same => n,Hangup()

這樣的簡單是不可思議的。在傳統的IVR系統中,這種事情可能需要幾天的時間才能完成。

一個記錄提示的應用[編輯]

在第15章中,我們創建了一個簡單的撥號計劃來記錄提示。這是相當有限的,因為它只記錄了一個文件名,因此需要複製每一個提示文件才能記錄新的提示。在這裡,我們擴展了它以創建一個完整的記錄提示的菜單:

[prompts]

exten => s,1,Answer

exten => s,n,Set(step1count=0) ; Initialize counters

; If we get no response after 3 times, we stop asking

same => n(beginning),GotoIf($[${step1count} > 2]?end)

same => n,Read(which,prompt-instructions,3)

same => n,Set(step1count=$[${step1count} + 1])

; All prompts must be 3 digits in length

same => n,GotoIf($[${LEN(${which})} != 3]?beginning)

same => n,Set(step1count=0) ; Successful response; reset counters

same => n,Set(step2count=0)

same => n(step2),Set(step2count=$[${step2count} + 1])

same => n,GotoIf($[${step2count} > 2]?beginning) ; No response after 3 tries

; If the file doesn't exist, then don't ask whether to play it

same => n,GotoIf($[${STAT(f,${which}.wav)} = 0]?recordonly)

same => n,Background(prompt-tolisten)

same => n(recordonly),Background(prompt-torecord)

same => n,WaitExten(10) ; Wait 10 seconds for a response

same => n,Goto(step2)

exten => 1,1,Set(step2count=0)

same => n,Background(${which})

same => n,Goto(s,step2)

exten => 2,1,Set(step2count=0)

same => n,Playback(prompt-waitforbeep)

same => n,Record(${CHANNEL(uniqueid)}.wav)

same => n(listen),Playback(${CHANNEL(uniqueid)})

same => n,Set(step3count=0)

same => n,Read(saveornot,prompt-1tolisten-2tosave-3todiscard,1)

same => n,GotoIf($["${saveornot}" = "1"]?listen)

same => n,GotoIf($["${saveornot}" = "2"]?saveit)

same => n,System(rm -f /var/lib/asterisk/sounds/${CHANNEL(uniqueid)}.wav)

same => n,Goto(s,beginning)

same => n(saveit),System(mv -f ${CHANNEL(uniqueid)}.wav ${which}.wav)

same => n,Playback(prompt-saved)

same => n,Goto(s,beginning)

在此系統中,提示符的名稱不再是描述性的;相反,它是一個數字。這意味著你可以使用相同的機制記錄更多種類的提示,但是取捨是你的提示將不再具有描述性名稱。

語音識別和文字轉語音[編輯]

雖然在大多數情況下,IVR系統向呼叫者提供預先記錄的提示並通過撥號面板接受輸入,但也可以:a)人為地生成提示,通常被稱為文本到語音;b)通過語音識別引擎接受口頭輸入。

雖然能夠與機器進行智能對話的概念是科學家們長期以來對我們的承諾,但實際的科學依然是複雜和錯誤的。儘管電腦具有驚人的功能,但電腦不適合欣賞人類言語微妙的細微差別。

話雖如此,應該指出的是,在過去的50年中,文字和言語表達方面都取得了驚人的進展。為一個非常具體的目的而精心設計的系統可以很好地工作。

不管市場營銷人員怎麼說,你的電腦仍然無法與你交談,如果你正在考慮將你的電話系統與這些技術相結合的任何系統,你需要牢記這一點。

文字轉語音[編輯]

文本到語音(也稱為語音合成)要求系統能夠用存儲的數據人為地構建語音。雖然如果我們簡單地給字母分配聲音,並讓計算機在讀取字母時產生每個聲音這個想法很吸引人,但英文語言並不完全是注音的。

表面上,關於電腦的想法是非常有吸引力的,實際上它的實用性有限。有關文本到語音與Asterisk的集成的更多信息,請參見第18章。

語音識別[編輯]

一旦我們使電腦能與我們交談,我們自然就想要和他們進行交談。任何嘗試學習外語的人都可以認識到教授電腦來認識語言的複雜性;而且,語音識別要考慮到,在計算機可以理解這些單詞之前,必須先將音頻轉換為數字格式。這個挑戰比起設想的還要大。例如,作為人類,我們自然能夠認識到與狗叫或汽車喇叭的聲音不同的語言。對於電腦來說,這是一件非常複雜的事情。此外,對於基於電話的語音識別系統,接收到的音頻總是具有非常低的保真度,因此計算機工作時將獲得更少的信息來進行處理。

Asterisk沒有內置語音識別,但是有許多第三方語音識別軟體包與Asterisk集成。其中大部分內容超出了本書的範圍,因為這些應用程式在Asterisk外部。

總結[編輯]

Asterisk作為IVR平台已經非常受歡迎。這本書在許多方面都是教你應用於IVR開發的技術。雖然主流媒體只注重Asterisk作為「免費PBX」,但實際情況是,Asterisk正在悄悄地掀起一場IVR行業風暴。在很多具有一定規模的組織中,Linux系統管理員都可能是使用Asterisk來解決以前無法解決或難以解決的電話問題的。這是一場隱秘的革命,但相對於它的無名卻不甚重要。

如果你使用IVR業務,你需要了解Asterisk。