Basicaly,a chatterbot is a computer program that when you provide it with some inputs in Natural Language (English, French ...) responds with something meaningful in that same language. Which means that the strength of a chatterbot could be directly measured by the quality of the output selected by the Bot in response to the user.
By the previous description,we could deduce that a very basic chatterbot can be written in a few lines of code in a given specific programming language.
Lets make our first chatterbot (notice that all the codes that will be used in this tutorial will be written in Visual Basic. So, it is assumed that the reader is familiar with these language
'
' Program Name: chatterbot1
' Description: this is a very basic example of a chatterbot program
'
' Author: Gonzales Cenelia
'
Option Explicit
Private KnowledgeBase() As Variant
Private bEndSession As Boolean
Private nNumOfLines As Integer
Const EM_LINESCROLL = &HB6
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _
ByVal wMsg As Long, ByVal wParam As Integer, ByVal lParam As Long) As Long
Private Sub Form_Load()
ReDim KnowledgeBase(5)
'initialising the 'KnowledgeBase' with data
KnowledgeBase = Array("I HEARD YOU!", "SO,YOU ARE TALKING TO ME.", "CONTINUE,I'M LISTENING.", _
"VERY INTERESTING CONVERSATION.", "TELL ME MORE...")
Timer1.Enabled = False
Timer2.Enabled = False
bEndSession = False
nNumOfLines = 0
End Sub
Private Sub Respond(strInput As String)
Dim strResponse As String
Dim iSelection As Integer
Randomize Timer
iSelection = (Rnd * UBound(KnowledgeBase))
If strInput = "BYE" Then
strResponse = "IT WAS NICE TALKING TO YOU USER, SEE YOU NEXT TIME!"
PrintLine (strResponse)
bEndSession = True
Else
strResponse = KnowledgeBase(iSelection)
PrintLine (strResponse)
End If
End Sub
Private Sub Command1_Click()
Dim strInput As String
strInput = Text1.Text
PrintLine (">" & strInput)
Timer1.Enabled = True
End Sub
Private Sub Text1_KeyPress(KeyAscii As Integer)
If KeyAscii = vbKeyReturn Then
Dim strInput As String
strInput = Text1.Text
PrintLine (">" & strInput)
Timer1.Enabled = True
End If
End Sub
Private Sub PrintLine(str As String)
Text2.Text = Text2.Text & str & vbNewLine
nNumOfLines = nNumOfLines + 1
If nNumOfLines > 10 Then
Call SendMessage(Text2.hwnd, EM_LINESCROLL, 0, (nNumOfLines - 10) * 4)
End If
End Sub
Private Sub Timer1_Timer()
Respond (Text1.Text)
Text1.Text = ""
Timer1.Enabled = False
If bEndSession = True Then
Timer2.Enabled = True
End If
End Sub
Private Sub Timer2_Timer()
Unload Chatterbot1
End Sub
Download Complete Project
Run The Application (Chatterbot1.exe)
As you can see,it doesn't take a lot of code to write a very basic program that can interact with a user but it would probably be very difficult to write a program that would really be capable of truely interpreting what the user is actualy saying and after that would also generate the approriate response to it. These has been a long term goal since the beginning and even before the very first computers were created. In 1951,the british mathematician Alan Turing has came up with the question Can machines think and he has also propose a test which is now known as the Turing Test. In this test,a computer program and also a real person is set to speak to a third person (the judge) and he has to decide which of them is the real person. Nowadays,there is a competition that was named the Loebner Prize and in this competition bots that has successfuly fool most of the judge for at list 5 minutes would win a prize of 100.000$. So far no computer program was able to pass this test successfuly. One of the major reason for this is that computer programs written to compute in such contest have naturaly the tendency of comiting a lot of typo (they are often out of the context of the conversation). Which means that generaly,it isn't that difficult for a judge to decide wheter he is speaking to a "computer program" or a real person. Also,the direct ancestor of all those program that tries to mimic a conversation between real human beings is Eliza,the first version of this program was written in 1966 by Joseph Weizenbaum a professor of MIT.
Chatbots in general are considered to belong to the weak a.i field (weak artificial intelligence) as opposed to strong a.i who's goal is to create programs that are as intelligent as humans or more intelligent. But it doesn't mean that chatbots do not have any true potential. Being able to create a program that could communicate the same way humans do would be a great advance for the a.i field. Chatbot is this part of artificial intelligence which is more accessible to hobbyist (it only take some average programming skill to be a chatbot programmer). So, programmers out there who wanted to create true a.i or some kind of artificial intelligence, writing intelligent chatbots is a great place to start!
So, now we know what to do to improve "our first chatterbot" and make it more intelligent.
Lets proceed on writing "our second bot", we will call it chatterbot2.
'
' Program Name: chatterbot2
' Description: this is an improved version of the previous chatterbot program "chatterbot1"
' this one will try a littlebit more to understand what the user is trying to say
'
' Author: Gonzales Cenelia
'
Option Explicit
Private KnowledgeBase As Variant
Private nNumOfLines As Integer
Const EM_LINESCROLL = &HB6
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _
ByVal wMsg As Long, ByVal wParam As Integer, ByVal lParam As Long) As Long
Private Sub Form_Load()
KnowledgeBase = Array( _
Array("WHAT IS YOUR NAME", "MY NAME IS CHATTERBOT2."), _
Array("HI", "HI THERE!"), _
Array("HOW ARE YOU", "I'M DOING FINE!"), _
Array("WHO ARE YOU", "I'M AN A.I PROGRAM."), _
Array("ARE YOU INTELLIGENT", "YES, OFCORSE."), _
Array("ARE YOU REAL", "DOES THAT QUESTION REALLY MATERS TO YOU?"))
Timer1.Enabled = False
Timer2.Enabled = False
End Sub
Private Sub Respond(strInput As String)
Dim strResponse As String
strResponse = FindMatch(strInput)
If strInput = "BYE" Then
strResponse = "IT WAS NICE TALKING TO YOU USER, SEE YOU NEXT TIME!"
Timer2.Enabled = True
ElseIf Len(strResponse) = 0 Then
strResponse = "I'M NOT SURE IF I UNDERSTAND WHAT YOU ARE TALKING ABOUT."
End If
PrintLine (strResponse)
End Sub
Private Function FindMatch(strInput As String) As String
Dim i As Integer
Dim strMatch As String
For i = 0 To UBound(KnowledgeBase) Step 1
If KnowledgeBase(i)(0) = strInput Then
strMatch = KnowledgeBase(i)(1)
Exit For
End If
Next
FindMatch = strMatch
End Function
Private Sub PrintLine(str As String)
Text2.Text = Text2.Text & str & vbNewLine
nNumOfLines = nNumOfLines + 1
If nNumOfLines > 10 Then
Call SendMessage(Text2.hwnd, EM_LINESCROLL, 0, (nNumOfLines - 10) * 4)
End If
End Sub
Private Sub Command1_Click()
Dim strInput As String
strInput = Text1.Text
PrintLine (">" & strInput)
Timer1.Enabled = True
End Sub
Private Sub Text1_KeyPress(KeyAscii As Integer)
If KeyAscii = vbKeyReturn Then
Dim strInput As String
strInput = Text1.Text
PrintLine (">" & strInput)
Timer1.Enabled = True
End If
End Sub
Private Sub Timer1_Timer()
Respond (Text1.Text)
Text1.Text = ""
Timer1.Enabled = False
End Sub
Private Sub Timer2_Timer()
Unload Chatterbot2
End Sub
Download Complete Project
Run The Application (Chatterbot2.exe)
Now,the program can understand some sentences like "what is your name", "are you intelligent" etc And also he can choose an appropriate response from his list of responses for this given sentence and just display it on the screen. Unlike the previous version of the program(chatterbot1) chatterbot2 is capable of choosing a suitable response to the given user input without choosing random responses that doesn't take into account what actualy the user trying to say.
We've also added a couple of new technics to theses new program: when the
program is unable to find a matching keyword the current user input, it simply
answers by saying that it doesn't understand wich is quiet human like.
There are quiet a few things that we can improve, the first one is that since the chatterbot tends to be very repetitive, we might create a mechanism to control these repetitions. We could simply store the previous response of that Chatbot within a string "sPrevResponse" and make some checkings when selecting the next bot response to see if it's not equal to the previous response. If it is the case, we then select a new response from the available responses.
The other thing that we could improve would be the way that the chatbot handles the users inputs, currently if you enter an input that is in lower case the Chatbot would not understand anything about it even if there would be a match inside the bot's database for that input. Also if the input contains extra spaces or punctuation characters (!;,.) this also would prevent the Chatbot from understanding the input. That's the reason why we will try to introduce some new mechanism to preprocess the users inputs before it can be searh into the Chatbot database. We could have a function to put the users inputs in upper case since the keywords inside the database are in uppercase and another procedure to just remove all of the punctuations and extra spaces that could be found within users input. That said, we now have enough material to write our next chatterbot: "Chattebot3". View the code for Chatterbot3
The other possibility is much more complex,it use's the concept of Fuzzy String Search. To apply this method,it could be useful at first to break the inputs and the current keyword in separate words,after that we could create two different vectors,the first one could be use to store the words for the input and the other one would store the words for the current keyword. Once we have done this we could use the Levenshtein distance for measuring the distance between the two word vectors. (Notice that in order for these method to be effective we would also need an extra keyword that would represent the subject of the current keyword).
So,there you have it,two different methods for improving the chatterbot.
Actualy we could combine both methods and just selectioning which one to use on each situation.
Finaly,there are still another problem that you may have noticed with the previous chatterbot,you could repeat the same sentence over and over and the program wouldn't have any reaction to this. We neeed also to correct this problem.
So,we are now ready to write our fourth chatterbot,we will simply call it chatterbot4. View the code for Chatterbot4
As you probably may have seen,the code for "chatterbot4" is very similar to the one for "chatterbot3" but also there was some key changes in it.
In particular,the function for searching for keywords inside the database is now a littlebit more flexible.
So,what next?
Dont worry,there are still a lot of things to be covered.
Before proceding to the next part of this tutorial, you are encouraged to try compiling and running the code for "chatterbot5" so that you can understand how it works and also to verifies the changes that have been made in it.
Has you may have seen, the implementation of the "current chatterbot", is now encapsulated into a class, also, there has been some new functions added to the new version of the program.
Private Sub SelectResponse()
this function selects a response from a list of responses, there is a new helper function that was added to the program "shuffle", this new function shuffles a list of strings randomly
Private Sub SavePrevInput()
this function simply saves the current user input into a variable (m_sPrevInput) before geting some new inputs from the user.
Private Sub SavePrevResponse()
the function "save_prev_response()" saves the current response of the chatterbot before the bot have started to search responses for the current input, the current responsesis save in the varaible (m_sPrevResponse).
Private Sub SavePrevEvent()
this function simply saves the current event (m_sEvent) into the variable (m_sPrevEvent).
An event can be when the program has dectected a "null input" from the user also, when the user repeats himself or even when the chatterbot makes repetitions has well etc.
Private Sub SetEvent(str As String)
sets the current event (m_sEvent)
Private Sub SaveInput()
makes a backup of the current input (m_sIntput) into the variable m_sInputBackup.
Private Sub SetInput(str As String)
sets the current input (m_sInput)
Private Sub RestoreInput()
restores the value of the current input (m_sInput) that has been saved previously into the variable m_sInputBackup.
Private Sub PrintResponse()
prints the response that has been selected by the "chat robot" on the screen.
Private Sub PreProcessInput()
this function does some preprocessing on the input like removing punctuations, redundant spaces charactes and also it converts the input to uppercase.
BotRepeat() As Boolean
verifies if the chatterbot has started to repeat himself.
UserRepeat() As Boolean
verifies if the user has repeat himself.
BotUnderstand() As Boolean
verifies that the bot understand the current user input (m_sInput).
NullInput() As Boolean
verifies if the current user input (m_sInput) is null.
NullInputRepetition() As Boolean
verifies if the user has repeated some null inputs.
UserWantToQuit() As Boolean
check to see if the user wants to quit the current session with the chatterbot.
SameEvent() As Boolean
verifies if the current event (m_sEvent) is the same as the previous one (m_sPrevEvent).
NoResponse() As Boolean
checks to see if the program has no response for the current input.
SameInput() As Boolean
verifies if the current input (m_sInput) is the same as the previous one (m_sPrevInput).
SimilarInput() As Boolean
checks to see if the current and previous input are similar, two inputs are considered similar if one of them is the substring of the other one
(ex: "how are you" and "how are you doing" would be considered similar because "how are you" is a substring of "how are you doing".
Private Sub GetInput()
gets inputs from the user.
Private Sub Respond()
handles all responses of the "chat robot" wheter it is for events or simply the current user input. So, basicaly, these function controls the behaviour of the program.
Private Sub FindMatch()
finds responses for the current input.
Private Sub HandleRepetition()
handles repetions made by the program.
Private Sub HandleUserRepetition()
handles repetitions made by the user.
Private Sub HandleEvent(str As String)
this function handles events in general.
you can clearly see that "chatterbot5" have much more functionalities than "chatterbot4" and also each functionalities is encapsulated into methods (functions)
of the class "CBot" but still there are a lot more improvements to be made on it too.
Chattebot5 introduce the concept of "state", in these new version of the Chatterbot, we associate a different "state" to some of the events that can occure during a conversation. Ex: when the user enters a null input, the chatterbot would set itsel into the "NULL INPUT**" state, when the user repeat the same sentence, it would go into the "REPETITION T1**" state, etc.
Also these new chatterbot uses a bigger database than the previous chatbot that we have seen so far: chatterbot1, chatterbot2, chatterbot3 ... But still, this is quiet insignificant due to the fact that most chatterbots in use today (the very popular ones) have a database of at least 10000 lines or more. So, this would definitly be one of the major goal that we might try to achieve into the next versions of the chatterbot.
But however for now, we will concentrate a little problem concerning the current chatterbot.
How did we arrive at this transformation? We may have done it by using two steps:
We make sure that the chatterbot have a list of response templates that is linked to the corresponding keywords. Responses templates are a sort of skeleton to build new responses for the chatterbot. usualy we used wildcards in the responses to indicate that it is a template. On the previous example, we have use the template: (SO, YOU THINK THAT*) to construct our response. During the reassambly process, we simply replace the wildcard by some part of the original input. In that same example, we have use: YOU ARE A MACHINE wich is actualy the complete original input from the user. After replacing the wildcard by the user's input, we have the following sentence: SO, YOU THINK THAT YOU ARE A MACHINE but we can not use these sentence as it is, before that we need to make some pronoun reversal in it.
Notice that it's not a good thing to use transposition too much during a conversation, the mechanism would become too obvious and it could create some repetition.
View the code for Chatterbot9
Some Exemples of sentences using "WHO ARE YOU" would be:
But a keyword such as "WHO IS" can only be found at the beginning or in the middle of a given sentence but it can not be found at end of the sentence or alone.
Exemples of sentences using the keyword: "WHO IS"
How do we make sure that the chatterbot will be able to distinguish such keywords and the specific places were they are aloud to be found on a sentence? We will simply introduce some new notations for keywords:
A keyword can have different meanings depending on it's position in a given sentence.
View the code for Chatterbot10
To illustrate these concept, we are going to look at the following conversation log:
USER: What is your favorite movie?
CHATTERBOT: IT IS TERMINATOR II.
USER: Why do you like these movie? (Now how are we suppose to answer that question if we knew nothing about the previous response of the Chatbot?)
So clearly, some inputs requires the usage of "context" in order to be able to formulate a correct answer. In the previous example, it would simply be: IT IS TERMINATOR II.
Now the Bot knows what it was talking about previously, it can more easealy formulate a good answer to the user's input.
we can now continue the previous conversation log:
(Context: IT IS TERMINATOR II)
CHATTERBOT: BECAUSE IT IS A SCIENCE-FICTION MOVIE AND I LOVE SCIENCE-FICTION.
Context also aloud us to control improper reaction from the Chatbot. Example, if the user enters the sentence: "Why do you like these movie?" during a conversation without the Chatterbot even talking about these subject.
It could simply respond by saying: WHAT ARE YOU TALKING ABOUT?
The context feature has been implemented in Chatterbot11.
View the code for Chatterbot11
Another great feature that would be very interesting to implement into a Chatterbot is the capacity to anticipate the next response of the user, these would make the Chatbot
looks even more smarter during a conversation.
We now have a complete architecture for the database, we just need to implement theses features into the next version of the chatbot (Chatterbot13)
View the code for Chatterbot12