Download

' This is sample IVR application written in "classic" Visual Basic. It speaks the current weather
' condition to a caller whose has identified the locality whose weather he wants by speaking
' the digits of its ZIP code.
'
' Please note that while the sample may not be considered short, that has to do with what the
' sample does and not the form of its user interface. To put that another way, the entirety of
' the voice user interface code is held in the short (3 dozen exectuable lines) subroutine named
' Answer() which is immediately below.

Sub Answer(kall As ComClientCall)

Dim i             As Integer
Dim Ok            As Boolean
Dim Zip           As String
Dim Rec           As ComRecognizer
Dim Syn           As ComSynthesizer
Dim conf          As Integer
Dim Done          As Boolean
Dim Char          As String
Dim Forecast      As String
Dim Properties(4) As String

' In this application we use 65% as a confidence threshold for recognition. You can use
' whatever makes sense in your application. A more robust application might have two
' thresholds. Confidence scores below the lower number might cause the application to
' prompt again, confidence scores above the higher number might cause the application to
' accept the recognition, and scores between the two numbers might require confirmation

Const ReqdConfidence As Integer = 6500

' Grammar IDs are arbitrary as we demonstrate with these oddball numbers

Const ZipGrammarId As Integer = 22
Const QuitGrammarId As Integer = 76

' Get an instance of the synthesizer and greet the caller

Set Syn = kall.getSynthesizer()
Syn.speak ("Welcome to the weather demonstration application. " + _
           "Say good bye or hang up when you are done.")

' Do some initialization while speaking

Properties(0) = "Digit1"
Properties(1) = "Digit2"
Properties(2) = "Digit3"
Properties(3) = "Digit4"
Properties(4) = "Digit5"

' Get an instance of the recognizer
' Load a grammar that handles the request for the ZIP code
' Load another that handles the request to quit the application
' Mark the grammars as active but not dynamic (modifiable)

Set Rec = kall.getRecognizer()
Ok = Rec.loadGrammar("ZIP", ZipGrammarId, True, False)
Ok = Rec.loadGrammar("Quit", QuitGrammarId, True, False)

' Wait for the speech to end now that the initialization is done

Syn.wait (-1)

Done = False

Do While (Not (kall.isDisconnected() Or Done))

 ' Start listening first and then prompt the caller

 Call Rec.listen
 Ok = Syn.speak("Please tell me the ZIP code for the town whose weather forecast you want to hear.")

 ' Wait for the recognizer to tell us how it did.
 ' We will wait at most 10 seconds for the user to begin to speak.
 ' In no case will we wait more than 30 seconds.

 conf = Rec.wait(10000, 30000)

 ' Stop listening

 Call Rec.stopListening

 ' Dump the state of the recognition for debugging

 Call Rec.dump

 ' On an error or disconnect we are done

 If conf < 0 Then
  Done = True
 
 ElseIf conf >= ReqdConfidence Then
  
  ' If we recognized a phrase in Quit grammar then we are done }

  If Rec.getGrammarId() = QuitGrammarId Then
   Done = True

  ' Otherwise we need a five digit ZIP code }

  Else
  
   Zip = ""

   For i = 0 To 4
    Zip = Zip + Rec.getPropertyTextByName(Properties(i))
   Next i

   If Len(Zip) <> 5 Then conf = 0
   
  End If
  
 End If
 
 ' Apologize if we didn't understand

 If Not Done And conf < ReqdConfidence Then
  Call NoRecognition(Rec, Syn)
 
 ' If all is well, we proceed

 ElseIf Not Done Then
 
  ' Tell the caller to wait

  Syn.speak ("Please wait ...")

  ' Amuse him with "music on hold"

  kall.loopMessage ("strumming")

  ' Get his forecast while he listens to music
    
  Forecast = DoRequest(kall, Zip)

  ' Stop playing music and put a delay between the music and the speech

  kall.stopPlaying
  kall.wait (500)

  ' Speak the forecast and display it for debugging

  Syn.speak (Forecast)
  kall.writeln (Forecast)

  ' Log the input and output to the call detail records table

  Ok = kall.cdrStatusMessage(0, Zip)
  Ok = kall.cdrStatusMessage(1, Forecast)

  ' Let him hear the forecast before we ask if he wants to go again
 
  Syn.wait (-1)
  
 End If
 
Loop

' If he is still on the line we will say good bye

If Not kall.isDisconnected() Then
 Syn.speak ("Good bye.")
 Syn.wait (-1)
End If

End Sub

Sub NoRecognition(Rec As ComRecognizer, Syn As ComSynthesizer)

  Call Rec.Reset
  Call Rec.listen

  Syn.speak ("I'm sorry, but I didn't get that.")
  Syn.wait (-1)

End Sub

' Access a web service to retrieve the weather

Function DoRequest(kall As ComClientCall, ZipCode As String) As String

 Dim QueryString As String
 Dim ObjXmlHttp As Object
 Dim ObjXmlDoc As Object
 
 ' Build a query string by appending a specific ZIP code to the base
 
 QueryString = "http://weather.yahooapis.com/forecastrss?p=" + ZipCode
                              
 ' We use the XML HTTP object to send the request and fetch the response
 
 Set ObjXmlHttp = CreateObject("Msxml2.XMLHTTP")
 ObjXmlHttp.open "GET", QueryString, False
 ObjXmlHttp.send
 
 ' Either apologize if we failed to get the forecast or
 ' or build an intelligible response if we succeeded
 
 If ObjXmlHttp.Status <> 200 Then
  DoRequest = "We are sorry but we had trouble determining the weather for your ZIP code. " + _
              "If the ZIP code is valid you can try again later."
  kall.writeln ("The weather service fails us: " + ObjXmlHttp.statusText + "(" + Str(ObjXmlHttp.Status) + " 

)")
  
 Else
   Set ObjXmlDoc = CreateObject("Msxml2.DomDocument.4.0")
   ObjXmlDoc.async = False
   ObjXmlDoc.loadXML (ObjXmlHttp.responseText)
   Call ObjXmlDoc.SetProperty("SelectionLanguage", "XPath")
   Call ObjXmlDoc.SetProperty("SelectionNamespaces", 

"xmlns:yweather='http://xml.weather.yahoo.com/ns/rss/1.0'")
 
  DoRequest = TranslateXMLtoForecast(ObjXmlDoc)
 End If

End Function

' Crack open the XML document

Function TranslateXMLtoForecast(XML As Object) As String

 Dim City As String
 Dim State As String
 Dim Outlook As String
 Dim Temperature As String
 
 ' For now we are interested in the city, wind speed and direction,
 ' current condition and temperature
 
 City = GetCity(XML)
 State = GetState(XML)
 Wind = GetWind(XML)
 Outlook = GetOutlook(XML)
 Temperature = GetTemperature(XML)
 
 ' Build two sentences from the five components above
 
 TranslateXMLtoForecast = "In " + City + " " + State + _
                         " the weather is " + Outlook + _
                         " with a temperature of " + Temperature + _
                         ". The winds are " + Wind + "."

End Function

' Pull the city information from the XML

Function GetCity(XML As Object) As String

 Dim Node As Object
 Dim Attr As Object
 
 Set Node = XML.selectSingleNode("//channel/yweather:location")
 Set Attr = Node.Attributes.getNamedItem("city")
 GetCity = Attr.Text
 
End Function

' Pull the state information from the XML

Function GetState(XML As Object)

 Dim Node As Object
 Dim Attr As Object
 
 Set Node = XML.selectSingleNode("//channel/yweather:location")
 Set Attr = Node.Attributes.getNamedItem("region")
 GetState = ExpandState(Attr.Text)
 
End Function

' Pull the wind information from the XML

Function GetWind(XML As Object)

 Dim Node As Object
 Dim Attr As Object
 Dim Speed As String
 Dim Degrees As String

 Set Node = XML.selectSingleNode("//channel/yweather:wind")
 Set Attr = Node.Attributes.getNamedItem("speed")
 Speed = Attr.Text
 
 Set Attr = Node.Attributes.getNamedItem("direction")
 Degrees = Attr.Text

 GetWind = "from the " + Direction(Degrees) + " at " + Speed + " miles per hour"
 
End Function

' Pull the forecast from the XML

Function GetOutlook(XML As Object)

 Dim Node As Object
 Dim Attr As Object

 Set Node = XML.selectSingleNode("//channel/item/yweather:condition")
 Set Attr = Node.Attributes.getNamedItem("text")
 GetOutlook = Attr.Text
  
End Function

' Pull the temperature information from the XML

Function GetTemperature(XML As Object)

 Dim Node As Object
 Dim Attr As Object
 
 Set Node = XML.selectSingleNode("//channel/item/yweather:condition")
 Set Attr = Node.Attributes.getNamedItem("temp")
 GetTemperature = Attr.Text + " degrees Fahrenheit"

End Function