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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +340 -375
app.py CHANGED
@@ -1,320 +1,3 @@
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,12 +14,7 @@ import config
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,7 +57,7 @@ else:
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
@@ -406,12 +84,76 @@ def get_first_column_values(local_df):
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,10 +164,14 @@ if 'selected_context' not in st.session_state:
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,67 +179,73 @@ if 'old_term' not in st.session_state:
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,11 +254,9 @@ def reset_chat_history():
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,7 +265,7 @@ with st.container():
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,50 +282,265 @@ with st.container():
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
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ############################################################################################################
2
  # Importing Libraries
3
 
 
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
  # 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
 
84
  else:
85
  return []
86
 
87
+
88
+ # # File Uploader in sidebar
89
+
90
+ # # Load terms from a CSV file
91
+ # def load_terms(file_input):
92
+ # try:
93
+ # if isinstance(file_input, str):
94
+ # data = pd.read_csv(file_input)
95
+ # else:
96
+ # data = pd.read_csv(io.StringIO(file_input.read().decode('utf-8')))
97
+ # return data
98
+ # except Exception as e:
99
+ # st.error(f"An error occurred while loading the file: {str(e)}")
100
+ # logging.exception(f"Error loading file: {e}")
101
+
102
+ # # Function to create a download link for a file
103
+ # def create_download_link(file_path, file_name):
104
+ # try:
105
+ # with open(file_path, "rb") as file:
106
+ # file_content = file.read()
107
+ # encoded_content = base64.b64encode(file_content).decode("utf-8")
108
+ # download_link = f'<a href="data:file/csv;base64,{encoded_content}" download="{file_name}">Download {file_name}</a>'
109
+ # return download_link
110
+ # except FileNotFoundError:
111
+ # error_message = f"The file {file_name} was not found."
112
+ # st.error(error_message)
113
+ # logging.exception(error_message)
114
+ # except Exception as e:
115
+ # error_message = f"An error occurred: {str(e)}"
116
+ # st.error(error_message)
117
+ # logging.exception(error_message)
118
+
119
+ # # Function to extract the first column values
120
+ # def get_first_column_values(df):
121
+ # if not df.empty:
122
+ # return df.iloc[:, 0].tolist()
123
+ # else:
124
+ # return []
125
+
126
  ############################################################################################################
127
  # Prepare terms (no user file uploader anymore—only config.default_terms_csv)
128
 
129
  terms = load_terms(config.default_terms_csv)
130
  term_list = get_first_column_values(terms)
131
 
132
+
133
+
134
+ # # Download link for the template file
135
+ # template_file_path = config.default_terms_csv
136
+
137
+ # # File Uploader
138
+ # uploaded_file = config.default_terms_csv#st.sidebar.file_uploader(" ", type=["csv"])
139
+ # if uploaded_file is not None:
140
+ # logging.info(f"File uploaded: {uploaded_file.name}")
141
+ # st.session_state.uploaded_file = uploaded_file
142
+
143
+ # # Load terms from the file
144
+ # if 'uploaded_file' in st.session_state and st.session_state.uploaded_file is not None:
145
+ # terms = load_terms(st.session_state.uploaded_file)
146
+ # else:
147
+ # terms = load_terms(template_file_path)
148
+
149
+ # # Extract first column values
150
+ # term_list = get_first_column_values(terms)
151
+
152
+ # # st.sidebar.markdown(create_download_link(template_file_path, "terms.csv"), unsafe_allow_html=True)
153
+
154
+ # # # line break in the sidebar
155
+ # # st.sidebar.markdown('<hr>', unsafe_allow_html=True)
156
+
157
  ############################################################################################################
158
  # Term Selection and session state
159
 
 
164
  st.session_state.selected_context = None
165
  if 'display_messages' not in st.session_state:
166
  st.session_state.display_messages = []
167
+
168
+ # Initialize session states for the selected term, counter, and display flag
169
  if 'display_term' not in st.session_state:
170
  st.session_state.display_term = False
171
  if 'initial_message_displayed' not in st.session_state:
172
  st.session_state.initial_message_displayed = False
173
+
174
+ # Initialize state to track the previously selected term
175
  if 'old_term' not in st.session_state:
176
  st.session_state.old_term = None
177
 
 
179
  selected_term = st.selectbox('**SELECT FROM THE DROPDOWN MENU**', term_list)
180
 
181
  if selected_term:
182
+ # If a new term is selected (including first time selection), reset or show the message
183
  if selected_term != st.session_state.old_term:
184
+ 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."
 
 
 
185
  st.session_state["display_messages"].append({"role": "user", "content": user_message})
186
+ # Update old_term in session state
187
  st.session_state.old_term = selected_term
188
+
189
  selected_context = terms.loc[terms['TERM'] == selected_term, 'CONTEXT'].values[0]
190
  st.session_state.selected_term = selected_term
191
  st.session_state.selected_context = selected_context
192
  st.session_state.display_term = True
193
+
194
+ # Update the prompt for the API
195
  updated_prompt = config.term_prompt(st.session_state.selected_term, st.session_state.selected_context, term_list)
196
+
197
  else:
198
+ # If nothing is selected or the selection is cleared, reset the old_term
199
  st.session_state.old_term = None
200
 
201
+ # Display the selected term and its context
202
  if st.session_state.display_term and st.session_state.selected_term:
203
  st.header(st.session_state.selected_term)
204
 
205
  with st.expander("INSTRUCTIONS FOR STUDENTS:"):
206
  st.markdown(config.instructions)
207
+ # with st.expander("**INSTRUCTORS**: For a look at the current terms file driving the interaction, click here:"):
208
+ # 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.")
209
+ # st.table(df)
210
+ # with st.expander("**INSTRUCTORS**: For a look at the prompt driving the chatbot, click here:"):
211
+ # prompt_text = config.term_prompt(st.session_state.selected_term, st.session_state.selected_context, term_list)
212
+ # st.markdown(prompt_text)
213
 
214
  ############################################################################################################
215
  # ChatGPT
216
  # Initialize the OpenAI client
217
  client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"])
218
 
219
+ # Initialize the session state variables if they don't exist
220
  if "openai_model" not in st.session_state:
221
  st.session_state["openai_model"] = config.ai_model
222
 
223
+ if "display_messages" not in st.session_state:
224
+ st.session_state.display_messages = []
225
+
226
+ # Update initial_context with the latest selected term and context
227
  if st.session_state.get('selected_term') and st.session_state.get('selected_context'):
228
+ updated_prompt = config.term_prompt(st.session_state.selected_term, st.session_state.selected_context, term_list)
229
+ # Replace the initial context in display_messages with the updated prompt
 
 
 
230
  if st.session_state.display_messages:
231
  st.session_state.display_messages[0]["content"] = updated_prompt
232
  else:
233
  st.session_state.display_messages = [{"role": "system", "content": updated_prompt}]
234
 
235
+ # Get user input
236
  prompt = st.chat_input("What do you know? What do you want to know?")
237
 
238
  # Input for new messages
239
  if prompt:
240
+ # Ensure the initial context is in the session state, add the user's message
241
  if not st.session_state["display_messages"]:
242
+ st.session_state["display_messages"].append(initial_context)
243
  st.session_state["display_messages"].append({"role": "user", "content": prompt})
244
 
245
  # Function to reset all chat-related session state
246
  def reset_chat_history():
247
  st.session_state["display_messages"] = []
248
+ # Reset other chat-related session states if they exist
249
  if 'selected_term' in st.session_state:
250
  st.session_state.selected_term = None
251
  if 'selected_context' in st.session_state:
 
254
  st.session_state.display_term = False
255
  st.rerun()
256
 
 
257
  # Main chat container
258
+ with st.container(height=400, border=True):
259
+ # Display chat history in reverse order including new messages
 
260
  for message in st.session_state["display_messages"][1:]:
261
  if message["role"] == "user":
262
  with st.chat_message("user"):
 
265
  with st.chat_message("assistant"):
266
  st.markdown(message["content"])
267
 
268
+ # Generate assistant's response and add it to the messages
269
  if prompt:
270
  with st.chat_message("assistant"):
271
  try:
 
282
  presence_penalty=config.presence_penalty,
283
  )
284
  response = st.write_stream(stream)
285
+ # Append the full response to the session state for display
286
+ st.session_state["display_messages"].append(
287
+ {"role": "assistant", "content": response}
288
+ )
289
+ logging.info(f"User prompt: {prompt}") # Log user prompts
290
+ logging.info(f"Assistant response: {response}") # Log assistant responses
291
  except Exception as e:
292
  st.error(f"An error occurred: {str(e)}")
293
+ logging.exception(f"Error generating response: {e}") # Log errors
294
 
295
+ # Add Clear Chat History button between container and warning message
296
  if st.button("Clear Chat History"):
297
  reset_chat_history()
298
+ logging.info("Chat history cleared") # Log when chat history is cleared
299
 
300
  st.markdown(config.warning_message, unsafe_allow_html=True)
301
 
302
  ############################################################################################################
303
+
304
  # Resources and About Sections in the Sidebar
305
 
306
  st.sidebar.title("Resources")
307
 
308
  for resource in config.resources:
309
  with st.sidebar:
310
+ with st.sidebar:
311
+ with st.expander(resource["title"]):
312
+ st.markdown(f"Description: {resource['description']}")
313
+ if "url" in resource:
314
+ st.markdown(f"[{resource['title']}]({resource['url']})")
315
+ if "file_path" in resource:
316
+ file_path = resource["file_path"]
317
+ if os.path.exists(file_path):
318
+ with open(file_path, "rb") as file:
319
+ file_bytes = file.read()
320
+ with st.spinner(f"Loading {resource['title']}..."):
321
+ st.download_button(
322
+ label=resource["title"],
323
+ data=file_bytes,
324
+ file_name=os.path.basename(file_path),
325
+ mime="application/octet-stream",
326
+ help=resource["description"],
327
+ )
328
+ else:
329
+ st.warning(f"File not found: {file_path}")
330
+
331
+ # Footer
332
  with st.sidebar:
333
  st.markdown("---")
334
+
335
  st.title("About")
336
+
337
+ # Using the config objects in your Streamlit app
338
  st.markdown(config.app_creation_message, unsafe_allow_html=True)
339
  st.markdown(config.app_repo_license_message, unsafe_allow_html=True)
340
 
341
+ # #################################################################
342
+ # # Streamlit app layout
343
+
344
+ # # Set the page to wide or centered mode
345
+ # st.set_page_config(layout="wide")
346
+
347
+ # # Load the terms file into a DataFrame using config.default_terms_csv
348
+ # df = pd.read_csv(config.default_terms_csv)
349
+
350
+ # # Streamlit app layout
351
+ # st.title(config.app_title)
352
+ # st.markdown(config.intro_para)
353
+ # st.caption(config.app_author)
354
+
355
+ # ############################################################################################################
356
+ # # Loading Terms
357
+
358
+ # def load_terms(file_path):
359
+ # """Loads the CSV from the directory."""
360
+ # try:
361
+ # return pd.read_csv(file_path)
362
+ # except Exception as e:
363
+ # st.error(f"An error occurred while loading the file: {str(e)}")
364
+ # logging.exception(f"Error loading file: {e}")
365
+ # return pd.DataFrame()
366
+
367
+ # # Function to extract the first column values
368
+ # def get_first_column_values(local_df):
369
+ # if not local_df.empty:
370
+ # return local_df.iloc[:, 0].tolist()
371
+ # else:
372
+ # return []
373
+
374
+ # ############################################################################################################
375
+ # # Prepare terms (no user file uploader anymore—only config.default_terms_csv)
376
+
377
+ # terms = load_terms(config.default_terms_csv)
378
+ # term_list = get_first_column_values(terms)
379
+
380
+ # ############################################################################################################
381
+ # # Term Selection and session state
382
+
383
+ # # Initialize the session state variables for selected term, context, and display messages
384
+ # if 'selected_term' not in st.session_state:
385
+ # st.session_state.selected_term = None
386
+ # if 'selected_context' not in st.session_state:
387
+ # st.session_state.selected_context = None
388
+ # if 'display_messages' not in st.session_state:
389
+ # st.session_state.display_messages = []
390
+ # if 'display_term' not in st.session_state:
391
+ # st.session_state.display_term = False
392
+ # if 'initial_message_displayed' not in st.session_state:
393
+ # st.session_state.initial_message_displayed = False
394
+ # if 'old_term' not in st.session_state:
395
+ # st.session_state.old_term = None
396
+
397
+ # # Dropdown menu for selecting a term
398
+ # selected_term = st.selectbox('**SELECT FROM THE DROPDOWN MENU**', term_list)
399
+
400
+ # if selected_term:
401
+ # # If a new term is selected, ask the user for input about that term
402
+ # if selected_term != st.session_state.old_term:
403
+ # user_message = (
404
+ # f"What is one thing you know about '{selected_term}'? What do you want to know about it? "
405
+ # "This could include a definition, examples, misconceptions, associations with other course terms, opinions, etc."
406
+ # )
407
+ # st.session_state["display_messages"].append({"role": "user", "content": user_message})
408
+ # st.session_state.old_term = selected_term
409
+
410
+ # selected_context = terms.loc[terms['TERM'] == selected_term, 'CONTEXT'].values[0]
411
+ # st.session_state.selected_term = selected_term
412
+ # st.session_state.selected_context = selected_context
413
+ # st.session_state.display_term = True
414
+
415
+ # # Build the prompt for the model
416
+ # updated_prompt = config.term_prompt(st.session_state.selected_term, st.session_state.selected_context, term_list)
417
+
418
+ # else:
419
+ # st.session_state.old_term = None
420
+
421
+ # # Display the selected term and context
422
+ # if st.session_state.display_term and st.session_state.selected_term:
423
+ # st.header(st.session_state.selected_term)
424
+
425
+ # with st.expander("INSTRUCTIONS FOR STUDENTS:"):
426
+ # st.markdown(config.instructions)
427
+
428
+ # ############################################################################################################
429
+ # # ChatGPT
430
+ # # Initialize the OpenAI client
431
+ # client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"])
432
+
433
+ # # Initialize the model in session state if it doesn't exist
434
+ # if "openai_model" not in st.session_state:
435
+ # st.session_state["openai_model"] = config.ai_model
436
+
437
+ # # Ensure the system prompt is set with the latest selected term and context
438
+ # if st.session_state.get('selected_term') and st.session_state.get('selected_context'):
439
+ # updated_prompt = config.term_prompt(
440
+ # st.session_state.selected_term,
441
+ # st.session_state.selected_context,
442
+ # term_list
443
+ # )
444
+ # if st.session_state.display_messages:
445
+ # st.session_state.display_messages[0]["content"] = updated_prompt
446
+ # else:
447
+ # st.session_state.display_messages = [{"role": "system", "content": updated_prompt}]
448
+
449
+ # # Chat input
450
+ # prompt = st.chat_input("What do you know? What do you want to know?")
451
+
452
+ # # Input for new messages
453
+ # if prompt:
454
+ # # If no initial context in display_messages, add it
455
+ # if not st.session_state["display_messages"]:
456
+ # st.session_state["display_messages"].append({"role": "system", "content": updated_prompt})
457
+ # st.session_state["display_messages"].append({"role": "user", "content": prompt})
458
+
459
+ # # Function to reset all chat-related session state
460
+ # def reset_chat_history():
461
+ # st.session_state["display_messages"] = []
462
+ # if 'selected_term' in st.session_state:
463
+ # st.session_state.selected_term = None
464
+ # if 'selected_context' in st.session_state:
465
+ # st.session_state.selected_context = None
466
+ # if 'display_term' in st.session_state:
467
+ # st.session_state.display_term = False
468
+ # st.rerun()
469
+
470
+ # ############################################################################################################
471
+ # # Main chat container
472
+
473
+ # with st.container():
474
+ # # Display chat history in reverse order
475
+ # for message in st.session_state["display_messages"][1:]:
476
+ # if message["role"] == "user":
477
+ # with st.chat_message("user"):
478
+ # st.markdown(message["content"])
479
+ # else:
480
+ # with st.chat_message("assistant"):
481
+ # st.markdown(message["content"])
482
+
483
+ # # Generate assistant response
484
+ # if prompt:
485
+ # with st.chat_message("assistant"):
486
+ # try:
487
+ # stream = client.chat.completions.create(
488
+ # model=st.session_state["openai_model"],
489
+ # messages=[
490
+ # {"role": m["role"], "content": m["content"]}
491
+ # for m in st.session_state["display_messages"]
492
+ # ],
493
+ # stream=True,
494
+ # temperature=config.temperature,
495
+ # max_tokens=config.max_tokens,
496
+ # frequency_penalty=config.frequency_penalty,
497
+ # presence_penalty=config.presence_penalty,
498
+ # )
499
+ # response = st.write_stream(stream)
500
+ # st.session_state["display_messages"].append({"role": "assistant", "content": response})
501
+ # logging.info(f"User prompt: {prompt}")
502
+ # logging.info(f"Assistant response: {response}")
503
+ # except Exception as e:
504
+ # st.error(f"An error occurred: {str(e)}")
505
+ # logging.exception(f"Error generating response: {e}")
506
+
507
+ # # Clear chat history button
508
+ # if st.button("Clear Chat History"):
509
+ # reset_chat_history()
510
+ # logging.info("Chat history cleared")
511
+
512
+ # st.markdown(config.warning_message, unsafe_allow_html=True)
513
+
514
+ # ############################################################################################################
515
+ # # Resources and About Sections in the Sidebar
516
+
517
+ # st.sidebar.title("Resources")
518
+
519
+ # for resource in config.resources:
520
+ # with st.sidebar:
521
+ # with st.expander(resource["title"]):
522
+ # st.markdown(f"Description: {resource['description']}")
523
+ # if "url" in resource:
524
+ # st.markdown(f"[{resource['title']}]({resource['url']})")
525
+ # if "file_path" in resource:
526
+ # file_path = resource["file_path"]
527
+ # if os.path.exists(file_path):
528
+ # with open(file_path, "rb") as file:
529
+ # file_bytes = file.read()
530
+ # with st.spinner(f"Loading {resource['title']}..."):
531
+ # st.download_button(
532
+ # label=resource["title"],
533
+ # data=file_bytes,
534
+ # file_name=os.path.basename(file_path),
535
+ # mime="application/octet-stream",
536
+ # help=resource["description"],
537
+ # )
538
+ # else:
539
+ # st.warning(f"File not found: {file_path}")
540
+
541
+ # with st.sidebar:
542
+ # st.markdown("---")
543
+ # st.title("About")
544
+ # st.markdown(config.app_creation_message, unsafe_allow_html=True)
545
+ # st.markdown(config.app_repo_license_message, unsafe_allow_html=True)
546
+