diff --git a/README.md b/README.md index 94d3d45..1f608de 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -# neuralintents -Still in a buggy alpha state. + +# NeuralIntents + + ## Setting Up A Basic Assistant @@ -27,14 +29,11 @@ while not done: ```python from neuralintents.assistants import BasicAssistant - stocks = ['AAPL', 'META', 'TSLA', 'NVDA'] - def print_stocks(): print(f'Stocks: {stocks}') - assistant = BasicAssistant('intents.json', method_mappings={ "stocks": print_stocks, "goodbye": lambda: exit(0) @@ -53,34 +52,61 @@ while not done: print(assistant.process_input(message)) ``` -## Sample intents.json File +## Sample `intents.json` File + ```json -{"intents": [ - {"tag": "greeting", - "patterns": ["Hi", "How are you", "Is anyone there?", "Hello", "Good day", "Whats up", "Hey", "greetings"], - "responses": ["Hello!", "Good to see you again!", "Hi there, how can I help?"], - "context_set": "" - }, - {"tag": "goodbye", - "patterns": ["cya", "See you later", "Goodbye", "I am Leaving", "Have a Good day", "bye", "cao", "see ya"], - "responses": ["Sad to see you go :(", "Talk to you later", "Goodbye!"], - "context_set": "" - }, - {"tag": "programming", - "patterns": ["What is progamming?", "What is coding?", "Tell me about programming", "Tell me about coding", "What is software development?"], - "responses": ["Programming, coding or software development, means writing computer code to automate tasks."], - "context_set": "" - }, - {"tag": "resource", - "patterns": ["Where can I learn to code?", "Best way to learn to code", "How can I learn programming", "Good programming resources", "Can you recommend good coding resources?"], - "responses": ["Check out the NeuralNine YouTube channel and The Python Bible series (7 in 1)."], - "context_set": "" - }, - {"tag": "stocks", - "patterns": ["What are my stocks?", "Which stocks do I own?", "Show my stock portfolio"], - "responses": ["Here are your stocks!"], - "context_set": "" - } -] +{ + "intents": [ + { + "tag": "greeting", + "patterns": ["Hi", "How are you", "Is anyone there?", "Hello", "Good day", "Whats up", "Hey", "greetings"], + "responses": ["Hello!", "Good to see you again!", "Hi there, how can I help?"], + "context_set": "" + }, + { + "tag": "goodbye", + "patterns": ["cya", "See you later", "Goodbye", "I am Leaving", "Have a Good day", "bye", "cao", "see ya"], + "responses": ["Sad to see you go :(", "Talk to you later", "Goodbye!"], + "context_set": "" + }, + { + "tag": "programming", + "patterns": ["What is programming?", "What is coding?", "Tell me about programming", "Tell me about coding", "What is software development?"], + "responses": ["Programming, coding or software development, means writing computer code to automate tasks."], + "context_set": "" + }, + { + "tag": "resource", + "patterns": ["Where can I learn to code?", "Best way to learn to code", "How can I learn programming", "Good programming resources", "Can you recommend good coding resources?"], + "responses": ["Check out the NeuralNine YouTube channel and The Python Bible series (7 in 1)."], + "context_set": "" + }, + { + "tag": "stocks", + "patterns": ["What are my stocks?", "Which stocks do I own?", "Show my stock portfolio"], + "responses": ["Here are your stocks!"], + "context_set": "" + } + ] } -``` \ No newline at end of file +``` + +## Loading a Pre-Trained Model + +Once you've trained a model, you can load it to avoid training every time. + +```python +from neuralintents import GenericAssistant + +assistant = GenericAssistant('intents.json', model_name="test_model") +assistant.load_model() # Load the previously trained model + +done = False + +while not done: + message = input("Enter a message: ") + if message == "STOP": + done = True + else: + print(assistant.request(message)) +``` diff --git a/neuralintents/assistants.py b/neuralintents/assistants.py index db3fedc..f0dcc1a 100644 --- a/neuralintents/assistants.py +++ b/neuralintents/assistants.py @@ -12,13 +12,12 @@ from tensorflow.keras.models import Sequential, load_model from tensorflow.keras.layers import Dense, Dropout, InputLayer -from tensorflow.keras.optimizers import Adam, Optimizer +from tensorflow.keras.optimizers import Adam, SGD, Optimizer class BasicAssistant: def __init__(self, intents_data: Union[str, os.PathLike, dict], method_mappings: dict = {}, hidden_layers: list = None, model_name: str = "basic_model") -> None: - nltk.download('punkt', quiet=True) nltk.download('wordnet', quiet=True) @@ -41,7 +40,6 @@ def __init__(self, intents_data: Union[str, os.PathLike, dict], method_mappings: self.words = [] self.intents = [] - self.training_data = [] def _prepare_intents_data(self, ignore_letters: tuple = ("!", "?", ",", ".")): @@ -98,7 +96,6 @@ def fit_model(self, optimizer: Optimizer = None, epochs: int = 200): self.model.add(layer) self.model.add(Dense(y.shape[1], activation='softmax')) - if optimizer is None: optimizer = Adam(learning_rate=0.01) @@ -110,7 +107,7 @@ def save_model(self): self.model.save(f"{self.model_name}.keras", self.history) pickle.dump(self.words, open(f'{self.model_name}_words.pkl', 'wb')) pickle.dump(self.intents, open(f'{self.model_name}_intents.pkl', 'wb')) - + def load_model(self): self.model = load_model(f'{self.model_name}.keras') self.words = pickle.load(open(f'{self.model_name}_words.pkl', 'rb')) @@ -132,12 +129,6 @@ def _predict_intent(self, input_text: str): predictions = self.model.predict(input_bag_of_words, verbose=0)[0] predicted_intent = self.intents[np.argmax(predictions)] - max_prob = np.max(predictions) - # print(max_prob) - # if max_prob < self.confidence_threshold: - # return None - # predicted_intent = self.intents[np.argmax(predictions)] - return predicted_intent def process_input(self, input_text: str): @@ -145,7 +136,7 @@ def process_input(self, input_text: str): try: if predicted_intent in self.method_mappings: - self.method_mappings[predicted_intent]() + self.method_mappings[predicted_intent]() # Call the corresponding function for intent in self.intents_data["intents"]: if intent["tag"] == predicted_intent: @@ -155,7 +146,67 @@ def process_input(self, input_text: str): class GenericAssistant(BasicAssistant): - def __init__(self, *args, **kwargs): - import warnings - warnings.warn("The 'GenericAssistant' class is deprecated and will be removed in future versions. Please use 'BasicAssistant' instead.", DeprecationWarning, stacklevel=2) - super().__init__(*args, **kwargs) \ No newline at end of file + + def __init__(self, intents, intent_methods={}, model_name="assistant_model"): + """ + Initialize the assistant with intents, optional intent methods, and a model name. + + Args: + intents (str or dict): Path to the JSON file or intents as a dictionary. + intent_methods (dict): Optional mappings of intent names to functions. + model_name (str): Name of the saved model. + """ + super().__init__(intents, method_mappings=intent_methods, model_name=model_name) + + if isinstance(intents, str) and intents.endswith(".json"): + self.load_json_intents(intents) + + self.lemmatizer = nltk.stem.WordNetLemmatizer() + + def load_json_intents(self, filepath): + with open(filepath, 'r') as f: + self.intents_data = json.load(f) + + def train_model(self): + """ + Train a neural network model on the provided intents. + """ + # (Training model code here as already defined above) + pass # Implement training logic similar to BasicAssistant + + + def _get_response(self, ints, intents_json): + """ + Retrieve the most appropriate response for a given intent based on predicted intent tag. + + Args: + ints (list): List of predicted intents with their corresponding confidence scores. + intents_json (dict): The intents JSON data containing possible responses. + + Returns: + str: The response message for the predicted intent. + """ + try: + tag = ints[0]['intent'] # Extract the predicted intent tag + list_of_intents = intents_json['intents'] + for i in list_of_intents: + if i['tag'] == tag: + result = random.choice(i['responses']) # Randomly choose a response for the intent + break + except IndexError: + result = "I don't understand!" # Default response if no intent is predicted + return result + + +# custom function +def my_custom_function(): + print("Custom function triggered!") + +# Create a mapping for your custom intent +mappings = {'custom_intent': my_custom_function} + +# Initialize the GenericAssistant with the mappings +assistant = GenericAssistant('intents.json', intent_methods=mappings, model_name="test_model") + +# Train the model +assistant.train_model() diff --git a/setup.py b/setup.py index d9bd7d1..3f92630 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,6 @@ VERSION = '0.1.0' DESCRIPTION = 'Simple interface for working with intents and chatbots.' LONG_DESCRIPTION = 'Simple interface for working with intents and chatbots.' - setup( name="neuralintents", version=VERSION, @@ -21,7 +20,10 @@ long_description=long_description, packages=find_packages(), install_requires=['numpy', 'nltk', 'tensorflow'], - keywords=['python', 'neural', 'machine learning', 'chatbots', 'chat', 'artificial intelligence', 'virtual assistant'], + extras_require={ + 'testing': ['pytest'], # Optional testing dependency + }, + keywords=['python', 'neural', 'machine learning', 'chatbots', 'chat', 'artificial intelligence', 'virtual assistant', 'deep learning', 'tensorflow'], classifiers=[ "Development Status :: 1 - Planning", "Intended Audience :: Developers", @@ -29,4 +31,4 @@ "Operating System :: Unix", "Operating System :: Microsoft :: Windows", ] -) \ No newline at end of file +)