;LumenVox -- Speech Understood ; ;Copyright (C) 2006, LumenVox, LLC ; ;Support ; ;See http://www.LumenVox.com for more information about ;our speech techology products. This is provided as only ;a working example of a speech-enabled IVR application ;using the integration of the LumenVox Speech ;Engine with Asterisk. For more information on Asterisk ;visit http://asterisk.org. ; ;This Dial Plan is provided as a free example. No warranties ;are expressed or implied. ; ;This macro will perform confirmation on recognitions ;if the confidence score falls below the THRESHOLD value. [macro-speech-confirm] exten => s,1,SpeechActivateGrammar(yes_no) exten => s,2,Set(TEMPSPEECH_TEXT=${TEXT}) exten => s,3,Set(CONFARG=$[Confirm${ARG1}]) exten => s,4,SpeechBackground(${CONFARG}) exten => s,5,SpeechStart exten => s,6,Noop exten => s,7,Set(CONFIRM=${SPEECH_TEXT(0)}) exten => s,8,GotoIf($["${SPEECH_TEXT(0)}" = "yes"]?9:10) exten => s,9,Set(CONFIRM=yes) exten => s,10,Set(TEXT=${TEMPSPEECH_TEXT}) exten => s,11,SpeechDeactivateGrammar(yes_no) ;This is the entry point for the pizza demo IVR [order-pizza] exten => s,1,Playback(GP-Greeting) ;The THRESHOLD is a value compared to the ;SPEECH_SCORE(x), which is the confidence score ;returned by the Speech Engine. exten => s,2,Set(THRESHOLD=500) exten => s,3,Goto(pizza-delivery,s,1) ;This context will get whether the caller ;requests delivery or takeout [pizza-delivery] exten => s,1,SpeechActivateGrammar(order) exten => s,2,SpeechStart exten => s,3,SpeechBackground(GP-DeliveryorTakeout) ;If there are no results (no input) then we re-prompt them. exten => s,4,GotoIf($["${SPEECH(results)}" = "0"]?5:7) exten => s,5,Playback(GP-NoDeliveryorTake-out) exten => s,6,Goto(2) exten => s,7,Set(TEXT=${SPEECH_TEXT(0)}) ;If the confidence score is below the threshold then we confirm the intent ;of the spoken phrase. exten => s,8,Gotoif($[ "${SPEECH_SCORE(0)}" > "${THRESHOLD}" ]?12:9) exten => s,9,Macro(speech-confirm,${SPEECH_TEXT(0)}) exten => s,10,GotoIf($["${CONFIRM}" = "no"]?3:11) exten => s,11,Noop(speech_score=${SPEECH_SCORE(0)}) ;If the intent has been confirmed then the type of order is fixed exten => s,12,Set(TYPE_OF_ORDER=${TEXT}) exten => s,13,SpeechDeactivateGrammar(order) exten => s,14,Noop exten => s,15,GotoIf($["${ARSO}" = "1"]?16:17) exten => s,16,Goto(confirm-order,s,1) exten => s,17,Goto(pizza-size,s,1) ;Now that we have the delivery option we want to know ;what size pizza they want. Each context will continue to ;check for caller input and confidence scores. [pizza-size] exten => s,1,SpeechActivateGrammar(size) exten => s,2,SpeechStart exten => s,3,SpeechBackground(GP-Size) exten => s,4,GotoIf($["{SPEECH(results)}" = "0"]?5:7) exten => s,5,Playback(GP-NI) exten => s,6,Goto(2) exten => s,7,Set(TEXT=${SPEECH_TEXT(0)}) exten => s,8,GotoIf($[ "${SPEECH_SCORE(0)}" > "${THRESHOLD}" ]?11:9) exten => s,9,Macro(speech-confirm,${SPEECH_TEXT(0)}) exten => s,10,GotoIf($["${CONFIRM}" = "no"]?3:11) exten => s,11,Set(SIZE=${TEXT}) exten => s,12,SpeechDeactivateGrammar(size) exten => s,13,GotoIf($["${ARSO}" = "1"]?14:15) exten => s,14,Goto(confirm-order,s,1) exten => s,15,Goto(pizza-crust,s,1) ;After we know what size pizza callers want, it is time ;for them to decide which crust style they want. [pizza-crust] exten => s,1,SpeechActivateGrammar(crust) exten => s,2,SpeechStart exten => s,3,SpeechBackground(GP-Crust) exten => s,4,GotoIf($["${SPEECH(results)}" = "0"]?5:7) exten => s,5,Playback(GP-NI) exten => s,6,Goto(2) exten => s,7,Set(TEXT=${SPEECH_TEXT(0)}) exten => s,8,GotoIf($[ "${SPEECH_SCORE(0)}" > "${THRESHOLD}" ]?11:9) exten => s,9,Macro(speech-confirm,${SPEECH_TEXT(0)}) exten => s,10,GotoIf($["${CONFIRM}" = "no"]?3:11) exten => s,11,Set(CRUST=${TEXT}) exten => s,12,SpeechDeactivateGrammar(crust) exten => s,13,GotoIf($["${ARSO}" = "1"]?14:15) exten => s,14,Goto(confirm-order,s,1) exten => s,15,Goto(speciality-or-custom,s,1) ;Here we present callers with the option to select ;from one of the speciality pizzas or pick their own ;toppings. See what happens when you try to change ;the toppings once a specialty pizza has been chosen. [speciality-or-custom] exten => s,1,SpeechActivateGrammar(specialityorcustom) exten => s,2,SpeechStart exten => s,3,SpeechBackground(GP-SpecialtyorCustom) exten => s,4,GotoIf($["${SPEECH(results)}" = "0"]?5:7) exten => s,5,Playback(GP-NI) exten => s,6,Goto(2) exten => s,7,Set(TEXT=${SPEECH_TEXT(0)}) exten => s,8,GotoIf($[ "${SPEECH_SCORE(0)}" > "${THRESHOLD}" ]?11:9) exten => s,9,Macro(speech-confirm,${SPEECH_TEXT(0)}) exten => s,10,GotoIf($["${CONFIRM}" = "no"]?3:11) exten => s,11,SpeechDeactivateGrammar(specialityorcustom) exten => s,12,Set(SORC=${TEXT}) exten => s,13,GotoIf($["${SPEECH_TEXT(0)}" = "Speciality"]?14:15) exten => s,14,Goto(select-speciality,s,1) exten => s,15,Goto(select-toppings,s,1) exten => s,16,Noop ;If callers want one of the speciality pizzas, ;here is their oportunity to choose one. [select-speciality] exten => s,1,SpeechActivateGrammar(speciality) exten => s,2,SpeechStart exten => s,3,SpeechBackground(GP-SpecialtyList) exten => s,4,GotoIf($["${SPEECH(results)}" = "0"]?5:7) exten => s,5,Playback(GP-NI) exten => s,6,Goto(2) exten => s,7,Set(TEXT=${SPEECH_TEXT(0)}) exten => s,8,GotoIf($[ "${SPEECH_SCORE(0)}" > "${THRESHOLD}" ]?11:9) exten => s,9,Macro(speech-confirm,${SPEECH_TEXT(0)}) exten => s,10,GotoIf($["${CONFIRM}" = "no"]?3:11) exten => s,11,Set(TOPPING=${TEXT}) exten => s,12,Noop exten => s,13,SpeechDeactivateGrammar(speciality) exten => s,14,Goto(confirm-order,s,1) ;If callers want to customise their own pizza ;here is their chance. [select-toppings] exten => s,1,SpeechActivateGrammar(pizza) exten => s,2,SpeechStart exten => s,3,SpeechBackground(GP-Toppings) exten => s,4,GotoIf($["${SPEECH(results)}" = "0"]?5:7) exten => s,5,Playback(GP-NI) exten => s,6,Goto(2) exten => s,7,Set(TEXT=${SPEECH_TEXT(0)}) exten => s,8,Gotoif($[ "${SPEECH_SCORE(0)}" > "${THRESHOLD}" ]?9:6) exten => s,9,Set(TOPPING=${TEXT}) exten => s,10,SpeechDeactivateGrammar(pizza) ;Since the Dial Plan cannot handle the complex object in the XML ;format returned by the pizza grammar it needs to be converted into ;a string that the Dial Plan can easily pass around. exten => s,11,AGI(xml-to-string.agi, ${TOPPING}) exten => s,12,Goto(confirm-order,s,1) ;When the choice of toppings has been made we need ;to confirm the order. You can see that a series ;of prompts are played back based on what the caller ;has selected. [confirm-order] exten => s,1,SpeechActivateGrammar(yes_no) exten => s,2,SpeechStart exten => s,3,Playback(GP-You_ordered_a) exten => s,4,Playback(${SIZE}) exten => s,5,Playback(${CRUST}) ;If the caller selected a specialty pizza then the ;name of that pizza is played back. exten => s,6,GotoIf($["${SORC}"="Speciality"]?7:10) exten => s,7,Playback(${TOPPING}) exten => s,8,Playback(pizza) exten => s,9,Goto(13) exten => s,10,Playback(pizza) exten => s,11,Playback(GP-With) ;If callers select their own toppings then ;the say_ingredients AGI Perl script will play those ;ingredients back. exten => s,12,AGI(say_ingredients.agi, ${TOPPING}) exten => s,13,Noop(${TOPPING}) ;Now we ask if this is what callers wanted, giving ;them an opportunity to make changes to their order. exten => s,14,SpeechBackground(GP-WasThisRight) exten => s,15,GotoIf($["${SPEECH(results)}" = "0"]?16:18) exten => s,16,Playback(GP-NI) exten => s,17,Goto(2) exten => s,18,GotoIf($["${SPEECH_TEXT(0)}" = "no"]?19:22) exten => s,19,SpeechDeactivateGrammar(yes_no) exten => s,20,Set(SPEECH(results)=0) exten => s,21,Goto(arso,s,1) exten => s,22,Goto(complete-order,s,1) ;ARSO (Add Remove or Start Over): we want to see where in ;the order process callers want to make changes. Add a topping, remove a topping, change the size, crust, or just start over. [arso] exten => s,1,SpeechActivateGrammar(arso) exten => s,2,SpeechStart exten => s,3,Playback(GP-Wanted=No) exten => s,4,SpeechBackground(GP-ARSO) exten => s,5,GotoIf($["${SPEECH(results)}" = "0"]?6:8) exten => s,6,Playback(GP-NI) exten => s,7,Goto(4) exten => s,8,GotoIf($["${SPEECH_TEXT(0)}" = "delivery"]?9:11) exten => s,9,Set(ARSO=1) exten => s,10,Goto(pizza-delivery,s,1) exten => s,11,GotoIf($["${SPEECH_TEXT(0)}" = "size"]?12:14) exten => s,12,Set(ARSO=1) exten => s,13,Goto(pizza-size,s,1) exten => s,14,GotoIf($["${SPEECH_TEXT(0)}" = "crust"]?15:17) exten => s,15,Set(ARSO=1) exten => s,16,Goto(pizza-crust,s,1) exten => s,17,GotoIf($["${SPEECH_TEXT(0)}" = "startover"]?18:20) exten => s,18,Set(ARSO=0) exten => s,19,Goto(order-pizza,s,1) exten => s,20,GotoIf($["${SPEECH_TEXT(0)}" = "add_topping"]?21:23) exten => s,21,Set(ARSO=1) exten => s,22,Goto(add_topping,s,1) exten => s,23,GotoIf($["${SPEECH_TEXT(0)}" = "rem_topping"]?24:4) exten => s,24,Set(ARSO=1) exten => s,25,Goto(remove_topping,s,1) ;This context will get any new topping(s) from the caller [add_topping] exten => s,1,SpeechActivateGrammar(pizza) exten => s,2,SpeechStart exten => s,3,GotoIf($["${SORC}"="Speciality"]?4:6) exten => s,4,Playback(GP-ChangeSpec) exten => s,5,Goto(speciality-or-custom,s,1) exten => s,6,SpeechBackground(GP-Adding) exten => s,7,GotoIf($["${SPEECH(results)}" = "0"]?9:11) exten => s,8,Playback(GP-NI) exten => s,9,Goto(2) exten => s,10,Gotoif($[ "${SPEECH_SCORE(0)}" > "${THRESHOLD}" ]?11:9) exten => s,11,Set(NEWTOPPING=${SPEECH_TEXT(0)}) exten => s,12,SpeechDeactivateGrammar(pizza) ;After getting the topping(s) it is converted to a string, then ;appended to the existing string of topping(s), and then the order ;is reconfirmed. exten => s,13,AGI(xml-to-string-newtopping.agi, ${NEWTOPPING}) exten => s,14,AGI(add_topping.agi, ${TOPPING},${NEWTOPPING}) exten => s,15,Goto(confirm-order,s,1) ;This will capture the topping(s) to be removed from the pizza. [remove_topping] exten => s,1,SpeechActivateGrammar(pizza) exten => s,2,SpeechStart exten => s,3,GotoIf($["${SORC}"="Speciality"]?4:6) exten => s,4,Playback(GP-ChangeSpec) exten => s,5,Goto(speciality-or-custom,s,1) exten => s,6,SpeechBackground(GP-Remove) exten => s,7,GotoIf($["${SPEECH(results)}" = "0"]?9:11) exten => s,8,Playback(GP-NI) exten => s,9,Goto(2) exten => s,10,Gotoif($[ "${SPEECH_SCORE(0)}" > "${THRESHOLD}" ]?11:9) exten => s,11,Set(NEWTOPPING=${SPEECH_TEXT(0)}) exten => s,12,SpeechDeactivateGrammar(pizza) ;After getting the topping(s) it is converted to a string, then ;appended to the existing string of topping(s), and then the order ;is reconfirmed. exten => s,13,AGI(xml-to-string-newtopping.agi, ${NEWTOPPING}) exten => s,14,AGI(remove_topping.agi, ${TOPPING},${NEWTOPPING}) exten => s,15,Goto(confirm-order,s,1) ;Finally, when the order is confirmed we tell the caller how to ;expect receipt of the pizza. We perform some clean-up on the ;speech object and the call by the SpeechDestroy and Hangup ;command lines. [complete-order] exten => s,1,Playback(${TYPE_OF_ORDER}) exten => s,2,SpeechDestroy/ exten => s,3,Wait(1) exten => s,4,Hangup [custom-pizza] exten => s,1,Answer exten => s,2,Wait(1) exten => s,3,SpeechCreate exten => s,4,Goto(order-pizza,s,1)