Difference between revisions of "CSC111 Lab 8 2011"
(→Playing with Eliza) |
(→The initial program) |
||
Line 30: | Line 30: | ||
Cut and paste the program below into a file called eliza.py: | Cut and paste the program below into a file called eliza.py: | ||
− | # | + | <br /> |
− | # | + | <source lang="python"> |
+ | # eliza.py | ||
+ | # | ||
# a very simple beginning for an eliza-like program | # a very simple beginning for an eliza-like program | ||
# | # | ||
Line 67: | Line 69: | ||
main() | main() | ||
+ | |||
+ | </source> | ||
+ | <br /> | ||
+ | <br /> | ||
Revision as of 14:07, 26 October 2011
--D. Thiebaut 15:04, 26 October 2011 (EDT)
Eliza!
Today we are going to therapy and will consult with Doctor Eliza.
Playing with Eliza
Eliza is named after Eliza Doolittle, of the 1913 George Bernard Shaw play Pigmalion, which is the inspiration for the musical My Fair Lady.
Joseph Weizenbaum originated the program. A good description of what how Eliza works can be found here.
First, play with Eliza a bit to get a feel for it. You can either use this page, or that one, or use the "therapist" included in emacs. To start the therapist in emacs, start emacs in your 111a-xx account, and type the following commands:
Shift ESC
- then
x doctor
and press the Enter key. Emacs will switch to "doctor" mode... When you are done and want to return to editing your program, type
CTRL-x k
The initial program
Cut and paste the program below into a file called eliza.py:
# eliza.py
#
# a very simple beginning for an eliza-like program
#
# 1) greet user
# 2) repeat a huge number of times:
# 2.1) get user's statement about life
# 2.2) respond in a way that seems intelligent
#
# Addition:
# cycles through a series of canned answers to get
# the user to think the computer is listening
canned = [ "\nPlease tell me more",
"\nI see...",
"\nI am listening..." ]
def main():
# 1) greet user
print "Welcome. Please tell me of your problems: "
print '(You may quit at any time by answering "bye")'
# 2) repeat a huge number of times
for i in range( 10000 ):
# 2.1) get user's statement about her life
user = raw_input( "\n> " )
if ( user.lower() == "bye" ):
break
# 2.2) respond semi-intelligently
# cycle through the list of canned sentences...
print( random.choice( canned ) )
main()
Make the program print the variables i, and index every time it prints a canned sentence. This will help you understand how it chooses its responses to the user. (Remember that the % operator when used between two integers returns the remainder of the division of the first by the second; 10 % 3 is 1. 11 % 4 is 3, etc.)
Run the program and enter at least 6 or 7 sentences. Observe how the program repeats itself in the way it responds to the user.
Go ahead and add a few more canned answers if you want :-) This will make it harder for a human to figure out the repetition, but not foolproof.
Selecting random canned answers
We have seen random numbers before. To generate random numbers we need to tell Python that we need the random module (hence the import random statement), and we use the function random.randrange( x ) to get a random number between 0 and x. To verify this, try the program below.
# random numbers import random
for i in range( 10 ) print random.randrange( 5 )
Do you see out how the randrange function works? Change 5 to another small number, say 11, and test your program again.
(You can double-check by taking a look at the python documentation on the random library.) Now that you have been reminded of the randrange() function, use it to compute the variable index used to select a canned response. In other words, change the line with the % operator (modulo operator) and use randrange instead...
Run your program and enter a few words to test the randomness of what the program outputs (by the way, you do not have to type sentences that make sense to test your program. Just the letter 'a' is enough of an input!)
Reflection
One way for Eliza to seem intelligent is to say the same thing the user just said, but to change the sentence from the first person to the second person. For example, if the user says "I am tired", Eliza will respond "You are tired". You can do that by replacing all occurrences of "I" by "you", "am" by "are", "my" by "your", and "me" by "you".
How can this be done?
Here is a possible solution:
user = raw_input( "\n> " ) # split user's sentence into words words = user.split( ) #create a copy new list of words that will be Eliza's response newWords = words[:] # take each word of user sentence and if the word represents # the first person singular, switch it to second person. for i in range( len( words ) ): if words[i] == "I": newWords[i] = "you"
# join the list of words in newWords in a string, and print it print ' '.join( newWords )
Go ahead and implement this modification. Play with it. Verify that when you use "I" in a sentence, the program replaces it by "you". Understand why the program actually does that.
Once you have tested this, go ahead and make your program also replace
"me" by "you" "am" by "are" "I've" by "you've" "I'm" by "you're" "I'll" by "you'll" "was" by "were" "my" by "your" "mine" by "yours" Adding a ? at the end of the reflected sentence
Once you have your list of new words newWords containing the reflected words, modify the last word of this list and add a "?" at the end of it. In other words, if newWords is [ "You", "are", "bored", "today" ], transform it into [ "You", "are", "bored", "today?" ].
Reflection or Canned Answer?
Depending on how you have modified your program, it may respond to the user with two sentences. One reflected and one canned. What you should do is make your program output the reflected answer when it finds out that it was able to change some of the words in the user's string, and make it output a canned answer when there is no reflection.
For example, if the user says "I am bored", your Eliza program will respond "you are bored?", but if the user says "never!", your program will respond with an answer of the type "Please go on..."
Figure out what kind of test you can use for your program to know if it is reflecting the user input, or not, and output either the reflected sentence, or a canned answer.
Hints #1: you could compare the original list of words entered by the user, to the list of words generated after the reflection.
Hints #2: Make sure that your adding the ? at the end of the last word make your program think there was a reflection where there wasn't one!
Test your program! It should really start showing some artificial intelligence!
Second level reflection: Switching second person to first person
What if the user says to the program "I don't like you"?
Right now your program will output "you don't like you?" which is not quite right. So we should try to fix this.
Go ahead, and make your program replace the 2nd person in the user's input by the first person. You will see that without doing a semantic analysis of the sentence, it is impossible to know whether "you" should be replaced by "I", or by "me". At this point, we will not worry about this, and simply replace "you" by "me" and this will have a higher probability of looking correct.
If your modification is correct, and the user enters "I don't like you", your program should output "you don't like me?".
Catching key words
You may have noticed that with the real Eliza program, when you say something like "No", or "never", the program picks up on this and responds something like "why are you so negative?". Let's make your program pick up on a "NO" answer.
All you need is an if statement that will test whether the user's answer is one word only, and this word is "no".
# check for reflection if words != newWords: # then output the reflected answer ... else: if len( words ) == 1 and words[0] =="no": print "you are begin very negative today!" else: # print canned answer
Note the and operator: it is a logical operator. It forces the whole expression of the if-statement to be true only if the two parts on each side of the "and" are true.
Random "negative canned" answers
Instead of your program always outputting "you are begin very negative today!" in the case explored in the previous section, make it select its response from a new series of canned negative responses (like "No?", "Really?", "You are awfully negative", "why not?", etc.) Picking up on "No" and "Never"
What if we not only wanted our program to pick up on "No", but also on "Never"? All we need to do is change the if statement to read "if the user's answer contains 1 word only, and this word is "no" or "never"..." Here is the test in python:
if len( words )==1 and ( words[0]=="no" or words[0]=="never" ): index = random.randrange( len( cannedNegative ) ) print cannedNegative[ index ] else: # print canned answer