File size: 10,538 Bytes
6b4dab8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f1ac257
6b4dab8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f1ac257
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6b4dab8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
#!/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()