├── IoT Workshop PPT.pptx ├── NOTES.IPYNB ├── chatterbot ├── __init__.py ├── __main__.py ├── adapters.py ├── chatterbot.py ├── comparisons.py ├── constants.py ├── conversation.py ├── corpus.py ├── exceptions.py ├── ext │ ├── __init__.py │ ├── django_chatterbot │ │ ├── __init__.py │ │ ├── abstract_models.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── migrations │ │ │ ├── 0001_initial.py │ │ │ ├── 0002_statement_extra_data.py │ │ │ ├── 0003_change_occurrence_default.py │ │ │ ├── 0004_rename_in_response_to.py │ │ │ ├── 0005_statement_created_at.py │ │ │ ├── 0006_create_conversation.py │ │ │ ├── 0007_response_created_at.py │ │ │ ├── 0008_update_conversations.py │ │ │ ├── 0009_tags.py │ │ │ ├── 0010_statement_text.py │ │ │ ├── 0011_blank_extra_data.py │ │ │ ├── 0012_statement_created_at.py │ │ │ ├── 0013_change_conversations.py │ │ │ ├── 0014_remove_statement_extra_data.py │ │ │ ├── 0015_statement_persona.py │ │ │ ├── 0016_statement_stemmed_text.py │ │ │ ├── 0017_tags_unique.py │ │ │ ├── 0018_text_max_length.py │ │ │ └── __init__.py │ │ ├── model_admin.py │ │ ├── models.py │ │ └── settings.py │ └── sqlalchemy_app │ │ ├── __init__.py │ │ └── models.py ├── filters.py ├── languages.py ├── logic │ ├── __init__.py │ ├── best_match.py │ ├── logic_adapter.py │ ├── mathematical_evaluation.py │ ├── specific_response.py │ ├── time_adapter.py │ └── unit_conversion.py ├── parsing.py ├── preprocessors.py ├── response_selection.py ├── search.py ├── storage │ ├── __init__.py │ ├── django_storage.py │ ├── mongodb.py │ ├── sql_storage.py │ └── storage_adapter.py ├── tagging.py ├── trainers.py └── utils.py ├── examples ├── __init__.py ├── basic_example.py ├── convert_units.py ├── default_response_example.py ├── django_app │ ├── README.rst │ ├── example_app │ │ ├── __init__.py │ │ ├── settings.py │ │ ├── static │ │ │ ├── css │ │ │ │ ├── bootstrap.css │ │ │ │ └── custom.css │ │ │ ├── favicon.ico │ │ │ ├── img │ │ │ │ └── chatterbot.png │ │ │ └── js │ │ │ │ ├── bootstrap.js │ │ │ │ ├── jquery.js │ │ │ │ └── js.cookie.js │ │ ├── templates │ │ │ ├── app.html │ │ │ └── nav.html │ │ ├── urls.py │ │ ├── views.py │ │ └── wsgi.py │ ├── manage.py │ ├── requirements.txt │ └── tests │ │ ├── __init__.py │ │ ├── test_api.py │ │ └── test_example.py ├── export_example.py ├── learning_feedback_example.py ├── math_and_time.py ├── memory_sql_example.py ├── specific_response_example.py ├── tagged_dataset_example.py ├── terminal_example.py ├── terminal_mongo_example.py ├── tkinter_gui.py ├── training_example_chatterbot_corpus.py ├── training_example_list_data.py └── training_example_ubuntu_corpus.py ├── python module1 ├── AWS exercise.docx ├── Assignment Python Fundamentals.pdf ├── Kenoics_curriculum-AI with Python_final.pdf ├── Python_Fundamentals_01_Control Flows.pdf ├── Python_Fundamentals_01_Data_Types_and_Operators.pdf └── instapdf.in-rich-dad-poor-dad-152.pdf ├── python module2 ├── Advanced Concepts Using Datastructures.pptx ├── Functions.pptx ├── Python Classes.pptx └── Python Scripting.pptx ├── python module3 └── Business Statistics (2).pptx └── tests_django ├── __init__.py ├── base_case.py ├── test_chatbot.py ├── test_chatterbot_corpus_training.py ├── test_chatterbot_settings.py ├── test_django_adapter.py ├── test_logic_adapter_integration.py ├── test_settings.py └── test_statement_integration.py /IoT Workshop PPT.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/IoT Workshop PPT.pptx -------------------------------------------------------------------------------- /NOTES.IPYNB: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "name": "stdout", 10 | "output_type": "stream", 11 | "text": [ 12 | "welcome\n" 13 | ] 14 | } 15 | ], 16 | "source": [ 17 | "print(\"welcome python\")" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 1, 23 | "metadata": {}, 24 | "outputs": [ 25 | { 26 | "name": "stdout", 27 | "output_type": "stream", 28 | "text": [ 29 | "False\n" 30 | ] 31 | } 32 | ], 33 | "source": [ 34 | "x,y=1,2\n", 35 | "if(x>y):\n", 36 | " print(\"True\")\n", 37 | "else:\n", 38 | " print(\"False\")" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 3, 44 | "metadata": {}, 45 | "outputs": [ 46 | { 47 | "name": "stdout", 48 | "output_type": "stream", 49 | "text": [ 50 | "werid\n" 51 | ] 52 | } 53 | ], 54 | "source": [ 55 | "#!/bin/python3\n", 56 | "\n", 57 | "import math\n", 58 | "import os\n", 59 | "import random\n", 60 | "import re\n", 61 | "import sys\n", 62 | "\n", 63 | "if __name__ == '__main__':\n", 64 | " n = int(input().strip())\n", 65 | "\n", 66 | " if \"n%2!==0\":\n", 67 | " print(\"werid\")\n", 68 | " else:\n", 69 | " print(\"not werid\")" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": 9, 75 | "metadata": {}, 76 | "outputs": [], 77 | "source": [ 78 | "if __name__ == '__main__':\n", 79 | " a = int(input())\n", 80 | " b = int(input())\n", 81 | " \n", 82 | " print(a+b)\n", 83 | " print(a-b)\n", 84 | " print(a*b)\n", 85 | "\n", 86 | "\n" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": null, 92 | "metadata": {}, 93 | "outputs": [], 94 | "source": [ 95 | "def is_leap(year):\n", 96 | " leap = False\n", 97 | " \n", 98 | " if\n", 99 | " \n", 100 | " return leap\n", 101 | "\n", 102 | "year = int(input())\n", 103 | "print(is_leap(year))" 104 | ] 105 | } 106 | ], 107 | "metadata": { 108 | "kernelspec": { 109 | "display_name": "Python 3", 110 | "language": "python", 111 | "name": "python3" 112 | }, 113 | "language_info": { 114 | "codemirror_mode": { 115 | "name": "ipython", 116 | "version": 3 117 | }, 118 | "file_extension": ".py", 119 | "mimetype": "text/x-python", 120 | "name": "python", 121 | "nbconvert_exporter": "python", 122 | "pygments_lexer": "ipython3", 123 | "version": "3.11.2" 124 | }, 125 | "orig_nbformat": 4 126 | }, 127 | "nbformat": 4, 128 | "nbformat_minor": 2 129 | } 130 | -------------------------------------------------------------------------------- /chatterbot/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | ChatterBot is a machine learning, conversational dialog engine. 3 | """ 4 | from .chatterbot import ChatBot 5 | 6 | 7 | __all__ = ( 8 | 'ChatBot', 9 | ) 10 | -------------------------------------------------------------------------------- /chatterbot/__main__.py: -------------------------------------------------------------------------------- 1 | import configparser 2 | import sys 3 | import os 4 | 5 | 6 | def get_chatterbot_version(): 7 | config = configparser.ConfigParser() 8 | 9 | current_directory = os.path.dirname(os.path.abspath(__file__)) 10 | parent_directory = os.path.abspath(os.path.join(current_directory, os.pardir)) 11 | config_file_path = os.path.join(parent_directory, 'setup.cfg') 12 | 13 | config.read(config_file_path) 14 | 15 | return config['chatterbot']['version'] 16 | 17 | 18 | if __name__ == '__main__': 19 | if '--version' in sys.argv: 20 | print(get_chatterbot_version()) 21 | -------------------------------------------------------------------------------- /chatterbot/adapters.py: -------------------------------------------------------------------------------- 1 | class Adapter(object): 2 | """ 3 | A superclass for all adapter classes. 4 | 5 | :param chatbot: A ChatBot instance. 6 | """ 7 | 8 | def __init__(self, chatbot, **kwargs): 9 | self.chatbot = chatbot 10 | 11 | class AdapterMethodNotImplementedError(NotImplementedError): 12 | """ 13 | An exception to be raised when an adapter method has not been implemented. 14 | Typically this indicates that the developer is expected to implement the 15 | method in a subclass. 16 | """ 17 | 18 | def __init__(self, message='This method must be overridden in a subclass method.'): 19 | """ 20 | Set the message for the exception. 21 | """ 22 | super().__init__(message) 23 | 24 | class InvalidAdapterTypeException(Exception): 25 | """ 26 | An exception to be raised when an adapter 27 | of an unexpected class type is received. 28 | """ 29 | pass 30 | -------------------------------------------------------------------------------- /chatterbot/chatterbot.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from chatterbot.storage import StorageAdapter 3 | from chatterbot.logic import LogicAdapter 4 | from chatterbot.search import TextSearch, IndexedTextSearch 5 | from chatterbot import utils 6 | 7 | 8 | class ChatBot(object): 9 | """ 10 | A conversational dialog chat bot. 11 | """ 12 | 13 | def __init__(self, name, **kwargs): 14 | self.name = name 15 | 16 | storage_adapter = kwargs.get('storage_adapter', 'chatterbot.storage.SQLStorageAdapter') 17 | 18 | logic_adapters = kwargs.get('logic_adapters', [ 19 | 'chatterbot.logic.BestMatch' 20 | ]) 21 | 22 | # Check that each adapter is a valid subclass of it's respective parent 23 | utils.validate_adapter_class(storage_adapter, StorageAdapter) 24 | 25 | # Logic adapters used by the chat bot 26 | self.logic_adapters = [] 27 | 28 | self.storage = utils.initialize_class(storage_adapter, **kwargs) 29 | 30 | primary_search_algorithm = IndexedTextSearch(self, **kwargs) 31 | text_search_algorithm = TextSearch(self, **kwargs) 32 | 33 | self.search_algorithms = { 34 | primary_search_algorithm.name: primary_search_algorithm, 35 | text_search_algorithm.name: text_search_algorithm 36 | } 37 | 38 | for adapter in logic_adapters: 39 | utils.validate_adapter_class(adapter, LogicAdapter) 40 | logic_adapter = utils.initialize_class(adapter, self, **kwargs) 41 | self.logic_adapters.append(logic_adapter) 42 | 43 | preprocessors = kwargs.get( 44 | 'preprocessors', [ 45 | 'chatterbot.preprocessors.clean_whitespace' 46 | ] 47 | ) 48 | 49 | self.preprocessors = [] 50 | 51 | for preprocessor in preprocessors: 52 | self.preprocessors.append(utils.import_module(preprocessor)) 53 | 54 | self.logger = kwargs.get('logger', logging.getLogger(__name__)) 55 | 56 | # Allow the bot to save input it receives so that it can learn 57 | self.read_only = kwargs.get('read_only', False) 58 | 59 | def get_response(self, statement=None, **kwargs): 60 | """ 61 | Return the bot's response based on the input. 62 | 63 | :param statement: An statement object or string. 64 | :returns: A response to the input. 65 | :rtype: Statement 66 | 67 | :param additional_response_selection_parameters: Parameters to pass to the 68 | chat bot's logic adapters to control response selection. 69 | :type additional_response_selection_parameters: dict 70 | 71 | :param persist_values_to_response: Values that should be saved to the response 72 | that the chat bot generates. 73 | :type persist_values_to_response: dict 74 | """ 75 | Statement = self.storage.get_object('statement') 76 | 77 | additional_response_selection_parameters = kwargs.pop('additional_response_selection_parameters', {}) 78 | 79 | persist_values_to_response = kwargs.pop('persist_values_to_response', {}) 80 | 81 | if isinstance(statement, str): 82 | kwargs['text'] = statement 83 | 84 | if isinstance(statement, dict): 85 | kwargs.update(statement) 86 | 87 | if statement is None and 'text' not in kwargs: 88 | raise self.ChatBotException( 89 | 'Either a statement object or a "text" keyword ' 90 | 'argument is required. Neither was provided.' 91 | ) 92 | 93 | if hasattr(statement, 'serialize'): 94 | kwargs.update(**statement.serialize()) 95 | 96 | tags = kwargs.pop('tags', []) 97 | 98 | text = kwargs.pop('text') 99 | 100 | input_statement = Statement(text=text, **kwargs) 101 | 102 | input_statement.add_tags(*tags) 103 | 104 | # Preprocess the input statement 105 | for preprocessor in self.preprocessors: 106 | input_statement = preprocessor(input_statement) 107 | 108 | # Make sure the input statement has its search text saved 109 | 110 | if not input_statement.search_text: 111 | input_statement.search_text = self.storage.tagger.get_text_index_string(input_statement.text) 112 | 113 | if not input_statement.search_in_response_to and input_statement.in_response_to: 114 | input_statement.search_in_response_to = self.storage.tagger.get_text_index_string(input_statement.in_response_to) 115 | 116 | response = self.generate_response(input_statement, additional_response_selection_parameters) 117 | 118 | # Update any response data that needs to be changed 119 | if persist_values_to_response: 120 | for response_key in persist_values_to_response: 121 | response_value = persist_values_to_response[response_key] 122 | if response_key == 'tags': 123 | input_statement.add_tags(*response_value) 124 | response.add_tags(*response_value) 125 | else: 126 | setattr(input_statement, response_key, response_value) 127 | setattr(response, response_key, response_value) 128 | 129 | if not self.read_only: 130 | self.learn_response(input_statement) 131 | 132 | # Save the response generated for the input 133 | self.storage.create(**response.serialize()) 134 | 135 | return response 136 | 137 | def generate_response(self, input_statement, additional_response_selection_parameters=None): 138 | """ 139 | Return a response based on a given input statement. 140 | 141 | :param input_statement: The input statement to be processed. 142 | """ 143 | Statement = self.storage.get_object('statement') 144 | 145 | results = [] 146 | result = None 147 | max_confidence = -1 148 | 149 | for adapter in self.logic_adapters: 150 | if adapter.can_process(input_statement): 151 | 152 | output = adapter.process(input_statement, additional_response_selection_parameters) 153 | results.append(output) 154 | 155 | self.logger.info( 156 | '{} selected "{}" as a response with a confidence of {}'.format( 157 | adapter.class_name, output.text, output.confidence 158 | ) 159 | ) 160 | 161 | if output.confidence > max_confidence: 162 | result = output 163 | max_confidence = output.confidence 164 | else: 165 | self.logger.info( 166 | 'Not processing the statement using {}'.format(adapter.class_name) 167 | ) 168 | 169 | class ResultOption: 170 | def __init__(self, statement, count=1): 171 | self.statement = statement 172 | self.count = count 173 | 174 | # If multiple adapters agree on the same statement, 175 | # then that statement is more likely to be the correct response 176 | if len(results) >= 3: 177 | result_options = {} 178 | for result_option in results: 179 | result_string = result_option.text + ':' + (result_option.in_response_to or '') 180 | 181 | if result_string in result_options: 182 | result_options[result_string].count += 1 183 | if result_options[result_string].statement.confidence < result_option.confidence: 184 | result_options[result_string].statement = result_option 185 | else: 186 | result_options[result_string] = ResultOption( 187 | result_option 188 | ) 189 | 190 | most_common = list(result_options.values())[0] 191 | 192 | for result_option in result_options.values(): 193 | if result_option.count > most_common.count: 194 | most_common = result_option 195 | 196 | if most_common.count > 1: 197 | result = most_common.statement 198 | 199 | response = Statement( 200 | text=result.text, 201 | in_response_to=input_statement.text, 202 | conversation=input_statement.conversation, 203 | persona='bot:' + self.name 204 | ) 205 | 206 | response.confidence = result.confidence 207 | 208 | return response 209 | 210 | def learn_response(self, statement, previous_statement=None): 211 | """ 212 | Learn that the statement provided is a valid response. 213 | """ 214 | if not previous_statement: 215 | previous_statement = statement.in_response_to 216 | 217 | if not previous_statement: 218 | previous_statement = self.get_latest_response(statement.conversation) 219 | if previous_statement: 220 | previous_statement = previous_statement.text 221 | 222 | previous_statement_text = previous_statement 223 | 224 | if not isinstance(previous_statement, (str, type(None), )): 225 | statement.in_response_to = previous_statement.text 226 | elif isinstance(previous_statement, str): 227 | statement.in_response_to = previous_statement 228 | 229 | self.logger.info('Adding "{}" as a response to "{}"'.format( 230 | statement.text, 231 | previous_statement_text 232 | )) 233 | 234 | # Save the input statement 235 | return self.storage.create(**statement.serialize()) 236 | 237 | def get_latest_response(self, conversation): 238 | """ 239 | Returns the latest response in a conversation if it exists. 240 | Returns None if a matching conversation cannot be found. 241 | """ 242 | from chatterbot.conversation import Statement as StatementObject 243 | 244 | conversation_statements = list(self.storage.filter( 245 | conversation=conversation, 246 | order_by=['id'] 247 | )) 248 | 249 | # Get the most recent statement in the conversation if one exists 250 | latest_statement = conversation_statements[-1] if conversation_statements else None 251 | 252 | if latest_statement: 253 | if latest_statement.in_response_to: 254 | 255 | response_statements = list(self.storage.filter( 256 | conversation=conversation, 257 | text=latest_statement.in_response_to, 258 | order_by=['id'] 259 | )) 260 | 261 | if response_statements: 262 | return response_statements[-1] 263 | else: 264 | return StatementObject( 265 | text=latest_statement.in_response_to, 266 | conversation=conversation 267 | ) 268 | else: 269 | # The case that the latest statement is not in response to another statement 270 | return latest_statement 271 | 272 | return None 273 | 274 | class ChatBotException(Exception): 275 | pass 276 | -------------------------------------------------------------------------------- /chatterbot/comparisons.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module contains various text-comparison algorithms 3 | designed to compare one statement to another. 4 | """ 5 | from chatterbot.exceptions import OptionalDependencyImportError 6 | from difflib import SequenceMatcher 7 | 8 | 9 | class Comparator: 10 | 11 | def __init__(self, language): 12 | 13 | self.language = language 14 | 15 | def __call__(self, statement_a, statement_b): 16 | return self.compare(statement_a, statement_b) 17 | 18 | def compare(self, statement_a, statement_b): 19 | return 0 20 | 21 | 22 | class LevenshteinDistance(Comparator): 23 | """ 24 | Compare two statements based on the Levenshtein distance 25 | of each statement's text. 26 | 27 | For example, there is a 65% similarity between the statements 28 | "where is the post office?" and "looking for the post office" 29 | based on the Levenshtein distance algorithm. 30 | """ 31 | 32 | def compare(self, statement_a, statement_b): 33 | """ 34 | Compare the two input statements. 35 | 36 | :return: The percent of similarity between the text of the statements. 37 | :rtype: float 38 | """ 39 | 40 | # Return 0 if either statement has a falsy text value 41 | if not statement_a.text or not statement_b.text: 42 | return 0 43 | 44 | # Get the lowercase version of both strings 45 | statement_a_text = str(statement_a.text.lower()) 46 | statement_b_text = str(statement_b.text.lower()) 47 | 48 | similarity = SequenceMatcher( 49 | None, 50 | statement_a_text, 51 | statement_b_text 52 | ) 53 | 54 | # Calculate a decimal percent of the similarity 55 | percent = round(similarity.ratio(), 2) 56 | 57 | return percent 58 | 59 | 60 | class SpacySimilarity(Comparator): 61 | """ 62 | Calculate the similarity of two statements using Spacy models. 63 | """ 64 | 65 | def __init__(self, language): 66 | super().__init__(language) 67 | try: 68 | import spacy 69 | except ImportError: 70 | message = ( 71 | 'Unable to import "spacy".\n' 72 | 'Please install "spacy" before using the SpacySimilarity comparator:\n' 73 | 'pip3 install "spacy>=2.1,<2.2"' 74 | ) 75 | raise OptionalDependencyImportError(message) 76 | 77 | self.nlp = spacy.load(self.language.ISO_639_1) 78 | 79 | def compare(self, statement_a, statement_b): 80 | """ 81 | Compare the two input statements. 82 | 83 | :return: The percent of similarity between the closest synset distance. 84 | :rtype: float 85 | """ 86 | document_a = self.nlp(statement_a.text) 87 | document_b = self.nlp(statement_b.text) 88 | 89 | return document_a.similarity(document_b) 90 | 91 | 92 | class JaccardSimilarity(Comparator): 93 | """ 94 | Calculates the similarity of two statements based on the Jaccard index. 95 | 96 | The Jaccard index is composed of a numerator and denominator. 97 | In the numerator, we count the number of items that are shared between the sets. 98 | In the denominator, we count the total number of items across both sets. 99 | Let's say we define sentences to be equivalent if 50% or more of their tokens are equivalent. 100 | Here are two sample sentences: 101 | 102 | The young cat is hungry. 103 | The cat is very hungry. 104 | 105 | When we parse these sentences to remove stopwords, we end up with the following two sets: 106 | 107 | {young, cat, hungry} 108 | {cat, very, hungry} 109 | 110 | In our example above, our intersection is {cat, hungry}, which has count of two. 111 | The union of the sets is {young, cat, very, hungry}, which has a count of four. 112 | Therefore, our `Jaccard similarity index`_ is two divided by four, or 50%. 113 | Given our similarity threshold above, we would consider this to be a match. 114 | 115 | .. _`Jaccard similarity index`: https://en.wikipedia.org/wiki/Jaccard_index 116 | """ 117 | 118 | def __init__(self, language): 119 | super().__init__(language) 120 | try: 121 | import spacy 122 | except ImportError: 123 | message = ( 124 | 'Unable to import "spacy".\n' 125 | 'Please install "spacy" before using the JaccardSimilarity comparator:\n' 126 | 'pip3 install "spacy>=2.1,<2.2"' 127 | ) 128 | raise OptionalDependencyImportError(message) 129 | 130 | self.nlp = spacy.load(self.language.ISO_639_1) 131 | 132 | def compare(self, statement_a, statement_b): 133 | """ 134 | Return the calculated similarity of two 135 | statements based on the Jaccard index. 136 | """ 137 | # Make both strings lowercase 138 | document_a = self.nlp(statement_a.text.lower()) 139 | document_b = self.nlp(statement_b.text.lower()) 140 | 141 | statement_a_lemmas = set([ 142 | token.lemma_ for token in document_a if not token.is_stop 143 | ]) 144 | statement_b_lemmas = set([ 145 | token.lemma_ for token in document_b if not token.is_stop 146 | ]) 147 | 148 | # Calculate Jaccard similarity 149 | numerator = len(statement_a_lemmas.intersection(statement_b_lemmas)) 150 | denominator = float(len(statement_a_lemmas.union(statement_b_lemmas))) 151 | ratio = numerator / denominator 152 | 153 | return ratio 154 | -------------------------------------------------------------------------------- /chatterbot/constants.py: -------------------------------------------------------------------------------- 1 | """ 2 | ChatterBot constants 3 | """ 4 | 5 | ''' 6 | The maximum length of characters that the text of a statement can contain. 7 | The number 255 is used because that is the maximum length of a char field 8 | in most databases. This value should be enforced on a per-model basis by 9 | the data model for each storage adapter. 10 | ''' 11 | STATEMENT_TEXT_MAX_LENGTH = 255 12 | 13 | ''' 14 | The maximum length of characters that the text label of a conversation can contain. 15 | The number 32 was chosen because that is the length of the string representation 16 | of a UUID4 with no hyphens. 17 | ''' 18 | CONVERSATION_LABEL_MAX_LENGTH = 32 19 | 20 | ''' 21 | The maximum length of text that can be stored in the persona field of the statement model. 22 | ''' 23 | PERSONA_MAX_LENGTH = 50 24 | 25 | # The maximum length of characters that the name of a tag can contain 26 | TAG_NAME_MAX_LENGTH = 50 27 | 28 | DEFAULT_DJANGO_APP_NAME = 'django_chatterbot' 29 | -------------------------------------------------------------------------------- /chatterbot/conversation.py: -------------------------------------------------------------------------------- 1 | from pytz import UTC 2 | from datetime import datetime 3 | from dateutil import parser as date_parser 4 | 5 | 6 | class StatementMixin(object): 7 | """ 8 | This class has shared methods used to 9 | normalize different statement models. 10 | """ 11 | 12 | statement_field_names = [ 13 | 'id', 14 | 'text', 15 | 'search_text', 16 | 'conversation', 17 | 'persona', 18 | 'tags', 19 | 'in_response_to', 20 | 'search_in_response_to', 21 | 'created_at', 22 | ] 23 | 24 | extra_statement_field_names = [] 25 | 26 | def get_statement_field_names(self): 27 | """ 28 | Return the list of field names for the statement. 29 | """ 30 | return self.statement_field_names + self.extra_statement_field_names 31 | 32 | def get_tags(self): 33 | """ 34 | Return the list of tags for this statement. 35 | """ 36 | return self.tags 37 | 38 | def add_tags(self, *tags): 39 | """ 40 | Add a list of strings to the statement as tags. 41 | """ 42 | self.tags.extend(tags) 43 | 44 | def serialize(self): 45 | """ 46 | :returns: A dictionary representation of the statement object. 47 | :rtype: dict 48 | """ 49 | data = {} 50 | 51 | for field_name in self.get_statement_field_names(): 52 | format_method = getattr(self, 'get_{}'.format( 53 | field_name 54 | ), None) 55 | 56 | if format_method: 57 | data[field_name] = format_method() 58 | else: 59 | data[field_name] = getattr(self, field_name) 60 | 61 | return data 62 | 63 | 64 | class Statement(StatementMixin): 65 | """ 66 | A statement represents a single spoken entity, sentence or 67 | phrase that someone can say. 68 | """ 69 | 70 | __slots__ = ( 71 | 'id', 72 | 'text', 73 | 'search_text', 74 | 'conversation', 75 | 'persona', 76 | 'tags', 77 | 'in_response_to', 78 | 'search_in_response_to', 79 | 'created_at', 80 | 'confidence', 81 | 'storage', 82 | ) 83 | 84 | def __init__(self, text, in_response_to=None, **kwargs): 85 | 86 | self.id = kwargs.get('id') 87 | self.text = str(text) 88 | self.search_text = kwargs.get('search_text', '') 89 | self.conversation = kwargs.get('conversation', '') 90 | self.persona = kwargs.get('persona', '') 91 | self.tags = kwargs.pop('tags', []) 92 | self.in_response_to = in_response_to 93 | self.search_in_response_to = kwargs.get('search_in_response_to', '') 94 | self.created_at = kwargs.get('created_at', datetime.now()) 95 | 96 | if not isinstance(self.created_at, datetime): 97 | self.created_at = date_parser.parse(self.created_at) 98 | 99 | # Set timezone to UTC if no timezone was provided 100 | if not self.created_at.tzinfo: 101 | self.created_at = self.created_at.replace(tzinfo=UTC) 102 | 103 | # This is the confidence with which the chat bot believes 104 | # this is an accurate response. This value is set when the 105 | # statement is returned by the chat bot. 106 | self.confidence = 0 107 | 108 | self.storage = None 109 | 110 | def __str__(self): 111 | return self.text 112 | 113 | def __repr__(self): 114 | return '' % (self.text) 115 | 116 | def save(self): 117 | """ 118 | Save the statement in the database. 119 | """ 120 | self.storage.update(self) 121 | -------------------------------------------------------------------------------- /chatterbot/corpus.py: -------------------------------------------------------------------------------- 1 | import os 2 | import io 3 | import glob 4 | from pathlib import Path 5 | from chatterbot.exceptions import OptionalDependencyImportError 6 | 7 | try: 8 | from chatterbot_corpus.corpus import DATA_DIRECTORY 9 | except (ImportError, ModuleNotFoundError): 10 | # Default to the home directory of the current user 11 | DATA_DIRECTORY = os.path.join( 12 | Path.home(), 13 | 'chatterbot_corpus', 14 | 'data' 15 | ) 16 | 17 | 18 | CORPUS_EXTENSION = 'yml' 19 | 20 | 21 | def get_file_path(dotted_path, extension='json'): 22 | """ 23 | Reads a dotted file path and returns the file path. 24 | """ 25 | # If the operating system's file path seperator character is in the string 26 | if os.sep in dotted_path or '/' in dotted_path: 27 | # Assume the path is a valid file path 28 | return dotted_path 29 | 30 | parts = dotted_path.split('.') 31 | if parts[0] == 'chatterbot': 32 | parts.pop(0) 33 | parts[0] = DATA_DIRECTORY 34 | 35 | corpus_path = os.path.join(*parts) 36 | 37 | path_with_extension = '{}.{}'.format(corpus_path, extension) 38 | if os.path.exists(path_with_extension): 39 | corpus_path = path_with_extension 40 | 41 | return corpus_path 42 | 43 | 44 | def read_corpus(file_name): 45 | """ 46 | Read and return the data from a corpus json file. 47 | """ 48 | try: 49 | import yaml 50 | except ImportError: 51 | message = ( 52 | 'Unable to import "yaml".\n' 53 | 'Please install "pyyaml" to enable chatterbot corpus functionality:\n' 54 | 'pip3 install pyyaml' 55 | ) 56 | raise OptionalDependencyImportError(message) 57 | 58 | with io.open(file_name, encoding='utf-8') as data_file: 59 | return yaml.safe_load(data_file) 60 | 61 | 62 | def list_corpus_files(dotted_path): 63 | """ 64 | Return a list of file paths to each data file in the specified corpus. 65 | """ 66 | corpus_path = get_file_path(dotted_path, extension=CORPUS_EXTENSION) 67 | paths = [] 68 | 69 | if os.path.isdir(corpus_path): 70 | paths = glob.glob(corpus_path + '/**/*.' + CORPUS_EXTENSION, recursive=True) 71 | else: 72 | paths.append(corpus_path) 73 | 74 | paths.sort() 75 | return paths 76 | 77 | 78 | def load_corpus(*data_file_paths): 79 | """ 80 | Return the data contained within a specified corpus. 81 | """ 82 | for file_path in data_file_paths: 83 | corpus = [] 84 | corpus_data = read_corpus(file_path) 85 | 86 | conversations = corpus_data.get('conversations', []) 87 | corpus.extend(conversations) 88 | 89 | categories = corpus_data.get('categories', []) 90 | 91 | yield corpus, categories, file_path 92 | -------------------------------------------------------------------------------- /chatterbot/exceptions.py: -------------------------------------------------------------------------------- 1 | class OptionalDependencyImportError(ImportError): 2 | """ 3 | An exception raised when a feature requires an optional dependency to be installed. 4 | """ 5 | pass 6 | -------------------------------------------------------------------------------- /chatterbot/ext/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/chatterbot/ext/__init__.py -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = ( 2 | 'chatterbot.ext.django_chatterbot.apps.DjangoChatterBotConfig' 3 | ) 4 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/abstract_models.py: -------------------------------------------------------------------------------- 1 | from chatterbot.conversation import StatementMixin 2 | from chatterbot import constants 3 | from django.db import models 4 | from django.utils import timezone 5 | from django.conf import settings 6 | 7 | 8 | DJANGO_APP_NAME = constants.DEFAULT_DJANGO_APP_NAME 9 | STATEMENT_MODEL = 'Statement' 10 | TAG_MODEL = 'Tag' 11 | 12 | if hasattr(settings, 'CHATTERBOT'): 13 | """ 14 | Allow related models to be overridden in the project settings. 15 | Default to the original settings if one is not defined. 16 | """ 17 | DJANGO_APP_NAME = settings.CHATTERBOT.get( 18 | 'django_app_name', 19 | DJANGO_APP_NAME 20 | ) 21 | STATEMENT_MODEL = settings.CHATTERBOT.get( 22 | 'statement_model', 23 | STATEMENT_MODEL 24 | ) 25 | 26 | 27 | class AbstractBaseTag(models.Model): 28 | """ 29 | The abstract base tag allows other models to be created 30 | using the attributes that exist on the default models. 31 | """ 32 | 33 | name = models.SlugField( 34 | max_length=constants.TAG_NAME_MAX_LENGTH, 35 | unique=True 36 | ) 37 | 38 | class Meta: 39 | abstract = True 40 | 41 | def __str__(self): 42 | return self.name 43 | 44 | 45 | class AbstractBaseStatement(models.Model, StatementMixin): 46 | """ 47 | The abstract base statement allows other models to be created 48 | using the attributes that exist on the default models. 49 | """ 50 | 51 | text = models.CharField( 52 | max_length=constants.STATEMENT_TEXT_MAX_LENGTH 53 | ) 54 | 55 | search_text = models.CharField( 56 | max_length=constants.STATEMENT_TEXT_MAX_LENGTH, 57 | blank=True 58 | ) 59 | 60 | conversation = models.CharField( 61 | max_length=constants.CONVERSATION_LABEL_MAX_LENGTH 62 | ) 63 | 64 | created_at = models.DateTimeField( 65 | default=timezone.now, 66 | help_text='The date and time that the statement was created at.' 67 | ) 68 | 69 | in_response_to = models.CharField( 70 | max_length=constants.STATEMENT_TEXT_MAX_LENGTH, 71 | null=True 72 | ) 73 | 74 | search_in_response_to = models.CharField( 75 | max_length=constants.STATEMENT_TEXT_MAX_LENGTH, 76 | blank=True 77 | ) 78 | 79 | persona = models.CharField( 80 | max_length=constants.PERSONA_MAX_LENGTH 81 | ) 82 | 83 | tags = models.ManyToManyField( 84 | TAG_MODEL, 85 | related_name='statements' 86 | ) 87 | 88 | # This is the confidence with which the chat bot believes 89 | # this is an accurate response. This value is set when the 90 | # statement is returned by the chat bot. 91 | confidence = 0 92 | 93 | class Meta: 94 | abstract = True 95 | 96 | def __str__(self): 97 | if len(self.text.strip()) > 60: 98 | return '{}...'.format(self.text[:57]) 99 | elif len(self.text.strip()) > 0: 100 | return self.text 101 | return '' 102 | 103 | def get_tags(self): 104 | """ 105 | Return the list of tags for this statement. 106 | (Overrides the method from StatementMixin) 107 | """ 108 | return list(self.tags.values_list('name', flat=True)) 109 | 110 | def add_tags(self, *tags): 111 | """ 112 | Add a list of strings to the statement as tags. 113 | (Overrides the method from StatementMixin) 114 | """ 115 | for _tag in tags: 116 | self.tags.get_or_create(name=_tag) 117 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from chatterbot.ext.django_chatterbot.model_admin import StatementAdmin, TagAdmin 3 | from chatterbot.ext.django_chatterbot.models import Statement, Tag 4 | 5 | 6 | admin.site.register(Statement, StatementAdmin) 7 | admin.site.register(Tag, TagAdmin) 8 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class DjangoChatterBotConfig(AppConfig): 5 | 6 | name = 'chatterbot.ext.django_chatterbot' 7 | label = 'django_chatterbot' 8 | verbose_name = 'Django ChatterBot' 9 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | from django.db import migrations, models 2 | import django.db.models.deletion 3 | 4 | 5 | class Migration(migrations.Migration): 6 | 7 | initial = True 8 | 9 | dependencies = [] 10 | 11 | operations = [ 12 | migrations.CreateModel( 13 | name='Response', 14 | fields=[ 15 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 16 | ('occurrence', models.PositiveIntegerField(default=0)), 17 | ], 18 | ), 19 | migrations.CreateModel( 20 | name='Statement', 21 | fields=[ 22 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 23 | ('text', models.CharField(max_length=255, unique=True)), 24 | ], 25 | ), 26 | migrations.AddField( 27 | model_name='response', 28 | name='response', 29 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='django_chatterbot.Statement'), 30 | ), 31 | migrations.AddField( 32 | model_name='response', 33 | name='statement', 34 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='in_response_to', to='django_chatterbot.Statement'), 35 | ), 36 | ] 37 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0002_statement_extra_data.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 1.10.2 on 2016-10-30 12:13 2 | from django.db import migrations, models 3 | 4 | 5 | class Migration(migrations.Migration): 6 | 7 | dependencies = [ 8 | ('django_chatterbot', '0001_initial'), 9 | ] 10 | 11 | operations = [ 12 | migrations.AddField( 13 | model_name='statement', 14 | name='extra_data', 15 | field=models.CharField(default='{}', max_length=500), 16 | preserve_default=False, 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0003_change_occurrence_default.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 1.9 on 2016-12-12 00:06 2 | from django.db import migrations, models 3 | 4 | 5 | class Migration(migrations.Migration): 6 | 7 | dependencies = [ 8 | ('django_chatterbot', '0002_statement_extra_data'), 9 | ] 10 | 11 | operations = [ 12 | migrations.AlterField( 13 | model_name='response', 14 | name='occurrence', 15 | field=models.PositiveIntegerField(default=1), 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0004_rename_in_response_to.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 1.10.3 on 2016-12-04 23:52 2 | from django.db import migrations, models 3 | import django.db.models.deletion 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('django_chatterbot', '0003_change_occurrence_default'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='response', 15 | name='statement', 16 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='in_response', to='django_chatterbot.Statement'), 17 | ), 18 | migrations.AlterField( 19 | model_name='response', 20 | name='response', 21 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='responses', to='django_chatterbot.Statement'), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0005_statement_created_at.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 1.10.1 on 2016-12-29 19:20 2 | from django.db import migrations, models 3 | import django.utils.timezone 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('django_chatterbot', '0004_rename_in_response_to'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='statement', 15 | name='created_at', 16 | field=models.DateTimeField( 17 | default=django.utils.timezone.now, 18 | help_text='The date and time that this statement was created at.' 19 | ), 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0006_create_conversation.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 1.9 on 2017-01-17 07:02 2 | from django.db import migrations, models 3 | import django.db.models.deletion 4 | import django.utils.timezone 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('django_chatterbot', '0005_statement_created_at'), 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='Conversation', 16 | fields=[ 17 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 18 | ], 19 | ), 20 | migrations.AlterField( 21 | model_name='statement', 22 | name='created_at', 23 | field=models.DateTimeField(default=django.utils.timezone.now, help_text='The date and time that this statement was created at.'), 24 | ), 25 | migrations.AddField( 26 | model_name='conversation', 27 | name='statements', 28 | field=models.ManyToManyField(help_text='The statements in this conversation.', related_name='conversation', to='django_chatterbot.Statement'), 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0007_response_created_at.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 1.11 on 2017-07-18 00:16 2 | from django.db import migrations, models 3 | import django.utils.timezone 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('django_chatterbot', '0006_create_conversation'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='response', 15 | name='created_at', 16 | field=models.DateTimeField( 17 | default=django.utils.timezone.now, 18 | help_text='The date and time that this response was created at.' 19 | ), 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0008_update_conversations.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 1.11 on 2017-07-18 11:25 2 | from django.db import migrations, models 3 | 4 | 5 | class Migration(migrations.Migration): 6 | 7 | dependencies = [ 8 | ('django_chatterbot', '0007_response_created_at'), 9 | ] 10 | 11 | operations = [ 12 | migrations.RemoveField( 13 | model_name='conversation', 14 | name='statements', 15 | ), 16 | migrations.RemoveField( 17 | model_name='response', 18 | name='occurrence', 19 | ), 20 | migrations.RemoveField( 21 | model_name='statement', 22 | name='created_at', 23 | ), 24 | migrations.AddField( 25 | model_name='conversation', 26 | name='responses', 27 | field=models.ManyToManyField(help_text='The responses in this conversation.', related_name='conversations', to='django_chatterbot.Response'), 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0009_tags.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 1.11a1 on 2017-07-07 00:12 2 | from django.db import migrations, models 3 | 4 | 5 | class Migration(migrations.Migration): 6 | 7 | dependencies = [ 8 | ('django_chatterbot', '0008_update_conversations'), 9 | ] 10 | 11 | operations = [ 12 | migrations.CreateModel( 13 | name='Tag', 14 | fields=[ 15 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 16 | ('name', models.SlugField()), 17 | ], 18 | options={ 19 | 'abstract': False, 20 | }, 21 | ), 22 | migrations.AlterField( 23 | model_name='statement', 24 | name='text', 25 | field=models.CharField(max_length=255, unique=True), 26 | ), 27 | migrations.AddField( 28 | model_name='tag', 29 | name='statements', 30 | field=models.ManyToManyField(related_name='tags', to='django_chatterbot.Statement'), 31 | ), 32 | ] 33 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0010_statement_text.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 1.11.4 on 2017-08-16 00:56 2 | from django.db import migrations, models 3 | 4 | 5 | class Migration(migrations.Migration): 6 | 7 | dependencies = [ 8 | ('django_chatterbot', '0009_tags'), 9 | ] 10 | 11 | operations = [ 12 | migrations.AlterField( 13 | model_name='statement', 14 | name='text', 15 | field=models.CharField(max_length=400, unique=True), 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0011_blank_extra_data.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 1.11.4 on 2017-08-20 13:55 2 | from django.db import migrations, models 3 | 4 | 5 | class Migration(migrations.Migration): 6 | 7 | dependencies = [ 8 | ('django_chatterbot', '0010_statement_text'), 9 | ] 10 | 11 | operations = [ 12 | migrations.AlterField( 13 | model_name='statement', 14 | name='extra_data', 15 | field=models.CharField(blank=True, max_length=500), 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0012_statement_created_at.py: -------------------------------------------------------------------------------- 1 | from django.db import migrations, models 2 | import django.utils.timezone 3 | 4 | 5 | class Migration(migrations.Migration): 6 | 7 | dependencies = [ 8 | ('django_chatterbot', '0011_blank_extra_data'), 9 | ] 10 | 11 | operations = [ 12 | migrations.AddField( 13 | model_name='statement', 14 | name='created_at', 15 | field=models.DateTimeField( 16 | default=django.utils.timezone.now, 17 | help_text='The date and time that the statement was created at.' 18 | ), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0013_change_conversations.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 1.11 on 2018-09-13 01:01 2 | from django.db import migrations, models 3 | 4 | 5 | class Migration(migrations.Migration): 6 | 7 | dependencies = [ 8 | ('django_chatterbot', '0012_statement_created_at'), 9 | ] 10 | 11 | operations = [ 12 | migrations.RemoveField( 13 | model_name='conversation', 14 | name='responses', 15 | ), 16 | migrations.RemoveField( 17 | model_name='response', 18 | name='response', 19 | ), 20 | migrations.RemoveField( 21 | model_name='response', 22 | name='statement', 23 | ), 24 | migrations.AddField( 25 | model_name='statement', 26 | name='conversation', 27 | field=models.CharField(default='default', max_length=32), 28 | preserve_default=False, 29 | ), 30 | migrations.AddField( 31 | model_name='statement', 32 | name='in_response_to', 33 | field=models.CharField(max_length=400, null=True), 34 | ), 35 | migrations.AlterField( 36 | model_name='statement', 37 | name='text', 38 | field=models.CharField(max_length=400), 39 | ), 40 | migrations.DeleteModel( 41 | name='Conversation', 42 | ), 43 | migrations.DeleteModel( 44 | name='Response', 45 | ), 46 | ] 47 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0014_remove_statement_extra_data.py: -------------------------------------------------------------------------------- 1 | from django.db import migrations 2 | 3 | 4 | class Migration(migrations.Migration): 5 | 6 | dependencies = [ 7 | ('django_chatterbot', '0013_change_conversations'), 8 | ] 9 | 10 | operations = [ 11 | migrations.RemoveField( 12 | model_name='statement', 13 | name='extra_data', 14 | ), 15 | ] 16 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0015_statement_persona.py: -------------------------------------------------------------------------------- 1 | from django.db import migrations, models 2 | 3 | 4 | class Migration(migrations.Migration): 5 | 6 | dependencies = [ 7 | ('django_chatterbot', '0014_remove_statement_extra_data'), 8 | ] 9 | 10 | operations = [ 11 | migrations.AddField( 12 | model_name='statement', 13 | name='persona', 14 | field=models.CharField(default='', max_length=50), 15 | preserve_default=False, 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0016_statement_stemmed_text.py: -------------------------------------------------------------------------------- 1 | from django.db import migrations, models 2 | 3 | 4 | class Migration(migrations.Migration): 5 | 6 | dependencies = [ 7 | ('django_chatterbot', '0015_statement_persona'), 8 | ] 9 | 10 | operations = [ 11 | migrations.AddField( 12 | model_name='statement', 13 | name='search_text', 14 | field=models.CharField(blank=True, max_length=400), 15 | ), 16 | migrations.AddField( 17 | model_name='statement', 18 | name='search_in_response_to', 19 | field=models.CharField(blank=True, max_length=400), 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0017_tags_unique.py: -------------------------------------------------------------------------------- 1 | from django.db import migrations, models 2 | 3 | 4 | class Migration(migrations.Migration): 5 | 6 | dependencies = [ 7 | ('django_chatterbot', '0016_statement_stemmed_text'), 8 | ] 9 | 10 | operations = [ 11 | migrations.RemoveField( 12 | model_name='tag', 13 | name='statements', 14 | ), 15 | migrations.AddField( 16 | model_name='statement', 17 | name='tags', 18 | field=models.ManyToManyField( 19 | related_name='statements', 20 | to='django_chatterbot.Tag' 21 | ), 22 | ), 23 | migrations.AlterField( 24 | model_name='tag', 25 | name='name', 26 | field=models.SlugField(unique=True), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/0018_text_max_length.py: -------------------------------------------------------------------------------- 1 | from django.db import migrations, models 2 | 3 | 4 | class Migration(migrations.Migration): 5 | 6 | dependencies = [ 7 | ('django_chatterbot', '0017_tags_unique'), 8 | ] 9 | 10 | operations = [ 11 | migrations.AlterField( 12 | model_name='statement', 13 | name='in_response_to', 14 | field=models.CharField(max_length=255, null=True), 15 | ), 16 | migrations.AlterField( 17 | model_name='statement', 18 | name='search_in_response_to', 19 | field=models.CharField(blank=True, max_length=255), 20 | ), 21 | migrations.AlterField( 22 | model_name='statement', 23 | name='search_text', 24 | field=models.CharField(blank=True, max_length=255), 25 | ), 26 | migrations.AlterField( 27 | model_name='statement', 28 | name='text', 29 | field=models.CharField(max_length=255), 30 | ), 31 | ] 32 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/chatterbot/ext/django_chatterbot/migrations/__init__.py -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/model_admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | 4 | class StatementAdmin(admin.ModelAdmin): 5 | list_display = ('text', 'in_response_to', 'conversation', 'created_at', ) 6 | list_filter = ('text', 'created_at', ) 7 | search_fields = ('text', ) 8 | 9 | 10 | class TagAdmin(admin.ModelAdmin): 11 | list_display = ('name', ) 12 | list_filter = ('name', ) 13 | search_fields = ('name', ) 14 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/models.py: -------------------------------------------------------------------------------- 1 | from chatterbot.ext.django_chatterbot.abstract_models import AbstractBaseStatement, AbstractBaseTag 2 | 3 | 4 | class Statement(AbstractBaseStatement): 5 | """ 6 | A statement represents a single spoken entity, sentence or 7 | phrase that someone can say. 8 | """ 9 | pass 10 | 11 | 12 | class Tag(AbstractBaseTag): 13 | """ 14 | A label that categorizes a statement. 15 | """ 16 | pass 17 | -------------------------------------------------------------------------------- /chatterbot/ext/django_chatterbot/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Default ChatterBot settings for Django. 3 | """ 4 | from django.conf import settings 5 | from chatterbot import constants 6 | 7 | 8 | CHATTERBOT_SETTINGS = getattr(settings, 'CHATTERBOT', {}) 9 | 10 | CHATTERBOT_DEFAULTS = { 11 | 'name': 'ChatterBot', 12 | 'storage_adapter': 'chatterbot.storage.DjangoStorageAdapter', 13 | 'django_app_name': constants.DEFAULT_DJANGO_APP_NAME 14 | } 15 | 16 | CHATTERBOT = CHATTERBOT_DEFAULTS.copy() 17 | CHATTERBOT.update(CHATTERBOT_SETTINGS) 18 | -------------------------------------------------------------------------------- /chatterbot/ext/sqlalchemy_app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/chatterbot/ext/sqlalchemy_app/__init__.py -------------------------------------------------------------------------------- /chatterbot/ext/sqlalchemy_app/models.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import Table, Column, Integer, String, DateTime, ForeignKey 2 | from sqlalchemy.orm import relationship 3 | from sqlalchemy.sql import func 4 | from sqlalchemy.ext.declarative import declared_attr, declarative_base 5 | 6 | from chatterbot.conversation import StatementMixin 7 | from chatterbot import constants 8 | 9 | 10 | class ModelBase(object): 11 | """ 12 | An augmented base class for SqlAlchemy models. 13 | """ 14 | 15 | @declared_attr 16 | def __tablename__(cls): 17 | """ 18 | Return the lowercase class name as the name of the table. 19 | """ 20 | return cls.__name__.lower() 21 | 22 | id = Column( 23 | Integer, 24 | primary_key=True, 25 | autoincrement=True 26 | ) 27 | 28 | 29 | Base = declarative_base(cls=ModelBase) 30 | 31 | 32 | tag_association_table = Table( 33 | 'tag_association', 34 | Base.metadata, 35 | Column('tag_id', Integer, ForeignKey('tag.id')), 36 | Column('statement_id', Integer, ForeignKey('statement.id')) 37 | ) 38 | 39 | 40 | class Tag(Base): 41 | """ 42 | A tag that describes a statement. 43 | """ 44 | 45 | name = Column( 46 | String(constants.TAG_NAME_MAX_LENGTH), 47 | unique=True 48 | ) 49 | 50 | 51 | class Statement(Base, StatementMixin): 52 | """ 53 | A Statement represents a sentence or phrase. 54 | """ 55 | 56 | confidence = 0 57 | 58 | text = Column( 59 | String(constants.STATEMENT_TEXT_MAX_LENGTH) 60 | ) 61 | 62 | search_text = Column( 63 | String(constants.STATEMENT_TEXT_MAX_LENGTH), 64 | nullable=False, 65 | server_default='' 66 | ) 67 | 68 | conversation = Column( 69 | String(constants.CONVERSATION_LABEL_MAX_LENGTH), 70 | nullable=False, 71 | server_default='' 72 | ) 73 | 74 | created_at = Column( 75 | DateTime(timezone=True), 76 | server_default=func.now() 77 | ) 78 | 79 | tags = relationship( 80 | 'Tag', 81 | secondary=lambda: tag_association_table, 82 | backref='statements' 83 | ) 84 | 85 | in_response_to = Column( 86 | String(constants.STATEMENT_TEXT_MAX_LENGTH), 87 | nullable=True 88 | ) 89 | 90 | search_in_response_to = Column( 91 | String(constants.STATEMENT_TEXT_MAX_LENGTH), 92 | nullable=False, 93 | server_default='' 94 | ) 95 | 96 | persona = Column( 97 | String(constants.PERSONA_MAX_LENGTH), 98 | nullable=False, 99 | server_default='' 100 | ) 101 | 102 | def get_tags(self): 103 | """ 104 | Return a list of tags for this statement. 105 | """ 106 | return [tag.name for tag in self.tags] 107 | 108 | def add_tags(self, *tags): 109 | """ 110 | Add a list of strings to the statement as tags. 111 | """ 112 | self.tags.extend([ 113 | Tag(name=tag) for tag in tags 114 | ]) 115 | -------------------------------------------------------------------------------- /chatterbot/filters.py: -------------------------------------------------------------------------------- 1 | def get_recent_repeated_responses(chatbot, conversation, sample=10, threshold=3, quantity=3): 2 | """ 3 | A filter that eliminates possibly repetitive responses to prevent 4 | a chat bot from repeating statements that it has recently said. 5 | """ 6 | from collections import Counter 7 | 8 | # Get the most recent statements from the conversation 9 | conversation_statements = list(chatbot.storage.filter( 10 | conversation=conversation, 11 | order_by=['id'] 12 | ))[sample * -1:] 13 | 14 | text_of_recent_responses = [ 15 | statement.text for statement in conversation_statements 16 | ] 17 | 18 | counter = Counter(text_of_recent_responses) 19 | 20 | # Find the n most common responses from the conversation 21 | most_common = counter.most_common(quantity) 22 | 23 | return [ 24 | counted[0] for counted in most_common 25 | if counted[1] >= threshold 26 | ] 27 | -------------------------------------------------------------------------------- /chatterbot/logic/__init__.py: -------------------------------------------------------------------------------- 1 | from chatterbot.logic.logic_adapter import LogicAdapter 2 | from chatterbot.logic.best_match import BestMatch 3 | from chatterbot.logic.mathematical_evaluation import MathematicalEvaluation 4 | from chatterbot.logic.specific_response import SpecificResponseAdapter 5 | from chatterbot.logic.time_adapter import TimeLogicAdapter 6 | from chatterbot.logic.unit_conversion import UnitConversion 7 | 8 | __all__ = ( 9 | 'LogicAdapter', 10 | 'BestMatch', 11 | 'MathematicalEvaluation', 12 | 'SpecificResponseAdapter', 13 | 'TimeLogicAdapter', 14 | 'UnitConversion', 15 | ) 16 | -------------------------------------------------------------------------------- /chatterbot/logic/best_match.py: -------------------------------------------------------------------------------- 1 | from chatterbot.logic import LogicAdapter 2 | from chatterbot import filters 3 | 4 | 5 | class BestMatch(LogicAdapter): 6 | """ 7 | A logic adapter that returns a response based on known responses to 8 | the closest matches to the input statement. 9 | 10 | :param excluded_words: 11 | The excluded_words parameter allows a list of words to be set that will 12 | prevent the logic adapter from returning statements that have text 13 | containing any of those words. This can be useful for preventing your 14 | chat bot from saying swears when it is being demonstrated in front of 15 | an audience. 16 | Defaults to None 17 | :type excluded_words: list 18 | """ 19 | 20 | def __init__(self, chatbot, **kwargs): 21 | super().__init__(chatbot, **kwargs) 22 | 23 | self.excluded_words = kwargs.get('excluded_words') 24 | 25 | def process(self, input_statement, additional_response_selection_parameters=None): 26 | search_results = self.search_algorithm.search(input_statement) 27 | 28 | # Use the input statement as the closest match if no other results are found 29 | closest_match = next(search_results, input_statement) 30 | 31 | # Search for the closest match to the input statement 32 | for result in search_results: 33 | closest_match = result 34 | 35 | # Stop searching if a match that is close enough is found 36 | if result.confidence >= self.maximum_similarity_threshold: 37 | break 38 | 39 | self.chatbot.logger.info('Using "{}" as a close match to "{}" with a confidence of {}'.format( 40 | closest_match.text, input_statement.text, closest_match.confidence 41 | )) 42 | 43 | recent_repeated_responses = filters.get_recent_repeated_responses( 44 | self.chatbot, 45 | input_statement.conversation 46 | ) 47 | 48 | for index, recent_repeated_response in enumerate(recent_repeated_responses): 49 | self.chatbot.logger.info('{}. Excluding recent repeated response of "{}"'.format( 50 | index, recent_repeated_response 51 | )) 52 | 53 | response_selection_parameters = { 54 | 'search_in_response_to': closest_match.search_text, 55 | 'exclude_text': recent_repeated_responses, 56 | 'exclude_text_words': self.excluded_words 57 | } 58 | 59 | alternate_response_selection_parameters = { 60 | 'search_in_response_to': self.chatbot.storage.tagger.get_text_index_string( 61 | input_statement.text 62 | ), 63 | 'exclude_text': recent_repeated_responses, 64 | 'exclude_text_words': self.excluded_words 65 | } 66 | 67 | if additional_response_selection_parameters: 68 | response_selection_parameters.update(additional_response_selection_parameters) 69 | alternate_response_selection_parameters.update(additional_response_selection_parameters) 70 | 71 | # Get all statements that are in response to the closest match 72 | response_list = list(self.chatbot.storage.filter(**response_selection_parameters)) 73 | 74 | alternate_response_list = [] 75 | 76 | if not response_list: 77 | self.chatbot.logger.info('No responses found. Generating alternate response list.') 78 | alternate_response_list = list(self.chatbot.storage.filter(**alternate_response_selection_parameters)) 79 | 80 | if response_list: 81 | self.chatbot.logger.info( 82 | 'Selecting response from {} optimal responses.'.format( 83 | len(response_list) 84 | ) 85 | ) 86 | 87 | response = self.select_response( 88 | input_statement, 89 | response_list, 90 | self.chatbot.storage 91 | ) 92 | 93 | response.confidence = closest_match.confidence 94 | self.chatbot.logger.info('Response selected. Using "{}"'.format(response.text)) 95 | elif alternate_response_list: 96 | ''' 97 | The case where there was no responses returned for the selected match 98 | but a value exists for the statement the match is in response to. 99 | ''' 100 | self.chatbot.logger.info( 101 | 'Selecting response from {} optimal alternate responses.'.format( 102 | len(alternate_response_list) 103 | ) 104 | ) 105 | response = self.select_response( 106 | input_statement, 107 | alternate_response_list, 108 | self.chatbot.storage 109 | ) 110 | 111 | response.confidence = closest_match.confidence 112 | self.chatbot.logger.info('Alternate response selected. Using "{}"'.format(response.text)) 113 | else: 114 | response = self.get_default_response(input_statement) 115 | 116 | return response 117 | -------------------------------------------------------------------------------- /chatterbot/logic/logic_adapter.py: -------------------------------------------------------------------------------- 1 | from chatterbot.adapters import Adapter 2 | from chatterbot.storage import StorageAdapter 3 | from chatterbot.search import IndexedTextSearch 4 | from chatterbot.conversation import Statement 5 | 6 | 7 | class LogicAdapter(Adapter): 8 | """ 9 | This is an abstract class that represents the interface 10 | that all logic adapters should implement. 11 | 12 | :param search_algorithm_name: The name of the search algorithm that should 13 | be used to search for close matches to the provided input. 14 | Defaults to the value of ``Search.name``. 15 | 16 | :param maximum_similarity_threshold: 17 | The maximum amount of similarity between two statement that is required 18 | before the search process is halted. The search for a matching statement 19 | will continue until a statement with a greater than or equal similarity 20 | is found or the search set is exhausted. 21 | Defaults to 0.95 22 | 23 | :param response_selection_method: 24 | The a response selection method. 25 | Defaults to ``get_first_response`` 26 | :type response_selection_method: collections.abc.Callable 27 | 28 | :param default_response: 29 | The default response returned by this logic adaper 30 | if there is no other possible response to return. 31 | :type default_response: str or list or tuple 32 | """ 33 | 34 | def __init__(self, chatbot, **kwargs): 35 | super().__init__(chatbot, **kwargs) 36 | from chatterbot.response_selection import get_first_response 37 | 38 | self.search_algorithm_name = kwargs.get( 39 | 'search_algorithm_name', 40 | IndexedTextSearch.name 41 | ) 42 | 43 | self.search_algorithm = self.chatbot.search_algorithms[ 44 | self.search_algorithm_name 45 | ] 46 | 47 | self.maximum_similarity_threshold = kwargs.get( 48 | 'maximum_similarity_threshold', 0.95 49 | ) 50 | 51 | # By default, select the first available response 52 | self.select_response = kwargs.get( 53 | 'response_selection_method', 54 | get_first_response 55 | ) 56 | 57 | default_responses = kwargs.get('default_response', []) 58 | 59 | # Convert a single string into a list 60 | if isinstance(default_responses, str): 61 | default_responses = [ 62 | default_responses 63 | ] 64 | 65 | self.default_responses = [ 66 | Statement(text=default) for default in default_responses 67 | ] 68 | 69 | def can_process(self, statement): 70 | """ 71 | A preliminary check that is called to determine if a 72 | logic adapter can process a given statement. By default, 73 | this method returns true but it can be overridden in 74 | child classes as needed. 75 | 76 | :rtype: bool 77 | """ 78 | return True 79 | 80 | def process(self, statement, additional_response_selection_parameters=None): 81 | """ 82 | Override this method and implement your logic for selecting a response to an input statement. 83 | 84 | A confidence value and the selected response statement should be returned. 85 | The confidence value represents a rating of how accurate the logic adapter 86 | expects the selected response to be. Confidence scores are used to select 87 | the best response from multiple logic adapters. 88 | 89 | The confidence value should be a number between 0 and 1 where 0 is the 90 | lowest confidence level and 1 is the highest. 91 | 92 | :param statement: An input statement to be processed by the logic adapter. 93 | :type statement: Statement 94 | 95 | :param additional_response_selection_parameters: Parameters to be used when 96 | filtering results to choose a response from. 97 | :type additional_response_selection_parameters: dict 98 | 99 | :rtype: Statement 100 | """ 101 | raise self.AdapterMethodNotImplementedError() 102 | 103 | def get_default_response(self, input_statement): 104 | """ 105 | This method is called when a logic adapter is unable to generate any 106 | other meaningful response. 107 | """ 108 | from random import choice 109 | 110 | if self.default_responses: 111 | response = choice(self.default_responses) 112 | else: 113 | try: 114 | response = self.chatbot.storage.get_random() 115 | except StorageAdapter.EmptyDatabaseException: 116 | response = input_statement 117 | 118 | self.chatbot.logger.info( 119 | 'No known response to the input was found. Selecting a random response.' 120 | ) 121 | 122 | # Set confidence to zero because a random response is selected 123 | response.confidence = 0 124 | 125 | return response 126 | 127 | @property 128 | def class_name(self): 129 | """ 130 | Return the name of the current logic adapter class. 131 | This is typically used for logging and debugging. 132 | """ 133 | return str(self.__class__.__name__) 134 | -------------------------------------------------------------------------------- /chatterbot/logic/mathematical_evaluation.py: -------------------------------------------------------------------------------- 1 | from chatterbot.logic import LogicAdapter 2 | from chatterbot.conversation import Statement 3 | from chatterbot import languages 4 | 5 | 6 | class MathematicalEvaluation(LogicAdapter): 7 | """ 8 | The MathematicalEvaluation logic adapter parses input to determine 9 | whether the user is asking a question that requires math to be done. 10 | If so, the equation is extracted from the input and returned with 11 | the evaluated result. 12 | 13 | For example: 14 | User: 'What is three plus five?' 15 | Bot: 'Three plus five equals eight' 16 | 17 | :kwargs: 18 | * *language* (``object``) -- 19 | The language is set to ``chatterbot.languages.ENG`` for English by default. 20 | """ 21 | 22 | def __init__(self, chatbot, **kwargs): 23 | super().__init__(chatbot, **kwargs) 24 | 25 | self.language = kwargs.get('language', languages.ENG) 26 | self.cache = {} 27 | 28 | def can_process(self, statement): 29 | """ 30 | Determines whether it is appropriate for this 31 | adapter to respond to the user input. 32 | """ 33 | response = self.process(statement) 34 | self.cache[statement.text] = response 35 | return response.confidence == 1 36 | 37 | def process(self, statement, additional_response_selection_parameters=None): 38 | """ 39 | Takes a statement string. 40 | Returns the equation from the statement with the mathematical terms solved. 41 | """ 42 | from mathparse import mathparse 43 | 44 | input_text = statement.text 45 | 46 | # Use the result cached by the process method if it exists 47 | if input_text in self.cache: 48 | cached_result = self.cache[input_text] 49 | self.cache = {} 50 | return cached_result 51 | 52 | # Getting the mathematical terms within the input statement 53 | expression = mathparse.extract_expression(input_text, language=self.language.ISO_639.upper()) 54 | 55 | response = Statement(text=expression) 56 | 57 | try: 58 | response.text = '{} = {}'.format( 59 | response.text, 60 | mathparse.parse(expression, language=self.language.ISO_639.upper()) 61 | ) 62 | 63 | # The confidence is 1 if the expression could be evaluated 64 | response.confidence = 1 65 | except mathparse.PostfixTokenEvaluationException: 66 | response.confidence = 0 67 | 68 | return response 69 | -------------------------------------------------------------------------------- /chatterbot/logic/specific_response.py: -------------------------------------------------------------------------------- 1 | from chatterbot.logic import LogicAdapter 2 | 3 | 4 | class SpecificResponseAdapter(LogicAdapter): 5 | """ 6 | Return a specific response to a specific input. 7 | 8 | :kwargs: 9 | * *input_text* (``str``) -- 10 | The input text that triggers this logic adapter. 11 | * *output_text* (``str``) -- 12 | The output text returned by this logic adapter. 13 | """ 14 | 15 | def __init__(self, chatbot, **kwargs): 16 | super().__init__(chatbot, **kwargs) 17 | from chatterbot.conversation import Statement 18 | 19 | self.input_text = kwargs.get('input_text') 20 | 21 | output_text = kwargs.get('output_text') 22 | self.response_statement = Statement(text=output_text) 23 | 24 | def can_process(self, statement): 25 | if statement.text == self.input_text: 26 | return True 27 | 28 | return False 29 | 30 | def process(self, statement, additional_response_selection_parameters=None): 31 | 32 | if statement.text == self.input_text: 33 | self.response_statement.confidence = 1 34 | else: 35 | self.response_statement.confidence = 0 36 | 37 | return self.response_statement 38 | -------------------------------------------------------------------------------- /chatterbot/logic/time_adapter.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from chatterbot.logic import LogicAdapter 3 | from chatterbot.conversation import Statement 4 | from chatterbot.exceptions import OptionalDependencyImportError 5 | 6 | 7 | class TimeLogicAdapter(LogicAdapter): 8 | """ 9 | The TimeLogicAdapter returns the current time. 10 | 11 | :kwargs: 12 | * *positive* (``list``) -- 13 | The time-related questions used to identify time questions. 14 | Defaults to a list of English sentences. 15 | * *negative* (``list``) -- 16 | The non-time-related questions used to identify time questions. 17 | Defaults to a list of English sentences. 18 | """ 19 | 20 | def __init__(self, chatbot, **kwargs): 21 | super().__init__(chatbot, **kwargs) 22 | try: 23 | from nltk import NaiveBayesClassifier 24 | except ImportError: 25 | message = ( 26 | 'Unable to import "nltk".\n' 27 | 'Please install "nltk" before using the TimeLogicAdapter:\n' 28 | 'pip3 install nltk' 29 | ) 30 | raise OptionalDependencyImportError(message) 31 | 32 | self.positive = kwargs.get('positive', [ 33 | 'what time is it', 34 | 'hey what time is it', 35 | 'do you have the time', 36 | 'do you know the time', 37 | 'do you know what time it is', 38 | 'what is the time' 39 | ]) 40 | 41 | self.negative = kwargs.get('negative', [ 42 | 'it is time to go to sleep', 43 | 'what is your favorite color', 44 | 'i had a great time', 45 | 'thyme is my favorite herb', 46 | 'do you have time to look at my essay', 47 | 'how do you have the time to do all this' 48 | 'what is it' 49 | ]) 50 | 51 | labeled_data = ( 52 | [ 53 | (name, 0) for name in self.negative 54 | ] + [ 55 | (name, 1) for name in self.positive 56 | ] 57 | ) 58 | 59 | train_set = [ 60 | (self.time_question_features(text), n) for (text, n) in labeled_data 61 | ] 62 | 63 | self.classifier = NaiveBayesClassifier.train(train_set) 64 | 65 | def time_question_features(self, text): 66 | """ 67 | Provide an analysis of significant features in the string. 68 | """ 69 | features = {} 70 | 71 | # A list of all words from the known sentences 72 | all_words = " ".join(self.positive + self.negative).split() 73 | 74 | # A list of the first word in each of the known sentence 75 | all_first_words = [] 76 | for sentence in self.positive + self.negative: 77 | all_first_words.append( 78 | sentence.split(' ', 1)[0] 79 | ) 80 | 81 | for word in text.split(): 82 | features['first_word({})'.format(word)] = (word in all_first_words) 83 | 84 | for word in text.split(): 85 | features['contains({})'.format(word)] = (word in all_words) 86 | 87 | for letter in 'abcdefghijklmnopqrstuvwxyz': 88 | features['count({})'.format(letter)] = text.lower().count(letter) 89 | features['has({})'.format(letter)] = (letter in text.lower()) 90 | 91 | return features 92 | 93 | def process(self, statement, additional_response_selection_parameters=None): 94 | now = datetime.now() 95 | 96 | time_features = self.time_question_features(statement.text.lower()) 97 | confidence = self.classifier.classify(time_features) 98 | response = Statement(text='The current time is ' + now.strftime('%I:%M %p')) 99 | 100 | response.confidence = confidence 101 | return response 102 | -------------------------------------------------------------------------------- /chatterbot/logic/unit_conversion.py: -------------------------------------------------------------------------------- 1 | from chatterbot.logic import LogicAdapter 2 | from chatterbot.conversation import Statement 3 | from chatterbot.exceptions import OptionalDependencyImportError 4 | from chatterbot import languages 5 | from chatterbot import parsing 6 | from mathparse import mathparse 7 | import re 8 | 9 | 10 | class UnitConversion(LogicAdapter): 11 | """ 12 | The UnitConversion logic adapter parse inputs to convert values 13 | between several metric units. 14 | 15 | For example: 16 | User: 'How many meters are in one kilometer?' 17 | Bot: '1000.0' 18 | 19 | :kwargs: 20 | * *language* (``object``) -- 21 | The language is set to ``chatterbot.languages.ENG`` for English by default. 22 | """ 23 | 24 | def __init__(self, chatbot, **kwargs): 25 | super().__init__(chatbot, **kwargs) 26 | try: 27 | from pint import UnitRegistry 28 | except ImportError: 29 | message = ( 30 | 'Unable to import "pint".\n' 31 | 'Please install "pint" before using the UnitConversion logic adapter:\n' 32 | 'pip3 install pint' 33 | ) 34 | raise OptionalDependencyImportError(message) 35 | 36 | self.language = kwargs.get('language', languages.ENG) 37 | self.cache = {} 38 | self.patterns = [ 39 | ( 40 | re.compile(r''' 41 | (([Hh]ow\s+many)\s+ 42 | (?P\S+)\s+ # meter, celsius, hours 43 | ((are)*\s*in)\s+ 44 | (?P([+-]?\d+(?:\.\d+)?)|(a|an)|(%s[-\s]?)+)\s+ 45 | (?P\S+)\s*) # meter, celsius, hours 46 | ''' % (parsing.numbers), 47 | (re.VERBOSE | re.IGNORECASE) 48 | ), 49 | lambda m: self.handle_matches(m) 50 | ), 51 | ( 52 | re.compile(r''' 53 | ((?P([+-]?\d+(?:\.\d+)?)|(%s[-\s]?)+)\s+ 54 | (?P\S+)\s+ # meter, celsius, hours 55 | (to)\s+ 56 | (?P\S+)\s*) # meter, celsius, hours 57 | ''' % (parsing.numbers), 58 | (re.VERBOSE | re.IGNORECASE) 59 | ), 60 | lambda m: self.handle_matches(m) 61 | ), 62 | ( 63 | re.compile(r''' 64 | ((?P([+-]?\d+(?:\.\d+)?)|(a|an)|(%s[-\s]?)+)\s+ 65 | (?P\S+)\s+ # meter, celsius, hours 66 | (is|are)\s+ 67 | (how\s+many)*\s+ 68 | (?P\S+)\s*) # meter, celsius, hours 69 | ''' % (parsing.numbers), 70 | (re.VERBOSE | re.IGNORECASE) 71 | ), 72 | lambda m: self.handle_matches(m) 73 | ) 74 | ] 75 | self.unit_registry = UnitRegistry() 76 | 77 | def get_unit(self, unit_variations): 78 | """ 79 | Get the first match unit metric object supported by pint library 80 | given a variation of unit metric names (Ex:['HOUR', 'hour']). 81 | 82 | :param unit_variations: A list of strings with names of units 83 | :type unit_variations: str 84 | """ 85 | for unit in unit_variations: 86 | try: 87 | return getattr(self.unit_registry, unit) 88 | except Exception: 89 | continue 90 | return None 91 | 92 | def get_valid_units(self, from_unit, target_unit): 93 | """ 94 | Returns the first match `pint.unit.Unit` object for from_unit and 95 | target_unit strings from a possible variation of metric unit names 96 | supported by pint library. 97 | 98 | :param from_unit: source metric unit 99 | :type from_unit: str 100 | 101 | :param from_unit: target metric unit 102 | :type from_unit: str 103 | """ 104 | from_unit_variations = [from_unit.lower(), from_unit.upper()] 105 | target_unit_variations = [target_unit.lower(), target_unit.upper()] 106 | from_unit = self.get_unit(from_unit_variations) 107 | target_unit = self.get_unit(target_unit_variations) 108 | return from_unit, target_unit 109 | 110 | def handle_matches(self, match): 111 | """ 112 | Returns a response statement from a matched input statement. 113 | 114 | :param match: It is a valid matched pattern from the input statement 115 | :type: `_sre.SRE_Match` 116 | """ 117 | response = Statement(text='') 118 | 119 | from_parsed = match.group("from") 120 | target_parsed = match.group("target") 121 | n_statement = match.group("number") 122 | 123 | if n_statement == 'a' or n_statement == 'an': 124 | n_statement = '1.0' 125 | 126 | n = mathparse.parse(n_statement, self.language.ISO_639.upper()) 127 | 128 | from_parsed, target_parsed = self.get_valid_units(from_parsed, target_parsed) 129 | 130 | if from_parsed is None or target_parsed is None: 131 | response.confidence = 0.0 132 | else: 133 | from_value = self.unit_registry.Quantity(float(n), from_parsed) 134 | target_value = from_value.to(target_parsed) 135 | response.confidence = 1.0 136 | response.text = str(target_value.magnitude) 137 | 138 | return response 139 | 140 | def can_process(self, statement): 141 | response = self.process(statement) 142 | self.cache[statement.text] = response 143 | return response.confidence == 1.0 144 | 145 | def process(self, statement, additional_response_selection_parameters=None): 146 | response = Statement(text='') 147 | input_text = statement.text 148 | try: 149 | # Use the result cached by the process method if it exists 150 | if input_text in self.cache: 151 | response = self.cache[input_text] 152 | self.cache = {} 153 | return response 154 | 155 | for pattern, func in self.patterns: 156 | p = pattern.match(input_text) 157 | if p is not None: 158 | response = func(p) 159 | if response.confidence == 1.0: 160 | break 161 | except Exception: 162 | response.confidence = 0.0 163 | finally: 164 | return response 165 | -------------------------------------------------------------------------------- /chatterbot/preprocessors.py: -------------------------------------------------------------------------------- 1 | """ 2 | Statement pre-processors. 3 | """ 4 | 5 | 6 | def clean_whitespace(statement): 7 | """ 8 | Remove any consecutive whitespace characters from the statement text. 9 | """ 10 | import re 11 | 12 | # Replace linebreaks and tabs with spaces 13 | statement.text = statement.text.replace('\n', ' ').replace('\r', ' ').replace('\t', ' ') 14 | 15 | # Remove any leeding or trailing whitespace 16 | statement.text = statement.text.strip() 17 | 18 | # Remove consecutive spaces 19 | statement.text = re.sub(' +', ' ', statement.text) 20 | 21 | return statement 22 | 23 | 24 | def unescape_html(statement): 25 | """ 26 | Convert escaped html characters into unescaped html characters. 27 | For example: "<b>" becomes "". 28 | """ 29 | import html 30 | 31 | statement.text = html.unescape(statement.text) 32 | 33 | return statement 34 | 35 | 36 | def convert_to_ascii(statement): 37 | """ 38 | Converts unicode characters to ASCII character equivalents. 39 | For example: "på fédéral" becomes "pa federal". 40 | """ 41 | import unicodedata 42 | 43 | text = unicodedata.normalize('NFKD', statement.text) 44 | text = text.encode('ascii', 'ignore').decode('utf-8') 45 | 46 | statement.text = str(text) 47 | return statement 48 | -------------------------------------------------------------------------------- /chatterbot/response_selection.py: -------------------------------------------------------------------------------- 1 | """ 2 | Response selection methods determines which response should be used in 3 | the event that multiple responses are generated within a logic adapter. 4 | """ 5 | import logging 6 | 7 | 8 | def get_most_frequent_response(input_statement, response_list, storage=None): 9 | """ 10 | :param input_statement: A statement, that closely matches an input to the chat bot. 11 | :type input_statement: Statement 12 | 13 | :param response_list: A list of statement options to choose a response from. 14 | :type response_list: list 15 | 16 | :param storage: An instance of a storage adapter to allow the response selection 17 | method to access other statements if needed. 18 | :type storage: StorageAdapter 19 | 20 | :return: The response statement with the greatest number of occurrences. 21 | :rtype: Statement 22 | """ 23 | matching_response = None 24 | occurrence_count = -1 25 | 26 | logger = logging.getLogger(__name__) 27 | logger.info('Selecting response with greatest number of occurrences.') 28 | 29 | for statement in response_list: 30 | count = len(list(storage.filter( 31 | text=statement.text, 32 | in_response_to=input_statement.text) 33 | )) 34 | 35 | # Keep the more common statement 36 | if count >= occurrence_count: 37 | matching_response = statement 38 | occurrence_count = count 39 | 40 | # Choose the most commonly occuring matching response 41 | return matching_response 42 | 43 | 44 | def get_first_response(input_statement, response_list, storage=None): 45 | """ 46 | :param input_statement: A statement, that closely matches an input to the chat bot. 47 | :type input_statement: Statement 48 | 49 | :param response_list: A list of statement options to choose a response from. 50 | :type response_list: list 51 | 52 | :param storage: An instance of a storage adapter to allow the response selection 53 | method to access other statements if needed. 54 | :type storage: StorageAdapter 55 | 56 | :return: Return the first statement in the response list. 57 | :rtype: Statement 58 | """ 59 | logger = logging.getLogger(__name__) 60 | logger.info('Selecting first response from list of {} options.'.format( 61 | len(response_list) 62 | )) 63 | return response_list[0] 64 | 65 | 66 | def get_random_response(input_statement, response_list, storage=None): 67 | """ 68 | :param input_statement: A statement, that closely matches an input to the chat bot. 69 | :type input_statement: Statement 70 | 71 | :param response_list: A list of statement options to choose a response from. 72 | :type response_list: list 73 | 74 | :param storage: An instance of a storage adapter to allow the response selection 75 | method to access other statements if needed. 76 | :type storage: StorageAdapter 77 | 78 | :return: Choose a random response from the selection. 79 | :rtype: Statement 80 | """ 81 | from random import choice 82 | logger = logging.getLogger(__name__) 83 | logger.info('Selecting a response from list of {} options.'.format( 84 | len(response_list) 85 | )) 86 | return choice(response_list) 87 | -------------------------------------------------------------------------------- /chatterbot/search.py: -------------------------------------------------------------------------------- 1 | class IndexedTextSearch: 2 | """ 3 | :param statement_comparison_function: A comparison class. 4 | Defaults to ``LevenshteinDistance``. 5 | 6 | :param search_page_size: 7 | The maximum number of records to load into memory at a time when searching. 8 | Defaults to 1000 9 | """ 10 | 11 | name = 'indexed_text_search' 12 | 13 | def __init__(self, chatbot, **kwargs): 14 | from chatterbot.comparisons import LevenshteinDistance 15 | 16 | self.chatbot = chatbot 17 | 18 | statement_comparison_function = kwargs.get( 19 | 'statement_comparison_function', 20 | LevenshteinDistance 21 | ) 22 | 23 | self.compare_statements = statement_comparison_function( 24 | language=self.chatbot.storage.tagger.language 25 | ) 26 | 27 | self.search_page_size = kwargs.get( 28 | 'search_page_size', 1000 29 | ) 30 | 31 | def search(self, input_statement, **additional_parameters): 32 | """ 33 | Search for close matches to the input. Confidence scores for 34 | subsequent results will order of increasing value. 35 | 36 | :param input_statement: A statement. 37 | :type input_statement: chatterbot.conversation.Statement 38 | 39 | :param **additional_parameters: Additional parameters to be passed 40 | to the ``filter`` method of the storage adapter when searching. 41 | 42 | :rtype: Generator yielding one closest matching statement at a time. 43 | """ 44 | self.chatbot.logger.info('Beginning search for close text match') 45 | 46 | input_search_text = input_statement.search_text 47 | 48 | if not input_statement.search_text: 49 | self.chatbot.logger.warn( 50 | 'No value for search_text was available on the provided input' 51 | ) 52 | 53 | input_search_text = self.chatbot.storage.tagger.get_text_index_string( 54 | input_statement.text 55 | ) 56 | 57 | search_parameters = { 58 | 'search_text_contains': input_search_text, 59 | 'persona_not_startswith': 'bot:', 60 | 'page_size': self.search_page_size 61 | } 62 | 63 | if additional_parameters: 64 | search_parameters.update(additional_parameters) 65 | 66 | statement_list = self.chatbot.storage.filter(**search_parameters) 67 | 68 | best_confidence_so_far = 0 69 | 70 | self.chatbot.logger.info('Processing search results') 71 | 72 | # Find the closest matching known statement 73 | for statement in statement_list: 74 | confidence = self.compare_statements(input_statement, statement) 75 | 76 | if confidence > best_confidence_so_far: 77 | best_confidence_so_far = confidence 78 | statement.confidence = confidence 79 | 80 | self.chatbot.logger.info('Similar text found: {} {}'.format( 81 | statement.text, confidence 82 | )) 83 | 84 | yield statement 85 | 86 | 87 | class TextSearch: 88 | """ 89 | :param statement_comparison_function: A comparison class. 90 | Defaults to ``LevenshteinDistance``. 91 | 92 | :param search_page_size: 93 | The maximum number of records to load into memory at a time when searching. 94 | Defaults to 1000 95 | """ 96 | 97 | name = 'text_search' 98 | 99 | def __init__(self, chatbot, **kwargs): 100 | from chatterbot.comparisons import LevenshteinDistance 101 | 102 | self.chatbot = chatbot 103 | 104 | statement_comparison_function = kwargs.get( 105 | 'statement_comparison_function', 106 | LevenshteinDistance 107 | ) 108 | 109 | self.compare_statements = statement_comparison_function( 110 | language=self.chatbot.storage.tagger.language 111 | ) 112 | 113 | self.search_page_size = kwargs.get( 114 | 'search_page_size', 1000 115 | ) 116 | 117 | def search(self, input_statement, **additional_parameters): 118 | """ 119 | Search for close matches to the input. Confidence scores for 120 | subsequent results will order of increasing value. 121 | 122 | :param input_statement: A statement. 123 | :type input_statement: chatterbot.conversation.Statement 124 | 125 | :param **additional_parameters: Additional parameters to be passed 126 | to the ``filter`` method of the storage adapter when searching. 127 | 128 | :rtype: Generator yielding one closest matching statement at a time. 129 | """ 130 | self.chatbot.logger.info('Beginning search for close text match') 131 | 132 | search_parameters = { 133 | 'persona_not_startswith': 'bot:', 134 | 'page_size': self.search_page_size 135 | } 136 | 137 | if additional_parameters: 138 | search_parameters.update(additional_parameters) 139 | 140 | statement_list = self.chatbot.storage.filter(**search_parameters) 141 | 142 | best_confidence_so_far = 0 143 | 144 | self.chatbot.logger.info('Processing search results') 145 | 146 | # Find the closest matching known statement 147 | for statement in statement_list: 148 | confidence = self.compare_statements(input_statement, statement) 149 | 150 | if confidence > best_confidence_so_far: 151 | best_confidence_so_far = confidence 152 | statement.confidence = confidence 153 | 154 | self.chatbot.logger.info('Similar text found: {} {}'.format( 155 | statement.text, confidence 156 | )) 157 | 158 | yield statement 159 | -------------------------------------------------------------------------------- /chatterbot/storage/__init__.py: -------------------------------------------------------------------------------- 1 | from chatterbot.storage.storage_adapter import StorageAdapter 2 | from chatterbot.storage.django_storage import DjangoStorageAdapter 3 | from chatterbot.storage.mongodb import MongoDatabaseAdapter 4 | from chatterbot.storage.sql_storage import SQLStorageAdapter 5 | 6 | 7 | __all__ = ( 8 | 'StorageAdapter', 9 | 'DjangoStorageAdapter', 10 | 'MongoDatabaseAdapter', 11 | 'SQLStorageAdapter', 12 | ) 13 | -------------------------------------------------------------------------------- /chatterbot/storage/django_storage.py: -------------------------------------------------------------------------------- 1 | from chatterbot.storage import StorageAdapter 2 | from chatterbot import constants 3 | 4 | 5 | class DjangoStorageAdapter(StorageAdapter): 6 | """ 7 | Storage adapter that allows ChatterBot to interact with 8 | Django storage backends. 9 | """ 10 | 11 | def __init__(self, **kwargs): 12 | super().__init__(**kwargs) 13 | 14 | self.django_app_name = kwargs.get( 15 | 'django_app_name', 16 | constants.DEFAULT_DJANGO_APP_NAME 17 | ) 18 | 19 | def get_statement_model(self): 20 | from django.apps import apps 21 | return apps.get_model(self.django_app_name, 'Statement') 22 | 23 | def get_tag_model(self): 24 | from django.apps import apps 25 | return apps.get_model(self.django_app_name, 'Tag') 26 | 27 | def count(self): 28 | Statement = self.get_model('statement') 29 | return Statement.objects.count() 30 | 31 | def filter(self, **kwargs): 32 | """ 33 | Returns a list of statements in the database 34 | that match the parameters specified. 35 | """ 36 | from django.db.models import Q 37 | 38 | Statement = self.get_model('statement') 39 | 40 | kwargs.pop('page_size', 1000) 41 | order_by = kwargs.pop('order_by', None) 42 | tags = kwargs.pop('tags', []) 43 | exclude_text = kwargs.pop('exclude_text', None) 44 | exclude_text_words = kwargs.pop('exclude_text_words', []) 45 | persona_not_startswith = kwargs.pop('persona_not_startswith', None) 46 | search_text_contains = kwargs.pop('search_text_contains', None) 47 | 48 | # Convert a single sting into a list if only one tag is provided 49 | if type(tags) == str: 50 | tags = [tags] 51 | 52 | if tags: 53 | kwargs['tags__name__in'] = tags 54 | 55 | statements = Statement.objects.filter(**kwargs) 56 | 57 | if exclude_text: 58 | statements = statements.exclude( 59 | text__in=exclude_text 60 | ) 61 | 62 | if exclude_text_words: 63 | or_query = [ 64 | ~Q(text__icontains=word) for word in exclude_text_words 65 | ] 66 | 67 | statements = statements.filter( 68 | *or_query 69 | ) 70 | 71 | if persona_not_startswith: 72 | statements = statements.exclude( 73 | persona__startswith='bot:' 74 | ) 75 | 76 | if search_text_contains: 77 | or_query = Q() 78 | 79 | for word in search_text_contains.split(' '): 80 | or_query |= Q(search_text__contains=word) 81 | 82 | statements = statements.filter( 83 | or_query 84 | ) 85 | 86 | if order_by: 87 | statements = statements.order_by(*order_by) 88 | 89 | for statement in statements.iterator(): 90 | yield statement 91 | 92 | def create(self, **kwargs): 93 | """ 94 | Creates a new statement matching the keyword arguments specified. 95 | Returns the created statement. 96 | """ 97 | Statement = self.get_model('statement') 98 | Tag = self.get_model('tag') 99 | 100 | tags = kwargs.pop('tags', []) 101 | 102 | if 'search_text' not in kwargs: 103 | kwargs['search_text'] = self.tagger.get_text_index_string(kwargs['text']) 104 | 105 | if 'search_in_response_to' not in kwargs: 106 | if kwargs.get('in_response_to'): 107 | kwargs['search_in_response_to'] = self.tagger.get_text_index_string(kwargs['in_response_to']) 108 | 109 | statement = Statement(**kwargs) 110 | 111 | statement.save() 112 | 113 | tags_to_add = [] 114 | 115 | for _tag in tags: 116 | tag, _ = Tag.objects.get_or_create(name=_tag) 117 | tags_to_add.append(tag) 118 | 119 | statement.tags.add(*tags_to_add) 120 | 121 | return statement 122 | 123 | def create_many(self, statements): 124 | """ 125 | Creates multiple statement entries. 126 | """ 127 | Statement = self.get_model('statement') 128 | Tag = self.get_model('tag') 129 | 130 | tag_cache = {} 131 | 132 | for statement in statements: 133 | 134 | statement_data = statement.serialize() 135 | tag_data = statement_data.pop('tags', []) 136 | 137 | statement_model_object = Statement(**statement_data) 138 | 139 | if not statement.search_text: 140 | statement_model_object.search_text = self.tagger.get_text_index_string(statement.text) 141 | 142 | if not statement.search_in_response_to and statement.in_response_to: 143 | statement_model_object.search_in_response_to = self.tagger.get_text_index_string(statement.in_response_to) 144 | 145 | statement_model_object.save() 146 | 147 | tags_to_add = [] 148 | 149 | for tag_name in tag_data: 150 | if tag_name in tag_cache: 151 | tag = tag_cache[tag_name] 152 | else: 153 | tag, _ = Tag.objects.get_or_create(name=tag_name) 154 | tag_cache[tag_name] = tag 155 | tags_to_add.append(tag) 156 | 157 | statement_model_object.tags.add(*tags_to_add) 158 | 159 | def update(self, statement): 160 | """ 161 | Update the provided statement. 162 | """ 163 | Statement = self.get_model('statement') 164 | Tag = self.get_model('tag') 165 | 166 | if hasattr(statement, 'id'): 167 | statement.save() 168 | else: 169 | statement = Statement.objects.create( 170 | text=statement.text, 171 | search_text=self.tagger.get_text_index_string(statement.text), 172 | conversation=statement.conversation, 173 | in_response_to=statement.in_response_to, 174 | search_in_response_to=self.tagger.get_text_index_string(statement.in_response_to), 175 | created_at=statement.created_at 176 | ) 177 | 178 | for _tag in statement.tags.all(): 179 | tag, _ = Tag.objects.get_or_create(name=_tag) 180 | 181 | statement.tags.add(tag) 182 | 183 | return statement 184 | 185 | def get_random(self): 186 | """ 187 | Returns a random statement from the database 188 | """ 189 | Statement = self.get_model('statement') 190 | 191 | statement = Statement.objects.order_by('?').first() 192 | 193 | if statement is None: 194 | raise self.EmptyDatabaseException() 195 | 196 | return statement 197 | 198 | def remove(self, statement_text): 199 | """ 200 | Removes the statement that matches the input text. 201 | Removes any responses from statements if the response text matches the 202 | input text. 203 | """ 204 | Statement = self.get_model('statement') 205 | 206 | statements = Statement.objects.filter(text=statement_text) 207 | 208 | statements.delete() 209 | 210 | def drop(self): 211 | """ 212 | Remove all data from the database. 213 | """ 214 | Statement = self.get_model('statement') 215 | Tag = self.get_model('tag') 216 | 217 | Statement.objects.all().delete() 218 | Tag.objects.all().delete() 219 | -------------------------------------------------------------------------------- /chatterbot/storage/mongodb.py: -------------------------------------------------------------------------------- 1 | import re 2 | from chatterbot.storage import StorageAdapter 3 | 4 | 5 | class MongoDatabaseAdapter(StorageAdapter): 6 | """ 7 | The MongoDatabaseAdapter is an interface that allows 8 | ChatterBot to store statements in a MongoDB database. 9 | 10 | :keyword database_uri: The URI of a remote instance of MongoDB. 11 | This can be any valid 12 | `MongoDB connection string `_ 13 | :type database_uri: str 14 | 15 | .. code-block:: python 16 | 17 | database_uri='mongodb://example.com:8100/' 18 | """ 19 | 20 | def __init__(self, **kwargs): 21 | super().__init__(**kwargs) 22 | from pymongo import MongoClient 23 | from pymongo.errors import OperationFailure 24 | 25 | self.database_uri = kwargs.get( 26 | 'database_uri', 'mongodb://localhost:27017/chatterbot-database' 27 | ) 28 | 29 | # Use the default host and port 30 | self.client = MongoClient(self.database_uri) 31 | 32 | # Increase the sort buffer to 42M if possible 33 | try: 34 | self.client.admin.command({'setParameter': 1, 'internalQueryExecMaxBlockingSortBytes': 44040192}) 35 | except OperationFailure: 36 | pass 37 | 38 | # Specify the name of the database 39 | self.database = self.client.get_database() 40 | 41 | # The mongo collection of statement documents 42 | self.statements = self.database['statements'] 43 | 44 | def get_statement_model(self): 45 | """ 46 | Return the class for the statement model. 47 | """ 48 | from chatterbot.conversation import Statement 49 | 50 | # Create a storage-aware statement 51 | statement = Statement 52 | statement.storage = self 53 | 54 | return statement 55 | 56 | def count(self): 57 | return self.statements.count() 58 | 59 | def mongo_to_object(self, statement_data): 60 | """ 61 | Return Statement object when given data 62 | returned from Mongo DB. 63 | """ 64 | Statement = self.get_model('statement') 65 | 66 | statement_data['id'] = statement_data['_id'] 67 | 68 | return Statement(**statement_data) 69 | 70 | def filter(self, **kwargs): 71 | """ 72 | Returns a list of statements in the database 73 | that match the parameters specified. 74 | """ 75 | import pymongo 76 | 77 | page_size = kwargs.pop('page_size', 1000) 78 | order_by = kwargs.pop('order_by', None) 79 | tags = kwargs.pop('tags', []) 80 | exclude_text = kwargs.pop('exclude_text', None) 81 | exclude_text_words = kwargs.pop('exclude_text_words', []) 82 | persona_not_startswith = kwargs.pop('persona_not_startswith', None) 83 | search_text_contains = kwargs.pop('search_text_contains', None) 84 | 85 | if tags: 86 | kwargs['tags'] = { 87 | '$in': tags 88 | } 89 | 90 | if exclude_text: 91 | if 'text' not in kwargs: 92 | kwargs['text'] = {} 93 | elif 'text' in kwargs and isinstance(kwargs['text'], str): 94 | text = kwargs.pop('text') 95 | kwargs['text'] = { 96 | '$eq': text 97 | } 98 | kwargs['text']['$nin'] = exclude_text 99 | 100 | if exclude_text_words: 101 | if 'text' not in kwargs: 102 | kwargs['text'] = {} 103 | elif 'text' in kwargs and isinstance(kwargs['text'], str): 104 | text = kwargs.pop('text') 105 | kwargs['text'] = { 106 | '$eq': text 107 | } 108 | exclude_word_regex = '|'.join([ 109 | '.*{}.*'.format(word) for word in exclude_text_words 110 | ]) 111 | kwargs['text']['$not'] = re.compile(exclude_word_regex) 112 | 113 | if persona_not_startswith: 114 | if 'persona' not in kwargs: 115 | kwargs['persona'] = {} 116 | elif 'persona' in kwargs and isinstance(kwargs['persona'], str): 117 | persona = kwargs.pop('persona') 118 | kwargs['persona'] = { 119 | '$eq': persona 120 | } 121 | kwargs['persona']['$not'] = re.compile('^bot:*') 122 | 123 | if search_text_contains: 124 | or_regex = '|'.join([ 125 | '{}'.format(re.escape(word)) for word in search_text_contains.split(' ') 126 | ]) 127 | kwargs['search_text'] = re.compile(or_regex) 128 | 129 | mongo_ordering = [] 130 | 131 | if order_by: 132 | 133 | # Sort so that newer datetimes appear first 134 | if 'created_at' in order_by: 135 | order_by.remove('created_at') 136 | mongo_ordering.append(('created_at', pymongo.DESCENDING, )) 137 | 138 | for order in order_by: 139 | mongo_ordering.append((order, pymongo.ASCENDING)) 140 | 141 | total_statements = self.statements.find(kwargs).count() 142 | 143 | for start_index in range(0, total_statements, page_size): 144 | if mongo_ordering: 145 | for match in self.statements.find(kwargs).sort(mongo_ordering).skip(start_index).limit(page_size): 146 | yield self.mongo_to_object(match) 147 | else: 148 | for match in self.statements.find(kwargs).skip(start_index).limit(page_size): 149 | yield self.mongo_to_object(match) 150 | 151 | def create(self, **kwargs): 152 | """ 153 | Creates a new statement matching the keyword arguments specified. 154 | Returns the created statement. 155 | """ 156 | Statement = self.get_model('statement') 157 | 158 | if 'tags' in kwargs: 159 | kwargs['tags'] = list(set(kwargs['tags'])) 160 | 161 | if 'search_text' not in kwargs: 162 | kwargs['search_text'] = self.tagger.get_text_index_string(kwargs['text']) 163 | 164 | if 'search_in_response_to' not in kwargs: 165 | if kwargs.get('in_response_to'): 166 | kwargs['search_in_response_to'] = self.tagger.get_text_index_string(kwargs['in_response_to']) 167 | 168 | inserted = self.statements.insert_one(kwargs) 169 | 170 | kwargs['id'] = inserted.inserted_id 171 | 172 | return Statement(**kwargs) 173 | 174 | def create_many(self, statements): 175 | """ 176 | Creates multiple statement entries. 177 | """ 178 | create_statements = [] 179 | 180 | for statement in statements: 181 | statement_data = statement.serialize() 182 | tag_data = list(set(statement_data.pop('tags', []))) 183 | statement_data['tags'] = tag_data 184 | 185 | if not statement.search_text: 186 | statement_data['search_text'] = self.tagger.get_text_index_string(statement.text) 187 | 188 | if not statement.search_in_response_to and statement.in_response_to: 189 | statement_data['search_in_response_to'] = self.tagger.get_text_index_string(statement.in_response_to) 190 | 191 | create_statements.append(statement_data) 192 | 193 | self.statements.insert_many(create_statements) 194 | 195 | def update(self, statement): 196 | data = statement.serialize() 197 | data.pop('id', None) 198 | data.pop('tags', None) 199 | 200 | data['search_text'] = self.tagger.get_text_index_string(data['text']) 201 | 202 | if data.get('in_response_to'): 203 | data['search_in_response_to'] = self.tagger.get_text_index_string(data['in_response_to']) 204 | 205 | update_data = { 206 | '$set': data 207 | } 208 | 209 | if statement.tags: 210 | update_data['$addToSet'] = { 211 | 'tags': { 212 | '$each': statement.tags 213 | } 214 | } 215 | 216 | search_parameters = {} 217 | 218 | if statement.id is not None: 219 | search_parameters['_id'] = statement.id 220 | else: 221 | search_parameters['text'] = statement.text 222 | search_parameters['conversation'] = statement.conversation 223 | 224 | update_operation = self.statements.update_one( 225 | search_parameters, 226 | update_data, 227 | upsert=True 228 | ) 229 | 230 | if update_operation.acknowledged: 231 | statement.id = update_operation.upserted_id 232 | 233 | return statement 234 | 235 | def get_random(self): 236 | """ 237 | Returns a random statement from the database 238 | """ 239 | from random import randint 240 | 241 | count = self.count() 242 | 243 | if count < 1: 244 | raise self.EmptyDatabaseException() 245 | 246 | random_integer = randint(0, count - 1) 247 | 248 | statements = self.statements.find().limit(1).skip(random_integer) 249 | 250 | return self.mongo_to_object(list(statements)[0]) 251 | 252 | def remove(self, statement_text): 253 | """ 254 | Removes the statement that matches the input text. 255 | """ 256 | self.statements.delete_one({'text': statement_text}) 257 | 258 | def drop(self): 259 | """ 260 | Remove the database. 261 | """ 262 | self.client.drop_database(self.database.name) 263 | -------------------------------------------------------------------------------- /chatterbot/storage/sql_storage.py: -------------------------------------------------------------------------------- 1 | from chatterbot.storage import StorageAdapter 2 | 3 | 4 | class SQLStorageAdapter(StorageAdapter): 5 | """ 6 | The SQLStorageAdapter allows ChatterBot to store conversation 7 | data in any database supported by the SQL Alchemy ORM. 8 | 9 | All parameters are optional, by default a sqlite database is used. 10 | 11 | It will check if tables are present, if they are not, it will attempt 12 | to create the required tables. 13 | 14 | :keyword database_uri: eg: sqlite:///database_test.sqlite3', 15 | The database_uri can be specified to choose database driver. 16 | :type database_uri: str 17 | """ 18 | 19 | def __init__(self, **kwargs): 20 | super().__init__(**kwargs) 21 | 22 | from sqlalchemy import create_engine 23 | from sqlalchemy.orm import sessionmaker 24 | 25 | self.database_uri = kwargs.get('database_uri', False) 26 | 27 | # None results in a sqlite in-memory database as the default 28 | if self.database_uri is None: 29 | self.database_uri = 'sqlite://' 30 | 31 | # Create a file database if the database is not a connection string 32 | if not self.database_uri: 33 | self.database_uri = 'sqlite:///db.sqlite3' 34 | 35 | self.engine = create_engine(self.database_uri, convert_unicode=True) 36 | 37 | if self.database_uri.startswith('sqlite://'): 38 | from sqlalchemy.engine import Engine 39 | from sqlalchemy import event 40 | 41 | @event.listens_for(Engine, 'connect') 42 | def set_sqlite_pragma(dbapi_connection, connection_record): 43 | dbapi_connection.execute('PRAGMA journal_mode=WAL') 44 | dbapi_connection.execute('PRAGMA synchronous=NORMAL') 45 | 46 | if not self.engine.dialect.has_table(self.engine, 'Statement'): 47 | self.create_database() 48 | 49 | self.Session = sessionmaker(bind=self.engine, expire_on_commit=True) 50 | 51 | def get_statement_model(self): 52 | """ 53 | Return the statement model. 54 | """ 55 | from chatterbot.ext.sqlalchemy_app.models import Statement 56 | return Statement 57 | 58 | def get_tag_model(self): 59 | """ 60 | Return the conversation model. 61 | """ 62 | from chatterbot.ext.sqlalchemy_app.models import Tag 63 | return Tag 64 | 65 | def model_to_object(self, statement): 66 | from chatterbot.conversation import Statement as StatementObject 67 | 68 | return StatementObject(**statement.serialize()) 69 | 70 | def count(self): 71 | """ 72 | Return the number of entries in the database. 73 | """ 74 | Statement = self.get_model('statement') 75 | 76 | session = self.Session() 77 | statement_count = session.query(Statement).count() 78 | session.close() 79 | return statement_count 80 | 81 | def remove(self, statement_text): 82 | """ 83 | Removes the statement that matches the input text. 84 | Removes any responses from statements where the response text matches 85 | the input text. 86 | """ 87 | Statement = self.get_model('statement') 88 | session = self.Session() 89 | 90 | query = session.query(Statement).filter_by(text=statement_text) 91 | record = query.first() 92 | 93 | session.delete(record) 94 | 95 | self._session_finish(session) 96 | 97 | def filter(self, **kwargs): 98 | """ 99 | Returns a list of objects from the database. 100 | The kwargs parameter can contain any number 101 | of attributes. Only objects which contain all 102 | listed attributes and in which all values match 103 | for all listed attributes will be returned. 104 | """ 105 | from sqlalchemy import or_ 106 | 107 | Statement = self.get_model('statement') 108 | Tag = self.get_model('tag') 109 | 110 | session = self.Session() 111 | 112 | page_size = kwargs.pop('page_size', 1000) 113 | order_by = kwargs.pop('order_by', None) 114 | tags = kwargs.pop('tags', []) 115 | exclude_text = kwargs.pop('exclude_text', None) 116 | exclude_text_words = kwargs.pop('exclude_text_words', []) 117 | persona_not_startswith = kwargs.pop('persona_not_startswith', None) 118 | search_text_contains = kwargs.pop('search_text_contains', None) 119 | 120 | # Convert a single sting into a list if only one tag is provided 121 | if type(tags) == str: 122 | tags = [tags] 123 | 124 | if len(kwargs) == 0: 125 | statements = session.query(Statement).filter() 126 | else: 127 | statements = session.query(Statement).filter_by(**kwargs) 128 | 129 | if tags: 130 | statements = statements.join(Statement.tags).filter( 131 | Tag.name.in_(tags) 132 | ) 133 | 134 | if exclude_text: 135 | statements = statements.filter( 136 | ~Statement.text.in_(exclude_text) 137 | ) 138 | 139 | if exclude_text_words: 140 | or_word_query = [ 141 | Statement.text.ilike('%' + word + '%') for word in exclude_text_words 142 | ] 143 | statements = statements.filter( 144 | ~or_(*or_word_query) 145 | ) 146 | 147 | if persona_not_startswith: 148 | statements = statements.filter( 149 | ~Statement.persona.startswith('bot:') 150 | ) 151 | 152 | if search_text_contains: 153 | or_query = [ 154 | Statement.search_text.contains(word) for word in search_text_contains.split(' ') 155 | ] 156 | statements = statements.filter( 157 | or_(*or_query) 158 | ) 159 | 160 | if order_by: 161 | 162 | if 'created_at' in order_by: 163 | index = order_by.index('created_at') 164 | order_by[index] = Statement.created_at.asc() 165 | 166 | statements = statements.order_by(*order_by) 167 | 168 | total_statements = statements.count() 169 | 170 | for start_index in range(0, total_statements, page_size): 171 | for statement in statements.slice(start_index, start_index + page_size): 172 | yield self.model_to_object(statement) 173 | 174 | session.close() 175 | 176 | def create(self, **kwargs): 177 | """ 178 | Creates a new statement matching the keyword arguments specified. 179 | Returns the created statement. 180 | """ 181 | Statement = self.get_model('statement') 182 | Tag = self.get_model('tag') 183 | 184 | session = self.Session() 185 | 186 | tags = set(kwargs.pop('tags', [])) 187 | 188 | if 'search_text' not in kwargs: 189 | kwargs['search_text'] = self.tagger.get_text_index_string(kwargs['text']) 190 | 191 | if 'search_in_response_to' not in kwargs: 192 | in_response_to = kwargs.get('in_response_to') 193 | if in_response_to: 194 | kwargs['search_in_response_to'] = self.tagger.get_text_index_string(in_response_to) 195 | 196 | statement = Statement(**kwargs) 197 | 198 | for tag_name in tags: 199 | tag = session.query(Tag).filter_by(name=tag_name).first() 200 | 201 | if not tag: 202 | # Create the tag 203 | tag = Tag(name=tag_name) 204 | 205 | statement.tags.append(tag) 206 | 207 | session.add(statement) 208 | 209 | session.flush() 210 | 211 | session.refresh(statement) 212 | 213 | statement_object = self.model_to_object(statement) 214 | 215 | self._session_finish(session) 216 | 217 | return statement_object 218 | 219 | def create_many(self, statements): 220 | """ 221 | Creates multiple statement entries. 222 | """ 223 | Statement = self.get_model('statement') 224 | Tag = self.get_model('tag') 225 | 226 | session = self.Session() 227 | 228 | create_statements = [] 229 | create_tags = {} 230 | 231 | for statement in statements: 232 | 233 | statement_data = statement.serialize() 234 | tag_data = statement_data.pop('tags', []) 235 | 236 | statement_model_object = Statement(**statement_data) 237 | 238 | if not statement.search_text: 239 | statement_model_object.search_text = self.tagger.get_text_index_string(statement.text) 240 | 241 | if not statement.search_in_response_to and statement.in_response_to: 242 | statement_model_object.search_in_response_to = self.tagger.get_text_index_string(statement.in_response_to) 243 | 244 | new_tags = set(tag_data) - set(create_tags.keys()) 245 | 246 | if new_tags: 247 | existing_tags = session.query(Tag).filter( 248 | Tag.name.in_(new_tags) 249 | ) 250 | 251 | for existing_tag in existing_tags: 252 | create_tags[existing_tag.name] = existing_tag 253 | 254 | for tag_name in tag_data: 255 | if tag_name in create_tags: 256 | tag = create_tags[tag_name] 257 | else: 258 | # Create the tag if it does not exist 259 | tag = Tag(name=tag_name) 260 | 261 | create_tags[tag_name] = tag 262 | 263 | statement_model_object.tags.append(tag) 264 | create_statements.append(statement_model_object) 265 | 266 | session.add_all(create_statements) 267 | session.commit() 268 | 269 | def update(self, statement): 270 | """ 271 | Modifies an entry in the database. 272 | Creates an entry if one does not exist. 273 | """ 274 | Statement = self.get_model('statement') 275 | Tag = self.get_model('tag') 276 | 277 | if statement is not None: 278 | session = self.Session() 279 | record = None 280 | 281 | if hasattr(statement, 'id') and statement.id is not None: 282 | record = session.query(Statement).get(statement.id) 283 | else: 284 | record = session.query(Statement).filter( 285 | Statement.text == statement.text, 286 | Statement.conversation == statement.conversation, 287 | ).first() 288 | 289 | # Create a new statement entry if one does not already exist 290 | if not record: 291 | record = Statement( 292 | text=statement.text, 293 | conversation=statement.conversation, 294 | persona=statement.persona 295 | ) 296 | 297 | # Update the response value 298 | record.in_response_to = statement.in_response_to 299 | 300 | record.created_at = statement.created_at 301 | 302 | record.search_text = self.tagger.get_text_index_string(statement.text) 303 | 304 | if statement.in_response_to: 305 | record.search_in_response_to = self.tagger.get_text_index_string(statement.in_response_to) 306 | 307 | for tag_name in statement.get_tags(): 308 | tag = session.query(Tag).filter_by(name=tag_name).first() 309 | 310 | if not tag: 311 | # Create the record 312 | tag = Tag(name=tag_name) 313 | 314 | record.tags.append(tag) 315 | 316 | session.add(record) 317 | 318 | self._session_finish(session) 319 | 320 | def get_random(self): 321 | """ 322 | Returns a random statement from the database. 323 | """ 324 | import random 325 | 326 | Statement = self.get_model('statement') 327 | 328 | session = self.Session() 329 | count = self.count() 330 | if count < 1: 331 | raise self.EmptyDatabaseException() 332 | 333 | random_index = random.randrange(0, count) 334 | random_statement = session.query(Statement)[random_index] 335 | 336 | statement = self.model_to_object(random_statement) 337 | 338 | session.close() 339 | return statement 340 | 341 | def drop(self): 342 | """ 343 | Drop the database. 344 | """ 345 | Statement = self.get_model('statement') 346 | Tag = self.get_model('tag') 347 | 348 | session = self.Session() 349 | 350 | session.query(Statement).delete() 351 | session.query(Tag).delete() 352 | 353 | session.commit() 354 | session.close() 355 | 356 | def create_database(self): 357 | """ 358 | Populate the database with the tables. 359 | """ 360 | from chatterbot.ext.sqlalchemy_app.models import Base 361 | Base.metadata.create_all(self.engine) 362 | 363 | def _session_finish(self, session, statement_text=None): 364 | from sqlalchemy.exc import InvalidRequestError 365 | try: 366 | session.commit() 367 | except InvalidRequestError: 368 | # Log the statement text and the exception 369 | self.logger.exception(statement_text) 370 | finally: 371 | session.close() 372 | -------------------------------------------------------------------------------- /chatterbot/storage/storage_adapter.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from chatterbot import languages 3 | from chatterbot.tagging import PosLemmaTagger 4 | 5 | 6 | class StorageAdapter(object): 7 | """ 8 | This is an abstract class that represents the interface 9 | that all storage adapters should implement. 10 | """ 11 | 12 | def __init__(self, *args, **kwargs): 13 | """ 14 | Initialize common attributes shared by all storage adapters. 15 | 16 | :param str tagger_language: The language that the tagger uses to remove stopwords. 17 | """ 18 | self.logger = kwargs.get('logger', logging.getLogger(__name__)) 19 | 20 | Tagger = kwargs.get('tagger', PosLemmaTagger) 21 | 22 | self.tagger = Tagger(language=kwargs.get( 23 | 'tagger_language', languages.ENG 24 | )) 25 | 26 | def get_model(self, model_name): 27 | """ 28 | Return the model class for a given model name. 29 | 30 | model_name is case insensitive. 31 | """ 32 | get_model_method = getattr(self, 'get_%s_model' % ( 33 | model_name.lower(), 34 | )) 35 | 36 | return get_model_method() 37 | 38 | def get_object(self, object_name): 39 | """ 40 | Return the class for a given object name. 41 | 42 | object_name is case insensitive. 43 | """ 44 | get_model_method = getattr(self, 'get_%s_object' % ( 45 | object_name.lower(), 46 | )) 47 | 48 | return get_model_method() 49 | 50 | def get_statement_object(self): 51 | from chatterbot.conversation import Statement 52 | 53 | StatementModel = self.get_model('statement') 54 | 55 | Statement.statement_field_names.extend( 56 | StatementModel.extra_statement_field_names 57 | ) 58 | 59 | return Statement 60 | 61 | def count(self): 62 | """ 63 | Return the number of entries in the database. 64 | """ 65 | raise self.AdapterMethodNotImplementedError( 66 | 'The `count` method is not implemented by this adapter.' 67 | ) 68 | 69 | def remove(self, statement_text): 70 | """ 71 | Removes the statement that matches the input text. 72 | Removes any responses from statements where the response text matches 73 | the input text. 74 | """ 75 | raise self.AdapterMethodNotImplementedError( 76 | 'The `remove` method is not implemented by this adapter.' 77 | ) 78 | 79 | def filter(self, **kwargs): 80 | """ 81 | Returns a list of objects from the database. 82 | The kwargs parameter can contain any number 83 | of attributes. Only objects which contain 84 | all listed attributes and in which all values 85 | match for all listed attributes will be returned. 86 | 87 | :param page_size: The maximum number of records to load into 88 | memory at once when returning results. 89 | Defaults to 1000 90 | 91 | :param order_by: The field name that should be used to determine 92 | the order that results are returned in. 93 | Defaults to None 94 | 95 | :param tags: A list of tags. When specified, the results will only 96 | include statements that have a tag in the provided list. 97 | Defaults to [] (empty list) 98 | 99 | :param exclude_text: If the ``text`` of a statement is an exact match 100 | for the value of this parameter the statement will not be 101 | included in the result set. 102 | Defaults to None 103 | 104 | :param exclude_text_words: If the ``text`` of a statement contains a 105 | word from this list then the statement will not be included in 106 | the result set. 107 | Defaults to [] (empty list) 108 | 109 | :param persona_not_startswith: If the ``persona`` field of a 110 | statement starts with the value specified by this parameter, 111 | then the statement will not be returned in the result set. 112 | Defaults to None 113 | 114 | :param search_text_contains: If the ``search_text`` field of a 115 | statement contains a word that is in the string provided to 116 | this parameter, then the statement will be included in the 117 | result set. 118 | Defaults to None 119 | """ 120 | raise self.AdapterMethodNotImplementedError( 121 | 'The `filter` method is not implemented by this adapter.' 122 | ) 123 | 124 | def create(self, **kwargs): 125 | """ 126 | Creates a new statement matching the keyword arguments specified. 127 | Returns the created statement. 128 | """ 129 | raise self.AdapterMethodNotImplementedError( 130 | 'The `create` method is not implemented by this adapter.' 131 | ) 132 | 133 | def create_many(self, statements): 134 | """ 135 | Creates multiple statement entries. 136 | """ 137 | raise self.AdapterMethodNotImplementedError( 138 | 'The `create_many` method is not implemented by this adapter.' 139 | ) 140 | 141 | def update(self, statement): 142 | """ 143 | Modifies an entry in the database. 144 | Creates an entry if one does not exist. 145 | """ 146 | raise self.AdapterMethodNotImplementedError( 147 | 'The `update` method is not implemented by this adapter.' 148 | ) 149 | 150 | def get_random(self): 151 | """ 152 | Returns a random statement from the database. 153 | """ 154 | raise self.AdapterMethodNotImplementedError( 155 | 'The `get_random` method is not implemented by this adapter.' 156 | ) 157 | 158 | def drop(self): 159 | """ 160 | Drop the database attached to a given adapter. 161 | """ 162 | raise self.AdapterMethodNotImplementedError( 163 | 'The `drop` method is not implemented by this adapter.' 164 | ) 165 | 166 | class EmptyDatabaseException(Exception): 167 | 168 | def __init__(self, message=None): 169 | default = 'The database currently contains no entries. At least one entry is expected. You may need to train your chat bot to populate your database.' 170 | super().__init__(message or default) 171 | 172 | class AdapterMethodNotImplementedError(NotImplementedError): 173 | """ 174 | An exception to be raised when a storage adapter method has not been implemented. 175 | Typically this indicates that the method should be implement in a subclass. 176 | """ 177 | pass 178 | -------------------------------------------------------------------------------- /chatterbot/tagging.py: -------------------------------------------------------------------------------- 1 | import string 2 | from chatterbot import languages 3 | 4 | 5 | class LowercaseTagger(object): 6 | """ 7 | Returns the text in lowercase. 8 | """ 9 | 10 | def __init__(self, language=None): 11 | self.language = language or languages.ENG 12 | 13 | def get_text_index_string(self, text): 14 | return text.lower() 15 | 16 | 17 | class PosLemmaTagger(object): 18 | 19 | def __init__(self, language=None): 20 | import spacy 21 | 22 | self.language = language or languages.ENG 23 | 24 | self.punctuation_table = str.maketrans(dict.fromkeys(string.punctuation)) 25 | 26 | self.nlp = spacy.load(self.language.ISO_639_1.lower()) 27 | 28 | def get_text_index_string(self, text): 29 | """ 30 | Return a string of text containing part-of-speech, lemma pairs. 31 | """ 32 | bigram_pairs = [] 33 | 34 | if len(text) <= 2: 35 | text_without_punctuation = text.translate(self.punctuation_table) 36 | if len(text_without_punctuation) >= 1: 37 | text = text_without_punctuation 38 | 39 | document = self.nlp(text) 40 | 41 | if len(text) <= 2: 42 | bigram_pairs = [ 43 | token.lemma_.lower() for token in document 44 | ] 45 | else: 46 | tokens = [ 47 | token for token in document if token.is_alpha and not token.is_stop 48 | ] 49 | 50 | if len(tokens) < 2: 51 | tokens = [ 52 | token for token in document if token.is_alpha 53 | ] 54 | 55 | for index in range(1, len(tokens)): 56 | bigram_pairs.append('{}:{}'.format( 57 | tokens[index - 1].pos_, 58 | tokens[index].lemma_.lower() 59 | )) 60 | 61 | if not bigram_pairs: 62 | bigram_pairs = [ 63 | token.lemma_.lower() for token in document 64 | ] 65 | 66 | return ' '.join(bigram_pairs) 67 | -------------------------------------------------------------------------------- /chatterbot/trainers.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import csv 4 | import time 5 | from dateutil import parser as date_parser 6 | from chatterbot.conversation import Statement 7 | from chatterbot.tagging import PosLemmaTagger 8 | from chatterbot import utils 9 | 10 | 11 | class Trainer(object): 12 | """ 13 | Base class for all other trainer classes. 14 | 15 | :param boolean show_training_progress: Show progress indicators for the 16 | trainer. The environment variable ``CHATTERBOT_SHOW_TRAINING_PROGRESS`` 17 | can also be set to control this. ``show_training_progress`` will override 18 | the environment variable if it is set. 19 | """ 20 | 21 | def __init__(self, chatbot, **kwargs): 22 | self.chatbot = chatbot 23 | 24 | environment_default = os.getenv('CHATTERBOT_SHOW_TRAINING_PROGRESS', True) 25 | self.show_training_progress = kwargs.get( 26 | 'show_training_progress', 27 | environment_default 28 | ) 29 | 30 | def get_preprocessed_statement(self, input_statement): 31 | """ 32 | Preprocess the input statement. 33 | """ 34 | for preprocessor in self.chatbot.preprocessors: 35 | input_statement = preprocessor(input_statement) 36 | 37 | return input_statement 38 | 39 | def train(self, *args, **kwargs): 40 | """ 41 | This method must be overridden by a child class. 42 | """ 43 | raise self.TrainerInitializationException() 44 | 45 | class TrainerInitializationException(Exception): 46 | """ 47 | Exception raised when a base class has not overridden 48 | the required methods on the Trainer base class. 49 | """ 50 | 51 | def __init__(self, message=None): 52 | default = ( 53 | 'A training class must be specified before calling train(). ' 54 | 'See http://chatterbot.readthedocs.io/en/stable/training.html' 55 | ) 56 | super().__init__(message or default) 57 | 58 | def _generate_export_data(self): 59 | result = [] 60 | for statement in self.chatbot.storage.filter(): 61 | if statement.in_response_to: 62 | result.append([statement.in_response_to, statement.text]) 63 | 64 | return result 65 | 66 | def export_for_training(self, file_path='./export.json'): 67 | """ 68 | Create a file from the database that can be used to 69 | train other chat bots. 70 | """ 71 | import json 72 | export = {'conversations': self._generate_export_data()} 73 | with open(file_path, 'w+', encoding='utf8') as jsonfile: 74 | json.dump(export, jsonfile, ensure_ascii=False) 75 | 76 | 77 | class ListTrainer(Trainer): 78 | """ 79 | Allows a chat bot to be trained using a list of strings 80 | where the list represents a conversation. 81 | """ 82 | 83 | def train(self, conversation): 84 | """ 85 | Train the chat bot based on the provided list of 86 | statements that represents a single conversation. 87 | """ 88 | previous_statement_text = None 89 | previous_statement_search_text = '' 90 | 91 | statements_to_create = [] 92 | 93 | for conversation_count, text in enumerate(conversation): 94 | if self.show_training_progress: 95 | utils.print_progress_bar( 96 | 'List Trainer', 97 | conversation_count + 1, len(conversation) 98 | ) 99 | 100 | statement_search_text = self.chatbot.storage.tagger.get_text_index_string(text) 101 | 102 | statement = self.get_preprocessed_statement( 103 | Statement( 104 | text=text, 105 | search_text=statement_search_text, 106 | in_response_to=previous_statement_text, 107 | search_in_response_to=previous_statement_search_text, 108 | conversation='training' 109 | ) 110 | ) 111 | 112 | previous_statement_text = statement.text 113 | previous_statement_search_text = statement_search_text 114 | 115 | statements_to_create.append(statement) 116 | 117 | self.chatbot.storage.create_many(statements_to_create) 118 | 119 | 120 | class ChatterBotCorpusTrainer(Trainer): 121 | """ 122 | Allows the chat bot to be trained using data from the 123 | ChatterBot dialog corpus. 124 | """ 125 | 126 | def train(self, *corpus_paths): 127 | from chatterbot.corpus import load_corpus, list_corpus_files 128 | 129 | data_file_paths = [] 130 | 131 | # Get the paths to each file the bot will be trained with 132 | for corpus_path in corpus_paths: 133 | data_file_paths.extend(list_corpus_files(corpus_path)) 134 | 135 | for corpus, categories, file_path in load_corpus(*data_file_paths): 136 | 137 | statements_to_create = [] 138 | 139 | # Train the chat bot with each statement and response pair 140 | for conversation_count, conversation in enumerate(corpus): 141 | 142 | if self.show_training_progress: 143 | utils.print_progress_bar( 144 | 'Training ' + str(os.path.basename(file_path)), 145 | conversation_count + 1, 146 | len(corpus) 147 | ) 148 | 149 | previous_statement_text = None 150 | previous_statement_search_text = '' 151 | 152 | for text in conversation: 153 | 154 | statement_search_text = self.chatbot.storage.tagger.get_text_index_string(text) 155 | 156 | statement = Statement( 157 | text=text, 158 | search_text=statement_search_text, 159 | in_response_to=previous_statement_text, 160 | search_in_response_to=previous_statement_search_text, 161 | conversation='training' 162 | ) 163 | 164 | statement.add_tags(*categories) 165 | 166 | statement = self.get_preprocessed_statement(statement) 167 | 168 | previous_statement_text = statement.text 169 | previous_statement_search_text = statement_search_text 170 | 171 | statements_to_create.append(statement) 172 | 173 | if statements_to_create: 174 | self.chatbot.storage.create_many(statements_to_create) 175 | 176 | 177 | class UbuntuCorpusTrainer(Trainer): 178 | """ 179 | Allow chatbots to be trained with the data from the Ubuntu Dialog Corpus. 180 | """ 181 | 182 | def __init__(self, chatbot, **kwargs): 183 | super().__init__(chatbot, **kwargs) 184 | home_directory = os.path.expanduser('~') 185 | 186 | self.data_download_url = kwargs.get( 187 | 'ubuntu_corpus_data_download_url', 188 | 'http://cs.mcgill.ca/~jpineau/datasets/ubuntu-corpus-1.0/ubuntu_dialogs.tgz' 189 | ) 190 | 191 | self.data_directory = kwargs.get( 192 | 'ubuntu_corpus_data_directory', 193 | os.path.join(home_directory, 'ubuntu_data') 194 | ) 195 | 196 | self.extracted_data_directory = os.path.join( 197 | self.data_directory, 'ubuntu_dialogs' 198 | ) 199 | 200 | # Create the data directory if it does not already exist 201 | if not os.path.exists(self.data_directory): 202 | os.makedirs(self.data_directory) 203 | 204 | def is_downloaded(self, file_path): 205 | """ 206 | Check if the data file is already downloaded. 207 | """ 208 | if os.path.exists(file_path): 209 | self.chatbot.logger.info('File is already downloaded') 210 | return True 211 | 212 | return False 213 | 214 | def is_extracted(self, file_path): 215 | """ 216 | Check if the data file is already extracted. 217 | """ 218 | 219 | if os.path.isdir(file_path): 220 | self.chatbot.logger.info('File is already extracted') 221 | return True 222 | return False 223 | 224 | def download(self, url, show_status=True): 225 | """ 226 | Download a file from the given url. 227 | Show a progress indicator for the download status. 228 | Based on: http://stackoverflow.com/a/15645088/1547223 229 | """ 230 | import requests 231 | 232 | file_name = url.split('/')[-1] 233 | file_path = os.path.join(self.data_directory, file_name) 234 | 235 | # Do not download the data if it already exists 236 | if self.is_downloaded(file_path): 237 | return file_path 238 | 239 | with open(file_path, 'wb') as open_file: 240 | print('Downloading %s' % url) 241 | response = requests.get(url, stream=True) 242 | total_length = response.headers.get('content-length') 243 | 244 | if total_length is None: 245 | # No content length header 246 | open_file.write(response.content) 247 | else: 248 | download = 0 249 | total_length = int(total_length) 250 | for data in response.iter_content(chunk_size=4096): 251 | download += len(data) 252 | open_file.write(data) 253 | if show_status: 254 | done = int(50 * download / total_length) 255 | sys.stdout.write('\r[%s%s]' % ('=' * done, ' ' * (50 - done))) 256 | sys.stdout.flush() 257 | 258 | # Add a new line after the download bar 259 | sys.stdout.write('\n') 260 | 261 | print('Download location: %s' % file_path) 262 | return file_path 263 | 264 | def extract(self, file_path): 265 | """ 266 | Extract a tar file at the specified file path. 267 | """ 268 | import tarfile 269 | 270 | print('Extracting {}'.format(file_path)) 271 | 272 | if not os.path.exists(self.extracted_data_directory): 273 | os.makedirs(self.extracted_data_directory) 274 | 275 | def track_progress(members): 276 | sys.stdout.write('.') 277 | for member in members: 278 | # This will be the current file being extracted 279 | yield member 280 | 281 | with tarfile.open(file_path) as tar: 282 | tar.extractall(path=self.extracted_data_directory, members=track_progress(tar)) 283 | 284 | self.chatbot.logger.info('File extracted to {}'.format(self.extracted_data_directory)) 285 | 286 | return True 287 | 288 | def train(self): 289 | import glob 290 | 291 | tagger = PosLemmaTagger(language=self.chatbot.storage.tagger.language) 292 | 293 | # Download and extract the Ubuntu dialog corpus if needed 294 | corpus_download_path = self.download(self.data_download_url) 295 | 296 | # Extract if the directory does not already exist 297 | if not self.is_extracted(self.extracted_data_directory): 298 | self.extract(corpus_download_path) 299 | 300 | extracted_corpus_path = os.path.join( 301 | self.extracted_data_directory, 302 | '**', '**', '*.tsv' 303 | ) 304 | 305 | def chunks(items, items_per_chunk): 306 | for start_index in range(0, len(items), items_per_chunk): 307 | end_index = start_index + items_per_chunk 308 | yield items[start_index:end_index] 309 | 310 | file_list = glob.glob(extracted_corpus_path) 311 | 312 | file_groups = tuple(chunks(file_list, 10000)) 313 | 314 | start_time = time.time() 315 | 316 | for tsv_files in file_groups: 317 | 318 | statements_from_file = [] 319 | 320 | for tsv_file in tsv_files: 321 | with open(tsv_file, 'r', encoding='utf-8') as tsv: 322 | reader = csv.reader(tsv, delimiter='\t') 323 | 324 | previous_statement_text = None 325 | previous_statement_search_text = '' 326 | 327 | for row in reader: 328 | if len(row) > 0: 329 | statement = Statement( 330 | text=row[3], 331 | in_response_to=previous_statement_text, 332 | conversation='training', 333 | created_at=date_parser.parse(row[0]), 334 | persona=row[1] 335 | ) 336 | 337 | for preprocessor in self.chatbot.preprocessors: 338 | statement = preprocessor(statement) 339 | 340 | statement.search_text = tagger.get_text_index_string(statement.text) 341 | statement.search_in_response_to = previous_statement_search_text 342 | 343 | previous_statement_text = statement.text 344 | previous_statement_search_text = statement.search_text 345 | 346 | statements_from_file.append(statement) 347 | 348 | self.chatbot.storage.create_many(statements_from_file) 349 | 350 | print('Training took', time.time() - start_time, 'seconds.') 351 | -------------------------------------------------------------------------------- /chatterbot/utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | ChatterBot utility functions 3 | """ 4 | 5 | 6 | def import_module(dotted_path): 7 | """ 8 | Imports the specified module based on the 9 | dot notated import path for the module. 10 | """ 11 | import importlib 12 | 13 | module_parts = dotted_path.split('.') 14 | module_path = '.'.join(module_parts[:-1]) 15 | module = importlib.import_module(module_path) 16 | 17 | return getattr(module, module_parts[-1]) 18 | 19 | 20 | def initialize_class(data, *args, **kwargs): 21 | """ 22 | :param data: A string or dictionary containing a import_path attribute. 23 | """ 24 | if isinstance(data, dict): 25 | import_path = data.get('import_path') 26 | data.update(kwargs) 27 | Class = import_module(import_path) 28 | 29 | return Class(*args, **data) 30 | else: 31 | Class = import_module(data) 32 | 33 | return Class(*args, **kwargs) 34 | 35 | 36 | def validate_adapter_class(validate_class, adapter_class): 37 | """ 38 | Raises an exception if validate_class is not a 39 | subclass of adapter_class. 40 | 41 | :param validate_class: The class to be validated. 42 | :type validate_class: class 43 | 44 | :param adapter_class: The class type to check against. 45 | :type adapter_class: class 46 | 47 | :raises: Adapter.InvalidAdapterTypeException 48 | """ 49 | from chatterbot.adapters import Adapter 50 | 51 | # If a dictionary was passed in, check if it has an import_path attribute 52 | if isinstance(validate_class, dict): 53 | 54 | if 'import_path' not in validate_class: 55 | raise Adapter.InvalidAdapterTypeException( 56 | 'The dictionary {} must contain a value for "import_path"'.format( 57 | str(validate_class) 58 | ) 59 | ) 60 | 61 | # Set the class to the import path for the next check 62 | validate_class = validate_class.get('import_path') 63 | 64 | if not issubclass(import_module(validate_class), adapter_class): 65 | raise Adapter.InvalidAdapterTypeException( 66 | '{} must be a subclass of {}'.format( 67 | validate_class, 68 | adapter_class.__name__ 69 | ) 70 | ) 71 | 72 | 73 | def get_response_time(chatbot, statement='Hello'): 74 | """ 75 | Returns the amount of time taken for a given 76 | chat bot to return a response. 77 | 78 | :param chatbot: A chat bot instance. 79 | :type chatbot: ChatBot 80 | 81 | :returns: The response time in seconds. 82 | :rtype: float 83 | """ 84 | import time 85 | 86 | start_time = time.time() 87 | 88 | chatbot.get_response(statement) 89 | 90 | return time.time() - start_time 91 | 92 | 93 | def print_progress_bar(description, iteration_counter, total_items, progress_bar_length=20): 94 | """ 95 | Print progress bar 96 | :param description: Training description 97 | :type description: str 98 | 99 | :param iteration_counter: Incremental counter 100 | :type iteration_counter: int 101 | 102 | :param total_items: total number items 103 | :type total_items: int 104 | 105 | :param progress_bar_length: Progress bar length 106 | :type progress_bar_length: int 107 | 108 | :returns: void 109 | :rtype: void 110 | """ 111 | import sys 112 | 113 | percent = float(iteration_counter) / total_items 114 | hashes = '#' * int(round(percent * progress_bar_length)) 115 | spaces = ' ' * (progress_bar_length - len(hashes)) 116 | sys.stdout.write('\r{0}: [{1}] {2}%'.format(description, hashes + spaces, int(round(percent * 100)))) 117 | sys.stdout.flush() 118 | if total_items == iteration_counter: 119 | print('\r') 120 | -------------------------------------------------------------------------------- /examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/examples/__init__.py -------------------------------------------------------------------------------- /examples/basic_example.py: -------------------------------------------------------------------------------- 1 | from chatterbot import ChatBot 2 | from chatterbot.trainers import ListTrainer 3 | 4 | # Create a new chat bot named Charlie 5 | chatbot = ChatBot('Charlie') 6 | 7 | trainer = ListTrainer(chatbot) 8 | 9 | trainer.train([ 10 | "Hi, can I help you?", 11 | "Sure, I'd like to book a flight to Iceland.", 12 | "Your flight has been booked." 13 | ]) 14 | 15 | # Get a response to the input text 'I would like to book a flight.' 16 | response = chatbot.get_response('I would like to book a flight.') 17 | 18 | print(response) 19 | -------------------------------------------------------------------------------- /examples/convert_units.py: -------------------------------------------------------------------------------- 1 | from chatterbot import ChatBot 2 | 3 | 4 | bot = ChatBot( 5 | 'Unit Converter', 6 | logic_adapters=[ 7 | 'chatterbot.logic.UnitConversion', 8 | ] 9 | ) 10 | 11 | questions = [ 12 | 'How many meters are in a kilometer?', 13 | 'How many meters are in one inch?', 14 | '0 celsius to fahrenheit', 15 | 'one hour is how many minutes ?' 16 | ] 17 | 18 | # Prints the convertion given the specific question 19 | for question in questions: 20 | response = bot.get_response(question) 21 | print(question + ' - Response: ' + response.text) 22 | -------------------------------------------------------------------------------- /examples/default_response_example.py: -------------------------------------------------------------------------------- 1 | from chatterbot import ChatBot 2 | from chatterbot.trainers import ListTrainer 3 | 4 | 5 | # Create a new instance of a ChatBot 6 | bot = ChatBot( 7 | 'Example Bot', 8 | storage_adapter='chatterbot.storage.SQLStorageAdapter', 9 | logic_adapters=[ 10 | { 11 | 'import_path': 'chatterbot.logic.BestMatch', 12 | 'default_response': 'I am sorry, but I do not understand.', 13 | 'maximum_similarity_threshold': 0.90 14 | } 15 | ] 16 | ) 17 | 18 | trainer = ListTrainer(bot) 19 | 20 | # Train the chat bot with a few responses 21 | trainer.train([ 22 | 'How can I help you?', 23 | 'I want to create a chat bot', 24 | 'Have you read the documentation?', 25 | 'No, I have not', 26 | 'This should help get you started: http://chatterbot.rtfd.org/en/latest/quickstart.html' 27 | ]) 28 | 29 | # Get a response for some unexpected input 30 | response = bot.get_response('How do I make an omelette?') 31 | print(response) 32 | -------------------------------------------------------------------------------- /examples/django_app/README.rst: -------------------------------------------------------------------------------- 1 | ========================= 2 | ChatterBot Django Example 3 | ========================= 4 | 5 | This is an example Django app that shows how to create a simple chat bot web 6 | app using Django_ and ChatterBot_. 7 | 8 | Documentation 9 | ------------- 10 | 11 | Start the Django app by running `python manage.py runserver 0.0.0.0:8000` 12 | 13 | Further documentation on getting set up with Django and ChatterBot can be 14 | found in the `ChatterBot documentation`_. 15 | 16 | .. _Django: https://www.djangoproject.com 17 | .. _ChatterBot: https://github.com/gunthercox/ChatterBot 18 | .. _ChatterBot documentation: http://chatterbot.readthedocs.io/en/stable/django/index.html 19 | -------------------------------------------------------------------------------- /examples/django_app/example_app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/examples/django_app/example_app/__init__.py -------------------------------------------------------------------------------- /examples/django_app/example_app/settings.py: -------------------------------------------------------------------------------- 1 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 2 | import os 3 | 4 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 5 | 6 | 7 | # Quick-start development settings - unsuitable for production 8 | # See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ 9 | 10 | # SECURITY WARNING: keep the secret key used in production secret! 11 | SECRET_KEY = 'fsch+6!=q+@ol&%0x!nwdl@48^ixbd4clx5f1i!5n^66y+pmn*' 12 | 13 | # SECURITY WARNING: don't run with debug turned on in production! 14 | DEBUG = True 15 | 16 | ALLOWED_HOSTS = [] 17 | 18 | 19 | # Application definition 20 | 21 | INSTALLED_APPS = ( 22 | 'django.contrib.admin', 23 | 'django.contrib.auth', 24 | 'django.contrib.contenttypes', 25 | 'django.contrib.sessions', 26 | 'django.contrib.messages', 27 | 'django.contrib.staticfiles', 28 | 29 | 'chatterbot.ext.django_chatterbot', 30 | 'example_app', 31 | ) 32 | 33 | # ChatterBot settings 34 | 35 | CHATTERBOT = { 36 | 'name': 'Django ChatterBot Example', 37 | 'django_app_name': 'django_chatterbot' 38 | } 39 | 40 | MIDDLEWARE_CLASSES = ( 41 | 'django.contrib.sessions.middleware.SessionMiddleware', 42 | 'django.middleware.common.CommonMiddleware', 43 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 44 | 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 45 | 'django.contrib.messages.middleware.MessageMiddleware', 46 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 47 | 'django.middleware.security.SecurityMiddleware', 48 | ) 49 | 50 | ROOT_URLCONF = 'example_app.urls' 51 | 52 | TEMPLATES = [ 53 | { 54 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 55 | 'DIRS': [], 56 | 'APP_DIRS': True, 57 | 'OPTIONS': { 58 | 'context_processors': [ 59 | 'django.template.context_processors.debug', 60 | 'django.template.context_processors.request', 61 | 'django.contrib.auth.context_processors.auth', 62 | 'django.contrib.messages.context_processors.messages', 63 | ], 64 | }, 65 | }, 66 | ] 67 | 68 | WSGI_APPLICATION = 'example_app.wsgi.application' 69 | 70 | 71 | # Database 72 | # https://docs.djangoproject.com/en/1.8/ref/settings/#databases 73 | 74 | DATABASES = { 75 | 'default': { 76 | 'ENGINE': 'django.db.backends.sqlite3', 77 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 78 | } 79 | } 80 | 81 | 82 | # Internationalization 83 | # https://docs.djangoproject.com/en/1.8/topics/i18n/ 84 | 85 | LANGUAGE_CODE = 'en-us' 86 | 87 | TIME_ZONE = 'UTC' 88 | 89 | USE_I18N = True 90 | 91 | USE_L10N = True 92 | 93 | USE_TZ = True 94 | 95 | 96 | # Static files (CSS, JavaScript, Images) 97 | # https://docs.djangoproject.com/en/1.8/howto/static-files/ 98 | 99 | STATIC_URL = '/static/' 100 | 101 | STATICFILES_DIRS = ( 102 | os.path.join( 103 | os.path.dirname(__file__), 104 | 'static', 105 | ), 106 | ) 107 | -------------------------------------------------------------------------------- /examples/django_app/example_app/static/css/custom.css: -------------------------------------------------------------------------------- 1 | /* Alternate the background color of the output rows */ 2 | .list-group-item:nth-child(even) { 3 | background-color: #bdf1ac; 4 | } 5 | 6 | .chat-log { 7 | max-height:200px; 8 | overflow-y:scroll; 9 | } -------------------------------------------------------------------------------- /examples/django_app/example_app/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/examples/django_app/example_app/static/favicon.ico -------------------------------------------------------------------------------- /examples/django_app/example_app/static/img/chatterbot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/examples/django_app/example_app/static/img/chatterbot.png -------------------------------------------------------------------------------- /examples/django_app/example_app/static/js/js.cookie.js: -------------------------------------------------------------------------------- 1 | /*! js-cookie v2.0.3 | MIT */ 2 | !function(a){if("function"==typeof define&&define.amd)define(a);else if("object"==typeof exports)module.exports=a();else{var b=window.Cookies,c=window.Cookies=a(window.jQuery);c.noConflict=function(){return window.Cookies=b,c}}}(function(){function a(){for(var a=0,b={};a1){if(f=a({path:"/"},d.defaults,f),"number"==typeof f.expires){var h=new Date;h.setMilliseconds(h.getMilliseconds()+864e5*f.expires),f.expires=h}try{g=JSON.stringify(e),/^[\{\[]/.test(g)&&(e=g)}catch(i){}return e=encodeURIComponent(String(e)),e=e.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),b=encodeURIComponent(String(b)),b=b.replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent),b=b.replace(/[\(\)]/g,escape),document.cookie=[b,"=",e,f.expires&&"; expires="+f.expires.toUTCString(),f.path&&"; path="+f.path,f.domain&&"; domain="+f.domain,f.secure?"; secure":""].join("")}b||(g={});for(var j=document.cookie?document.cookie.split("; "):[],k=/(%[0-9A-Z]{2})+/g,l=0;l 3 | 4 | 5 | Django ChatterBot Example 6 | 7 | 8 | 9 | 10 | 11 | {% include 'nav.html' %} 12 | 13 |
14 | 15 |
16 |

Django ChatterBot Example

17 |

18 | This is a web app that allows you to talk to ChatterBot. 19 |

20 | 21 |
22 | 23 |
24 |
25 |
    26 |
27 | 28 |
29 | 30 | 31 | 32 | 33 |
34 | 35 |
36 |
37 | 38 |
39 | 40 |
41 | 42 | 43 | 44 | 45 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /examples/django_app/example_app/templates/nav.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | -------------------------------------------------------------------------------- /examples/django_app/example_app/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from django.contrib import admin 3 | from example_app.views import ChatterBotAppView, ChatterBotApiView 4 | 5 | 6 | urlpatterns = [ 7 | url(r'^$', ChatterBotAppView.as_view(), name='main'), 8 | url(r'^admin/', admin.site.urls, name='admin'), 9 | url(r'^api/chatterbot/', ChatterBotApiView.as_view(), name='chatterbot'), 10 | ] 11 | -------------------------------------------------------------------------------- /examples/django_app/example_app/views.py: -------------------------------------------------------------------------------- 1 | import json 2 | from django.views.generic.base import TemplateView 3 | from django.views.generic import View 4 | from django.http import JsonResponse 5 | from chatterbot import ChatBot 6 | from chatterbot.ext.django_chatterbot import settings 7 | 8 | 9 | class ChatterBotAppView(TemplateView): 10 | template_name = 'app.html' 11 | 12 | 13 | class ChatterBotApiView(View): 14 | """ 15 | Provide an API endpoint to interact with ChatterBot. 16 | """ 17 | 18 | chatterbot = ChatBot(**settings.CHATTERBOT) 19 | 20 | def post(self, request, *args, **kwargs): 21 | """ 22 | Return a response to the statement in the posted data. 23 | 24 | * The JSON data should contain a 'text' attribute. 25 | """ 26 | input_data = json.loads(request.body.decode('utf-8')) 27 | 28 | if 'text' not in input_data: 29 | return JsonResponse({ 30 | 'text': [ 31 | 'The attribute "text" is required.' 32 | ] 33 | }, status=400) 34 | 35 | response = self.chatterbot.get_response(input_data) 36 | 37 | response_data = response.serialize() 38 | 39 | return JsonResponse(response_data, status=200) 40 | 41 | def get(self, request, *args, **kwargs): 42 | """ 43 | Return data corresponding to the current conversation. 44 | """ 45 | return JsonResponse({ 46 | 'name': self.chatterbot.name 47 | }) 48 | -------------------------------------------------------------------------------- /examples/django_app/example_app/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for django_chatterbot project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example_app.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /examples/django_app/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example_app.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /examples/django_app/requirements.txt: -------------------------------------------------------------------------------- 1 | django>=2.2,<2.3 2 | # chatterbot>=0.8,<1.1 3 | -------------------------------------------------------------------------------- /examples/django_app/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/examples/django_app/tests/__init__.py -------------------------------------------------------------------------------- /examples/django_app/tests/test_api.py: -------------------------------------------------------------------------------- 1 | import json 2 | from django.test import TestCase 3 | from django.urls import reverse 4 | 5 | 6 | class ApiTestCase(TestCase): 7 | 8 | def setUp(self): 9 | super().setUp() 10 | self.api_url = reverse('chatterbot') 11 | 12 | def test_invalid_text(self): 13 | response = self.client.post( 14 | self.api_url, 15 | data=json.dumps({ 16 | 'type': 'classmethod' 17 | }), 18 | content_type='application/json', 19 | format='json' 20 | ) 21 | 22 | self.assertEqual(response.status_code, 400) 23 | self.assertIn('text', response.json()) 24 | self.assertEqual(['The attribute "text" is required.'], response.json()['text']) 25 | 26 | def test_post(self): 27 | """ 28 | Test that a response is returned. 29 | """ 30 | response = self.client.post( 31 | self.api_url, 32 | data=json.dumps({ 33 | 'text': 'How are you?' 34 | }), 35 | content_type='application/json', 36 | format='json' 37 | ) 38 | 39 | self.assertEqual(response.status_code, 200) 40 | self.assertIn('text', response.json()) 41 | self.assertGreater(len(response.json()['text']), 1) 42 | self.assertIn('in_response_to', response.json()) 43 | 44 | def test_post_unicode(self): 45 | """ 46 | Test that a response is returned. 47 | """ 48 | response = self.client.post( 49 | self.api_url, 50 | data=json.dumps({ 51 | 'text': u'سلام' 52 | }), 53 | content_type='application/json', 54 | format='json' 55 | ) 56 | 57 | self.assertEqual(response.status_code, 200) 58 | self.assertIn('text', response.json()) 59 | self.assertGreater(len(response.json()['text']), 1) 60 | self.assertIn('in_response_to', response.json()) 61 | 62 | def test_escaped_unicode_post(self): 63 | """ 64 | Test that unicode reponce 65 | """ 66 | response = self.client.post( 67 | self.api_url, 68 | data=json.dumps({ 69 | 'text': '\u2013' 70 | }), 71 | content_type='application/json', 72 | format=json 73 | ) 74 | 75 | self.assertEqual(response.status_code, 200) 76 | self.assertIn('text', response.json()) 77 | self.assertIn('in_response_to', response.json()) 78 | 79 | def test_post_tags(self): 80 | post_data = { 81 | 'text': 'Good morning.', 82 | 'tags': [ 83 | 'user:jen@example.com' 84 | ] 85 | } 86 | response = self.client.post( 87 | self.api_url, 88 | data=json.dumps(post_data), 89 | content_type='application/json', 90 | format='json' 91 | ) 92 | 93 | self.assertEqual(response.status_code, 200) 94 | self.assertIn('text', response.json()) 95 | self.assertIn('in_response_to', response.json()) 96 | self.assertIn('tags', response.json()) 97 | self.assertEqual(response.json()['tags'], []) 98 | 99 | def test_get(self): 100 | response = self.client.get(self.api_url) 101 | 102 | self.assertEqual(response.status_code, 200) 103 | 104 | def test_patch(self): 105 | response = self.client.patch(self.api_url) 106 | 107 | self.assertEqual(response.status_code, 405) 108 | 109 | def test_put(self): 110 | response = self.client.put(self.api_url) 111 | 112 | self.assertEqual(response.status_code, 405) 113 | 114 | def test_delete(self): 115 | response = self.client.delete(self.api_url) 116 | 117 | self.assertEqual(response.status_code, 405) 118 | -------------------------------------------------------------------------------- /examples/django_app/tests/test_example.py: -------------------------------------------------------------------------------- 1 | import json 2 | from django.test import TestCase 3 | from django.urls import reverse 4 | 5 | 6 | class ViewTestCase(TestCase): 7 | 8 | def setUp(self): 9 | super().setUp() 10 | self.url = reverse('main') 11 | 12 | def test_get_main_page(self): 13 | """ 14 | Test that the main page can be loaded. 15 | """ 16 | response = self.client.get(self.url) 17 | self.assertEqual(response.status_code, 200) 18 | 19 | 20 | class ApiTestCase(TestCase): 21 | """ 22 | Tests to make sure that the ChatterBot app is 23 | properly working with the Django example app. 24 | """ 25 | 26 | def setUp(self): 27 | super().setUp() 28 | self.api_url = reverse('chatterbot') 29 | 30 | def test_post(self): 31 | """ 32 | Test that a response is returned. 33 | """ 34 | data = { 35 | 'text': 'How are you?' 36 | } 37 | response = self.client.post( 38 | self.api_url, 39 | data=json.dumps(data), 40 | content_type='application/json', 41 | format='json' 42 | ) 43 | 44 | self.assertEqual(response.status_code, 200) 45 | self.assertIn('text', response.json()) 46 | self.assertIn('in_response_to', response.json()) 47 | 48 | def test_post_tags(self): 49 | post_data = { 50 | 'text': 'Good morning.', 51 | 'tags': [ 52 | 'user:jen@example.com' 53 | ] 54 | } 55 | response = self.client.post( 56 | self.api_url, 57 | data=json.dumps(post_data), 58 | content_type='application/json', 59 | format='json' 60 | ) 61 | 62 | self.assertEqual(response.status_code, 200) 63 | self.assertIn('text', response.json()) 64 | self.assertIn('in_response_to', response.json()) 65 | self.assertIn('tags', response.json()) 66 | self.assertEqual(response.json()['tags'], []) 67 | 68 | 69 | class ApiIntegrationTestCase(TestCase): 70 | """ 71 | Test to make sure the ChatterBot API view works 72 | properly with the example Django app. 73 | """ 74 | 75 | def setUp(self): 76 | super().setUp() 77 | self.api_url = reverse('chatterbot') 78 | 79 | def test_get(self): 80 | response = self.client.get(self.api_url) 81 | 82 | self.assertIn('name', response.json()) 83 | -------------------------------------------------------------------------------- /examples/export_example.py: -------------------------------------------------------------------------------- 1 | from chatterbot import ChatBot 2 | from chatterbot.trainers import ChatterBotCorpusTrainer 3 | 4 | ''' 5 | This is an example showing how to create an export file from 6 | an existing chat bot that can then be used to train other bots. 7 | ''' 8 | 9 | chatbot = ChatBot('Export Example Bot') 10 | 11 | # First, lets train our bot with some data 12 | trainer = ChatterBotCorpusTrainer(chatbot) 13 | 14 | trainer.train('chatterbot.corpus.english') 15 | 16 | # Now we can export the data to a file 17 | trainer.export_for_training('./my_export.json') 18 | -------------------------------------------------------------------------------- /examples/learning_feedback_example.py: -------------------------------------------------------------------------------- 1 | from chatterbot import ChatBot 2 | from chatterbot.conversation import Statement 3 | 4 | """ 5 | This example shows how to create a chat bot that 6 | will learn responses based on an additional feedback 7 | element from the user. 8 | """ 9 | 10 | # Uncomment the following line to enable verbose logging 11 | # import logging 12 | # logging.basicConfig(level=logging.INFO) 13 | 14 | # Create a new instance of a ChatBot 15 | bot = ChatBot( 16 | 'Feedback Learning Bot', 17 | storage_adapter='chatterbot.storage.SQLStorageAdapter' 18 | ) 19 | 20 | 21 | def get_feedback(): 22 | 23 | text = input() 24 | 25 | if 'yes' in text.lower(): 26 | return True 27 | elif 'no' in text.lower(): 28 | return False 29 | else: 30 | print('Please type either "Yes" or "No"') 31 | return get_feedback() 32 | 33 | 34 | print('Type something to begin...') 35 | 36 | # The following loop will execute each time the user enters input 37 | while True: 38 | try: 39 | input_statement = Statement(text=input()) 40 | response = bot.generate_response( 41 | input_statement 42 | ) 43 | 44 | print('\n Is "{}" a coherent response to "{}"? \n'.format( 45 | response.text, 46 | input_statement.text 47 | )) 48 | if get_feedback() is False: 49 | print('please input the correct one') 50 | correct_response = Statement(text=input()) 51 | bot.learn_response(correct_response, input_statement) 52 | print('Responses added to bot!') 53 | 54 | # Press ctrl-c or ctrl-d on the keyboard to exit 55 | except (KeyboardInterrupt, EOFError, SystemExit): 56 | break 57 | -------------------------------------------------------------------------------- /examples/math_and_time.py: -------------------------------------------------------------------------------- 1 | from chatterbot import ChatBot 2 | 3 | 4 | bot = ChatBot( 5 | 'Math & Time Bot', 6 | logic_adapters=[ 7 | 'chatterbot.logic.MathematicalEvaluation', 8 | 'chatterbot.logic.TimeLogicAdapter' 9 | ] 10 | ) 11 | 12 | # Print an example of getting one math based response 13 | response = bot.get_response('What is 4 + 9?') 14 | print(response) 15 | 16 | # Print an example of getting one time based response 17 | response = bot.get_response('What time is it?') 18 | print(response) 19 | -------------------------------------------------------------------------------- /examples/memory_sql_example.py: -------------------------------------------------------------------------------- 1 | from chatterbot import ChatBot 2 | 3 | # Uncomment the following lines to enable verbose logging 4 | # import logging 5 | # logging.basicConfig(level=logging.INFO) 6 | 7 | # Create a new instance of a ChatBot 8 | bot = ChatBot( 9 | 'SQLMemoryTerminal', 10 | storage_adapter='chatterbot.storage.SQLStorageAdapter', 11 | database_uri=None, 12 | logic_adapters=[ 13 | 'chatterbot.logic.MathematicalEvaluation', 14 | 'chatterbot.logic.TimeLogicAdapter', 15 | 'chatterbot.logic.BestMatch' 16 | ] 17 | ) 18 | 19 | # Get a few responses from the bot 20 | 21 | bot.get_response('What time is it?') 22 | 23 | bot.get_response('What is 7 plus 7?') 24 | -------------------------------------------------------------------------------- /examples/specific_response_example.py: -------------------------------------------------------------------------------- 1 | from chatterbot import ChatBot 2 | 3 | 4 | # Create a new instance of a ChatBot 5 | bot = ChatBot( 6 | 'Exact Response Example Bot', 7 | storage_adapter='chatterbot.storage.SQLStorageAdapter', 8 | logic_adapters=[ 9 | { 10 | 'import_path': 'chatterbot.logic.BestMatch' 11 | }, 12 | { 13 | 'import_path': 'chatterbot.logic.SpecificResponseAdapter', 14 | 'input_text': 'Help me!', 15 | 'output_text': 'Ok, here is a link: http://chatterbot.rtfd.org' 16 | } 17 | ] 18 | ) 19 | 20 | # Get a response given the specific input 21 | response = bot.get_response('Help me!') 22 | print(response) 23 | -------------------------------------------------------------------------------- /examples/tagged_dataset_example.py: -------------------------------------------------------------------------------- 1 | from chatterbot import ChatBot 2 | from chatterbot.conversation import Statement 3 | 4 | 5 | chatbot = ChatBot( 6 | 'Example Bot', 7 | # This database will be a temporary in-memory database 8 | database_uri=None 9 | ) 10 | 11 | label_a_statements = [ 12 | Statement(text='Hello', tags=['label_a']), 13 | Statement(text='Hi', tags=['label_a']), 14 | Statement(text='How are you?', tags=['label_a']) 15 | ] 16 | 17 | label_b_statements = [ 18 | Statement(text='I like dogs.', tags=['label_b']), 19 | Statement(text='I like cats.', tags=['label_b']), 20 | Statement(text='I like animals.', tags=['label_b']) 21 | ] 22 | 23 | chatbot.storage.create_many( 24 | label_a_statements + label_b_statements 25 | ) 26 | 27 | # Return a response from "label_a_statements" 28 | response_from_label_a = chatbot.get_response( 29 | 'How are you?', 30 | additional_response_selection_parameters={ 31 | 'tags': ['label_a'] 32 | } 33 | ) 34 | 35 | # Return a response from "label_b_statements" 36 | response_from_label_b = chatbot.get_response( 37 | 'How are you?', 38 | additional_response_selection_parameters={ 39 | 'tags': ['label_b'] 40 | } 41 | ) 42 | 43 | print('Response from label_a collection:', response_from_label_a.text) 44 | print('Response from label_b collection:', response_from_label_b.text) 45 | -------------------------------------------------------------------------------- /examples/terminal_example.py: -------------------------------------------------------------------------------- 1 | from chatterbot import ChatBot 2 | 3 | 4 | # Uncomment the following lines to enable verbose logging 5 | # import logging 6 | # logging.basicConfig(level=logging.INFO) 7 | 8 | # Create a new instance of a ChatBot 9 | bot = ChatBot( 10 | 'Terminal', 11 | storage_adapter='chatterbot.storage.SQLStorageAdapter', 12 | logic_adapters=[ 13 | 'chatterbot.logic.MathematicalEvaluation', 14 | 'chatterbot.logic.TimeLogicAdapter', 15 | 'chatterbot.logic.BestMatch' 16 | ], 17 | database_uri='sqlite:///database.sqlite3' 18 | ) 19 | 20 | print('Type something to begin...') 21 | 22 | # The following loop will execute each time the user enters input 23 | while True: 24 | try: 25 | user_input = input() 26 | 27 | bot_response = bot.get_response(user_input) 28 | 29 | print(bot_response) 30 | 31 | # Press ctrl-c or ctrl-d on the keyboard to exit 32 | except (KeyboardInterrupt, EOFError, SystemExit): 33 | break 34 | -------------------------------------------------------------------------------- /examples/terminal_mongo_example.py: -------------------------------------------------------------------------------- 1 | from chatterbot import ChatBot 2 | 3 | # Uncomment the following lines to enable verbose logging 4 | # import logging 5 | # logging.basicConfig(level=logging.INFO) 6 | 7 | # Create a new ChatBot instance 8 | bot = ChatBot( 9 | 'Terminal', 10 | storage_adapter='chatterbot.storage.MongoDatabaseAdapter', 11 | logic_adapters=[ 12 | 'chatterbot.logic.BestMatch' 13 | ], 14 | database_uri='mongodb://localhost:27017/chatterbot-database' 15 | ) 16 | 17 | print('Type something to begin...') 18 | 19 | while True: 20 | try: 21 | user_input = input() 22 | 23 | bot_response = bot.get_response(user_input) 24 | 25 | print(bot_response) 26 | 27 | # Press ctrl-c or ctrl-d on the keyboard to exit 28 | except (KeyboardInterrupt, EOFError, SystemExit): 29 | break 30 | -------------------------------------------------------------------------------- /examples/tkinter_gui.py: -------------------------------------------------------------------------------- 1 | from chatterbot import ChatBot 2 | import tkinter as tk 3 | try: 4 | import ttk as ttk 5 | import ScrolledText 6 | except ImportError: 7 | import tkinter.ttk as ttk 8 | import tkinter.scrolledtext as ScrolledText 9 | import time 10 | 11 | 12 | class TkinterGUIExample(tk.Tk): 13 | 14 | def __init__(self, *args, **kwargs): 15 | """ 16 | Create & set window variables. 17 | """ 18 | tk.Tk.__init__(self, *args, **kwargs) 19 | 20 | self.chatbot = ChatBot( 21 | "GUI Bot", 22 | storage_adapter="chatterbot.storage.SQLStorageAdapter", 23 | logic_adapters=[ 24 | "chatterbot.logic.BestMatch" 25 | ], 26 | database_uri="sqlite:///database.sqlite3" 27 | ) 28 | 29 | self.title("Chatterbot") 30 | 31 | self.initialize() 32 | 33 | def initialize(self): 34 | """ 35 | Set window layout. 36 | """ 37 | self.grid() 38 | 39 | self.respond = ttk.Button(self, text='Get Response', command=self.get_response) 40 | self.respond.grid(column=0, row=0, sticky='nesw', padx=3, pady=3) 41 | 42 | self.usr_input = ttk.Entry(self, state='normal') 43 | self.usr_input.grid(column=1, row=0, sticky='nesw', padx=3, pady=3) 44 | 45 | self.conversation_lbl = ttk.Label(self, anchor=tk.E, text='Conversation:') 46 | self.conversation_lbl.grid(column=0, row=1, sticky='nesw', padx=3, pady=3) 47 | 48 | self.conversation = ScrolledText.ScrolledText(self, state='disabled') 49 | self.conversation.grid(column=0, row=2, columnspan=2, sticky='nesw', padx=3, pady=3) 50 | 51 | def get_response(self): 52 | """ 53 | Get a response from the chatbot and display it. 54 | """ 55 | user_input = self.usr_input.get() 56 | self.usr_input.delete(0, tk.END) 57 | 58 | response = self.chatbot.get_response(user_input) 59 | 60 | self.conversation['state'] = 'normal' 61 | self.conversation.insert( 62 | tk.END, "Human: " + user_input + "\n" + "ChatBot: " + str(response.text) + "\n" 63 | ) 64 | self.conversation['state'] = 'disabled' 65 | 66 | time.sleep(0.5) 67 | 68 | 69 | gui_example = TkinterGUIExample() 70 | gui_example.mainloop() 71 | -------------------------------------------------------------------------------- /examples/training_example_chatterbot_corpus.py: -------------------------------------------------------------------------------- 1 | from chatterbot import ChatBot 2 | from chatterbot.trainers import ChatterBotCorpusTrainer 3 | import logging 4 | 5 | 6 | ''' 7 | This is an example showing how to train a chat bot using the 8 | ChatterBot Corpus of conversation dialog. 9 | ''' 10 | 11 | # Enable info level logging 12 | logging.basicConfig(level=logging.INFO) 13 | 14 | chatbot = ChatBot('Example Bot') 15 | 16 | # Start by training our bot with the ChatterBot corpus data 17 | trainer = ChatterBotCorpusTrainer(chatbot) 18 | 19 | trainer.train( 20 | 'chatterbot.corpus.english' 21 | ) 22 | 23 | # Now let's get a response to a greeting 24 | response = chatbot.get_response('How are you doing today?') 25 | print(response) 26 | -------------------------------------------------------------------------------- /examples/training_example_list_data.py: -------------------------------------------------------------------------------- 1 | from chatterbot import ChatBot 2 | from chatterbot.trainers import ListTrainer 3 | 4 | 5 | ''' 6 | This is an example showing how to train a chat bot using the 7 | ChatterBot ListTrainer. 8 | ''' 9 | 10 | chatbot = ChatBot('Example Bot') 11 | 12 | # Start by training our bot with the ChatterBot corpus data 13 | trainer = ListTrainer(chatbot) 14 | 15 | trainer.train([ 16 | 'Hello, how are you?', 17 | 'I am doing well.', 18 | 'That is good to hear.', 19 | 'Thank you' 20 | ]) 21 | 22 | # You can train with a second list of data to add response variations 23 | 24 | trainer.train([ 25 | 'Hello, how are you?', 26 | 'I am great.', 27 | 'That is awesome.', 28 | 'Thanks' 29 | ]) 30 | 31 | # Now let's get a response to a greeting 32 | response = chatbot.get_response('How are you doing today?') 33 | print(response) 34 | -------------------------------------------------------------------------------- /examples/training_example_ubuntu_corpus.py: -------------------------------------------------------------------------------- 1 | """ 2 | This example shows how to train a chat bot using the 3 | Ubuntu Corpus of conversation dialog. 4 | """ 5 | import logging 6 | from chatterbot import ChatBot 7 | from chatterbot.trainers import UbuntuCorpusTrainer 8 | 9 | # Enable info level logging 10 | logging.basicConfig(level=logging.INFO) 11 | 12 | chatbot = ChatBot('Example Bot') 13 | 14 | trainer = UbuntuCorpusTrainer(chatbot) 15 | 16 | # Start by training our bot with the Ubuntu corpus data 17 | trainer.train() 18 | 19 | # Now let's get a response to a greeting 20 | response = chatbot.get_response('How are you doing today?') 21 | print(response) 22 | -------------------------------------------------------------------------------- /python module1/AWS exercise.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/python module1/AWS exercise.docx -------------------------------------------------------------------------------- /python module1/Assignment Python Fundamentals.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/python module1/Assignment Python Fundamentals.pdf -------------------------------------------------------------------------------- /python module1/Kenoics_curriculum-AI with Python_final.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/python module1/Kenoics_curriculum-AI with Python_final.pdf -------------------------------------------------------------------------------- /python module1/Python_Fundamentals_01_Control Flows.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/python module1/Python_Fundamentals_01_Control Flows.pdf -------------------------------------------------------------------------------- /python module1/Python_Fundamentals_01_Data_Types_and_Operators.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/python module1/Python_Fundamentals_01_Data_Types_and_Operators.pdf -------------------------------------------------------------------------------- /python module1/instapdf.in-rich-dad-poor-dad-152.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/python module1/instapdf.in-rich-dad-poor-dad-152.pdf -------------------------------------------------------------------------------- /python module2/Advanced Concepts Using Datastructures.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/python module2/Advanced Concepts Using Datastructures.pptx -------------------------------------------------------------------------------- /python module2/Functions.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/python module2/Functions.pptx -------------------------------------------------------------------------------- /python module2/Python Classes.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/python module2/Python Classes.pptx -------------------------------------------------------------------------------- /python module2/Python Scripting.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/python module2/Python Scripting.pptx -------------------------------------------------------------------------------- /python module3/Business Statistics (2).pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/python module3/Business Statistics (2).pptx -------------------------------------------------------------------------------- /tests_django/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RashmivernekarN/python_Moduls/0e6cb3b20a4f88f028e32cc0fccbd534a6bf58f4/tests_django/__init__.py -------------------------------------------------------------------------------- /tests_django/base_case.py: -------------------------------------------------------------------------------- 1 | from chatterbot import ChatBot 2 | from django.test import TransactionTestCase 3 | from tests_django import test_settings 4 | 5 | 6 | class ChatterBotTestCase(TransactionTestCase): 7 | 8 | def setUp(self): 9 | super().setUp() 10 | self.chatbot = ChatBot(**test_settings.CHATTERBOT) 11 | -------------------------------------------------------------------------------- /tests_django/test_chatbot.py: -------------------------------------------------------------------------------- 1 | from tests_django.base_case import ChatterBotTestCase 2 | from chatterbot.conversation import Statement 3 | 4 | 5 | class ChatBotTests(ChatterBotTestCase): 6 | 7 | def test_get_response_text(self): 8 | self.chatbot.get_response(text='Test') 9 | 10 | def test_no_statements_known(self): 11 | """ 12 | If there is no statements in the database, then the 13 | user's input is the only thing that can be returned. 14 | """ 15 | statement_text = 'How are you?' 16 | response = self.chatbot.get_response(statement_text) 17 | results = list(self.chatbot.storage.filter(text=statement_text)) 18 | 19 | self.assertEqual(response.text, statement_text) 20 | self.assertEqual(response.confidence, 0) 21 | 22 | # Make sure that the input and output were saved 23 | self.assertEqual(len(results), 2) 24 | self.assertEqual(results[0].text, statement_text) 25 | self.assertEqual(results[1].text, statement_text) 26 | 27 | def test_one_statement_known_no_response(self): 28 | """ 29 | Test the case where a single statement is known, but 30 | it is not in response to any other statement. 31 | """ 32 | self.chatbot.storage.create(text='Hello', in_response_to=None) 33 | 34 | response = self.chatbot.get_response('Hi') 35 | 36 | self.assertEqual(response.confidence, 0) 37 | self.assertEqual(response.text, 'Hello') 38 | 39 | def test_one_statement_one_response_known(self): 40 | """ 41 | Test the case that one response is known and there is a response 42 | entry for it in the database. 43 | """ 44 | self.chatbot.storage.create(text='Hello', in_response_to='Hi') 45 | 46 | response = self.chatbot.get_response('Hi') 47 | 48 | self.assertEqual(response.confidence, 0) 49 | self.assertEqual(response.text, 'Hello') 50 | 51 | def test_two_statements_one_response_known(self): 52 | """ 53 | Test the case that one response is known and there is a response 54 | entry for it in the database. 55 | """ 56 | self.chatbot.storage.create(text='Hi', in_response_to=None) 57 | self.chatbot.storage.create(text='Hello', in_response_to='Hi') 58 | 59 | response = self.chatbot.get_response('Hi') 60 | 61 | self.assertEqual(response.confidence, 1) 62 | self.assertEqual(response.text, 'Hello') 63 | 64 | def test_three_statements_two_responses_known(self): 65 | self.chatbot.storage.create(text='Hi', in_response_to=None) 66 | self.chatbot.storage.create(text='Hello', in_response_to='Hi') 67 | self.chatbot.storage.create(text='How are you?', in_response_to='Hello') 68 | 69 | first_response = self.chatbot.get_response('Hi') 70 | second_response = self.chatbot.get_response('How are you?') 71 | 72 | self.assertEqual(first_response.confidence, 1) 73 | self.assertEqual(first_response.text, 'Hello') 74 | self.assertEqual(second_response.confidence, 0) 75 | 76 | def test_four_statements_three_responses_known(self): 77 | self.chatbot.storage.create(text='Hi', in_response_to=None) 78 | self.chatbot.storage.create(text='Hello', in_response_to='Hi') 79 | self.chatbot.storage.create(text='How are you?', in_response_to='Hello') 80 | self.chatbot.storage.create(text='I am well.', in_response_to='How are you?') 81 | 82 | first_response = self.chatbot.get_response('Hi') 83 | second_response = self.chatbot.get_response('How are you?') 84 | 85 | self.assertEqual(first_response.confidence, 1) 86 | self.assertEqual(first_response.text, 'Hello') 87 | self.assertEqual(second_response.confidence, 1) 88 | self.assertEqual(second_response.text, 'I am well.') 89 | 90 | def test_second_response_unknown(self): 91 | self.chatbot.storage.create(text='Hi', in_response_to=None) 92 | self.chatbot.storage.create(text='Hello', in_response_to='Hi') 93 | 94 | first_response = self.chatbot.get_response( 95 | text='Hi', 96 | conversation='test' 97 | ) 98 | second_response = self.chatbot.get_response( 99 | text='How are you?', 100 | conversation='test' 101 | ) 102 | 103 | results = list(self.chatbot.storage.filter(text='How are you?')) 104 | 105 | self.assertEqual(first_response.confidence, 1) 106 | self.assertEqual(first_response.text, 'Hello') 107 | self.assertEqual(first_response.in_response_to, 'Hi') 108 | 109 | self.assertEqual(second_response.confidence, 0) 110 | self.assertEqual(second_response.in_response_to, 'How are you?') 111 | 112 | # Make sure that the second response was saved to the database 113 | self.assertEqual(len(results), 1) 114 | self.assertEqual(results[0].in_response_to, 'Hi') 115 | 116 | def test_statement_added_to_conversation(self): 117 | """ 118 | An input statement should be added to the recent response list. 119 | """ 120 | statement = Statement(text='Wow!', conversation='test') 121 | response = self.chatbot.get_response(statement) 122 | 123 | self.assertEqual(statement.text, response.text) 124 | self.assertEqual(response.conversation, 'test') 125 | 126 | def test_get_response_additional_response_selection_parameters(self): 127 | self.chatbot.storage.create_many([ 128 | Statement('A', conversation='test_1'), 129 | Statement('B', conversation='test_1', in_response_to='A'), 130 | Statement('A', conversation='test_2'), 131 | Statement('C', conversation='test_2', in_response_to='A'), 132 | ]) 133 | 134 | statement = Statement(text='A', conversation='test_3') 135 | response = self.chatbot.get_response(statement, additional_response_selection_parameters={ 136 | 'conversation': 'test_2' 137 | }) 138 | 139 | self.assertEqual(response.text, 'C') 140 | self.assertEqual(response.conversation, 'test_3') 141 | 142 | def test_get_response_unicode(self): 143 | """ 144 | Test the case that a unicode string is passed in. 145 | """ 146 | response = self.chatbot.get_response(u'سلام') 147 | self.assertGreater(len(response.text), 0) 148 | 149 | def test_get_response_emoji(self): 150 | """ 151 | Test the case that the input string contains an emoji. 152 | """ 153 | response = self.chatbot.get_response(u'💩 ') 154 | self.assertGreater(len(response.text), 0) 155 | 156 | def test_get_response_non_whitespace(self): 157 | """ 158 | Test the case that a non-whitespace C1 control string is passed in. 159 | """ 160 | response = self.chatbot.get_response(u'€Ž‘’') 161 | self.assertGreater(len(response.text), 0) 162 | 163 | def test_get_response_two_byte_characters(self): 164 | """ 165 | Test the case that a string containing two-byte characters is passed in. 166 | """ 167 | response = self.chatbot.get_response(u'田中さんにあげて下さい') 168 | self.assertGreater(len(response.text), 0) 169 | 170 | def test_get_response_corrupted_text(self): 171 | """ 172 | Test the case that a string contains "corrupted" text. 173 | """ 174 | response = self.chatbot.get_response(u'Ṱ̺̺̕h̼͓̲̦̳̘̲e͇̣̰̦̬͎ ̢̼̻̱̘h͚͎͙̜̣̲ͅi̦̲̣̰̤v̻͍e̺̭̳̪̰-m̢iͅn̖̺̞̲̯̰d̵̼̟͙̩̼̘̳.̨̹͈̣') 175 | self.assertGreater(len(response.text), 0) 176 | 177 | def test_response_with_tags_added(self): 178 | """ 179 | If an input statement has tags added to it, 180 | that data should saved with the input statement. 181 | """ 182 | self.chatbot.get_response(Statement( 183 | text='Hello', 184 | in_response_to='Hi', 185 | tags=['test'] 186 | )) 187 | 188 | results = list(self.chatbot.storage.filter(text='Hello')) 189 | 190 | self.assertEqual(len(results), 2) 191 | self.assertIn('test', results[0].get_tags()) 192 | self.assertEqual(results[1].get_tags(), []) 193 | 194 | def test_get_response_with_text_and_kwargs(self): 195 | self.chatbot.get_response('Hello', conversation='greetings') 196 | 197 | results = list(self.chatbot.storage.filter(text='Hello')) 198 | 199 | self.assertEqual(len(results), 2) 200 | self.assertEqual(results[0].conversation, 'greetings') 201 | self.assertEqual(results[1].conversation, 'greetings') 202 | 203 | def test_get_response_missing_text(self): 204 | with self.assertRaises(self.chatbot.ChatBotException): 205 | self.chatbot.get_response() 206 | 207 | def test_get_response_missing_text_with_conversation(self): 208 | with self.assertRaises(self.chatbot.ChatBotException): 209 | self.chatbot.get_response(conversation='test') 210 | 211 | def test_generate_response(self): 212 | statement = Statement(text='Many insects adopt a tripedal gait for rapid yet stable walking.') 213 | response = self.chatbot.generate_response(statement) 214 | 215 | self.assertEqual(response.text, statement.text) 216 | self.assertEqual(response.confidence, 0) 217 | 218 | def test_learn_response(self): 219 | previous_response = Statement(text='Define Hemoglobin.') 220 | statement = Statement(text='Hemoglobin is an oxygen-transport metalloprotein.') 221 | self.chatbot.learn_response(statement, previous_response) 222 | results = list(self.chatbot.storage.filter(text=statement.text)) 223 | 224 | self.assertEqual(len(results), 1) 225 | 226 | def test_get_response_does_not_add_new_statement(self): 227 | """ 228 | Test that a new statement is not learned if `read_only` is set to True. 229 | """ 230 | self.chatbot.read_only = True 231 | self.chatbot.get_response('Hi!') 232 | results = list(self.chatbot.storage.filter(text='Hi!')) 233 | 234 | self.assertEqual(len(results), 0) 235 | 236 | def test_get_latest_response_from_zero_responses(self): 237 | response = self.chatbot.get_latest_response('invalid') 238 | 239 | self.assertIsNone(response) 240 | 241 | def test_get_latest_response_from_one_responses(self): 242 | self.chatbot.storage.create(text='A', conversation='test') 243 | self.chatbot.storage.create(text='B', conversation='test', in_response_to='A') 244 | 245 | response = self.chatbot.get_latest_response('test') 246 | 247 | self.assertEqual(response.text, 'A') 248 | 249 | def test_get_latest_response_from_two_responses(self): 250 | self.chatbot.storage.create(text='A', conversation='test') 251 | self.chatbot.storage.create(text='B', conversation='test', in_response_to='A') 252 | self.chatbot.storage.create(text='C', conversation='test', in_response_to='B') 253 | 254 | response = self.chatbot.get_latest_response('test') 255 | 256 | self.assertEqual(response.text, 'B') 257 | 258 | def test_get_latest_response_from_three_responses(self): 259 | self.chatbot.storage.create(text='A', conversation='test') 260 | self.chatbot.storage.create(text='B', conversation='test', in_response_to='A') 261 | self.chatbot.storage.create(text='C', conversation='test', in_response_to='B') 262 | self.chatbot.storage.create(text='D', conversation='test', in_response_to='C') 263 | 264 | response = self.chatbot.get_latest_response('test') 265 | 266 | self.assertEqual(response.text, 'C') 267 | 268 | def test_search_text_results_after_training(self): 269 | """ 270 | ChatterBot should return close matches to an input 271 | string when filtering using the search_text parameter. 272 | """ 273 | self.chatbot.storage.create_many([ 274 | Statement('Example A for search.'), 275 | Statement('Another example.'), 276 | Statement('Example B for search.'), 277 | Statement(text='Another statement.'), 278 | ]) 279 | 280 | results = list(self.chatbot.storage.filter( 281 | search_text=self.chatbot.storage.tagger.get_text_index_string( 282 | 'Example A for search.' 283 | ) 284 | )) 285 | 286 | self.assertEqual(len(results), 1, msg=[r.text for r in results]) 287 | self.assertEqual('Example A for search.', results[0].text) 288 | 289 | def test_search_text_contains_results_after_training(self): 290 | """ 291 | ChatterBot should return close matches to an input 292 | string when filtering using the search_text parameter. 293 | """ 294 | self.chatbot.storage.create_many([ 295 | Statement('Example A for search.'), 296 | Statement('Another example.'), 297 | Statement('Example B for search.'), 298 | Statement(text='Another statement.'), 299 | ]) 300 | 301 | results = list(self.chatbot.storage.filter( 302 | search_text_contains=self.chatbot.storage.tagger.get_text_index_string( 303 | 'Example A for search.' 304 | ) 305 | )) 306 | 307 | self.assertEqual(len(results), 2, msg=[r.text for r in results]) 308 | self.assertEqual('Example A for search.', results[0].text) 309 | self.assertEqual('Example B for search.', results[1].text) 310 | -------------------------------------------------------------------------------- /tests_django/test_chatterbot_corpus_training.py: -------------------------------------------------------------------------------- 1 | from tests_django.base_case import ChatterBotTestCase 2 | from chatterbot.trainers import ChatterBotCorpusTrainer 3 | 4 | 5 | class ChatterBotCorpusTrainingTestCase(ChatterBotTestCase): 6 | """ 7 | Test case for training with data from the ChatterBot Corpus. 8 | 9 | Note: This class has a mirror tests/training_tests/ 10 | """ 11 | 12 | def setUp(self): 13 | super().setUp() 14 | 15 | self.trainer = ChatterBotCorpusTrainer( 16 | self.chatbot, 17 | show_training_progress=False 18 | ) 19 | 20 | def tearDown(self): 21 | super().tearDown() 22 | self.chatbot.storage.drop() 23 | 24 | def test_train_with_english_greeting_corpus(self): 25 | self.trainer.train('chatterbot.corpus.english.greetings') 26 | 27 | results = list(self.chatbot.storage.filter(text='Hello')) 28 | 29 | self.assertGreater(len(results), 1) 30 | 31 | def test_train_with_english_greeting_corpus_tags(self): 32 | self.trainer.train('chatterbot.corpus.english.greetings') 33 | 34 | results = list(self.chatbot.storage.filter(text='Hello')) 35 | 36 | self.assertGreater(len(results), 1) 37 | statement = results[0] 38 | self.assertEqual(['greetings'], statement.get_tags()) 39 | 40 | def test_train_with_multiple_corpora(self): 41 | self.trainer.train( 42 | 'chatterbot.corpus.english.greetings', 43 | 'chatterbot.corpus.english.conversations', 44 | ) 45 | results = list(self.chatbot.storage.filter(text='Hello')) 46 | 47 | self.assertGreater(len(results), 1) 48 | 49 | def test_train_with_english_corpus(self): 50 | self.trainer.train('chatterbot.corpus.english') 51 | results = list(self.chatbot.storage.filter(text='Hello')) 52 | 53 | self.assertGreater(len(results), 1) 54 | -------------------------------------------------------------------------------- /tests_django/test_chatterbot_settings.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from django.conf import settings 3 | 4 | 5 | class SettingsTestCase(TestCase): 6 | 7 | def test_modified_settings(self): 8 | with self.settings(CHATTERBOT={'name': 'Jim'}): 9 | self.assertIn('name', settings.CHATTERBOT) 10 | self.assertEqual('Jim', settings.CHATTERBOT['name']) 11 | 12 | def test_name_setting(self): 13 | with self.settings(): 14 | self.assertIn('name', settings.CHATTERBOT) 15 | self.assertEqual('Test Django ChatterBot', settings.CHATTERBOT['name']) 16 | -------------------------------------------------------------------------------- /tests_django/test_logic_adapter_integration.py: -------------------------------------------------------------------------------- 1 | from tests_django.base_case import ChatterBotTestCase 2 | from chatterbot.conversation import Statement 3 | 4 | 5 | class LogicIntegrationTestCase(ChatterBotTestCase): 6 | """ 7 | Tests to make sure that logic adapters 8 | function correctly when using Django. 9 | """ 10 | 11 | def setUp(self): 12 | super().setUp() 13 | 14 | self.chatbot.storage.create(text='Default statement') 15 | 16 | def test_best_match(self): 17 | from chatterbot.logic import BestMatch 18 | 19 | adapter = BestMatch(self.chatbot) 20 | 21 | statement1 = self.chatbot.storage.create( 22 | text='Do you like programming?', 23 | conversation='test' 24 | ) 25 | 26 | self.chatbot.storage.create( 27 | text='Yes', 28 | in_response_to=statement1.text, 29 | conversation='test' 30 | ) 31 | 32 | response = adapter.process(statement1) 33 | 34 | self.assertEqual(response.text, 'Yes') 35 | self.assertEqual(response.confidence, 1) 36 | 37 | def test_mathematical_evaluation(self): 38 | from chatterbot.logic import MathematicalEvaluation 39 | 40 | adapter = MathematicalEvaluation(self.chatbot) 41 | 42 | statement = Statement(text='What is 6 + 6?') 43 | 44 | response = adapter.process(statement) 45 | 46 | self.assertEqual(response.text, '6 + 6 = 12') 47 | self.assertEqual(response.confidence, 1) 48 | 49 | def test_time(self): 50 | from chatterbot.logic import TimeLogicAdapter 51 | 52 | adapter = TimeLogicAdapter(self.chatbot) 53 | 54 | statement = Statement(text='What time is it?') 55 | 56 | response = adapter.process(statement) 57 | 58 | self.assertIn('The current time is', response.text) 59 | self.assertEqual(response.confidence, 1) 60 | -------------------------------------------------------------------------------- /tests_django/test_settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for when tests are run. 3 | """ 4 | import os 5 | from chatterbot import constants 6 | 7 | DEBUG = True 8 | 9 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 10 | 11 | SECRET_KEY = 'fake-key' 12 | 13 | INSTALLED_APPS = [ 14 | 'django.contrib.auth', 15 | 'django.contrib.contenttypes', 16 | 'django.contrib.sessions', 17 | 'chatterbot.ext.django_chatterbot', 18 | 'tests_django', 19 | ] 20 | 21 | CHATTERBOT = { 22 | 'name': 'Test Django ChatterBot', 23 | 'logic_adapters': [ 24 | { 25 | 'import_path': 'chatterbot.logic.BestMatch', 26 | }, 27 | { 28 | 'import_path': 'chatterbot.logic.MathematicalEvaluation', 29 | } 30 | ], 31 | 'storage_adapter': 'chatterbot.storage.DjangoStorageAdapter', 32 | 'django_app_name': constants.DEFAULT_DJANGO_APP_NAME, 33 | 'initialize': False 34 | } 35 | 36 | MIDDLEWARE_CLASSES = ( 37 | 'django.contrib.sessions.middleware.SessionMiddleware', 38 | 'django.middleware.common.CommonMiddleware', 39 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 40 | 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 41 | 'django.contrib.messages.middleware.MessageMiddleware', 42 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 43 | 'django.middleware.security.SecurityMiddleware', 44 | ) 45 | 46 | DATABASES = { 47 | 'default': { 48 | 'ENGINE': 'django.db.backends.sqlite3', 49 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 50 | } 51 | } 52 | 53 | # Using the MD5 password hasher improves test performance 54 | PASSWORD_HASHERS = ( 55 | 'django.contrib.auth.hashers.MD5PasswordHasher', 56 | ) 57 | 58 | USE_TZ = True 59 | 60 | LOGGING = { 61 | 'version': 1, 62 | 'disable_existing_loggers': False, 63 | 'handlers': { 64 | 'console': { 65 | 'class': 'logging.StreamHandler', 66 | }, 67 | }, 68 | 'loggers': { 69 | 'django': { 70 | 'handlers': ['console'], 71 | 'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'), 72 | }, 73 | }, 74 | } 75 | -------------------------------------------------------------------------------- /tests_django/test_statement_integration.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from chatterbot.conversation import Statement as StatementObject 3 | from chatterbot.ext.django_chatterbot.models import Statement as StatementModel 4 | 5 | 6 | class StatementIntegrationTestCase(TestCase): 7 | """ 8 | Test case to make sure that the Django Statement model 9 | and ChatterBot Statement object have a common interface. 10 | """ 11 | 12 | def setUp(self): 13 | super().setUp() 14 | 15 | from datetime import datetime 16 | from pytz import UTC 17 | 18 | now = datetime(2020, 2, 15, 3, 14, 10, 0, UTC) 19 | 20 | self.object = StatementObject(text='_', created_at=now) 21 | self.model = StatementModel(text='_', created_at=now) 22 | 23 | # Simulate both statements being saved 24 | self.model.save() 25 | self.object.id = self.model.id 26 | 27 | def test_text(self): 28 | self.assertTrue(hasattr(self.object, 'text')) 29 | self.assertTrue(hasattr(self.model, 'text')) 30 | 31 | def test_in_response_to(self): 32 | self.assertTrue(hasattr(self.object, 'in_response_to')) 33 | self.assertTrue(hasattr(self.model, 'in_response_to')) 34 | 35 | def test_conversation(self): 36 | self.assertTrue(hasattr(self.object, 'conversation')) 37 | self.assertTrue(hasattr(self.model, 'conversation')) 38 | 39 | def test_tags(self): 40 | self.assertTrue(hasattr(self.object, 'tags')) 41 | self.assertTrue(hasattr(self.model, 'tags')) 42 | 43 | def test__str__(self): 44 | self.assertTrue(hasattr(self.object, '__str__')) 45 | self.assertTrue(hasattr(self.model, '__str__')) 46 | 47 | self.assertEqual(str(self.object), str(self.model)) 48 | 49 | def test_add_tags(self): 50 | self.object.add_tags('a', 'b') 51 | self.model.add_tags('a', 'b') 52 | 53 | self.assertIn('a', self.object.get_tags()) 54 | self.assertIn('a', self.model.get_tags()) 55 | 56 | def test_serialize(self): 57 | object_data = self.object.serialize() 58 | model_data = self.model.serialize() 59 | 60 | self.assertEqual(object_data, model_data) 61 | --------------------------------------------------------------------------------