{"id":19798597,"url":"https://github.com/eriknyquist/chatbot_utils","last_synced_at":"2025-05-01T05:30:24.421Z","repository":{"id":62561778,"uuid":"174659300","full_name":"eriknyquist/chatbot_utils","owner":"eriknyquist","description":"RegEx-based fuzzy command / response handling for conversational chatbots","archived":false,"fork":false,"pushed_at":"2022-06-05T20:48:09.000Z","size":153,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-06T08:27:38.755Z","etag":null,"topics":["chatbot","chatbots","conversational-bots","conversational-chatbot","fuzzy-matching","pure-python","python","python3"],"latest_commit_sha":null,"homepage":"https://chatbot-utils.readthedocs.io","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eriknyquist.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-03-09T06:51:09.000Z","updated_at":"2023-11-26T18:49:48.000Z","dependencies_parsed_at":"2022-11-03T15:15:33.444Z","dependency_job_id":null,"html_url":"https://github.com/eriknyquist/chatbot_utils","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eriknyquist%2Fchatbot_utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eriknyquist%2Fchatbot_utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eriknyquist%2Fchatbot_utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eriknyquist%2Fchatbot_utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eriknyquist","download_url":"https://codeload.github.com/eriknyquist/chatbot_utils/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251830449,"owners_count":21650802,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chatbot","chatbots","conversational-bots","conversational-chatbot","fuzzy-matching","pure-python","python","python3"],"created_at":"2024-11-12T07:30:42.950Z","updated_at":"2025-05-01T05:30:24.078Z","avatar_url":"https://github.com/eriknyquist.png","language":"Python","readme":"chatbot_utils\n=============\n\n.. |travis_badge| image:: https://travis-ci.org/eriknyquist/chatbot_utils.svg?branch=master\n    :target: https://travis-ci.org/eriknyquist/chatbot_utils\n\n.. |docs_badge| image:: https://readthedocs.org/projects/chatbot-utils/badge/?version=latest\n    :target: https://chatbot-utils.readthedocs.io/en/latest/?badge=latest\n\n|travis_badge| |docs_badge|\n\n.. contents:: Table of Contents\n\nChatbot utils provides easy-to-use tools for building a chatbot capable of\nreturning flexible, contextual responses when provided with text input.\n\nSupports Python 2.x and 3.x.\n\nBy *Contextual responses*, I mean something like this;\n\n::\n\n    human \u003e\u003e hey, what time is it?\n      bot \u003e\u003e it's 10.32pm\n    human \u003e\u003e is that past my bedtime?\n      bot \u003e\u003e no, you're good\n\nThe second phrase typed by the human, ``\"is that past my bedtime?\"``, is\nambiguous, and required the bot to understand that this was an incomplete\nquestion related to the previous question, i.e. the **context**.\n\nInstallation\n------------\n\nFrom PyPi\n#########\n\n::\n\n    pip install chatbot_utils\n\nFrom Github\n###########\n\n#. ``git clone github.com/eriknyquist/chatbot_utils``\n#. ``cd chatbot_utils``\n#. ``python setup.py build``\n#. ``python setup.py install``\n\nAPI documentation\n-----------------\n\nRead the API documentation `here \u003chttps://chatbot-utils.readthedocs.io/\u003e`_\n\n\nExample bot with chatbot_utils, showing how to use contexts\n-----------------------------------------------------------\n\nThe following example shows how to create a bot that can provide contexual responses\nto specific questions:\n\n.. code-block:: python\n\n    import random\n    import time\n\n    from chatbot_utils.responder import Responder\n    from chatbot_utils.utils import ContextCreator, get_input\n\n    random.seed(time.time())\n\n\n    responder = Responder()\n\n\n    # Add a context for talking about cats\n    with ContextCreator(responder) as ctx:\n        # Phrase to trigger entry into cat context\n        ctx.add_entry_phrases(([\"(.* )?(talk about|tell( me)? about) cats?.*\"], [\"Sure, I love cats\"]))\n\n        # These phrases will only be recognized after the entry phrase has been seen\n        ctx.add_responses(\n            ([\"(.* )?favou?rite thing about (them|cats?).*\"], [\"They are fuzzy\"]),\n            ([\"(.* )?(do )?you have (one|(a )?cat).*\"], [\"No, computer programs can't have cats.\"])\n        )\n\n        # Add a nested context inside the cat context (you can do this as deep as you like)\n        with ContextCreator(ctx) as subctx:\n            # Phrase to trigger entry into cat food context, will only be recognized when we're already in the cat context\n            subctx.add_entry_phrases(([\"(.* )?(talk about|tell( me)? about) food?.*\"], [\"Sure, let's talk about cat food\"]))\n\n            # These phrases will only be recognized after BOTH entry phrases have been seen\n            subctx.add_responses(\n                ([\"(.* )?(favou?rite|best) type( of food)?.*\"], [\"Computer programs do not eat cat food.\"]),\n            )\n\n            # Add explicit exit phrase for cat food subcontext (if no exit phrase is added,\n            # then he only way to exit the context is using a phrase that was added to the top-level\n            # responder object with Responder.add_response())\n            subctx.add_exit_phrases(([\"(.* )?(stop talking about ((dog )?food|this)|talk about something else).*\"], [\"OK, no more dog food talk.\"]))\n\n\n    # Add a context for talking about dogs\n    with ContextCreator(responder) as ctx:\n        # Phrase to trigger entry into dog context\n        ctx.add_entry_phrases(([\"(.* )?(talk about|tell( me)? about) dogs?.*\"], [\"Sure, I think dogs are great\"]))\n\n        # These phrases will only be recognized after the entry phrase has been seen\n        ctx.add_responses(\n            ([\"(.* )?favou?rite thing about (them|dogs?).*\"], [\"They are loyal\"]),\n            ([\"(.* )?(do )?you have (one|(a )?dog).*\"], [\"No, computer programs can't have dogs.\"])\n        )\n\n        # Add a nested context inside the dog context (you can do this as deep as you like)\n        with ContextCreator(ctx) as subctx:\n            # Phrase to trigger entry into dog food context, will only be recognized when we're already in the dog context\n            subctx.add_entry_phrases(([\"(.* )?(talk about|tell( me)? about) food?.*\"], [\"Sure, let's talk about dog food\"]))\n\n            # These phrases will only be recognized after BOTH entry phrases have been seen\n            subctx.add_responses(\n                ([\"(.* )?(favou?rite|best) type( of food)?.*\"], [\"Computer programs do not eat dog food.\"]),\n            )\n\n\n    # One of these responses will be randomly chosen whenever an unrecognized phrase is seen\n    responder.add_default_response([\"Oh, really?\", \"Mmhmm.\", \"Indeed.\", \"How fascinating.\"])\n\n    # These phrases will only be recognized when no context is active\n    responder.add_responses(\n        ([\"(.* )?hello.*\"], [\"How do you do?\", \"Hello!\", \"Oh, hi.\"]),\n        ([\"(. *)?(good)?bye.*\"], [\"Alright then, goodbye.\", \"See ya.\", \"Bye.\"])\n    )\n\n    # Simple prompt to get input from command line and pass to responder\n    while True:\n        text = get_input(\" \u003e \")\n        resp, groups = responder.get_response(text)\n        print(\"\\n\\\"%s\\\"\\n\" % (random.choice(resp)))\n\n\nSave this file as ``example_bot.py`` and run it with ``python example_bot.py``.\nExample output:\n\n::\n\n     #~$ python example_bot.py\n\n     \u003e hello!\n\n     \"Hello!\"\n\n     \u003e hey, can we talk about dogs for a bit?\n\n     \"Sure, I think dogs are great\"\n\n     \u003e what's your favourite thing about them?\n\n     \"They are loyal\"\n\n     \u003e do you have one?\n\n     \"No, computer programs can't have dogs.\"\n\n     \u003e OK, let's talk about cats now\n\n     \"Sure, I love cats\"\n\n     \u003e do you have one?\n\n     \"No, computer programs can't have cats.\"\n\n     \u003e and what's your favourite thing about them?\n\n     \"They are fuzzy\"\n\n\nExample bot with chatbot_utils, showing how to use format tokens\n----------------------------------------------------------------\n\nThe following example shows how to create a bot that can remember what you said your\nfavourite movie was, ad report it back later when asked:\n\n.. code-block:: python\n\n    from chatbot_utils.responder import Responder\n    from chatbot_utils.utils import ContextCreator, get_input\n\n    responder = Responder()\n\n    responder.add_default_response(\"Please tell me what your favourite movie is\")\n\n    responder.add_responses(\n        # When the bot is told what my favourite film is, it will save whatever film I said (4th\n        # parenthesis group, or p3) in a new variable named \"faveMovie\"\n        ([\"(.* )?(favou?rite|fave) (movie|film) is (.*)$\"],\n         \"Cool, I will remember that your favourite film is {p3}!;;faveMovie={p3}\"),\n\n        # When the bot is asked to recall what my favourite film is, it will report the value of 'faveMovie'\n        ([\"(.*)?(what is|what'?s|(can you )?tell me )?(what('?s)? )?my (fave|favou?rite) (movie|film).*\"],\n         \"Your favourite film is {faveMovie}!\")\n    )\n\n    # Simple prompt to get input from command line and pass to responder\n    while True:\n        text = get_input(\" \u003e \")\n        resp, groups = responder.get_response(text)\n        print(\"\\n\\\"%s\\\"\\n\" % resp)\n\n\nSave this file as ``example_bot.py`` and run it with ``python example_bot.py``.\nExample output:\n\n::\n\n    #~$ python example_bot.py\n\n    \u003e howdy!\n\n    \"Please tell me what your favourite movie is\"\n\n    \u003e hmm, OK, I guess my favourite film is Gone With The Wind\n\n    \"Cool, I will remember that your favourite film is Gone With The Wind!\"\n\n    \u003e hey, can you tell me what my fave movie is?\n\n    \"Your favourite film is Gone With The Wind!\"\n\n    \u003e alright, now my favorite movie is spiderman 2\n\n    \"Cool, I will remember that your favourite film is spiderman 2!\"\n\n    \u003e what's my favourite film?\n\n    \"Your favourite film is spiderman 2!\"\n\n    \u003e\n\nPerformance characterizations\n-----------------------------\n\nA core component of ``chatbot_utils`` is a custom dictionary called a ReDict,\nwhich expects values to be set with regular expressions as keys. Values can then\nbe retrieved from the dict by providing input text as the key, and any values\nwith a matching associated regular expression will be returned.\n\nReDicts with a large number of regular expressions (for example, a Responder\nwith several thousand pattern/response pairs added using the ``add_response``\nmethod) may take a significant amount of time when compiling the regular\nexpression(s) initially. By default, this is done automatically on first\nattempt to access a ReDict, but you can also call ``Responder.compile()``\nexplicitly to control when the regular expressions associated with a responder\nare compiled.\n\nOne additional quirk to note is that having more parenthesis groups in your\nregular expressions results in a significant increase in compile time for\nReDicts with a large number of items.\n\nAnalysis: compile time \u0026 fetch time with 100k items, no parenthesis groups\n##########################################################################\n\nEach regular expression in the 100k items of test data used for this analysis\nwas 14-19 characters in length, used several common special characters\nand was of the following form:\n\n::\n\n    foo? 10|bar* 10\n\nThe *Time to compile* was calculated simply by timing the ``ReDict.compile()``\nmethod. The *Time to fetch* is an average calculated by randomly fetching 10% of\nthe total number of items in the dict (e.g. for a dict with 1000 pattern/value\npairs added, 100 randomly-selected items would be fetched).\n\n.. image:: images/100000_items_no_extra_groups.png\n\nAnalysis: compile time \u0026 fetch time with 100k items, extra parenthesis groups\n#############################################################################\n\nEach regular expression in the 100k items of test data used for this analysis\nwas at least 25-30 characters in length, used several common special characters\nand was of the following form (note the addition parenthesis groups):\n\n::\n\n    (f)(o)o? 10|b((a)(r)*) 10\n\nSame as the previous test, the *Time to compile* was calculated by timing the\n``ReDict.compile()`` method, and the *Time to fetch* is an average calculated by\nrandomly fetching 10% of the total number of items in the dict.\n\n.. image:: images/100000_items_extra_groups.png\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feriknyquist%2Fchatbot_utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feriknyquist%2Fchatbot_utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feriknyquist%2Fchatbot_utils/lists"}