ChatbotApp / chatbotlib /demo_chatbot.py
ctgadget's picture
changed python file for chatbot demo to 'demo_chatbot' and added some error handling in case the user has required files missing.
f1ac257
#!/usr/bin/env python
"""The chatbot demo app is the "Demo the chatbot page" in the main page"""
# the code for the page
def run_app():
"""
Application code for the Chatbot demo
"""
############################
# :: IMPORTS AND CONSTANTS #
############################
import nltk
from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
import pickle
import numpy as np
import pandas as pd
import time
import json
import random
import datetime
import streamlit as st
from streamlit_chat import message
from keras.models import load_model
# Load commands
commands = json.loads(open('commands.json').read())
######################################
# :: HELPER FUNCTIONS FOR PROCESSING #
######################################
def clean_up_sentence(sentence):
"""
Tokenize and lemmatize the input sentence.
Args:
sentence (str): The input sentence to be preprocessed.
Returns:
list: The list of preprocessed words.
"""
sentence_words = nltk.word_tokenize(sentence)
sentence_words = [lemmatizer.lemmatize(word.lower()) for word in sentence_words]
return sentence_words
def bag_of_words(sentence):
"""Converts a sentence into a bag of words representation.
Args:
sentence (str): The input sentence to convert.
Returns:
numpy.ndarray: The bag of words representation as a NumPy array.
"""
sentence_words = clean_up_sentence(sentence)
bag = np.zeros(len(words), dtype=np.float32)
indices = np.where(np.isin(words, sentence_words))
bag[indices] = 1
return bag
def predict_class(sentence):
"""
Predicts the intent based on the input sentence.
Args:
sentence (str): The input sentence.
Returns:
list: A list of dictionaries containing the predicted intents and their probabilities, sorted by probability.
"""
p = bag_of_words(sentence)
res = chatbot_model.predict(np.array([p]))[0]
ERROR_THRESHOLD = 0.25
threshold_indices = np.where(res > ERROR_THRESHOLD)[0]
results = [{"intent": classes[i], "probability": str(res[i])} for i in threshold_indices]
results.sort(key=lambda x: x["probability"], reverse=True)
return results
def get_random_response(commands_json, tag):
"""
Retrieves a random response for the given tag from the commands JSON.
Args:
commands_json (dict): The JSON object containing the commands.
tag (str): The tag associated with the intent.
Returns:
str: A random response for the given tag.
"""
list_of_commands = commands_json["intents"]
for i in list_of_commands:
if i["tag"] == tag:
result = random.choice(i["responses"])
return result
return "I'm sorry, I don't understand."
def chatbot_response(text):
"""
Generate a response from the chatbot based on the user input.
Args:
text (str): The user input message.
Returns:
tuple: A tuple containing the generated response from the chatbot and the execution time.
"""
start_time = time.time()
ints = predict_class(text)
elapsed_time = time.time() - start_time
if ints:
tag = ints[0]['intent']
res = get_random_response(commands, tag)
return res, elapsed_time
else:
return "I'm sorry, I don't understand.", elapsed_time
def get_text():
"""
Displays a text input box and returns the user input.
Returns:
str: The user input.
"""
input_text = st.text_input("You: ", "Hello, how are you?", key="input")
return input_text
def get_chat_history_df():
"""
Retrieve the chat history from the session state and create a DataFrame.
Returns:
pd.DataFrame: The DataFrame containing the chat history with columns 'User Input' and 'Bot Response'.
"""
# Get the chat history from the session state
chat_history = zip(st.session_state['past'], st.session_state['generated_responses'])
# Convert chat history to a list
chat_history_list = list(chat_history)
# Create a dataframe from the chat history list
chat_history_df = pd.DataFrame(chat_history_list, columns=['User Input', 'Bot Response'])
return chat_history_df
def export_chat_history(chat_history_df):
"""
Export the chat history DataFrame to a CSV file and provide a download link.
Args:
chat_history_df (pd.DataFrame): The DataFrame containing the chat history.
Returns:
bool: True if the export is successful, False otherwise.
"""
try:
# Get the current datetime
current_datetime = datetime.datetime.now().strftime("%m/%d/%Y_%I_%M_%S_%p")
# Define the CSV file path
chat_history_filename = f'chat_history_{current_datetime}.csv'
# Write the dataframe to a CSV file
chat_history_csv = chat_history_df.to_csv(index=False).encode("utf-8")
# Provide a download link for the CSV file
st.download_button(
label="Download Chat History",
data=chat_history_csv,
file_name=chat_history_filename,
mime="text/csv",
help="Download the chat history session to a CSV file."
)
return True
except Exception as e:
st.error(f"Export failed: {str(e)}")
return False
def clear_session_state():
"""
Clear the session state variables related to chat history.
This function clears the session state variables 'generated_responses' and 'past',
which store the generated responses and user inputs in the chat history.
"""
# Clear the session state variables
st.session_state['generated_responses'] = []
st.session_state['past'] = []
###############
# :: MAIN APP #
###############
st.markdown("<h1 style='text-align: left;'>NLP Chatbot Demo 💬</h1>", unsafe_allow_html=True)
st.subheader(
"""
NLP Chatbot is a conversational chat bot. Begin by entering in a prompt below.
"""
)
try:
# Load preprocessed data and the model
words = pickle.load(open('words.pkl', 'rb'))
classes = pickle.load(open('classes.pkl', 'rb'))
chatbot_model = load_model('chatbot_model.h5')
except Exception as e:
st.error("An error occurred from missing a generated file...")
st.error(str(e))
st.info("""
Double check if you followed all the steps in **Train the Chatbot Model** prior to running the demo.
- Upload the commands.json file for processing
- Load the pickle data
- Create training data
- Build the model
""")
# Explanation of code using st.markdown with bullet points
st.markdown("""
- This chatbot app offers the following options:
- Option 1: Clear Chat Log
- Option 2: Preview the Chat History
- Option 3: Export Chat History
- To manage these options, three columns are created using `st.columns(3)`.
- Column 1 contains a checkbox labeled 'Clear Chat Log'. Selecting it will clear the chat log. Make sure to leave the text input box empty as well.
- Column 2 contains a checkbox labeled 'Preview the Chat History'. Selecting it will display the chat history.
- Column 3 contains a checkbox labeled 'Export Chat History'. Selecting it will export the chat history as a CSV file.
- Please interact with the checkboxes to perform the desired actions.
""")
st.write("---")
# Create a container for the columns
container = st.container()
# Add the columns inside the container
with container:
col1, col2, col3 = st.columns(3)
# Add a button to clear session state
if col1.checkbox("Clear Chat Log"):
clear_session_state()
if col2.checkbox("Preview the Chat History"):
chat_history_df = get_chat_history_df()
st.write(chat_history_df)
# Add a button to export chat history in the third column
if col3.checkbox("Export Chat History"):
chat_history_df = get_chat_history_df()
export_chat_history(chat_history_df)
# Initialize session states
if 'generated_responses' not in st.session_state:
st.session_state['generated_responses'] = []
if 'execution_times' not in st.session_state:
st.session_state['execution_times'] = []
if 'past' not in st.session_state:
st.session_state['past'] = []
# Get user input
user_input = get_text()
if user_input:
# Generate response
response, exec_time = chatbot_response(user_input)
# Update session states
st.session_state.past.append(user_input)
st.session_state.generated_responses.append(response)
st.session_state.execution_times.append(exec_time)
# Display the execution time of the response as a metric
st.metric("Execution Time", f"{exec_time:.2f} seconds")
if st.session_state['generated_responses']:
# Display generated responses and user inputs
for i in range(len(st.session_state['generated_responses']) - 1, -1, -1):
# Unique key for each generated response widget
message(f"Bot: {st.session_state['generated_responses'][i]}",
is_user=False,
avatar_style='bottts-neutral',
seed=10,
key=f"response_{i}"
)
# Unique key for each user input widget
message(f"You: {st.session_state['past'][i]}",
is_user=True,
avatar_style="open-peeps",
seed=1,
key=f"user_{i}"
)
# End of app
if __name__ == "__main__":
run_app()