require 'net/http' require 'rexml/document' BEGIN { $server = 'weather.yahooapis.com' $query = '/forecastrss?p=' $welcome = 'Welcome to the weather demonstration application.' $prompt = 'Please tell me the ZIP code for the town whose weather forecast you want to hear.' $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.' $ZipGrammarId = 22 $QuitGrammarId = 67 $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' } $propertyNames = %w{ Digit1 Digit2 Digit3 Digit4 Digit5 } } def Answer(kall) # Get an instance of the recognizer, into it # Load a grammar that handles the request for ZIP code # Load another grammar that handles the request to exit rec = kall.getRecognizer() rec.loadGrammar('ZIP', $ZipGrammarId, true, false) rec.loadGrammar('Quit', $QuitGrammarId, true, false) # Get an instance of the synthesizer and greet the caller syn = kall.getSynthesizer() syn.speak('Welcome to the weather demonstration application.') syn.wait(-1) # Repeat indefinitely while true # Start listening first and ... # ... then prompt for a ZIP code rec.listen() syn.speak($prompt) # Wait for the recognizer to tell us how it did conf = rec.wait(10000, 30000) # Stop listening rec.stopListening() # Quit if the caller disconnects break if conf < 0 # Dump the state of the recognition for debugging rec.dump() # Arbitrariy we set a 65% confidence threshold if conf < 6500 NoRecognition(syn, rec) next end # If we recognized a phrase in the Quit grammar then we are done break if rec.getGrammarId() == $QuitGrammarId # Build a string from the key strokes zip = '' for i in 0..4 zip += rec.getPropertyTextByName( $propertyNames[i] ) end # Apologize and move on if we heard less than 5 digits if zip.size() != 5 NoRecognition(syn, rec) next end # 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 syn.speak('Good bye.') syn.wait(-1) end #-------------------------------------------------------------------------------------- # When we don't hear 5 digits we reset the recognizer and apologize #-------------------------------------------------------------------------------------- def NoRecognition(syn, rec) rec.reset() syn.speak( 'I\'m sorry, but I didn\'t get that.') syn.wait(-1) 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