Tools for creating chatbots
Project description
Chatbot 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.
By Contextual 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 good
The second phrase typed by the human, "is that past my bedtime?", is ambiguous, and required the bot to understand that this was an incomplete question related to the previous question, i.e. the context.
Installation
From PyPi
pip install chatbot_utils
From Github
git clone github.com/eriknyquist/chatbot_utils
cd chatbot_utils
python setup.py build
python setup.py install
API documentation
Read the API documentation here
Example bot with chatbot_utils, showing how to use contexts
The following example shows how to create a bot that can provide contexual responses to specific questions:
import random
import time
from chatbot_utils.responder import Responder
from chatbot_utils.utils import ContextCreator, get_input
random.seed(time.time())
responder = Responder()
# Add a context for talking about cats
with ContextCreator(responder) as ctx:
# Phrase to trigger entry into cat context
ctx.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 seen
ctx.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)
with ContextCreator(ctx) as subctx:
# Phrase to trigger entry into cat food context, will only be recognized when we're already in the cat context
subctx.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 seen
subctx.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 dogs
with ContextCreator(responder) as ctx:
# Phrase to trigger entry into dog context
ctx.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 seen
ctx.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)
with ContextCreator(ctx) as subctx:
# Phrase to trigger entry into dog food context, will only be recognized when we're already in the dog context
subctx.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 seen
subctx.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 seen
responder.add_default_response(["Oh, really?", "Mmhmm.", "Indeed.", "How fascinating."])
# These phrases will only be recognized when no context is active
responder.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 responder
while True:
text = get_input(" > ")
resp, groups = responder.get_response(text)
print("\n\"%s\"\n" % (random.choice(resp)))
Save this file as example_bot.py and run it with python 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 tokens
The 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:
from chatbot_utils.responder import Responder
from chatbot_utils.utils import ContextCreator, get_input
responder = 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 responder
while True:
text = get_input(" > ")
resp, groups = responder.get_response(text)
print("\n\"%s\"\n" % resp)
Save this file as example_bot.py and run it with python 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 characterizations
A core component of chatbot_utils is 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 the add_response method) 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 call Responder.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 groups
Each 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* 10
The Time to compile was calculated simply by timing the ReDict.compile() method. The Time to fetch is 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 groups
Each 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)*) 10
Same as the previous test, the Time to compile was calculated by timing the ReDict.compile() method, and the Time to fetch is an average calculated by randomly fetching 10% of the total number of items in the dict.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
File details
Details for the file chatbot_utils-1.1.0-py3-none-any.whl
.
File metadata
- Download URL: chatbot_utils-1.1.0-py3-none-any.whl
- Upload date:
- Size: 21.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.50.2 CPython/3.7.6
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | e1dca9db078f6a30c0a6a5492c1eb24ccd0de75c3a4b2a6aa4809bf673fd01c3 |
|
MD5 | 9aa93882f28c111129d512fad98f9ff5 |
|
BLAKE2b-256 | e4a9d42bc28192bbfdb89497f17d4ab9762b0ac6a383039046381f835c8c2f7c |
File details
Details for the file chatbot_utils-1.1.0-py2-none-any.whl
.
File metadata
- Download URL: chatbot_utils-1.1.0-py2-none-any.whl
- Upload date:
- Size: 21.8 kB
- Tags: Python 2
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.2.0 pkginfo/1.6.1 requests/2.24.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.50.2 CPython/3.7.6
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4c8fb405a8ce56bb8c44dab1be8f773f8acd52938d5cf52d7910390944389da1 |
|
MD5 | 7b331329388486ac68e355ce23953246 |
|
BLAKE2b-256 | 915814902c6de450bfaf442bc08371e7c04887bc5ae3210d333ab551b8746604 |