You know "regular expressions" as well :) They are the patterns that you place between the slashes, e.g., /<text>(.*)<\/text>/m is a regular expression. The cartoon is pointing out that you could use something similar to match an email address, e.g., find the "@" char, find the "."s, etc., and pull it out of a larger text.
Back to our chatbot, note I have held off adding all of your user inputs from last week to our web page. My worry is that it will be a giant string that will fill up the playground window when you print it. However, I will probably add them this weekend, so be prepared. It should not affect the way your program operates, just makes it harder for a human reader to look at the string.
Last week we built a method, findUIMatch, that could take something a user typed in, and see if there was a match in our collective wisdom. This week I would like to turn to the 2nd step, seeing if we can find a response. To remind you, here is the code we ended up with last week, as it should show up in your chatbot_helper.rb file. I filled in my solution for problems 1 and 2. Yours can be different, as long as it works. Feel free to use my code below if you never got yours to work.
require 'net/http' require 'uri' require 'rexml/document' def get_page(site,path) the_page = site + path #builds larger string out of two pieces res = Net::HTTP.get URI.parse(the_page) return res #should be raw xml end def getCollectiveWisdom() return get_page('http://www.cs.uoregon.edu/classes/08W/cis170', '/cis170-cloud.html') end def getText( entry ) #find the <text>...</text> tag and pull out the text text = entry[/<text>(.*)<\/text>/m] n = text.length() text = text.slice(6,n-13) #pull out middle stuff (6+7 is length of two tags) return text end def getID( entry ) #find the <id>...<id> tag and pull out the id id = entry[/<id>(.*)<\/id>/m] id = id.delete("<\/id>") #deletes all chars between double quotes return id end def findUIMatch( user_input, xml ) REXML::Document.new(xml).root.get_elements('user_input').each do |entry| entry = entry.to_s text = getText(entry) if( user_input == text ) #think about less strict matches return getID(entry) end end return nil end
In essence, what we want to add to above is a method findUIResponse( id ), where the id is the value returned by findUIMatch. So something like below. Note: don't try typing this into the playground. For now, I just want to use it to show you where we are heading.
ui = "What color is the sky?" xml = getCollectiveWisdom() #from last week - get the whole xml page id = findUIMatch( ui, xml ) #from last week - should return "0" for this ui if( id != nil ) response = findUIResponse( id, xml ) #we will have to write this method puts "Chatbot says: " + response #chatbot responds to user's question endThat's our goal. But let's start by working on smaller pieces like last week. I suppose we need to know what a response looks like. Go ahead and surf into the cloud page: http://www.cs.uoregon.edu/classes/08W/cis170/cis170-cloud.html. And then right-click and view source. You should see something like this on the page.
<response> <id>0</id> <quid>0</quid> <text>The Martian sky is honey colored.</text> <author>google</author> </response>Note that there are two types of id in a response. The first, with a <quid> tag, is a reference to a user_input. Above, a quid of 0 means we should find a user_input that has an <id> of 0. That is the user_input this response goes with! The other tag above, <id>, is the local id of this response. Sorry if it is confusing. One more time: the quid refers to a user_input some place else; the <id> refers to this response. Both are used to give elements a unique identification on the page.
We know, from last week, that there is a user_input with text "What color is the sky?". And we remember that it had an <id> of 0. So the response above matches it given its <quid> is 0. If you look more closely at the web page string, you will see another response with a <quid> of 0. This means that it also matches the question "What color is the sky?", e.g., "Blue."
Ok, so let's figure this out. I have a method that will take a user input string and give me back its id (from the collective). What I need to do now is find a response that has a quid that matches that id. It seems similar to last week. Here's that powerful code from last week that enumerated all the user_input elements in the page:
require 'rexml/document' #you should add this line at the top of your helper file at some point xml = getCollectiveWisdom() REXML::Document.new(xml).root.get_elements('user_input').each do |entry| entry = entry.to_s #convert to a string puts "************an entry:\n" puts entry #print out the string endGuess what? I can reuse this code, with one tiny change, to enumerate all responses on the page.
Problem 1. Make the change to the code above so that you see all the responses (not user_input) printed out. At this point, I will leave it up to you whether you want to work from fxri (the playground) or an editor like SciTE. You could just append the text above to your helper file, make the changes, and run it in SciTE to see what happens.
Ok, let's think about this. We now can get all the responses handed to us, one by one. Each will be stored in a variable called entry. We do not know if the response we are given in entry matches the id we are looking for, e.g., the id of "What color is the sky?" is 0. So it seems we will need to pull the quid out of the response. Once we have it, we can check it against what we are looking for.
Problem 2. Write a method getQUID( entry ). You should be able to use the getID method, already defined in your helper file, as a guide to the strategy to use. Go ahead and add the getQUID method to your helper file. Now you can test it out by adding the following code to the helper file and running it in SciTE. You could also copy your getQUID method definition into the playground and paste in the code below. Your choice.
entry = '<response> <id>1</id> <quid>0</quid> <text>The Martian sky is honey colored.</text> <author>google</author> </response>' result0 = getQUID( entry ) #should return 0Problem 3. We are getting close! First, add the getQUID method from problem 2 to your chatbot_helper.rb file, if you have not already. Now add the method below to the file.
def findResponseMatch( ui_id, xml ) REXML::Document.new(xml).root.get_elements(?).each do |entry| entry = entry.to_s quid = getQUID( entry ) if( quid == ui_id ) #we found a match! text = getText(entry) #get to reuse this method, cool return text #hand back response so can give to user end end return nil #dang, did not find a response endOnly thing you have to fill in is the string that replaces the ? I placed in the REXML line; you should have this from problem 1. When I tried mine out in fxri, I saw below. You should test yours to see if you get the same.
irb(main):074:0> findResponseMatch( 0, xml ) => "The Martian sky is honey colored." irb(main):075:0> findResponseMatch( 1, xml ) => nil
Problem 4 One more step and we have a working chatbot. Paste the code below into your chatbot_helper.rb file. Note that for this code to work, findUIMatch and findResponseMatch must be working.
def mainLoop( cw ) puts "Some welcoming statement goes here." while( true ) print "Type your input:" #print does not do a \n ui = gets.delete("\n") #delete the line-return from user input case ui when "Bye" break #end the loop when "Bye." break when "Quit" break end id = findUIMatch( ui, cw ) if( id == nil ) addNewUserInput( ui, cw ) puts "Me: Sorry, that's new to me." next #skip over rest and continue loop at top end response = findResponseMatch( id, cw ) if( response == nil ) puts "Me: Sorry, I've seen that before but don't have a response." next end print "Me: " + response + "\n" end #do anything needed here before quitting puts "Me: So long for now." end def addNewUserInput( ui, cw ) #do nothing for now end mainLoop( getCollectiveWisdom() ) #this starts the chatbot runningRun it and you should see your chatbot in action. If you type "What color is the sky?", you should get a response. If you type "Bye", that should end the session. Feel free to tailor your bot to your personality, e.g., change what it types out to the user. Your turn-in is your entire chatbot_helper.rb file. The grader will make sure it works.
For next week, we will look at making the chatbot a little more flexible in matching misspelled words.