Download

'******************************************************************************
' This is the weather by ZIP code demo in which the user enters the ZIP code 
' via the keypad and the HTTP GET transaction is performed asynchronously.
'******************************************************************************/
Imports System
Imports System.IO
Imports System.Net
Imports System.Xml
Imports System.Text
Imports System.Threading
Imports System.Reflection
Imports System.Collections

Imports IVRForBeginners

'******************************************************************************
' All .Net IVR applications are implemented as classes derived from our base
'******************************************************************************/
Public Class VbWeather
 Inherits NetClientCall

 Private Shared prompt As String
 Private Shared welcome As String
 Private Shared regrets As String
 Private Shared baseQuery As String
 Private Shared dirs As Hashtable
 Private Shared states As Hashtable

 Private zip As String
 Private weather As String
 Private iar As IAsyncResult
 Private req As HttpWebRequest
 Private resp As HttpWebResponse

 '******************************************************************************
 ' We set some constant variables 
 '******************************************************************************/
 Public Shared Shadows Function Initialize() As Boolean

  prompt = "Please enter a five digit ZIP code or press the pound key to quit."
  welcome = "Welcome to the weather demonstration application."
  regrets = "We are sorry but we had trouble determining the weather for that ZIP code. " + _
            "If the ZIP code is valid you can try again later."

  baseQuery = "http://weather.yahooapis.com/forecastrss?p="

  BuildStatesTable()

  Initialize = True

 End Function

 '******************************************************************************
 ' The required Answer() method always comprises the entire Voice User 
 ' Interface for an IVR application. 
 '******************************************************************************/
 Public Sub Answer()

  Dim i, millis As Integer
  Dim syn As Synthesizer
  Dim buffer As StringBuilder

  Try

   ' If the caller hangs up we want an exception

   hangupThrows(True)

   ' Get an instance of the synthesizer and greet the caller
   ' We should check for a null object which indicates failure

   syn = getSynthesizer()
   syn.speak(welcome)
   syn.wait()

   Do While (True)

    ' Tell the caller what we want ( 5 keystrokes )

    syn.speak(prompt)

    ' And wait for him to give it to us

    If Not inputWait(5, "#", 20000) Then Exit Do

    ' We have no patience if we got fewer

    If inputAvailable() < 5 Then Exit Do

    ' If we have the input tell the user to be patient

    syn.speak("Please wait")

    ' Build a ZIP code from the key presses

    buffer = New StringBuilder
    For i = 1 To 5
     buffer.Append(getChar())
    Next i
    zip = buffer.ToString()

    ' Make an asynchronous request of the web service 

    RequestWeather()

    Do While Not iar.IsCompleted

     ' Amuse the user with "music on hold" while we wait

     millis = playMessage("strumming")

     ' Wait for the request to complete, the music to stop,
     ' or for the user to hang up. When the music stops we
     ' just play it again but we could count the iterations
     ' of the loop to enforce a time out.

     wait(iar.AsyncWaitHandle, millis)
    Loop

    ' When the request completes we fetch the data and build the forecast

    CompleteRequest()

    ' That done we kill the music, add a bit of silence 
    ' and then deliver the forecast to the caller 

    stopPlaying()
    wait(500)
    syn.speak(weather)

    ' While speaking we add an entry to the call detail records

    cdrStatusMessage(0, zip)
    cdrStatusMessage(1, weather)

    ' Then we wait for the forecast to be completely spoken

    syn.wait()
   Loop

   ' Be polite and say good bye before we hang up

   syn.speak("Good bye.")
   syn.wait()

  ' If the caller hangs up we will cancel the web service request

  Catch e1 As NetClientCallTermination
   CancelRequest()
   Console.WriteLine(e1.Message)

  ' Shouldn't happen, but you never know

  Catch e2 As System.Exception
   CancelRequest()
   Console.WriteLine(e2.Message)

  End Try

 End Sub

 '******************************************************************************
 ' We use this hash table to translate state abbreviations we get from the web
 ' service to more easily pronounceable stuff.
 '******************************************************************************/
 Private Shared Sub BuildStatesTable()

  states = New Hashtable

  states.Add("AL", "Alabama")
  states.Add("AK", "Alaska")
  states.Add("AZ", "Arizona")
  states.Add("AR", "Arkansas")
  states.Add("CA", "California")
  states.Add("CO", "Colorado")
  states.Add("CT", "Connecticut")
  states.Add("DE", "Delaware")
  states.Add("DC", "D C")
  states.Add("FL", "Florida")
  states.Add("GA", "Georgia")
  states.Add("HI", "Hawaii")
  states.Add("ID", "Idaho")
  states.Add("IL", "Illinois")
  states.Add("IN", "Indiana")
  states.Add("IA", "Iowa")
  states.Add("KS", "Kansas")
  states.Add("KY", "Kentucky")
  states.Add("LA", "Louisiana")
  states.Add("ME", "Maine")
  states.Add("MD", "Maryland")
  states.Add("MA", "Massachusetts")
  states.Add("MI", "Michigan")
  states.Add("MN", "Minnesota")
  states.Add("MS", "Mississippi")
  states.Add("MO", "Missouri")
  states.Add("MT", "Montana")
  states.Add("NE", "Nebraska")
  states.Add("NV", "Nevada")
  states.Add("NH", "New Hampshire")
  states.Add("NJ", "New Jersey")
  states.Add("NM", "New Mexico")
  states.Add("NY", "New York")
  states.Add("NC", "North Carolina")
  states.Add("ND", "North Dakota")
  states.Add("OH", "Ohio")
  states.Add("OK", "Oklahoma")
  states.Add("OR", "Oregon")
  states.Add("PA", "Pennsylvania")
  states.Add("PR", "Puerto Rico")
  states.Add("RI", "Rhode Island")
  states.Add("SC", "South Carolina")
  states.Add("SD", "South Dakota")
  states.Add("TN", "Tennessee")
  states.Add("TX", "Texas")
  states.Add("UT", "Utah")
  states.Add("VT", "Vermont")
  states.Add("VA", "Virginia")
  states.Add("WA", "Washington")
  states.Add("WV", "West Virginia")
  states.Add("WI", "Wisconsin")
  states.Add("WY", "Wyoming")

 End Sub

 '******************************************************************************
 ' Pulls the city and state from the XML document
 '******************************************************************************/
 Private Function GetCity(ByVal doc As XmlDocument, ByVal mgr As XmlNamespaceManager) As String

  Dim city, temp1, temp2 As String
  Dim node As XmlNode

  ' The city and the state reside in the same node ...

  node = doc.SelectSingleNode("//channel/yweather:location", mgr)

  ' ... as distinct attributes 

  temp1 = node.Attributes.GetNamedItem("city").InnerText
  temp2 = node.Attributes.GetNamedItem("region").InnerText

  ' Expand the state abbreviation if we know it ...

  If states.Contains(temp2) Then
   GetCity = temp1 + " " + states.Item(temp2)

  ' ... or take it as is if we don't

  Else
   GetCity = temp1 + " " + temp2

  End If

 End Function

 '******************************************************************************
 ' Pulls the temperature from the XML document
 '******************************************************************************/
 Private Function GetTemperature(ByVal doc As XmlDocument, ByVal mgr As XmlNamespaceManager) As String

  Dim temp As String
  Dim node As XmlNode

  node = doc.SelectSingleNode("//channel/item/yweather:condition", mgr)
  temp = node.Attributes.GetNamedItem("temp").InnerText
  GetTemperature = temp + " degrees Fahrenheit"

 End Function

 '******************************************************************************
 ' Pulls the current condition from the XML document
 '******************************************************************************/
 Private Function GetOutlook(ByVal doc As XmlDocument, ByVal mgr As XmlNamespaceManager) As String

  Dim node As XmlNode

  node = doc.SelectSingleNode("//channel/item/yweather:condition", mgr)
  GetOutlook = node.Attributes.GetNamedItem("text").InnerText

 End Function

 '******************************************************************************
 ' Pulls the wind speed and direction from the XML document
 '******************************************************************************/
 Private Function GetWind(ByVal doc As XmlDocument, ByVal mgr As XmlNamespaceManager) As String

  Dim degrees As Integer
  Dim wind, temp1, temp2 As String
  Dim node As XmlNode

  node = doc.SelectSingleNode("//channel/yweather:wind", mgr)
  temp1 = node.Attributes.GetNamedItem("direction").InnerText
  temp2 = node.Attributes.GetNamedItem("speed").InnerText

  degrees = Val(temp1)
  GetWind = "from the " + Direction(degrees) + " at " + temp2 + " miles per hour"

 End Function

 Function Direction(ByVal num As Integer) As String

  If num <= 11 Then
   Direction = "north"

  ElseIf num <= 33 Then
   Direction = "north northeast"

  ElseIf num <= 56 Then
   Direction = "northeast"

  ElseIf num <= 78 Then
   Direction = "east northeast"

  ElseIf num <= 101 Then
   Direction = "east"

  ElseIf num <= 123 Then
   Direction = "east southeast"

  ElseIf num <= 146 Then
   Direction = "southeast"

  ElseIf num <= 168 Then
   Direction = "south southeast"

  ElseIf num <= 191 Then
   Direction = "south"

  ElseIf num <= 213 Then
   Direction = "south southwest"

  ElseIf num <= 236 Then
   Direction = "southwest"

  ElseIf num <= 258 Then
   Direction = "west southwest"

  ElseIf num <= 281 Then
   Direction = "west"

  ElseIf num <= 303 Then
   Direction = "west northwest"

  ElseIf num <= 326 Then
   Direction = "northwest"

  ElseIf num <= 348 Then
   Direction = "north northwest"

  Else
   Direction = "north"

End If

End Function

 '******************************************************************************
 ' If the user hangs up we use this function to cancel the outstanding web 
 ' service(request)
 '******************************************************************************/
 Private Sub CancelRequest()

  Try

   If Not req Is Nothing Then
    req.Abort()
    CompleteRequest()
   End If

  Catch e As System.Exception
   Console.WriteLine(e.Message)
  End Try

 End Sub

 '******************************************************************************
 ' When the asynchronous HTTP transation completes we fetch the results
 '******************************************************************************/
 Private Sub CompleteRequest()

  Dim isOpen As Boolean
  Dim city, outlook, temp, wind As String
  Dim doc As XmlDocument
  Dim msg As StringBuilder
  Dim mgr As XmlNamespaceManager

  doc = Nothing
  resp = Nothing
  isOpen = False
  weather = Nothing

  Try

   resp = req.EndGetResponse(iar)
   isOpen = True

   ' The response from the web service is XML so load it into a document

   doc = New XmlDocument
   doc.Load(resp.GetResponseStream())

   ' Get a namespace manager and add the namespace

   mgr = New XmlNamespaceManager(doc.NameTable)
   mgr.AddNamespace("yweather", "http://xml.weather.yahoo.com/ns/rss/1.0")

   ' Then pull the city, temperature, current condition and wind speed from it

   city = GetCity(doc, mgr)
   temp = GetTemperature(doc, mgr)
   outlook = GetOutlook(doc, mgr)
   wind = GetWind(doc, mgr)

   ' We take those bits of information to build a two sentence forecast

   msg = New StringBuilder
   msg.Append("In ")
   msg.Append(city)
   msg.Append(", the weather is ")
   msg.Append(outlook)
   msg.Append(" with a temperature of ")
   msg.Append(temp)
   msg.Append(". The winds are ")
   msg.Append(wind)
   msg.Append(".")

   weather = msg.ToString()

  Catch e As InvalidOperationException
   isOpen = False

  Catch e As System.Exception
   Console.WriteLine(e.Message)

  ' Make sure we close the connection when we are done

  Finally
   If (isOpen) Then resp.Close()
  End Try

  ' If we failed to build a forecast we'll offer an apology instead

  If weather = Nothing Then weather = regrets

  End Sub

 '******************************************************************************
 ' Starts an asynchronous HTTP GET transaction
 '******************************************************************************/
 Private Sub RequestWeather()

  req = WebRequest.Create(baseQuery + zip)
  iar = req.BeginGetResponse(Nothing, Nothing)

 End Sub

End Class