Package: chatbot-utils
Table of ContentsInstallationFrom PyPiFrom GithubAPI documentationExample bot with chatbot_utils, showing how to use contextsExample bot with chatbot_utils, showing how to use format tokensPerformance characterizationsAnalysis: compile time & fetch time with 100k items, no parenthesis groupsAnalysis: compile time & fetch time with 100k items, extra parenthesis groupsChatbot utils provides easy-to-use tools for building a chatbot capable of
returning flexible, contextual responses when provided with text input.Supports Python 2.x and 3.x.ByContextual responses, I mean something like this;human >> hey, what time is it?
  bot >> it's 10.32pm
human >> is that past my bedtime?
  bot >> no, you're goodThe second phrase typed by the human,"is that past mybedtime?", is
ambiguous, and required the bot to understand that this was an incomplete
question related to the previous question, i.e. thecontext.InstallationFrom PyPipip install chatbot_utilsFrom Githubgit clone github.com/eriknyquist/chatbot_utilscd chatbot_utilspython setup.py buildpython setup.py installAPI documentationRead the API documentationhereExample bot with chatbot_utils, showing how to use contextsThe following example shows how to create a bot that can provide contexual responses
to specific questions:importrandomimporttimefromchatbot_utils.responderimportResponderfromchatbot_utils.utilsimportContextCreator,get_inputrandom.seed(time.time())responder=Responder()# Add a context for talking about catswithContextCreator(responder)asctx:# Phrase to trigger entry into cat contextctx.add_entry_phrases((["(.* )?(talk about|tell( me)? about) cats?.*"],["Sure, I love cats"]))# These phrases will only be recognized after the entry phrase has been seenctx.add_responses((["(.* )?favou?rite thing about (them|cats?).*"],["They are fuzzy"]),(["(.* )?(do )?you have (one|(a )?cat).*"],["No, computer programs can't have cats."]))# Add a nested context inside the cat context (you can do this as deep as you like)withContextCreator(ctx)assubctx:# Phrase to trigger entry into cat food context, will only be recognized when we're already in the cat contextsubctx.add_entry_phrases((["(.* )?(talk about|tell( me)? about) food?.*"],["Sure, let's talk about cat food"]))# These phrases will only be recognized after BOTH entry phrases have been seensubctx.add_responses((["(.* )?(favou?rite|best) type( of food)?.*"],["Computer programs do not eat cat food."]),)# Add explicit exit phrase for cat food subcontext (if no exit phrase is added,# then he only way to exit the context is using a phrase that was added to the top-level# responder object with Responder.add_response())subctx.add_exit_phrases((["(.* )?(stop talking about ((dog )?food|this)|talk about something else).*"],["OK, no more dog food talk."]))# Add a context for talking about dogswithContextCreator(responder)asctx:# Phrase to trigger entry into dog contextctx.add_entry_phrases((["(.* )?(talk about|tell( me)? about) dogs?.*"],["Sure, I think dogs are great"]))# These phrases will only be recognized after the entry phrase has been seenctx.add_responses((["(.* )?favou?rite thing about (them|dogs?).*"],["They are loyal"]),(["(.* )?(do )?you have (one|(a )?dog).*"],["No, computer programs can't have dogs."]))# Add a nested context inside the dog context (you can do this as deep as you like)withContextCreator(ctx)assubctx:# Phrase to trigger entry into dog food context, will only be recognized when we're already in the dog contextsubctx.add_entry_phrases((["(.* )?(talk about|tell( me)? about) food?.*"],["Sure, let's talk about dog food"]))# These phrases will only be recognized after BOTH entry phrases have been seensubctx.add_responses((["(.* )?(favou?rite|best) type( of food)?.*"],["Computer programs do not eat dog food."]),)# One of these responses will be randomly chosen whenever an unrecognized phrase is seenresponder.add_default_response(["Oh, really?","Mmhmm.","Indeed.","How fascinating."])# These phrases will only be recognized when no context is activeresponder.add_responses((["(.* )?hello.*"],["How do you do?","Hello!","Oh, hi."]),(["(. *)?(good)?bye.*"],["Alright then, goodbye.","See ya.","Bye."]))# Simple prompt to get input from command line and pass to responderwhileTrue:text=get_input(" > ")resp,groups=responder.get_response(text)print("\n\"%s\"\n"%(random.choice(resp)))Save this file asexample_bot.pyand run it withpython example_bot.py.
Example output:#~$ python example_bot.py

> hello!

"Hello!"

> hey, can we talk about dogs for a bit?

"Sure, I think dogs are great"

> what's your favourite thing about them?

"They are loyal"

> do you have one?

"No, computer programs can't have dogs."

> OK, let's talk about cats now

"Sure, I love cats"

> do you have one?

"No, computer programs can't have cats."

> and what's your favourite thing about them?

"They are fuzzy"Example bot with chatbot_utils, showing how to use format tokensThe following example shows how to create a bot that can remember what you said your
favourite movie was, ad report it back later when asked:fromchatbot_utils.responderimportResponderfromchatbot_utils.utilsimportContextCreator,get_inputresponder=Responder()responder.add_default_response("Please tell me what your favourite movie is")responder.add_responses(# When the bot is told what my favourite film is, it will save whatever film I said (4th# parenthesis group, or p3) in a new variable named "faveMovie"(["(.* )?(favou?rite|fave) (movie|film) is (.*)$"],"Cool, I will remember that your favourite film is{p3}!;;faveMovie={p3}"),# When the bot is asked to recall what my favourite film is, it will report the value of 'faveMovie'(["(.*)?(what is|what'?s|(can you )?tell me )?(what('?s)? )?my (fave|favou?rite) (movie|film).*"],"Your favourite film is{faveMovie}!"))# Simple prompt to get input from command line and pass to responderwhileTrue:text=get_input(" > ")resp,groups=responder.get_response(text)print("\n\"%s\"\n"%resp)Save this file asexample_bot.pyand run it withpython example_bot.py.
Example output:#~$ python example_bot.py

> howdy!

"Please tell me what your favourite movie is"

> hmm, OK, I guess my favourite film is Gone With The Wind

"Cool, I will remember that your favourite film is Gone With The Wind!"

> hey, can you tell me what my fave movie is?

"Your favourite film is Gone With The Wind!"

> alright, now my favorite movie is spiderman 2

"Cool, I will remember that your favourite film is spiderman 2!"

> what's my favourite film?

"Your favourite film is spiderman 2!"

>Performance characterizationsA core component ofchatbot_utilsis a custom dictionary called a ReDict,
which expects values to be set with regular expressions as keys. Values can then
be retrieved from the dict by providing input text as the key, and any values
with a matching associated regular expression will be returned.ReDicts with a large number of regular expressions (for example, a Responder
with several thousand pattern/response pairs added using theadd_responsemethod) may take a significant amount of time when compiling the regular
expression(s) initially. By default, this is done automatically on first
attempt to access a ReDict, but you can also callResponder.compile()explicitly to control when the regular expressions associated with a responder
are compiled.One additional quirk to note is that having more parenthesis groups in your
regular expressions results in a significant increase in compile time for
ReDicts with a large number of items.Analysis: compile time & fetch time with 100k items, no parenthesis groupsEach regular expression in the 100k items of test data used for this analysis
was 14-19 characters in length, used several common special characters
and was of the following form:foo? 10|bar* 10TheTime to compilewas calculated simply by timing theReDict.compile()method. TheTime to fetchis an average calculated by randomly fetching 10% of
the total number of items in the dict (e.g. for a dict with 1000 pattern/value
pairs added, 100 randomly-selected items would be fetched).Analysis: compile time & fetch time with 100k items, extra parenthesis groupsEach regular expression in the 100k items of test data used for this analysis
was at least 25-30 characters in length, used several common special characters
and was of the following form (note the addition parenthesis groups):(f)(o)o? 10|b((a)(r)*) 10Same as the previous test, theTime to compilewas calculated by timing theReDict.compile()method, and theTime to fetchis an average calculated by
randomly fetching 10% of the total number of items in the dict.