Chapter 17. Interactive Voice Response
One day Alice came to a fork in the road and saw a Cheshire cat in a tree. “Which road do I take?” she asked.
“Where do you want to go?” was his response.
“I don’t know,” Alice answered.
“Then,” said the cat, “it doesn’t matter.”
In this chapter we will talk about IVR. If what you want is an automated attendant, we have written a chapter for that as well (Chapter 15, The Automated Attendant). The term IVR is often misused to refer to an automated attendant, but the two are very different things.[150]
What Is IVR?
The purpose of an Interactive Voice Response (IVR) system is to take input from a caller, perform an action based on that input (commonly, looking up data in an external system such as a database), and return a result to the caller.[151] Traditionally, IVR systems have been complex, expensive, and annoying to implement. Asterisk changes all that.
Components of an IVR
The most basic elements of an IVR are quite similar to those of an automated attendant, though the goal is different. We need at least one prompt to tell the caller what the IVR expects from him, a method of receiving input from the caller, logic to verify that the caller’s response is valid input, logic to determine what the next step of the IVR should be, and finally, a storage mechanism for the responses, if applicable. We might think of an IVR as a decision tree, although it need not have any branches. For example, a survey may present exactly the same set of prompts to each caller, regardless of what choices the callers make, and the only routing logic involved is whether the responses given are valid for the questions.
From the caller’s perspective, every IVR needs to start with a prompt. This initial prompt will tell the caller what the IVR is for and ask the caller to provide the first input. We discussed prompts in the automated attendant in Chapter 15, The Automated Attendant. Later, we’ll create a dialplan that will allow you to better manage multiple voice prompts.
The second component of an IVR is a method for
receiving input from the caller. Recall that in Chapter 15, The Automated Attendant we discussed the Background()
and WaitExten() applications for receiving a new
extension. While you could create an IVR using
Background() and WaitExten(), it is
generally easier and more practical to use the Read()
application, which handles both the prompt and the capture of the
response. The Read() application was designed specifically for use with IVR systems. Its
syntax is as follows:
Read(variable[,filename[&filename2...]][,maxdigits][,option][,attempts][,timeout])
The arguments are described in Table 17.1, “The Read() application”.
Table 17.1. The Read() application
Once the input is received, it must be validated.
If you do not validate the input, you are most likely going to find your
callers complaining of an unstable application. It is not enough to handle
the inputs you are expecting; you also need to handle inputs you do not
expect. For example, callers may get frustrated and dial
0 when in your IVR; if you’ve done a good job, you will
handle this gracefully and connect them to somebody who can help them, or
provide a useful alternative. A well-designed IVR (just like any program)
will try to anticipate every possible input and provide mechanisms to
gracefully handle that input.
Once the input is validated, you can submit it to an external resource for processing. This could be done via a database query, a submission to a URI, an AGI program, or many other things. This external application should produce a result, which you will want to relay back to the caller. This could be a detailed result, such as “Your account balance is…,” or a simple confirmation, such as “Your account has been updated.” We can’t think of any case where some sort of result returned to the caller is not required.
Sometimes the IVR may have multiple steps, and therefore a result might include a request for more information from the caller in order to move to the next step of the IVR application.
It is possible to design very complex IVR systems, with dozens or even hundreds of possible paths. We’ve said it before and we’ll say it again: people don’t like talking to your phone system, regardless of how clever it is. Keep your IVR simple for your callers, and they are much more likely to get some benefit from it.
IVR Design Considerations
When designing your own IVR, there are some important things to keep in mind. We’ve put together this list of some things to do, and things not to do in your IVR.
Do
Keep it simple.
Have an option to dial
0to reach a live person.Handle errors gracefully.
Don’t
Think that an IVR can completely replace people.
Use your IVR to show people how clever you are.
Try to replicate your website with an IVR.
Bother building an IVR if you can’t take numeric input. Nobody wants to have to spell her name on the dialpad of her phone.[152]
Force your callers to listen to advertising. Remember that they can hang up at any moment they wish.
Asterisk Modules for Building IVRs
The “front end” of the IVR (the parts that interact with the
callers) can be handled in the dialplan. In theory, it might be possible
to build an IVR system using the dialplan alone (perhaps with the
astdb to store and retrieve data). In practice, your
IVR is going to need to communicate with something external to
Asterisk.
CURL
The CURL() dialplan function in
Asterisk allows you to span entire web applications with a single line
of dialplan code. We’ll use it in our sample IVR later in this
chapter.
While you’ll find CURL()
itself to be quite simple to use, the creation of the web application
will require experience with web development.
func_odbc
Using func_odbc, it is possible to
develop extremely complex applications in Asterisk using nothing more
than dialplan code and database lookups. If you are not a strong
programmer but are very adept with Asterisk dialplans and databases,
you’ll love func_odbc just as much as we do. Check it
out in Chapter 16, Relational Database Integration.
AGI
The Asterisk Gateway Interface is such an important part of integrating external applications with Asterisk that we gave it its own chapter. You can find more information in Chapter 21, Asterisk Gateway Interface (AGI).
AMI
The Asterisk Manager Interface is a socket interface that you can use to get configuration and status information, request actions to be performed, and get notified about things happening to calls. We’ve written an entire chapter on AMI, as well. You can find more information in Chapter 20, Asterisk Manager Interface (AMI).
A Simple IVR Using CURL
The GNU/Linux program cURL is
useful for retrieving data from a URI. In Asterisk,
CURL() is a dialplan function.
We’re going to use CURL() as an
example of what an extremely simple IVR can look like. We’re going to
request our external IP address from the website http://www.whatismyip.org.
Important
In reality, most IVR applications are going to
be far more complex. Even most uses of CURL() will
tend to be complex, since a URI can return a massive and highly variable
amount of data, the vast majority of which will be incomprehensible to
Asterisk. The point being that an IVR is not just about the dialplan; it
is also very much about the external applications that are triggered by
the dialplan, which are doing the real work of the IVR.
Before you can use CURL(), you
have to ensure it is installed.
Installing the cURL Module
Installing cURL is easy. If it was not on your system when
you last compiled Asterisk, after installing it you’ll need to recompile
Asterisk so that it can locate the cURL dependencies and compile the
func_curl.so module.
$sudo yum -y install libcurl-devel
$sudo apt-get install libcurl4-openssl-dev
The Dialplan
The dialplan for our example IVR is very simple. The
CURL() function will retrieve our IP address from
http://www.whatismyip.org, and then
SayAlpha() will speak the results to the
caller:
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()
The simplicity of this is impossibly cool. In a traditional IVR system, this sort of thing could take days to program.
A Prompt-Recording Application
In Chapter 15, The Automated Attendant we created a simple bit of dialplan to record prompts. It was fairly limited in that it only recorded one filename, and thus for each prompt the file needed to be copied before a new prompt could be recorded. Here, we expand upon that to create a complete menu for recording prompts:
[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) ; We have a successful response, so reset our 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)
In this system, the name of the prompt is no longer descriptive, but rather it is a number. This means that you can record a far greater variety of prompts using the same mechanism, but the tradeoff is that your prompts will no longer have descriptive names.
Speech Recognition and Text-to-Speech
Although in most cases an IVR system presents prerecorded prompts to the caller and accepts input by way of the dialpad, it is also possible to: a) generate prompts artificially, popularly known as text-to-speech; and b) accept verbal inputs through a speech recognition engine.
While the concept of being able to have an intelligent conversation with a machine is something sci-fi authors have been promising us for many long years, the actual science of this remains complex and error-prone. Despite their amazing capabilities, computers are ill-suited to the task of appreciating the subtle nuances of human speech.
Having said that, it should be noted that over the last 50 years or so, amazing advances have been made in both text-to-speech and speech recognition. A well-designed system created for a very specific purpose can work very well indeed.
Despite what the marketing people will say, your computer still can’t talk to you, and you need to bear this in mind if you are contemplating any sort of system that combines your telephone system with these technologies.
Text-to-Speech
Text-to-speech (also known as speech synthesis) requires that a system be able to artificially construct speech from stored data. While it would be nice if we could simply assign a sound to a letter and have the computer produce each sound as it reads the letters, the written English language is not totally phonetic.
While on the surface, the idea of a speaking computer is very attractive, the reality is that it has limited usefulness. More information about integration of text-to-speech with Asterisk can be found in Chapter 18, External Services.
Speech Recognition
As soon as we’ve convinced computers to talk to us, we will naturally want to be able to talk to them.[153] Anyone who has tried to learn a foreign language can begin to recognize the complexity of teaching a computer to understand words; however, speech recognition also has to take into account the fact that before a computer can even attempt the task of understanding the words, it must first convert the audio into a digital format. This challenge is larger than one might at first think. For example, as humans we are naturally able to recognize speech as distinct from, say, the sound of a barking dog or a car horn. For a computer, this is a very complicated thing. Additionally, for a telephone-based speech recognition system, the audio that is received is always going to be of very low fidelity, and thus the computer will have that much less information to work with.[154]
Asterisk does not have speech recognition built in, but there are many third-party speech recognition packages that integrate with Asterisk.
Conclusion
Asterisk has become extremely popular as an IVR platform. While the media only really pays attention to Asterisk as a “free PBX,” the reality is that Asterisk is quietly taking the IVR industry by storm. Within any respectable-sized organization, it is very likely that the Linux system administrators are using Asterisk to solve telecom problems that previously were either unsolvable or impossibly expensive to solve. This is a stealthy revolution, but no less significant for its relative obscurity.
If you are in the IVR business, you need to get to know Asterisk.
[150] We suspect this is because “IVR” is much easier to say than “automated attendant.”
[151] In contrast to an auto attendant, the purpose of which is to route calls.
[152] Especially if it’s something like Van Meggelen.
[153] Actually, most of us talk to our computers, but this is seldom polite.
[154] If the speech recognition has to happen from a cell phone in a noisy conference hall, it becomes near-impossible.





View 2 comments



