keefereuther commited on
Commit
b78ecb4
·
verified ·
1 Parent(s): 3bbd149

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +387 -122
app.py CHANGED
@@ -1,3 +1,320 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ############################################################################################################
2
  # Importing Libraries
3
 
@@ -14,7 +331,12 @@ import config
14
  from openai import OpenAI
15
 
16
  # Set up logging
17
- logging.basicConfig(filename='app.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
 
 
 
 
 
18
 
19
  ############################################################################################################
20
  # Password protection
@@ -57,80 +379,39 @@ else:
57
  # Set the page to wide or centered mode
58
  st.set_page_config(layout="wide")
59
 
60
- # Load the terms file into a DataFrame
61
  df = pd.read_csv(config.default_terms_csv)
62
 
63
  # Streamlit app layout
64
  st.title(config.app_title)
65
  st.markdown(config.intro_para)
66
  st.caption(config.app_author)
67
- # st.sidebar.title(config.sidebar_title)
68
- # with st.sidebar:
69
- # with st.expander("Click here for instructions."):
70
- # st.write(config.sidebar_instructions)
71
 
72
  ############################################################################################################
73
- # File Uploader in sidebar
74
 
75
- # Load terms from a CSV file
76
- def load_terms(file_input):
77
  try:
78
- if isinstance(file_input, str):
79
- data = pd.read_csv(file_input)
80
- else:
81
- data = pd.read_csv(io.StringIO(file_input.read().decode('utf-8')))
82
- return data
83
  except Exception as e:
84
  st.error(f"An error occurred while loading the file: {str(e)}")
85
  logging.exception(f"Error loading file: {e}")
86
-
87
- # Function to create a download link for a file
88
- def create_download_link(file_path, file_name):
89
- try:
90
- with open(file_path, "rb") as file:
91
- file_content = file.read()
92
- encoded_content = base64.b64encode(file_content).decode("utf-8")
93
- download_link = f'<a href="data:file/csv;base64,{encoded_content}" download="{file_name}">Download {file_name}</a>'
94
- return download_link
95
- except FileNotFoundError:
96
- error_message = f"The file {file_name} was not found."
97
- st.error(error_message)
98
- logging.exception(error_message)
99
- except Exception as e:
100
- error_message = f"An error occurred: {str(e)}"
101
- st.error(error_message)
102
- logging.exception(error_message)
103
 
104
  # Function to extract the first column values
105
- def get_first_column_values(df):
106
- if not df.empty:
107
- return df.iloc[:, 0].tolist()
108
  else:
109
  return []
110
 
111
- # Download link for the template file
112
- template_file_path = config.default_terms_csv
113
-
114
- # File Uploader
115
- uploaded_file = config.default_terms_csv#st.sidebar.file_uploader(" ", type=["csv"])
116
- if uploaded_file is not None:
117
- logging.info(f"File uploaded: {uploaded_file.name}")
118
- st.session_state.uploaded_file = uploaded_file
119
-
120
- # Load terms from the file
121
- if 'uploaded_file' in st.session_state and st.session_state.uploaded_file is not None:
122
- terms = load_terms(st.session_state.uploaded_file)
123
- else:
124
- terms = load_terms(template_file_path)
125
 
126
- # Extract first column values
127
  term_list = get_first_column_values(terms)
128
 
129
- # st.sidebar.markdown(create_download_link(template_file_path, "terms.csv"), unsafe_allow_html=True)
130
-
131
- # # line break in the sidebar
132
- # st.sidebar.markdown('<hr>', unsafe_allow_html=True)
133
-
134
  ############################################################################################################
135
  # Term Selection and session state
136
 
@@ -141,14 +422,10 @@ if 'selected_context' not in st.session_state:
141
  st.session_state.selected_context = None
142
  if 'display_messages' not in st.session_state:
143
  st.session_state.display_messages = []
144
-
145
- # Initialize session states for the selected term, counter, and display flag
146
  if 'display_term' not in st.session_state:
147
  st.session_state.display_term = False
148
  if 'initial_message_displayed' not in st.session_state:
149
  st.session_state.initial_message_displayed = False
150
-
151
- # Initialize state to track the previously selected term
152
  if 'old_term' not in st.session_state:
153
  st.session_state.old_term = None
154
 
@@ -156,73 +433,67 @@ if 'old_term' not in st.session_state:
156
  selected_term = st.selectbox('**SELECT FROM THE DROPDOWN MENU**', term_list)
157
 
158
  if selected_term:
159
- # If a new term is selected (including first time selection), reset or show the message
160
  if selected_term != st.session_state.old_term:
161
- user_message = f"What is one thing you know about '{selected_term}'? What do you want to know about it? This could include a definition, examples, misconceptions, associations with other course terms, opinions, etc."
 
 
 
162
  st.session_state["display_messages"].append({"role": "user", "content": user_message})
163
- # Update old_term in session state
164
  st.session_state.old_term = selected_term
165
-
166
  selected_context = terms.loc[terms['TERM'] == selected_term, 'CONTEXT'].values[0]
167
  st.session_state.selected_term = selected_term
168
  st.session_state.selected_context = selected_context
169
  st.session_state.display_term = True
170
-
171
- # Update the prompt for the API
172
  updated_prompt = config.term_prompt(st.session_state.selected_term, st.session_state.selected_context, term_list)
173
-
174
  else:
175
- # If nothing is selected or the selection is cleared, reset the old_term
176
  st.session_state.old_term = None
177
 
178
- # Display the selected term and its context
179
  if st.session_state.display_term and st.session_state.selected_term:
180
  st.header(st.session_state.selected_term)
181
 
182
  with st.expander("INSTRUCTIONS FOR STUDENTS:"):
183
  st.markdown(config.instructions)
184
- # with st.expander("**INSTRUCTORS**: For a look at the current terms file driving the interaction, click here:"):
185
- # st.markdown("This is the terms.csv file that drives the interaction. You can edit this file to change the terms and context that the chatbot uses. You may add any term or phrase. You may leave the context blank if you prefer or you can add anything relevant that the GPT does not normally know about the term. This may include relevant learning objectives, course examples, notable scientists, assessment dates, syllabus information, etc.")
186
- # st.table(df)
187
- # with st.expander("**INSTRUCTORS**: For a look at the prompt driving the chatbot, click here:"):
188
- # prompt_text = config.term_prompt(st.session_state.selected_term, st.session_state.selected_context, term_list)
189
- # st.markdown(prompt_text)
190
 
191
  ############################################################################################################
192
  # ChatGPT
193
  # Initialize the OpenAI client
194
  client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"])
195
 
196
- # Initialize the session state variables if they don't exist
197
  if "openai_model" not in st.session_state:
198
  st.session_state["openai_model"] = config.ai_model
199
 
200
- if "display_messages" not in st.session_state:
201
- st.session_state.display_messages = []
202
-
203
- # Update initial_context with the latest selected term and context
204
  if st.session_state.get('selected_term') and st.session_state.get('selected_context'):
205
- updated_prompt = config.term_prompt(st.session_state.selected_term, st.session_state.selected_context, term_list)
206
- # Replace the initial context in display_messages with the updated prompt
 
 
 
207
  if st.session_state.display_messages:
208
  st.session_state.display_messages[0]["content"] = updated_prompt
209
  else:
210
  st.session_state.display_messages = [{"role": "system", "content": updated_prompt}]
211
 
212
- # Get user input
213
  prompt = st.chat_input("What do you know? What do you want to know?")
214
 
215
  # Input for new messages
216
  if prompt:
217
- # Ensure the initial context is in the session state, add the user's message
218
  if not st.session_state["display_messages"]:
219
- st.session_state["display_messages"].append(initial_context)
220
  st.session_state["display_messages"].append({"role": "user", "content": prompt})
221
 
222
  # Function to reset all chat-related session state
223
  def reset_chat_history():
224
  st.session_state["display_messages"] = []
225
- # Reset other chat-related session states if they exist
226
  if 'selected_term' in st.session_state:
227
  st.session_state.selected_term = None
228
  if 'selected_context' in st.session_state:
@@ -231,9 +502,11 @@ def reset_chat_history():
231
  st.session_state.display_term = False
232
  st.rerun()
233
 
 
234
  # Main chat container
235
- with st.container(height=400, border=True):
236
- # Display chat history in reverse order including new messages
 
237
  for message in st.session_state["display_messages"][1:]:
238
  if message["role"] == "user":
239
  with st.chat_message("user"):
@@ -242,7 +515,7 @@ with st.container(height=400, border=True):
242
  with st.chat_message("assistant"):
243
  st.markdown(message["content"])
244
 
245
- # Generate assistant's response and add it to the messages
246
  if prompt:
247
  with st.chat_message("assistant"):
248
  try:
@@ -259,58 +532,50 @@ with st.container(height=400, border=True):
259
  presence_penalty=config.presence_penalty,
260
  )
261
  response = st.write_stream(stream)
262
- # Append the full response to the session state for display
263
- st.session_state["display_messages"].append(
264
- {"role": "assistant", "content": response}
265
- )
266
- logging.info(f"User prompt: {prompt}") # Log user prompts
267
- logging.info(f"Assistant response: {response}") # Log assistant responses
268
  except Exception as e:
269
  st.error(f"An error occurred: {str(e)}")
270
- logging.exception(f"Error generating response: {e}") # Log errors
271
 
272
- # Add Clear Chat History button between container and warning message
273
  if st.button("Clear Chat History"):
274
  reset_chat_history()
275
- logging.info("Chat history cleared") # Log when chat history is cleared
276
 
277
  st.markdown(config.warning_message, unsafe_allow_html=True)
278
 
279
  ############################################################################################################
280
-
281
  # Resources and About Sections in the Sidebar
282
 
283
  st.sidebar.title("Resources")
284
 
285
  for resource in config.resources:
286
  with st.sidebar:
287
- with st.sidebar:
288
- with st.expander(resource["title"]):
289
- st.markdown(f"Description: {resource['description']}")
290
- if "url" in resource:
291
- st.markdown(f"[{resource['title']}]({resource['url']})")
292
- if "file_path" in resource:
293
- file_path = resource["file_path"]
294
- if os.path.exists(file_path):
295
- with open(file_path, "rb") as file:
296
- file_bytes = file.read()
297
- with st.spinner(f"Loading {resource['title']}..."):
298
- st.download_button(
299
- label=resource["title"],
300
- data=file_bytes,
301
- file_name=os.path.basename(file_path),
302
- mime="application/octet-stream",
303
- help=resource["description"],
304
- )
305
- else:
306
- st.warning(f"File not found: {file_path}")
307
-
308
- # Footer
309
  with st.sidebar:
310
  st.markdown("---")
311
-
312
  st.title("About")
313
-
314
- # Using the config objects in your Streamlit app
315
  st.markdown(config.app_creation_message, unsafe_allow_html=True)
316
  st.markdown(config.app_repo_license_message, unsafe_allow_html=True)
 
 
1
+ # ############################################################################################################
2
+ # # Importing Libraries
3
+
4
+ # import streamlit as st
5
+ # import hmac
6
+ # import pandas as pd
7
+ # import random
8
+ # import os
9
+ # import time
10
+ # import base64
11
+ # import logging
12
+ # import io
13
+ # import config
14
+ # from openai import OpenAI
15
+
16
+ # # Set up logging
17
+ # logging.basicConfig(filename='app.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
18
+
19
+ # ############################################################################################################
20
+ # # Password protection
21
+
22
+ # def check_credentials():
23
+ # """Returns `True` if the user had the correct username and password."""
24
+
25
+ # def credentials_entered():
26
+ # """Checks whether the entered username and password are correct."""
27
+ # if (
28
+ # hmac.compare_digest(st.session_state["username"], st.secrets["username"]) and
29
+ # hmac.compare_digest(st.session_state["password"], st.secrets["password"])
30
+ # ):
31
+ # st.session_state["credentials_correct"] = True
32
+ # del st.session_state["username"] # Don't store the username.
33
+ # del st.session_state["password"] # Don't store the password.
34
+ # else:
35
+ # st.session_state["credentials_correct"] = False
36
+
37
+ # # Return True if the credentials are validated.
38
+ # if st.session_state.get("credentials_correct", False):
39
+ # return True
40
+
41
+ # # Show input for username and password.
42
+ # st.text_input("Username", on_change=credentials_entered, key="username")
43
+ # st.text_input("Password", type="password", on_change=credentials_entered, key="password")
44
+
45
+ # if "credentials_correct" in st.session_state:
46
+ # logging.warning("Invalid login attempt") # Log invalid login attempts
47
+ # return False
48
+
49
+ # if not check_credentials():
50
+ # st.stop() # Do not continue if check_credentials is not True.
51
+ # else:
52
+ # logging.info("Successful login") # Log successful logins
53
+
54
+ # ############################################################################################################
55
+ # # Streamlit app layout
56
+
57
+ # # Set the page to wide or centered mode
58
+ # st.set_page_config(layout="wide")
59
+
60
+ # # Load the terms file into a DataFrame
61
+ # df = pd.read_csv(config.default_terms_csv)
62
+
63
+ # # Streamlit app layout
64
+ # st.title(config.app_title)
65
+ # st.markdown(config.intro_para)
66
+ # st.caption(config.app_author)
67
+ # # st.sidebar.title(config.sidebar_title)
68
+ # # with st.sidebar:
69
+ # # with st.expander("Click here for instructions."):
70
+ # # st.write(config.sidebar_instructions)
71
+
72
+ # ############################################################################################################
73
+ # # File Uploader in sidebar
74
+
75
+ # # Load terms from a CSV file
76
+ # def load_terms(file_input):
77
+ # try:
78
+ # if isinstance(file_input, str):
79
+ # data = pd.read_csv(file_input)
80
+ # else:
81
+ # data = pd.read_csv(io.StringIO(file_input.read().decode('utf-8')))
82
+ # return data
83
+ # except Exception as e:
84
+ # st.error(f"An error occurred while loading the file: {str(e)}")
85
+ # logging.exception(f"Error loading file: {e}")
86
+
87
+ # # Function to create a download link for a file
88
+ # def create_download_link(file_path, file_name):
89
+ # try:
90
+ # with open(file_path, "rb") as file:
91
+ # file_content = file.read()
92
+ # encoded_content = base64.b64encode(file_content).decode("utf-8")
93
+ # download_link = f'<a href="data:file/csv;base64,{encoded_content}" download="{file_name}">Download {file_name}</a>'
94
+ # return download_link
95
+ # except FileNotFoundError:
96
+ # error_message = f"The file {file_name} was not found."
97
+ # st.error(error_message)
98
+ # logging.exception(error_message)
99
+ # except Exception as e:
100
+ # error_message = f"An error occurred: {str(e)}"
101
+ # st.error(error_message)
102
+ # logging.exception(error_message)
103
+
104
+ # # Function to extract the first column values
105
+ # def get_first_column_values(df):
106
+ # if not df.empty:
107
+ # return df.iloc[:, 0].tolist()
108
+ # else:
109
+ # return []
110
+
111
+ # # Download link for the template file
112
+ # template_file_path = config.default_terms_csv
113
+
114
+ # # File Uploader
115
+ # uploaded_file = config.default_terms_csv#st.sidebar.file_uploader(" ", type=["csv"])
116
+ # if uploaded_file is not None:
117
+ # logging.info(f"File uploaded: {uploaded_file.name}")
118
+ # st.session_state.uploaded_file = uploaded_file
119
+
120
+ # # Load terms from the file
121
+ # if 'uploaded_file' in st.session_state and st.session_state.uploaded_file is not None:
122
+ # terms = load_terms(st.session_state.uploaded_file)
123
+ # else:
124
+ # terms = load_terms(template_file_path)
125
+
126
+ # # Extract first column values
127
+ # term_list = get_first_column_values(terms)
128
+
129
+ # # st.sidebar.markdown(create_download_link(template_file_path, "terms.csv"), unsafe_allow_html=True)
130
+
131
+ # # # line break in the sidebar
132
+ # # st.sidebar.markdown('<hr>', unsafe_allow_html=True)
133
+
134
+ # ############################################################################################################
135
+ # # Term Selection and session state
136
+
137
+ # # Initialize the session state variables for selected term, context, and display messages
138
+ # if 'selected_term' not in st.session_state:
139
+ # st.session_state.selected_term = None
140
+ # if 'selected_context' not in st.session_state:
141
+ # st.session_state.selected_context = None
142
+ # if 'display_messages' not in st.session_state:
143
+ # st.session_state.display_messages = []
144
+
145
+ # # Initialize session states for the selected term, counter, and display flag
146
+ # if 'display_term' not in st.session_state:
147
+ # st.session_state.display_term = False
148
+ # if 'initial_message_displayed' not in st.session_state:
149
+ # st.session_state.initial_message_displayed = False
150
+
151
+ # # Initialize state to track the previously selected term
152
+ # if 'old_term' not in st.session_state:
153
+ # st.session_state.old_term = None
154
+
155
+ # # Dropdown menu for selecting a term
156
+ # selected_term = st.selectbox('**SELECT FROM THE DROPDOWN MENU**', term_list)
157
+
158
+ # if selected_term:
159
+ # # If a new term is selected (including first time selection), reset or show the message
160
+ # if selected_term != st.session_state.old_term:
161
+ # user_message = f"What is one thing you know about '{selected_term}'? What do you want to know about it? This could include a definition, examples, misconceptions, associations with other course terms, opinions, etc."
162
+ # st.session_state["display_messages"].append({"role": "user", "content": user_message})
163
+ # # Update old_term in session state
164
+ # st.session_state.old_term = selected_term
165
+
166
+ # selected_context = terms.loc[terms['TERM'] == selected_term, 'CONTEXT'].values[0]
167
+ # st.session_state.selected_term = selected_term
168
+ # st.session_state.selected_context = selected_context
169
+ # st.session_state.display_term = True
170
+
171
+ # # Update the prompt for the API
172
+ # updated_prompt = config.term_prompt(st.session_state.selected_term, st.session_state.selected_context, term_list)
173
+
174
+ # else:
175
+ # # If nothing is selected or the selection is cleared, reset the old_term
176
+ # st.session_state.old_term = None
177
+
178
+ # # Display the selected term and its context
179
+ # if st.session_state.display_term and st.session_state.selected_term:
180
+ # st.header(st.session_state.selected_term)
181
+
182
+ # with st.expander("INSTRUCTIONS FOR STUDENTS:"):
183
+ # st.markdown(config.instructions)
184
+ # # with st.expander("**INSTRUCTORS**: For a look at the current terms file driving the interaction, click here:"):
185
+ # # st.markdown("This is the terms.csv file that drives the interaction. You can edit this file to change the terms and context that the chatbot uses. You may add any term or phrase. You may leave the context blank if you prefer or you can add anything relevant that the GPT does not normally know about the term. This may include relevant learning objectives, course examples, notable scientists, assessment dates, syllabus information, etc.")
186
+ # # st.table(df)
187
+ # # with st.expander("**INSTRUCTORS**: For a look at the prompt driving the chatbot, click here:"):
188
+ # # prompt_text = config.term_prompt(st.session_state.selected_term, st.session_state.selected_context, term_list)
189
+ # # st.markdown(prompt_text)
190
+
191
+ # ############################################################################################################
192
+ # # ChatGPT
193
+ # # Initialize the OpenAI client
194
+ # client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"])
195
+
196
+ # # Initialize the session state variables if they don't exist
197
+ # if "openai_model" not in st.session_state:
198
+ # st.session_state["openai_model"] = config.ai_model
199
+
200
+ # if "display_messages" not in st.session_state:
201
+ # st.session_state.display_messages = []
202
+
203
+ # # Update initial_context with the latest selected term and context
204
+ # if st.session_state.get('selected_term') and st.session_state.get('selected_context'):
205
+ # updated_prompt = config.term_prompt(st.session_state.selected_term, st.session_state.selected_context, term_list)
206
+ # # Replace the initial context in display_messages with the updated prompt
207
+ # if st.session_state.display_messages:
208
+ # st.session_state.display_messages[0]["content"] = updated_prompt
209
+ # else:
210
+ # st.session_state.display_messages = [{"role": "system", "content": updated_prompt}]
211
+
212
+ # # Get user input
213
+ # prompt = st.chat_input("What do you know? What do you want to know?")
214
+
215
+ # # Input for new messages
216
+ # if prompt:
217
+ # # Ensure the initial context is in the session state, add the user's message
218
+ # if not st.session_state["display_messages"]:
219
+ # st.session_state["display_messages"].append(initial_context)
220
+ # st.session_state["display_messages"].append({"role": "user", "content": prompt})
221
+
222
+ # # Function to reset all chat-related session state
223
+ # def reset_chat_history():
224
+ # st.session_state["display_messages"] = []
225
+ # # Reset other chat-related session states if they exist
226
+ # if 'selected_term' in st.session_state:
227
+ # st.session_state.selected_term = None
228
+ # if 'selected_context' in st.session_state:
229
+ # st.session_state.selected_context = None
230
+ # if 'display_term' in st.session_state:
231
+ # st.session_state.display_term = False
232
+ # st.rerun()
233
+
234
+ # # Main chat container
235
+ # with st.container(height=400, border=True):
236
+ # # Display chat history in reverse order including new messages
237
+ # for message in st.session_state["display_messages"][1:]:
238
+ # if message["role"] == "user":
239
+ # with st.chat_message("user"):
240
+ # st.markdown(message["content"])
241
+ # else:
242
+ # with st.chat_message("assistant"):
243
+ # st.markdown(message["content"])
244
+
245
+ # # Generate assistant's response and add it to the messages
246
+ # if prompt:
247
+ # with st.chat_message("assistant"):
248
+ # try:
249
+ # stream = client.chat.completions.create(
250
+ # model=st.session_state["openai_model"],
251
+ # messages=[
252
+ # {"role": m["role"], "content": m["content"]}
253
+ # for m in st.session_state["display_messages"]
254
+ # ],
255
+ # stream=True,
256
+ # temperature=config.temperature,
257
+ # max_tokens=config.max_tokens,
258
+ # frequency_penalty=config.frequency_penalty,
259
+ # presence_penalty=config.presence_penalty,
260
+ # )
261
+ # response = st.write_stream(stream)
262
+ # # Append the full response to the session state for display
263
+ # st.session_state["display_messages"].append(
264
+ # {"role": "assistant", "content": response}
265
+ # )
266
+ # logging.info(f"User prompt: {prompt}") # Log user prompts
267
+ # logging.info(f"Assistant response: {response}") # Log assistant responses
268
+ # except Exception as e:
269
+ # st.error(f"An error occurred: {str(e)}")
270
+ # logging.exception(f"Error generating response: {e}") # Log errors
271
+
272
+ # # Add Clear Chat History button between container and warning message
273
+ # if st.button("Clear Chat History"):
274
+ # reset_chat_history()
275
+ # logging.info("Chat history cleared") # Log when chat history is cleared
276
+
277
+ # st.markdown(config.warning_message, unsafe_allow_html=True)
278
+
279
+ # ############################################################################################################
280
+
281
+ # # Resources and About Sections in the Sidebar
282
+
283
+ # st.sidebar.title("Resources")
284
+
285
+ # for resource in config.resources:
286
+ # with st.sidebar:
287
+ # with st.sidebar:
288
+ # with st.expander(resource["title"]):
289
+ # st.markdown(f"Description: {resource['description']}")
290
+ # if "url" in resource:
291
+ # st.markdown(f"[{resource['title']}]({resource['url']})")
292
+ # if "file_path" in resource:
293
+ # file_path = resource["file_path"]
294
+ # if os.path.exists(file_path):
295
+ # with open(file_path, "rb") as file:
296
+ # file_bytes = file.read()
297
+ # with st.spinner(f"Loading {resource['title']}..."):
298
+ # st.download_button(
299
+ # label=resource["title"],
300
+ # data=file_bytes,
301
+ # file_name=os.path.basename(file_path),
302
+ # mime="application/octet-stream",
303
+ # help=resource["description"],
304
+ # )
305
+ # else:
306
+ # st.warning(f"File not found: {file_path}")
307
+
308
+ # # Footer
309
+ # with st.sidebar:
310
+ # st.markdown("---")
311
+
312
+ # st.title("About")
313
+
314
+ # # Using the config objects in your Streamlit app
315
+ # st.markdown(config.app_creation_message, unsafe_allow_html=True)
316
+ # st.markdown(config.app_repo_license_message, unsafe_allow_html=True)
317
+
318
  ############################################################################################################
319
  # Importing Libraries
320
 
 
331
  from openai import OpenAI
332
 
333
  # Set up logging
334
+ logging.basicConfig(
335
+ filename='app.log',
336
+ level=logging.INFO,
337
+ format='%(asctime)s - %(levelname)s - %(message)s',
338
+ datefmt='%Y-%m-%d %H:%M:%S'
339
+ )
340
 
341
  ############################################################################################################
342
  # Password protection
 
379
  # Set the page to wide or centered mode
380
  st.set_page_config(layout="wide")
381
 
382
+ # Load the terms file into a DataFrame using config.default_terms_csv
383
  df = pd.read_csv(config.default_terms_csv)
384
 
385
  # Streamlit app layout
386
  st.title(config.app_title)
387
  st.markdown(config.intro_para)
388
  st.caption(config.app_author)
 
 
 
 
389
 
390
  ############################################################################################################
391
+ # Loading Terms
392
 
393
+ def load_terms(file_path):
394
+ """Loads the CSV from the directory."""
395
  try:
396
+ return pd.read_csv(file_path)
 
 
 
 
397
  except Exception as e:
398
  st.error(f"An error occurred while loading the file: {str(e)}")
399
  logging.exception(f"Error loading file: {e}")
400
+ return pd.DataFrame()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
401
 
402
  # Function to extract the first column values
403
+ def get_first_column_values(local_df):
404
+ if not local_df.empty:
405
+ return local_df.iloc[:, 0].tolist()
406
  else:
407
  return []
408
 
409
+ ############################################################################################################
410
+ # Prepare terms (no user file uploader anymore—only config.default_terms_csv)
 
 
 
 
 
 
 
 
 
 
 
 
411
 
412
+ terms = load_terms(config.default_terms_csv)
413
  term_list = get_first_column_values(terms)
414
 
 
 
 
 
 
415
  ############################################################################################################
416
  # Term Selection and session state
417
 
 
422
  st.session_state.selected_context = None
423
  if 'display_messages' not in st.session_state:
424
  st.session_state.display_messages = []
 
 
425
  if 'display_term' not in st.session_state:
426
  st.session_state.display_term = False
427
  if 'initial_message_displayed' not in st.session_state:
428
  st.session_state.initial_message_displayed = False
 
 
429
  if 'old_term' not in st.session_state:
430
  st.session_state.old_term = None
431
 
 
433
  selected_term = st.selectbox('**SELECT FROM THE DROPDOWN MENU**', term_list)
434
 
435
  if selected_term:
436
+ # If a new term is selected, ask the user for input about that term
437
  if selected_term != st.session_state.old_term:
438
+ user_message = (
439
+ f"What is one thing you know about '{selected_term}'? What do you want to know about it? "
440
+ "This could include a definition, examples, misconceptions, associations with other course terms, opinions, etc."
441
+ )
442
  st.session_state["display_messages"].append({"role": "user", "content": user_message})
 
443
  st.session_state.old_term = selected_term
444
+
445
  selected_context = terms.loc[terms['TERM'] == selected_term, 'CONTEXT'].values[0]
446
  st.session_state.selected_term = selected_term
447
  st.session_state.selected_context = selected_context
448
  st.session_state.display_term = True
449
+
450
+ # Build the prompt for the model
451
  updated_prompt = config.term_prompt(st.session_state.selected_term, st.session_state.selected_context, term_list)
452
+
453
  else:
 
454
  st.session_state.old_term = None
455
 
456
+ # Display the selected term and context
457
  if st.session_state.display_term and st.session_state.selected_term:
458
  st.header(st.session_state.selected_term)
459
 
460
  with st.expander("INSTRUCTIONS FOR STUDENTS:"):
461
  st.markdown(config.instructions)
 
 
 
 
 
 
462
 
463
  ############################################################################################################
464
  # ChatGPT
465
  # Initialize the OpenAI client
466
  client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"])
467
 
468
+ # Initialize the model in session state if it doesn't exist
469
  if "openai_model" not in st.session_state:
470
  st.session_state["openai_model"] = config.ai_model
471
 
472
+ # Ensure the system prompt is set with the latest selected term and context
 
 
 
473
  if st.session_state.get('selected_term') and st.session_state.get('selected_context'):
474
+ updated_prompt = config.term_prompt(
475
+ st.session_state.selected_term,
476
+ st.session_state.selected_context,
477
+ term_list
478
+ )
479
  if st.session_state.display_messages:
480
  st.session_state.display_messages[0]["content"] = updated_prompt
481
  else:
482
  st.session_state.display_messages = [{"role": "system", "content": updated_prompt}]
483
 
484
+ # Chat input
485
  prompt = st.chat_input("What do you know? What do you want to know?")
486
 
487
  # Input for new messages
488
  if prompt:
489
+ # If no initial context in display_messages, add it
490
  if not st.session_state["display_messages"]:
491
+ st.session_state["display_messages"].append({"role": "system", "content": updated_prompt})
492
  st.session_state["display_messages"].append({"role": "user", "content": prompt})
493
 
494
  # Function to reset all chat-related session state
495
  def reset_chat_history():
496
  st.session_state["display_messages"] = []
 
497
  if 'selected_term' in st.session_state:
498
  st.session_state.selected_term = None
499
  if 'selected_context' in st.session_state:
 
502
  st.session_state.display_term = False
503
  st.rerun()
504
 
505
+ ############################################################################################################
506
  # Main chat container
507
+
508
+ with st.container():
509
+ # Display chat history in reverse order
510
  for message in st.session_state["display_messages"][1:]:
511
  if message["role"] == "user":
512
  with st.chat_message("user"):
 
515
  with st.chat_message("assistant"):
516
  st.markdown(message["content"])
517
 
518
+ # Generate assistant response
519
  if prompt:
520
  with st.chat_message("assistant"):
521
  try:
 
532
  presence_penalty=config.presence_penalty,
533
  )
534
  response = st.write_stream(stream)
535
+ st.session_state["display_messages"].append({"role": "assistant", "content": response})
536
+ logging.info(f"User prompt: {prompt}")
537
+ logging.info(f"Assistant response: {response}")
 
 
 
538
  except Exception as e:
539
  st.error(f"An error occurred: {str(e)}")
540
+ logging.exception(f"Error generating response: {e}")
541
 
542
+ # Clear chat history button
543
  if st.button("Clear Chat History"):
544
  reset_chat_history()
545
+ logging.info("Chat history cleared")
546
 
547
  st.markdown(config.warning_message, unsafe_allow_html=True)
548
 
549
  ############################################################################################################
 
550
  # Resources and About Sections in the Sidebar
551
 
552
  st.sidebar.title("Resources")
553
 
554
  for resource in config.resources:
555
  with st.sidebar:
556
+ with st.expander(resource["title"]):
557
+ st.markdown(f"Description: {resource['description']}")
558
+ if "url" in resource:
559
+ st.markdown(f"[{resource['title']}]({resource['url']})")
560
+ if "file_path" in resource:
561
+ file_path = resource["file_path"]
562
+ if os.path.exists(file_path):
563
+ with open(file_path, "rb") as file:
564
+ file_bytes = file.read()
565
+ with st.spinner(f"Loading {resource['title']}..."):
566
+ st.download_button(
567
+ label=resource["title"],
568
+ data=file_bytes,
569
+ file_name=os.path.basename(file_path),
570
+ mime="application/octet-stream",
571
+ help=resource["description"],
572
+ )
573
+ else:
574
+ st.warning(f"File not found: {file_path}")
575
+
 
 
576
  with st.sidebar:
577
  st.markdown("---")
 
578
  st.title("About")
 
 
579
  st.markdown(config.app_creation_message, unsafe_allow_html=True)
580
  st.markdown(config.app_repo_license_message, unsafe_allow_html=True)
581
+