119 lines
3.6 KiB
Python
119 lines
3.6 KiB
Python
import json
|
|
import pickle
|
|
import random
|
|
from tkinter import *
|
|
|
|
import nltk
|
|
import numpy as np
|
|
import text2emotion as te
|
|
from keras.models import load_model
|
|
from nltk.stem import WordNetLemmatizer
|
|
|
|
lemmatizer = WordNetLemmatizer()
|
|
model = load_model('chatbot_model.h5')
|
|
intents = json.loads(open('intents.json', encoding='utf-8').read())
|
|
intents = {i['tag']: (i['patterns'], i['responses']) for i in intents}
|
|
words = pickle.load(open('words.pkl', 'rb'))
|
|
classes = pickle.load(open('classes.pkl', 'rb'))
|
|
|
|
|
|
def clean_up_text(text):
|
|
text_words = nltk.word_tokenize(text)
|
|
text_words = [lemmatizer.lemmatize(word.lower()) for word in text_words]
|
|
return text_words
|
|
|
|
|
|
def predict_class(text):
|
|
bow = np.array([1 if w in clean_up_text(text) else 0 for w in words])
|
|
pred = model.predict(np.array([bow]))[0]
|
|
return classes[np.argmax(pred)]
|
|
|
|
|
|
def chatbot_response(text, emotion):
|
|
intent = predict_class(text)
|
|
return random.choice(intents[intent][1][emotion])
|
|
|
|
|
|
def determine_emotion(text):
|
|
emotions = te.get_emotion(text)
|
|
emotion = max(emotions, key=emotions.get)
|
|
return 'Neutral' if emotion == 'Surprise' or emotions[emotion] < 0.5 else emotion
|
|
|
|
|
|
def update_image(emotion):
|
|
global image
|
|
if emotion == "Happy":
|
|
image = PhotoImage(file="happy.png")
|
|
elif emotion == "Angry":
|
|
image = PhotoImage(file="concerned.png")
|
|
elif emotion in ["Sad", "Fear"]:
|
|
image = PhotoImage(file="reassuring.png")
|
|
else:
|
|
image = PhotoImage(file="neutral.png")
|
|
image_label.configure(image=image)
|
|
|
|
|
|
def send(event):
|
|
msg = EntryBox.get("1.0", 'end-1c').strip()
|
|
EntryBox.delete("0.0", END)
|
|
if msg:
|
|
emotion = determine_emotion(msg)
|
|
update_image(emotion)
|
|
ChatLog.config(state=NORMAL)
|
|
ChatLog.insert(END, "You: " + msg + '\n\n')
|
|
ChatLog.config(foreground="#442265", font=("Verdana", 12))
|
|
res = chatbot_response(msg, emotion)
|
|
ChatLog.insert(END, "Bot: " + res + '\n\n')
|
|
ChatLog.config(state=DISABLED)
|
|
ChatLog.yview(END)
|
|
return 'break'
|
|
|
|
|
|
def on_entry_focus_in(event):
|
|
if EntryBox.get("1.0", END).strip() == DEFAULT_TEXT:
|
|
EntryBox.delete("1.0", END)
|
|
EntryBox.config(fg="black")
|
|
|
|
|
|
def on_entry_focus_out(event):
|
|
if EntryBox.get("1.0", END).strip() == "":
|
|
EntryBox.insert(END, DEFAULT_TEXT)
|
|
EntryBox.config(fg="grey")
|
|
|
|
|
|
DEFAULT_TEXT = 'Enter text here'
|
|
GAP = 5
|
|
WINDOW_WIDTH = 600
|
|
WINDOW_HEIGHT = 400
|
|
CHAT_WIDTH = WINDOW_WIDTH - 30
|
|
ENTRY_HEIGHT = 100
|
|
IMAGE_HEIGHT = 100
|
|
CHAT_HEIGHT = WINDOW_HEIGHT - ENTRY_HEIGHT - IMAGE_HEIGHT - 4 * GAP
|
|
|
|
base = Tk()
|
|
base.title("Empathic Robot")
|
|
base.geometry(f"{WINDOW_WIDTH}x{WINDOW_HEIGHT}")
|
|
base.resizable(width=FALSE, height=FALSE)
|
|
|
|
ChatLog = Text(base, bd=0, bg="white", font="Arial")
|
|
ChatLog.config(state=DISABLED)
|
|
|
|
scrollbar = Scrollbar(base, command=ChatLog.yview, cursor="heart")
|
|
ChatLog['yscrollcommand'] = scrollbar.set
|
|
|
|
EntryBox = Text(base, bd=0, bg="white", font="Arial")
|
|
EntryBox.insert(END, DEFAULT_TEXT)
|
|
EntryBox.config(fg="grey")
|
|
EntryBox.bind("<Return>", send)
|
|
EntryBox.bind("<FocusIn>", on_entry_focus_in)
|
|
EntryBox.bind("<FocusOut>", on_entry_focus_out)
|
|
|
|
image = PhotoImage(file="neutral.png")
|
|
image_label = Label(base, image=image)
|
|
image_label.place(x=GAP, y=GAP, width=WINDOW_WIDTH - 2 * GAP, height=IMAGE_HEIGHT)
|
|
scrollbar.place(x=CHAT_WIDTH + GAP, y=IMAGE_HEIGHT + 2 * GAP, height=CHAT_HEIGHT)
|
|
ChatLog.place(x=GAP, y=IMAGE_HEIGHT + 2 * GAP, height=CHAT_HEIGHT, width=CHAT_WIDTH)
|
|
EntryBox.place(x=GAP, y=IMAGE_HEIGHT + CHAT_HEIGHT + 3 * GAP, height=ENTRY_HEIGHT, width=WINDOW_WIDTH - 2 * GAP)
|
|
|
|
base.mainloop()
|