forked from jerrytigerxu/Simple-Python-Chatbot
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit dc7ccd4
Showing
6 changed files
with
484 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
|
||
import nltk | ||
from nltk.stem import WordNetLemmatizer | ||
lemmatizer = WordNetLemmatizer() | ||
import pickle | ||
import numpy as np | ||
|
||
from keras.models import load_model | ||
model = load_model('chatbot_model.h5') | ||
import json | ||
import random | ||
intents = json.loads(open('intents.json').read()) | ||
words = pickle.load(open('words.pkl','rb')) | ||
classes = pickle.load(open('classes.pkl','rb')) | ||
|
||
|
||
def clean_up_sentence(sentence): | ||
sentence_words = nltk.word_tokenize(sentence) | ||
sentence_words = [lemmatizer.lemmatize(word.lower()) for word in sentence_words] | ||
return sentence_words | ||
|
||
# return bag of words array: 0 or 1 for each word in the bag that exists in the sentence | ||
|
||
def bow(sentence, words, show_details=True): | ||
# tokenize the pattern | ||
sentence_words = clean_up_sentence(sentence) | ||
# bag of words - matrix of N words, vocabulary matrix | ||
bag = [0]*len(words) | ||
for s in sentence_words: | ||
for i,w in enumerate(words): | ||
if w == s: | ||
# assign 1 if current word is in the vocabulary position | ||
bag[i] = 1 | ||
if show_details: | ||
print ("found in bag: %s" % w) | ||
return(np.array(bag)) | ||
|
||
def predict_class(sentence, model): | ||
# filter out predictions below a threshold | ||
p = bow(sentence, words,show_details=False) | ||
res = model.predict(np.array([p]))[0] | ||
ERROR_THRESHOLD = 0.25 | ||
results = [[i,r] for i,r in enumerate(res) if r>ERROR_THRESHOLD] | ||
# sort by strength of probability | ||
results.sort(key=lambda x: x[1], reverse=True) | ||
return_list = [] | ||
for r in results: | ||
return_list.append({"intent": classes[r[0]], "probability": str(r[1])}) | ||
return return_list | ||
|
||
def getResponse(ints, intents_json): | ||
tag = ints[0]['intent'] | ||
list_of_intents = intents_json['intents'] | ||
for i in list_of_intents: | ||
if(i['tag']== tag): | ||
result = random.choice(i['responses']) | ||
break | ||
return result | ||
|
||
def chatbot_response(msg): | ||
ints = predict_class(msg, model) | ||
res = getResponse(ints, intents) | ||
return res | ||
|
||
|
||
#Creating GUI with tkinter | ||
import tkinter | ||
from tkinter import * | ||
|
||
|
||
def send(): | ||
msg = EntryBox.get("1.0",'end-1c').strip() | ||
EntryBox.delete("0.0",END) | ||
|
||
if msg != '': | ||
ChatLog.config(state=NORMAL) | ||
ChatLog.insert(END, "You: " + msg + '\n\n') | ||
ChatLog.config(foreground="#442265", font=("Verdana", 12 )) | ||
|
||
res = chatbot_response(msg) | ||
ChatLog.insert(END, "Bot: " + res + '\n\n') | ||
|
||
ChatLog.config(state=DISABLED) | ||
ChatLog.yview(END) | ||
|
||
|
||
base = Tk() | ||
base.title("Hello") | ||
base.geometry("400x500") | ||
base.resizable(width=FALSE, height=FALSE) | ||
|
||
#Create Chat window | ||
ChatLog = Text(base, bd=0, bg="white", height="8", width="50", font="Arial",) | ||
|
||
ChatLog.config(state=DISABLED) | ||
|
||
#Bind scrollbar to Chat window | ||
scrollbar = Scrollbar(base, command=ChatLog.yview, cursor="heart") | ||
ChatLog['yscrollcommand'] = scrollbar.set | ||
|
||
#Create Button to send message | ||
SendButton = Button(base, font=("Verdana",12,'bold'), text="Send", width="12", height=5, | ||
bd=0, bg="#32de97", activebackground="#3c9d9b",fg='#ffffff', | ||
command= send ) | ||
|
||
#Create the box to enter message | ||
EntryBox = Text(base, bd=0, bg="white",width="29", height="5", font="Arial") | ||
#EntryBox.bind("<Return>", send) | ||
|
||
|
||
#Place all components on the screen | ||
scrollbar.place(x=376,y=6, height=386) | ||
ChatLog.place(x=6,y=6, height=386, width=370) | ||
EntryBox.place(x=128, y=401, height=90, width=265) | ||
SendButton.place(x=6, y=401, height=90) | ||
|
||
base.mainloop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
(lp0 | ||
Vadverse_drug | ||
p1 | ||
aVblood_pressure | ||
p2 | ||
aVblood_pressure_search | ||
p3 | ||
aVgoodbye | ||
p4 | ||
aVgreeting | ||
p5 | ||
aVhospital_search | ||
p6 | ||
aVoptions | ||
p7 | ||
aVpharmacy_search | ||
p8 | ||
aVthanks | ||
p9 | ||
a. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
{"intents": [ | ||
{"tag": "greeting", | ||
"patterns": ["Hi there", "How are you", "Is anyone there?","Hey","Hola", "Hello", "Good day"], | ||
"responses": ["Hello, thanks for asking", "Good to see you again", "Hi there, how can I help?"], | ||
"context": [""] | ||
}, | ||
{"tag": "goodbye", | ||
"patterns": ["Bye", "See you later", "Goodbye", "Nice chatting to you, bye", "Till next time"], | ||
"responses": ["See you!", "Have a nice day", "Bye! Come back again soon."], | ||
"context": [""] | ||
}, | ||
{"tag": "thanks", | ||
"patterns": ["Thanks", "Thank you", "That's helpful", "Awesome, thanks", "Thanks for helping me"], | ||
"responses": ["Happy to help!", "Any time!", "My pleasure"], | ||
"context": [""] | ||
}, | ||
{"tag": "noanswer", | ||
"patterns": [], | ||
"responses": ["Sorry, can't understand you", "Please give me more info", "Not sure I understand"], | ||
"context": [""] | ||
}, | ||
{"tag": "options", | ||
"patterns": ["How you could help me?", "What you can do?", "What help you provide?", "How you can be helpful?", "What support is offered"], | ||
"responses": ["I can guide you through Adverse drug reaction list, Blood pressure tracking, Hospitals and Pharmacies", "Offering support for Adverse drug reaction, Blood pressure, Hospitals and Pharmacies"], | ||
"context": [""] | ||
}, | ||
{"tag": "adverse_drug", | ||
"patterns": ["How to check Adverse drug reaction?", "Open adverse drugs module", "Give me a list of drugs causing adverse behavior", "List all drugs suitable for patient with adverse reaction", "Which drugs dont have adverse reaction?" ], | ||
"responses": ["Navigating to Adverse drug reaction module"], | ||
"context": [""] | ||
}, | ||
{"tag": "blood_pressure", | ||
"patterns": ["Open blood pressure module", "Task related to blood pressure", "Blood pressure data entry", "I want to log blood pressure results", "Blood pressure data management" ], | ||
"responses": ["Navigating to Blood Pressure module"], | ||
"context": [""] | ||
}, | ||
{"tag": "blood_pressure_search", | ||
"patterns": ["I want to search for blood pressure result history", "Blood pressure for patient", "Load patient blood pressure result", "Show blood pressure results for patient", "Find blood pressure results by ID" ], | ||
"responses": ["Please provide Patient ID", "Patient ID?"], | ||
"context": ["search_blood_pressure_by_patient_id"] | ||
}, | ||
{"tag": "search_blood_pressure_by_patient_id", | ||
"patterns": [], | ||
"responses": ["Loading Blood pressure result for Patient"], | ||
"context": [""] | ||
}, | ||
{"tag": "pharmacy_search", | ||
"patterns": ["Find me a pharmacy", "Find pharmacy", "List of pharmacies nearby", "Locate pharmacy", "Search pharmacy" ], | ||
"responses": ["Please provide pharmacy name"], | ||
"context": ["search_pharmacy_by_name"] | ||
}, | ||
{"tag": "search_pharmacy_by_name", | ||
"patterns": [], | ||
"responses": ["Loading pharmacy details"], | ||
"context": [""] | ||
}, | ||
{"tag": "hospital_search", | ||
"patterns": ["Lookup for hospital", "Searching for hospital to transfer patient", "I want to search hospital data", "Hospital lookup for patient", "Looking up hospital details" ], | ||
"responses": ["Please provide hospital name or location"], | ||
"context": ["search_hospital_by_params"] | ||
}, | ||
{"tag": "search_hospital_by_params", | ||
"patterns": [], | ||
"responses": ["Please provide hospital type"], | ||
"context": ["search_hospital_by_type"] | ||
}, | ||
{"tag": "search_hospital_by_type", | ||
"patterns": [], | ||
"responses": ["Loading hospital details"], | ||
"context": [""] | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import nltk | ||
nltk.download('punkt') | ||
nltk.download('wordnet') | ||
from nltk.stem import WordNetLemmatizer | ||
lemmatizer = WordNetLemmatizer() | ||
import json | ||
import pickle | ||
|
||
import numpy as np | ||
from keras.models import Sequential | ||
from keras.layers import Dense, Activation, Dropout | ||
from keras.optimizers import SGD | ||
import random | ||
|
||
words=[] | ||
classes = [] | ||
documents = [] | ||
ignore_words = ['?', '!'] | ||
data_file = open('intents.json').read() | ||
intents = json.loads(data_file) | ||
|
||
|
||
for intent in intents['intents']: | ||
for pattern in intent['patterns']: | ||
|
||
# take each word and tokenize it | ||
w = nltk.word_tokenize(pattern) | ||
words.extend(w) | ||
# adding documents | ||
documents.append((w, intent['tag'])) | ||
|
||
# adding classes to our class list | ||
if intent['tag'] not in classes: | ||
classes.append(intent['tag']) | ||
|
||
words = [lemmatizer.lemmatize(w.lower()) for w in words if w not in ignore_words] | ||
words = sorted(list(set(words))) | ||
|
||
classes = sorted(list(set(classes))) | ||
|
||
print (len(documents), "documents") | ||
|
||
print (len(classes), "classes", classes) | ||
|
||
print (len(words), "unique lemmatized words", words) | ||
|
||
|
||
pickle.dump(words,open('words.pkl','wb')) | ||
pickle.dump(classes,open('classes.pkl','wb')) | ||
|
||
# initializing training data | ||
training = [] | ||
output_empty = [0] * len(classes) | ||
for doc in documents: | ||
# initializing bag of words | ||
bag = [] | ||
# list of tokenized words for the pattern | ||
pattern_words = doc[0] | ||
# lemmatize each word - create base word, in attempt to represent related words | ||
pattern_words = [lemmatizer.lemmatize(word.lower()) for word in pattern_words] | ||
# create our bag of words array with 1, if word match found in current pattern | ||
for w in words: | ||
bag.append(1) if w in pattern_words else bag.append(0) | ||
|
||
# output is a '0' for each tag and '1' for current tag (for each pattern) | ||
output_row = list(output_empty) | ||
output_row[classes.index(doc[1])] = 1 | ||
|
||
training.append([bag, output_row]) | ||
# shuffle our features and turn into np.array | ||
random.shuffle(training) | ||
training = np.array(training) | ||
# create train and test lists. X - patterns, Y - intents | ||
train_x = list(training[:,0]) | ||
train_y = list(training[:,1]) | ||
print("Training data created") | ||
|
||
|
||
# Create model - 3 layers. First layer 128 neurons, second layer 64 neurons and 3rd output layer contains number of neurons | ||
# equal to number of intents to predict output intent with softmax | ||
model = Sequential() | ||
model.add(Dense(128, input_shape=(len(train_x[0]),), activation='relu')) | ||
model.add(Dropout(0.5)) | ||
model.add(Dense(64, activation='relu')) | ||
model.add(Dropout(0.5)) | ||
model.add(Dense(len(train_y[0]), activation='softmax')) | ||
|
||
# Compile model. Stochastic gradient descent with Nesterov accelerated gradient gives good results for this model | ||
sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True) | ||
model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy']) | ||
|
||
#fitting and saving the model | ||
hist = model.fit(np.array(train_x), np.array(train_y), epochs=200, batch_size=5, verbose=1) | ||
model.save('chatbot_model.h5', hist) | ||
|
||
print("model created") |
Oops, something went wrong.