| |
| |
|
|
| import streamlit as st |
| import hmac |
| import pandas as pd |
| import random |
| import os |
| import time |
| import base64 |
| import logging |
| import io |
| import config |
| from openai import OpenAI |
|
|
| |
| logging.basicConfig(filename='app.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S') |
|
|
| |
| |
|
|
| def check_credentials(): |
| """Returns `True` if the user had the correct username and password.""" |
|
|
| def credentials_entered(): |
| """Checks whether the entered username and password are correct.""" |
| if ( |
| hmac.compare_digest(st.session_state["username"], st.secrets["username"]) and |
| hmac.compare_digest(st.session_state["password"], st.secrets["password"]) |
| ): |
| st.session_state["credentials_correct"] = True |
| del st.session_state["username"] |
| del st.session_state["password"] |
| else: |
| st.session_state["credentials_correct"] = False |
|
|
| |
| if st.session_state.get("credentials_correct", False): |
| return True |
|
|
| |
| st.text_input("Username", on_change=credentials_entered, key="username") |
| st.text_input("Password", type="password", on_change=credentials_entered, key="password") |
| |
| if "credentials_correct" in st.session_state: |
| logging.warning("Invalid login attempt") |
| return False |
|
|
| if not check_credentials(): |
| st.stop() |
| else: |
| logging.info("Successful login") |
|
|
| |
| |
|
|
| |
| st.set_page_config(layout="wide") |
|
|
| |
| df = pd.read_csv(config.default_terms_csv) |
|
|
| |
| st.title(config.app_title) |
| st.markdown(config.intro_para) |
| st.caption(config.app_author) |
|
|
| |
| |
|
|
| def load_terms(file_path): |
| """Loads the CSV from the directory.""" |
| try: |
| return pd.read_csv(file_path) |
| except Exception as e: |
| st.error(f"An error occurred while loading the file: {str(e)}") |
| logging.exception(f"Error loading file: {e}") |
| return pd.DataFrame() |
|
|
| |
| def get_first_column_values(local_df): |
| if not local_df.empty: |
| return local_df.iloc[:, 0].tolist() |
| else: |
| return [] |
|
|
|
|
| |
| |
|
|
| terms = load_terms(config.default_terms_csv) |
| term_list = get_first_column_values(terms) |
|
|
|
|
| |
| |
|
|
| |
| if 'selected_term' not in st.session_state: |
| st.session_state.selected_term = None |
| if 'selected_context' not in st.session_state: |
| st.session_state.selected_context = None |
| if 'display_messages' not in st.session_state: |
| st.session_state.display_messages = [] |
|
|
| |
| if 'display_term' not in st.session_state: |
| st.session_state.display_term = False |
| if 'initial_message_displayed' not in st.session_state: |
| st.session_state.initial_message_displayed = False |
|
|
| |
| if 'old_term' not in st.session_state: |
| st.session_state.old_term = None |
|
|
| |
| selected_term = st.selectbox('**SELECT FROM THE DROPDOWN MENU**', term_list) |
|
|
| if selected_term: |
| |
| if selected_term != st.session_state.old_term: |
| 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." |
| st.session_state["display_messages"].append({"role": "user", "content": user_message}) |
| |
| st.session_state.old_term = selected_term |
| |
| selected_context = terms.loc[terms['TERM'] == selected_term, 'CONTEXT'].values[0] |
| st.session_state.selected_term = selected_term |
| st.session_state.selected_context = selected_context |
| st.session_state.display_term = True |
| |
| |
| updated_prompt = config.term_prompt(st.session_state.selected_term, st.session_state.selected_context, term_list) |
| |
| else: |
| |
| st.session_state.old_term = None |
|
|
| |
| if st.session_state.display_term and st.session_state.selected_term: |
| st.header(st.session_state.selected_term) |
|
|
| with st.expander("INSTRUCTIONS FOR STUDENTS:"): |
| st.markdown(config.instructions) |
|
|
| |
| |
| |
| client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"]) |
|
|
| |
| if "openai_model" not in st.session_state: |
| st.session_state["openai_model"] = config.ai_model |
|
|
| if "display_messages" not in st.session_state: |
| st.session_state.display_messages = [] |
|
|
| |
| if st.session_state.get('selected_term') and st.session_state.get('selected_context'): |
| updated_prompt = config.term_prompt(st.session_state.selected_term, st.session_state.selected_context, term_list) |
| |
| if st.session_state.display_messages: |
| st.session_state.display_messages[0]["content"] = updated_prompt |
| else: |
| st.session_state.display_messages = [{"role": "system", "content": updated_prompt}] |
|
|
| |
| prompt = st.chat_input("What do you know? What do you want to know?") |
|
|
| |
| if prompt: |
| |
| if not st.session_state["display_messages"]: |
| st.session_state["display_messages"].append(initial_context) |
| st.session_state["display_messages"].append({"role": "user", "content": prompt}) |
|
|
| |
| def reset_chat_history(): |
| st.session_state["display_messages"] = [] |
| |
| if 'selected_term' in st.session_state: |
| st.session_state.selected_term = None |
| if 'selected_context' in st.session_state: |
| st.session_state.selected_context = None |
| if 'display_term' in st.session_state: |
| st.session_state.display_term = False |
| st.rerun() |
|
|
| |
| with st.container(height=400, border=True): |
| |
| for message in st.session_state["display_messages"][1:]: |
| if message["role"] == "user": |
| with st.chat_message("user"): |
| st.markdown(message["content"]) |
| else: |
| with st.chat_message("assistant"): |
| st.markdown(message["content"]) |
|
|
| |
| if prompt: |
| with st.chat_message("assistant"): |
| try: |
| stream = client.chat.completions.create( |
| model=st.session_state["openai_model"], |
| messages=[ |
| {"role": m["role"], "content": m["content"]} |
| for m in st.session_state["display_messages"] |
| ], |
| stream=True, |
| temperature=config.temperature, |
| max_tokens=config.max_tokens, |
| frequency_penalty=config.frequency_penalty, |
| presence_penalty=config.presence_penalty, |
| ) |
| response = st.write_stream(stream) |
| |
| st.session_state["display_messages"].append( |
| {"role": "assistant", "content": response} |
| ) |
| logging.info(f"User prompt: {prompt}") |
| logging.info(f"Assistant response: {response}") |
| except Exception as e: |
| st.error(f"An error occurred: {str(e)}") |
| logging.exception(f"Error generating response: {e}") |
|
|
| |
| if st.button("Clear Chat History"): |
| reset_chat_history() |
| logging.info("Chat history cleared") |
|
|
| st.markdown(config.warning_message, unsafe_allow_html=True) |
|
|
| |
|
|
| |
|
|
| st.sidebar.title("Resources") |
|
|
| for resource in config.resources: |
| with st.sidebar: |
| with st.sidebar: |
| with st.expander(resource["title"]): |
| st.markdown(f"Description: {resource['description']}") |
| if "url" in resource: |
| st.markdown(f"[{resource['title']}]({resource['url']})") |
| if "file_path" in resource: |
| file_path = resource["file_path"] |
| if os.path.exists(file_path): |
| with open(file_path, "rb") as file: |
| file_bytes = file.read() |
| with st.spinner(f"Loading {resource['title']}..."): |
| st.download_button( |
| label=resource["title"], |
| data=file_bytes, |
| file_name=os.path.basename(file_path), |
| mime="application/octet-stream", |
| help=resource["description"], |
| ) |
| else: |
| st.warning(f"File not found: {file_path}") |
|
|
| |
| with st.sidebar: |
| st.markdown("---") |
|
|
| st.title("About") |
|
|
| |
| st.markdown(config.app_creation_message, unsafe_allow_html=True) |
| st.markdown(config.app_repo_license_message, unsafe_allow_html=True) |
|
|