├── LICENSE ├── README.md ├── app.py ├── chat.py ├── data.pth ├── intents.json ├── model.py ├── nltk_utils.py ├── static ├── app.js ├── images │ └── chatbox-icon.svg └── style.css ├── templates └── base.html └── train.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Gayan Sachintha 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Python Flask AI Chatbot 3 | 4 |     5 | 6 | A dynamic and responsive AI Chatbot built with Python, Flask, and neural networks. Designed to handle inquiries about services, bookings, and customer support with ease and accuracy. 7 | 8 | ## Features 9 | 10 | - **Real-time Interaction**: Engage with users through a conversational interface. 11 | - **Custom Neural Network**: Powered by a bespoke model for natural language understanding. 12 | - **Easy Integration**: Seamless incorporation into websites or applications. 13 | - **Scalable & Flexible**: Designed to grow with your business needs. 14 | - **API Testing with Postman**: Easily test and interact with the chatbot API. 15 | 16 | ## Installation 17 | 18 | 1. **Clone the Repository** 19 | 20 | ```bash 21 | git gh repo clone Gayan-Sachintha/Riverston-Life-AI-Chatbot-flask 22 | cd yourprojectname 23 | ``` 24 | 25 | 2. **Create a Virtual Environment (Optional)** 26 | 27 | ```bash 28 | python -m venv venv 29 | source venv/bin/activate # On Windows use `venv\Scripts\activate` 30 | ``` 31 | 32 | 3. **Install Requirements** 33 | 34 | ```bash 35 | pip install -r requirements.txt 36 | ``` 37 | 38 | 4. **Set Up Environment Variables** 39 | 40 | Create a `.env` file in the project root directory and add the necessary configurations. 41 | 42 | ## Usage 43 | 44 | Start the server with the following command: 45 | 46 | ```bash 47 | python app.py 48 | ``` 49 | 50 | The chatbot is now live at `http://localhost:5000/`. Interact with the chatbot through the provided endpoints. 51 | 52 | ## Testing with Postman 53 | 54 | To test the chatbot API with Postman, follow these steps: 55 | 56 | 1. **Install Postman** 57 | 58 | Download and install Postman from [the official site](https://www.postman.com/downloads/). 59 | 60 | 2. **Import Collection** 61 | 62 | Create a new collection in Postman for your chatbot APIs. 63 | 64 | 3. **Create a POST Request** 65 | 66 | - URL: `http://localhost:5000/predict` 67 | - Body type: `raw` (JSON) 68 | - Request Body Example: `{"message": "Hello"}` 69 | 70 | 4. **Send Request** 71 | 72 | Hit the send button to receive a response from your chatbot. 73 | 74 | This setup allows you to easily test and debug your chatbot's responses. 75 | 76 | ## Contributing 77 | 78 | Contributions are welcome! Please follow these steps: 79 | 80 | 1. Fork the repository. 81 | 2. Create a new branch: `git checkout -b feature-yourfeaturename`. 82 | 3. Make your changes and commit them: `git commit -m 'Add some feature'`. 83 | 4. Push to the branch: `git push origin feature-yourfeaturename`. 84 | 5. Submit a pull request. 85 | 86 | ## License 87 | 88 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE) file for details. 89 | 90 | ## Contact 91 | 92 | For support or inquiries, reach out to us at `gayansachintha2000@gmail.com`. 93 | 94 | --- 95 | 96 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request, jsonify 2 | from flask_cors import CORS 3 | from chat import get_response 4 | 5 | app = Flask(__name__) 6 | CORS(app) 7 | 8 | @app.post("/predict") 9 | def predict(): 10 | text = request.get_json().get("message") 11 | response = get_response(text) 12 | message = {"answer": response} 13 | return jsonify(message) 14 | 15 | 16 | if __name__ == "__main__": 17 | app.run(debug=True) 18 | -------------------------------------------------------------------------------- /chat.py: -------------------------------------------------------------------------------- 1 | import random 2 | import json 3 | 4 | import torch 5 | 6 | from model import NeuralNet 7 | from nltk_utils import bag_of_words, tokenize 8 | 9 | device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') 10 | 11 | with open('intents.json', 'r') as json_data: 12 | intents = json.load(json_data) 13 | 14 | FILE = "data.pth" 15 | data = torch.load(FILE) 16 | 17 | input_size = data["input_size"] 18 | hidden_size = data["hidden_size"] 19 | output_size = data["output_size"] 20 | all_words = data['all_words'] 21 | tags = data['tags'] 22 | model_state = data["model_state"] 23 | 24 | model = NeuralNet(input_size, hidden_size, output_size).to(device) 25 | model.load_state_dict(model_state) 26 | model.eval() 27 | 28 | bot_name = "Sam" 29 | 30 | 31 | def get_response(msg): 32 | sentence = tokenize(msg) 33 | X = bag_of_words(sentence, all_words) 34 | X = X.reshape(1, X.shape[0]) 35 | X = torch.from_numpy(X).to(device) 36 | 37 | output = model(X) 38 | _, predicted = torch.max(output, dim=1) 39 | 40 | tag = tags[predicted.item()] 41 | 42 | probs = torch.softmax(output, dim=1) 43 | prob = probs[0][predicted.item()] 44 | if prob.item() > 0.75: 45 | for intent in intents['intents']: 46 | if tag == intent["tag"]: 47 | return random.choice(intent['responses']) 48 | 49 | return "I do not understand..." 50 | 51 | 52 | if __name__ == "__main__": 53 | print("Let's chat! (type 'quit' to exit)") 54 | while True: 55 | # sentence = "do you use credit cards?" 56 | sentence = input("You: ") 57 | if sentence == "quit": 58 | break 59 | 60 | resp = get_response(sentence) 61 | print(resp) 62 | 63 | -------------------------------------------------------------------------------- /data.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gayan-Sachintha/Riverston-Life-AI-Chatbot-flask/465d68326973270a53e1d6454c6317937df69ce2/data.pth -------------------------------------------------------------------------------- /intents.json: -------------------------------------------------------------------------------- 1 | { 2 | "intents": [ 3 | { 4 | "tag": "atv_ride_info", 5 | "patterns": [ 6 | "Can I get information on ATV rides?", 7 | "What does the ATV ride package include?", 8 | "I'd like to know more about the ATV ride.", 9 | "What are the options for ATV rides?" 10 | ], 11 | "responses": [ 12 | "Certainly! Our ATV Ride packages are as follows: 1) Full Package: Dinner, breakfast, morning tea, camping night, a 2km ATV bike ride, and BBQ grill for LKR4500 per person. 2) Standard Package: Dinner, breakfast, morning tea, camping night, and BBQ grill for LKR3000 per person. 3) Camping Only: Just the camping experience for LKR1000 per person. 4) ATV Ride Only: Choose from a 1.5km basic track for LKR2000, a 2km track for LKR2500, a 2km track with a muddy trail for LKR3000, or a full 2km muddy track experience for LKR4000. For bookings, contact us at 0716012892." 13 | ] 14 | }, 15 | { 16 | "tag": "eco_resort_info", 17 | "patterns": [ 18 | "Tell me about the eco resort packages.", 19 | "What can I expect from the eco resort stay?", 20 | "I'm interested in the eco resort stays.", 21 | "Details on eco resort accommodation." 22 | ], 23 | "responses": [ 24 | "Our Nature Life Eco Resort offers a serene experience with these packages: 1) Deluxe Package: Dinner, breakfast, morning tea, cabana night, a 2km ATV bike ride, and BBQ grill for LKR5500 per person. 2) Comfort Package: Dinner, breakfast, morning tea, cabana night, and BBQ grill for LKR3800 per person. 3) Cabana Only: A peaceful stay in our cabana for LKR1500 per person. To reserve your stay, reach out to us at 0716012892." 25 | ] 26 | }, 27 | { 28 | "tag": "contact_info", 29 | "patterns": [ 30 | "How can I contact you?", 31 | "I need the contact details.", 32 | "Where can I get more information?", 33 | "Give me the contact numbers." 34 | ], 35 | "responses": [ 36 | "You can contact us for more information or to make a reservation at the following numbers: 0716012892, 0701492017, or 0712590829. We're happy to assist you!" 37 | ] 38 | }, 39 | { 40 | "tag": "booking", 41 | "patterns": [ 42 | "I want to book a package.", 43 | "How do I make a reservation?", 44 | "Can I book an ATV ride now?", 45 | "I would like to reserve a cabana." 46 | ], 47 | "responses": [ 48 | "To book a package with us, please call us at 0716012892 or 0701492017. You can also send us a message on WhatsApp at 0712590829. We're looking forward to your visit!" 49 | ] 50 | }, 51 | { 52 | "tag": "group_accommodation", 53 | "patterns": [ 54 | "Can you accommodate a large group?", 55 | "We are a group of fifteen, can you accommodate us?", 56 | "What's the maximum number of people you can accommodate?" 57 | ], 58 | "responses": [ 59 | "We can accommodate groups of up to fifteen people. For further details or to discuss arrangements for larger groups, please get in touch with us at 0716012892. We'd love to host your group!" 60 | ] 61 | }, 62 | { 63 | "tag": "greetings", 64 | "patterns": [ 65 | "Hi", 66 | "Hello", 67 | "Hey", 68 | "Good morning", 69 | "Good afternoon", 70 | "Good evening", 71 | "Is anyone there?", 72 | "Greetings", 73 | "What's up" 74 | ], 75 | "responses": [ 76 | "Hello! How can I assist you today?", 77 | "Hi there! Looking for some adventure or relaxation?", 78 | "Greetings! Are you interested in our ATV rides or eco resort stays?", 79 | "Good day! How may I help you with your travel plans?", 80 | "Hey there! Ready to explore the Dust & Dirt packages or the serene Nature Life Eco Resort?" 81 | ] 82 | }, 83 | { 84 | "tag": "thank_you", 85 | "patterns": [ 86 | "Thanks", 87 | "Thank you", 88 | "Appreciate it", 89 | "Cheers", 90 | "Thanks for the help", 91 | "Thanks for the information" 92 | ], 93 | "responses": [ 94 | "You're welcome! If you have any more questions, feel free to ask.", 95 | "No problem at all! I'm here to help if you need anything else.", 96 | "My pleasure! Don't hesitate to reach out if you need further assistance.", 97 | "Glad I could assist you! Let me know if there's anything else I can do for you." 98 | ] 99 | }, 100 | { 101 | "tag": "contact_info", 102 | "patterns": [ 103 | "How can I contact you?", 104 | "What's your phone number?", 105 | "I need the contact details.", 106 | "Where can I get more information?", 107 | "Give me the contact numbers.", 108 | "How do I reach you for a booking?" 109 | ], 110 | "responses": [ 111 | "You can contact us for more information or to make a reservation at the following numbers: 0716012892, 0701492017, or 0712590829. We're happy to assist you!", 112 | "For inquiries and bookings, please call us at 0716012892 or 0701492017. You can also send us a message on WhatsApp at 0712590829. We look forward to hearing from you!" 113 | ] 114 | }, 115 | { 116 | "tag": "asking_details", 117 | "patterns": [ 118 | "Can you tell me more about the packages?", 119 | "I need more details on what's included.", 120 | "What does the package consist of?", 121 | "Give me the details of the ATV ride." 122 | ], 123 | "responses": [ 124 | "Of course! Our ATV Ride packages include options with dinner, breakfast, and camping. For the Eco Resort, we offer cabana stays with meals included. Would you like to know more about specific packages?", 125 | "Sure! We have various options depending on the adventure level and comfort you're seeking. From ATV rides to peaceful cabana stays, all our packages come with meal options and additional amenities. Which one are you interested in?" 126 | ] 127 | } 128 | ] 129 | } -------------------------------------------------------------------------------- /model.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | 4 | 5 | class NeuralNet(nn.Module): 6 | def __init__(self, input_size, hidden_size, num_classes): 7 | super(NeuralNet, self).__init__() 8 | self.l1 = nn.Linear(input_size, hidden_size) 9 | self.l2 = nn.Linear(hidden_size, hidden_size) 10 | self.l3 = nn.Linear(hidden_size, num_classes) 11 | self.relu = nn.ReLU() 12 | 13 | def forward(self, x): 14 | out = self.l1(x) 15 | out = self.relu(out) 16 | out = self.l2(out) 17 | out = self.relu(out) 18 | out = self.l3(out) 19 | # no activation and no softmax at the end 20 | return out 21 | -------------------------------------------------------------------------------- /nltk_utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import nltk 3 | # nltk.download('punkt') 4 | from nltk.stem.porter import PorterStemmer 5 | stemmer = PorterStemmer() 6 | 7 | 8 | def tokenize(sentence): 9 | """ 10 | split sentence into array of words/tokens 11 | a token can be a word or punctuation character, or number 12 | """ 13 | return nltk.word_tokenize(sentence) 14 | 15 | 16 | def stem(word): 17 | """ 18 | stemming = find the root form of the word 19 | examples: 20 | words = ["organize", "organizes", "organizing"] 21 | words = [stem(w) for w in words] 22 | -> ["organ", "organ", "organ"] 23 | """ 24 | return stemmer.stem(word.lower()) 25 | 26 | 27 | def bag_of_words(tokenized_sentence, words): 28 | """ 29 | return bag of words array: 30 | 1 for each known word that exists in the sentence, 0 otherwise 31 | example: 32 | sentence = ["hello", "how", "are", "you"] 33 | words = ["hi", "hello", "I", "you", "bye", "thank", "cool"] 34 | bog = [ 0 , 1 , 0 , 1 , 0 , 0 , 0] 35 | """ 36 | # stem each word 37 | sentence_words = [stem(word) for word in tokenized_sentence] 38 | # initialize bag with 0 for each word 39 | bag = np.zeros(len(words), dtype=np.float32) 40 | for idx, w in enumerate(words): 41 | if w in sentence_words: 42 | bag[idx] = 1 43 | 44 | return bag 45 | -------------------------------------------------------------------------------- /static/app.js: -------------------------------------------------------------------------------- 1 | class Chatbox { 2 | constructor() { 3 | this.args = { 4 | openButton: document.querySelector('.chatbox__button'), 5 | chatbox: document.querySelector('.chatbox__support'), 6 | sendButton: document.querySelector('.send__button'), 7 | } 8 | this.state = false; 9 | this.messages = []; 10 | } 11 | 12 | display() { 13 | const { openButton, chatbox, sendButton } = this.args; 14 | 15 | openButton.addEventListener('click', () => this.toggleState(chatbox)) 16 | sendButton.addEventListener('click', () => this.onSendButton(chatbox)) 17 | 18 | const node = chatBox.querySelector('input'); 19 | node.addEventListener("keyup", ({ key }) => { 20 | if (key === "Enter") { 21 | this.onSendButton(chatbox); 22 | } 23 | }) 24 | } 25 | 26 | toggleState(chatbox) { 27 | this.state = !this.state; 28 | if (this.state) { 29 | chatbox.classList.add('chatbox--active') 30 | } else { 31 | chatbox.classList.remove('chatbox--active') 32 | } 33 | } 34 | 35 | onSendButton(chatbox) { 36 | 37 | var textField = chatbox.querySelector('input'); 38 | let text1 = textField.value; 39 | if (text1 === '') { 40 | return; 41 | } 42 | 43 | let msg1 = {name: "User", message: text1 } 44 | this.messages.push(msg1); 45 | 46 | fetch ('http://127.0.0.1:5000/predict', { 47 | method: 'POST', 48 | body: JSON.stringify({message: text1}), 49 | mode: 'cors', 50 | headers: { 51 | 'Content-Type': 'application/json' 52 | }, 53 | }) 54 | .then(r => r.json()) 55 | .then(r => { 56 | let msg2 = {name: "Gayan", message: r.answer }; 57 | this.messages.push(msg2); 58 | this.updateChatText(chatbox) 59 | textField.value = '' 60 | }).catch((error) => { 61 | console.error('Error:', error); 62 | this.updateChatText(chatbox) 63 | textField.value = '' 64 | }); 65 | } 66 | 67 | updateChatText(chatbox) { 68 | var html = ''; 69 | this.messages.slice().forEach(function(item,){ 70 | if(item.name === "Gayan") 71 | { 72 | html += '
'; 73 | }else 74 | { 75 | html += ' '; 76 | } 77 | }); 78 | 79 | const chatmessage = chatbox.querySelector('.chatbox__messages'); 80 | chatmessage.innerHTML = html; 81 | } 82 | } 83 | 84 | const chatbox = new Chatbox(); 85 | chatbox.display(); -------------------------------------------------------------------------------- /static/images/chatbox-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | --primaryColor: #222823; 3 | --secondaryColor: #F3C13E; 4 | --textColor: #343d36; 5 | --borderRadius: 8px; 6 | --boxShadow: 0 2px 4px rgba(0,0,0,0.1); 7 | } 8 | 9 | * { 10 | box-sizing: border-box; 11 | margin: 0; 12 | padding: 0; 13 | } 14 | 15 | body { 16 | font-family: 'Nunito', sans-serif; 17 | font-weight: 400; 18 | font-size: 16px; 19 | background: var(--backgroundColor);} 20 | 21 | *, *::before, *::after { 22 | box-sizing: inherit; 23 | } 24 | 25 | .chatbox { 26 | position: fixed; 27 | bottom: 20px; 28 | right: 20px; 29 | font-size: 0.9rem; 30 | } 31 | 32 | .chatbox__support { 33 | display: flex; 34 | flex-direction: column; 35 | background: #626963; 36 | width: 350px; 37 | height: 450px; 38 | border-radius: var(--borderRadius); 39 | box-shadow: var(--boxShadow); 40 | overflow: hidden; 41 | visibility: hidden; 42 | opacity: 0; 43 | transition: visibility 1s, opacity 0.2s linear; 44 | 45 | } 46 | 47 | .chatbox--active { 48 | visibility: visible; 49 | opacity: 1; 50 | transition-delay: 0s; 51 | } 52 | 53 | .chatbox__button { 54 | text-align: right; 55 | border-radius: 50%; 56 | padding: 8px; 57 | margin-left: auto; 58 | margin-bottom: 1rem; 59 | cursor: pointer; 60 | } 61 | 62 | .chatbox__button img { 63 | width: 24px; 64 | } 65 | 66 | .chatbox__header { 67 | background: var(--primaryColor); 68 | color: #ffffff; 69 | padding: 12px 20px; 70 | display: flex; 71 | align-items: center; 72 | justify-content: start; 73 | font-weight: 600; 74 | } 75 | 76 | .chatbox__image--header img { 77 | border-radius: 50%; 78 | margin-right: 10px; 79 | } 80 | 81 | .chatbox__content--header h4 { 82 | margin-bottom: 5px; 83 | } 84 | 85 | .chatbox__content--header p { 86 | font-size: 0.85rem; 87 | } 88 | 89 | .chatbox__messages { 90 | padding: 10px; 91 | overflow-y: auto; 92 | flex-grow: 1; 93 | } 94 | 95 | .messages__item { 96 | display: block; 97 | padding: 10px 15px; 98 | margin: 5px 0; 99 | border-radius: 20px; 100 | max-width: 80%; 101 | width: fit-content; 102 | } 103 | 104 | .messages__item--visitor { 105 | background: var(--secondaryColor); 106 | color: #222823; 107 | align-self: flex-end; 108 | } 109 | 110 | .messages__item--operator { 111 | margin-left: auto; 112 | background: var(--secondaryColor); 113 | color: 222823; 114 | } 115 | 116 | .chatbox__footer { 117 | padding: 10px; 118 | display: flex; 119 | align-items: center; 120 | background: #465248; 121 | } 122 | 123 | .chatbox__footer input[type="text"] { 124 | flex-grow: 1; 125 | margin-right: 10px; 126 | padding: 10px; 127 | border: 1px solid #ccc; 128 | border-radius: 20px; 129 | outline: none; 130 | } 131 | 132 | .chatbox__send--footer { 133 | background: var(--primaryColor); 134 | color: #ffffff; 135 | border: none; 136 | padding: 8px 16px; 137 | border-radius: 20px; 138 | cursor: pointer; 139 | transition: background-color 0.3s; 140 | } 141 | 142 | .chatbox__send--footer:hover { 143 | background: #F3C13E; 144 | color: var(--backgroundColor); 145 | } 146 | 147 | @keyframes slideIn { 148 | from { 149 | transform: translateY(20px); 150 | opacity: 0; 151 | } 152 | to { 153 | transform: translateY(0); 154 | opacity: 1; 155 | } 156 | } 157 | 158 | .messages__item { 159 | animation: slideIn 0.5s ease-out forwards; 160 | } 161 | 162 | .custom-icon { 163 | font-size: 40px; 164 | color: #F3C13E; 165 | } -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |Hi.How can I help you?
23 |