diff --git a/.gitignore b/.gitignore index fc70fb8..175a007 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ .streamlit/secrets.toml +# Ignore Python cache files +*.pyc +__pycache__/ \ No newline at end of file diff --git a/__pycache__/chatbot.cpython-310.pyc b/__pycache__/chatbot.cpython-310.pyc new file mode 100644 index 0000000..5557460 Binary files /dev/null and b/__pycache__/chatbot.cpython-310.pyc differ diff --git a/__pycache__/sidebar.cpython-310.pyc b/__pycache__/sidebar.cpython-310.pyc new file mode 100644 index 0000000..65e39f3 Binary files /dev/null and b/__pycache__/sidebar.cpython-310.pyc differ diff --git a/admin_panel.py b/admin_panel.py new file mode 100644 index 0000000..e69de29 diff --git a/chatbot.py b/chatbot.py new file mode 100644 index 0000000..e69de29 diff --git a/chatlog.py b/chatlog.py new file mode 100644 index 0000000..e69de29 diff --git a/db.py b/db.py new file mode 100644 index 0000000..e69de29 diff --git a/export.py b/export.py new file mode 100644 index 0000000..e69de29 diff --git a/instructions.py b/instructions.py new file mode 100644 index 0000000..e69de29 diff --git a/main.py b/main.py index 6e4f41d..9bba124 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,14 @@ -import logging +# main.py +import datetime +import io +import csv +import psycopg2 from openai import OpenAI +import logging import streamlit as st -import psycopg2 +from sidebar import setup_sidebar +# from chatbot import process_chat_input +# from admin_panel import handle_admin_actions st.title("CherGPT Basic") @@ -9,24 +16,23 @@ if "is_admin" not in st.session_state: st.session_state["is_admin"] = False + +# Set up the sidebar +setup_sidebar() + +# Admin panel actions +# handle_admin_actions() + +# Chatbot interaction +# process_chat_input() + + # Initialize variables for custom and existing instructions custom_instructions = "" existing_instructions = "" client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"]) -with st.sidebar: - st.title("Settings") - with st.expander("Admin config"): - admin_password = st.text_input("Enter Admin Password", type="password") - - if admin_password == st.secrets["ADMIN_PASSWORD"]: - st.session_state["is_admin"] = True - st.success("Authenticated as Admin") - elif admin_password: # Only display message if something was entered - st.error("Incorrect password") - st.session_state["is_admin"] = False - def connect_to_db(): try: @@ -40,26 +46,194 @@ def connect_to_db(): return None -def create_instructions_table_if_not_exists(): +def initialize_db(): conn = connect_to_db() + if conn is None: + return try: - with conn.cursor() as cur: + with conn, conn.cursor() as cur: + # Create custom_instructions table cur.execute(""" - CREATE TABLE IF NOT EXISTS instructions ( + CREATE TABLE IF NOT EXISTS custom_instructions ( id SERIAL PRIMARY KEY, - content TEXT, + instructions TEXT, timestamp TIMESTAMP DEFAULT current_timestamp ); """) + + # Create chat_logs table + cur.execute(""" + CREATE TABLE IF NOT EXISTS chat_logs ( + id SERIAL PRIMARY KEY, + timestamp TIMESTAMP DEFAULT current_timestamp, + prompt TEXT, + response TEXT + ); + """) + except Exception as e: + logging.error(f"Error initializing database: {e}") + finally: + if conn is not None: + conn.close() + + +# Call the initialization function at the appropriate place in your application +initialize_db() + + +# insert chatlog into DB +def insert_chat_log(prompt, response): + conn = connect_to_db() + if conn is None: + logging.error("Failed to connect to the database.") + return + + try: + with conn, conn.cursor() as cur: + cur.execute(""" + INSERT INTO chat_logs (prompt, response) + VALUES (%s, %s) + """, (prompt, response)) conn.commit() - print("Checked for 'instructions' table; created if not exists.") + logging.info("Chat log inserted successfully.") except Exception as e: - print(f"Error creating 'instructions' table: {e}") + logging.error(f"Error inserting chat log: {e}") finally: - conn.close() + if conn is not None: + conn.close() +# fetch chatlog -create_instructions_table_if_not_exists() + +def fetch_chat_logs(): + conn = connect_to_db() + if conn is None: + logging.error("Failed to connect to the database for fetching logs.") + return [] + try: + with conn, conn.cursor() as cur: + cur.execute("SELECT * FROM chat_logs") + chat_logs = cur.fetchall() + logging.info(f"Fetched {len(chat_logs)} chat log records.") + return chat_logs + except Exception as e: + logging.error(f"Error fetching chat logs: {e}") + return [] + finally: + if conn is not None: + conn.close() + +# fetch past hour chatlog + + +def fetch_recent_chat_logs(hours=1): + conn = connect_to_db() + if conn is None: + logging.error("Failed to connect to the database for fetching logs.") + return [] + + one_hour_ago = datetime.datetime.now() - datetime.timedelta(hours=hours) + logging.info(f"Fetching logs from: {one_hour_ago}") + + try: + with conn, conn.cursor() as cur: + cur.execute(""" + SELECT * FROM chat_logs + WHERE timestamp >= %s + """, (one_hour_ago,)) + chat_logs = cur.fetchall() + logging.info(f"Fetched {len(chat_logs)} chat log records.") + return chat_logs + except Exception as e: + logging.error(f"Error fetching recent chat logs: {e}") + return [] + finally: + if conn is not None: + conn.close() + +# test datetime conversion + + +def test_timestamp_conversion(): + conn = connect_to_db() + if conn is None: + logging.error("Failed to connect to the database.") + return + + try: + with conn, conn.cursor() as cur: + cur.execute("SELECT timestamp FROM chat_logs LIMIT 1") + record = cur.fetchone() + if record: + print("Timestamp type:", type(record[0])) + else: + print("No records found.") + except Exception as e: + logging.error(f"Error fetching a timestamp: {e}") + finally: + if conn is not None: + conn.close() + + +test_timestamp_conversion() + + +# export chatlog + + +def export_chat_logs_to_csv(filename='chat_logs.csv'): + chat_logs = fetch_chat_logs() + if not chat_logs: + print("No chat logs to export.") + return + + # Create a CSV in memory + output = io.StringIO() + writer = csv.writer(output) + # Writing headers + writer.writerow(['ID', 'Timestamp', 'Prompt', 'Response']) + writer.writerows(chat_logs) + return output.getvalue() + + +# delete chatlog +def delete_all_chatlogs(): + conn = connect_to_db() + if conn is None: + logging.error("Failed to connect to the database.") + return + try: + with conn, conn.cursor() as cur: + cur.execute("DELETE FROM chat_logs") + conn.commit() + logging.info("All chat logs deleted successfully.") + except Exception as e: + logging.error(f"Error deleting chat logs: {e}") + finally: + if conn is not None: + conn.close() + +# insights + + +def generate_insights_with_openai(chat_logs): + # Constructing the conversation context for GPT-3.5-turbo + conversation_context = [ + {"role": "system", "content": "Analyze the following chat logs and provide the top 5 insights on how students' questioning techniques could be improved:"}] + for log in chat_logs: + conversation_context.append({"role": "user", "content": log[2]}) + conversation_context.append({"role": "assistant", "content": log[3]}) + + # Sending the context to OpenAI's GPT-3.5-turbo model + response = openai.ChatCompletion.create( + model="gpt-3.5-turbo", + messages=conversation_context + ) + + return response.choices[0].message['content'] + + +# Create update instructions def update_instructions(new_instructions): @@ -109,6 +283,7 @@ def get_latest_instructions(): custominstructions_area_height = 300 + # Admin panel for custom instructions if st.session_state.get("is_admin"): with st.sidebar: @@ -122,6 +297,25 @@ def get_latest_instructions(): update_instructions(custom_instructions) st.success("Instructions updated successfully") st.experimental_rerun() + csv_data = export_chat_logs_to_csv() + if csv_data: + st.download_button( + label="Download Chat Logs", + data=csv_data, + file_name='chat_logs.csv', + mime='text/csv', + ) + if st.button("Delete All Chat Logs"): + delete_all_chatlogs() + + if st.button("Generate Insights from Recent Chats"): + recent_chats = fetch_recent_chat_logs(1) # Last hour + print(recent_chats) + if recent_chats: + insights = generate_insights_with_openai(recent_chats) + st.write(insights) + else: + st.write("No recent chats to analyze.") if "openai_model" not in st.session_state: st.session_state["openai_model"] = "gpt-3.5-turbo" @@ -161,6 +355,7 @@ def get_latest_instructions(): ): full_response += (response.choices[0].delta.content or "") message_placeholder.markdown(full_response + "▌") + insert_chat_log(prompt, full_response) message_placeholder.markdown(full_response) # Append the assistant's response to the messages for display diff --git a/openai_integration.py b/openai_integration.py new file mode 100644 index 0000000..e69de29 diff --git a/sidebar.py b/sidebar.py new file mode 100644 index 0000000..e99ff01 --- /dev/null +++ b/sidebar.py @@ -0,0 +1,17 @@ +import streamlit as st + + +def setup_sidebar(): + with st.sidebar: + st.title("Settings") + with st.expander("Admin config"): + admin_password = st.text_input( + "Enter Admin Password", type="password") + + if admin_password == st.secrets["ADMIN_PASSWORD"]: + st.session_state["is_admin"] = True + st.success("Authenticated as Admin") + elif admin_password: # Only display message if something was entered + st.error("Incorrect password") + st.session_state["is_admin"] = False + pass