Download

require 'net/http'
require 'rexml/document'

BEGIN {

  $server = 'weather.yahooapis.com'

  $query  = '/forecastrss?p='

  $welcome = 'Welcome to the weather demonstration application.'

  $prompt = 'Please enter a five digit ZIP code or press the pound key to quit.'

  $regrets = '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.'

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


#-------------------------------------------------------------------------------------- 
# The voice user interface is here - Ask the caller for a 5 digit ZIP code
#-------------------------------------------------------------------------------------- 
def Answer(kall)

   # Get an instance of the synthesizer and greet the caller

   syn = kall.getSynthesizer()
   syn.speak($welcome)
   syn.wait(-1)

   # Repeat indefinitely

   while true

     # Ask the user for a ZIP code

     syn.speak($prompt)
     syn.wait(-1)

     # Wait for 5 keystrokes or a terminator but not more than 20 seconds

     ok = kall.inputWait1(5, '#', 20000)

     # If the time out elapses or the caller hangs up we are done

     break if !ok

     # We have no patience if he gave us less than 5 digits

     break if kall.inputAvailable() < 5

     # Build a string from the key strokes

     zip = '     '
     for i in 0..4
       zip[i] = kall.getChar()
     end 

    # If there is a terminator in there we are done

    break if zip.index('#')

    # Tell the caller to wait

    syn.speak('Please wait ...')

    # Amuse him with "music on hold"

    kall.loopMessage('strumming')

    # Get his forecast
    
    forecast = DoRequest(zip)

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

    kall.stopPlaying()
    kall.wait(500)

    # Speak the forecast

     syn.speak(forecast)
     puts forecast

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

     kall.cdrStatusMessage(0, zip)
     kall.cdrStatusMessage(1, forecast)

     # Let him hear the forecast before we ask if he wants to go again

     syn.wait(-1)
 
  end

    # Ta-ta for now

    if !kall.isDisconnected()
      syn.speak('Good bye.')
      syn.wait(-1)
    end

end

#-------------------------------------------------------------------------------------- 
# Request the weather from the web service
#-------------------------------------------------------------------------------------- 
def DoRequest(zip)

  conx         = Net::HTTP.new($server, 80)
  resp, data = conx.get($query + zip, nil)

  if resp.code != '200'
   forecast = $regrets
   puts 'The web service fails us: ' + resp.message + ' (' + resp.code + ')'
  else  
   forecast = ParseXML(data)
  end

  return forecast

end

#-------------------------------------------------------------------------------------- 
# Parse the XML document returned
#-------------------------------------------------------------------------------------- 
def ParseXML(xml)
 
  begin

    doc  = REXML::Document.new(xml)

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

    forecast = 'In ' + city + ' the weather is ' + outlook + 
               ' with a temperature of ' + temp + 
               '. The winds are ' + wind + '.'

  rescue Exception => e

    forecast = $regrets

    puts "\n"
    puts e.message()
    puts e.backtrace.join("\n")
    puts "\n"

  end

  return forecast
 
end

# -----------------------------------------------------------------------------------------------
# Extract the city and state from the XML document
# -----------------------------------------------------------------------------------------------
def GetCity(doc)

  temp1 = doc.root.elements["channel/yweather:location"].attributes["city"]
  temp2 = doc.root.elements["channel/yweather:location"].attributes["region"]

  if $states[temp2]
   city = temp1 + ' ' + $states[temp2] 
  else 
   city = temp1 + ' ' + temp2
  end

 return city

end

# -----------------------------------------------------------------------------------------------
# Extract the forecast from the XML document
# -----------------------------------------------------------------------------------------------
def GetWind(doc)

  temp1 = doc.root.elements["channel/yweather:wind"].attributes["direction"]
  temp2 = doc.root.elements["channel/yweather:wind"].attributes["speed"]

  wind = 'from the ' + Direction( temp1.to_i() ) + ' at ' + temp2 + ' miles per hour'

  return wind

end

# -----------------------------------------------------------------------------------------------
# Extract the temperature from the XML document
# -----------------------------------------------------------------------------------------------
def GetTemperature(doc)

  temp = doc.root.elements["channel/item/yweather:condition"].attributes["temp"]
  temp = temp + ' degrees Fahrenheit'

  return temp

end 

# -----------------------------------------------------------------------------------------------
# Extract the forecast from the XML document
# -----------------------------------------------------------------------------------------------
def GetOutlook(doc)

  outlook = doc.root.elements["channel/item/yweather:condition"].attributes["text"]

  return outlook

end

#-------------------------------------------------------------------------------------- 
# Translate wind direction in degress to text
#-------------------------------------------------------------------------------------- 
def Direction(degrees)

 if degrees <= 11
  dir = 'north'
 elsif degrees <= 33
  dir = 'north northeast'
 elsif degrees <= 56
  dir = 'northeast'
 elsif degrees <= 78
  dir = 'east northeast'
 elsif degrees <= 101
  dir = 'east'
 elsif degrees <= 123
  dir = 'east southeast'
 elsif degrees <= 146
  dir = 'southeast'
 elsif degrees <= 168
  dir = 'south southeast'
 elsif degrees <= 191
  dir = 'south'
 elsif degrees <= 213
  dir = 'south southwest'
 elsif degrees <= 236
  dir = 'southwest'
 elsif degrees <= 258
  dir = 'west southwest'
 elsif degrees <= 281
  dir = 'west'
 elsif degrees <= 303
  dir = 'west northwest'
 elsif degrees <= 326
  dir = 'northwest'
 elsif degrees <= 348
  dir = 'north northwest'
 else
  dir = 'north'
 end

 return dir

end