import streamlit as st import openai from dotenv import load_dotenv import os import json from openai import Client load_dotenv() # Set up the OpenAI API key openai.api_key = os.getenv("OPENAI_API_KEY") MODEL = 'gpt-3.5-turbo' client = Client() # Define theme and style suggestions THEMES = [ "Ambition", "Good vs. Evil", "Lady Macbeth's Influence", "Guilt and Regret", "Regicide and Natural Order", "The Supernatural" ] STYLES = [ "Formal and Analytical", "Casual and Conversational", "Humorous and Engaging", "Historical Context Focused" ] # Common weaknesses to track and address WEAKNESSES = { "thesis_formation": "Struggles with forming clear, arguable thesis statements", "evidence_selection": "Has difficulty selecting appropriate textual evidence", "analysis_depth": "Needs help deepening analysis of quotations", "structure": "Challenges with organizing essay structure", "context": "Difficulty connecting to historical/social context", "conventions": "Issues with grammar, citations, or academic conventions" } class StudentProfile: def __init__(self): self.weaknesses = {key: 0 for key in WEAKNESSES.keys()} self.identified_weaknesses = [] self.strengths = [] def update_weaknesses(self, weakness_types): for weakness in weakness_types: self.weaknesses[weakness] += 1 self._evaluate_weaknesses() def _evaluate_weaknesses(self): self.identified_weaknesses = [] total_interactions = sum(self.weaknesses.values()) if total_interactions == 0: return for weakness, count in self.weaknesses.items(): if count / total_interactions > 0.3: self.identified_weaknesses.append(weakness) def add_strength(self, strength): if strength not in self.strengths: self.strengths.append(strength) def get_personalized_prompt(self): if not self.identified_weaknesses: return "How would you like to develop your analysis further?" weakness_descriptions = [WEAKNESSES[w] for w in self.identified_weaknesses] if "thesis_formation" in self.identified_weaknesses: return ("Let's work on crafting a stronger thesis. Can you state your main argument in one clear sentence? " "Remember, a good thesis is specific, debatable, and sets up your entire essay.") elif "evidence_selection" in self.identified_weaknesses: return ("I notice you could use help selecting the best quotations. What moment in the play best illustrates " "your point? Look for passages that are rich in language and thematic significance.") elif "analysis_depth" in self.identified_weaknesses: return ("Let's dig deeper into your analysis. For your chosen quotation, can you explain: " "1) What the words literally mean, 2) How the language techniques work, " "3) Why this matters to your overall argument?") elif len(self.identified_weaknesses) > 1: return (f"I notice we should focus on: {', '.join(weakness_descriptions)}. " "Let's tackle these one at a time. Which area would you like to work on first?") else: return (f"Let's focus on improving your {weakness_descriptions[0]}. " "Can you show me how you would approach this in your next point?") class EssayTutor: def __init__(self, selected_theme, selected_style): self.conversation = [] self.selected_theme = selected_theme self.selected_style = selected_style self.student_profile = StudentProfile() system_message = { "role": "system", "content": ( "You are a friendly, humorous, and intelligent personalized tutor for Shakespeare's 'Macbeth'. " f"Today, the students (which are 14 to 17 years old) will focus on the theme of '{selected_theme}' using a '{selected_style}' style - they are not experts" "Your goal is to help the student develop a well-argued essay by guiding them to craft a clear thesis, " "integrate key quotations, and link ideas to historical context (including references to King James I). " "Be engaging and offer continuous assessment of the student's progress. " "Additionally, identify and address the student's specific weaknesses in essay writing by: " "1) Noticing patterns in their responses, " "2) Providing targeted exercises to improve those areas, " "3) Adjusting your feedback to their needs" ) } self.conversation.append(system_message) init_message = { "role": "assistant", "content": ( f"Welcome, future Shakespeare scholar! Today, we'll build your essay on *Macbeth* focusing on '{selected_theme}'. " "First, I'd like to understand your current approach. Could you share:\n" "1) Your initial thoughts about this theme in Macbeth\n" "2) Any specific challenges you face when writing about Shakespeare\n" "This will help me personalize our session to your needs." ) } self.conversation.append(init_message) def get_response(self): response = client.chat.completions.create( model=MODEL, messages=self.conversation ) return response.choices[0].message.content def add_message(self, role, message): self.conversation.append({"role": role, "content": message}) def analyze_student_response(self, student_message): analysis_prompt = { "role": "user", "content": ( f"Analyze this student response for essay writing strengths and weaknesses:\n\n" f"'{student_message}'\n\n" "Consider these potential weaknesses:\n" f"{WEAKNESSES}\n\n" "Return a JSON format analysis with:\n" "- 'weaknesses': list of weakness keys present (from the list above)\n" "- 'strengths': list of demonstrated strengths\n" "- 'feedback': brief constructive feedback\n" "Only return valid JSON, no additional text." ) } try: analysis_convo = self.conversation.copy() analysis_convo.append(analysis_prompt) response = client.chat.completions.create( model=MODEL, messages=analysis_convo, response_format={"type": "json_object"} ) analysis = json.loads(response.choices[0].message.content) return analysis except Exception as e: print(f"Analysis error: {e}") return {"weaknesses": [], "strengths": [], "feedback": ""} def assess_progress(self): if self.student_profile.identified_weaknesses: prompt = self.student_profile.get_personalized_prompt() else: prompt = ( "Let's assess the student progress. Can you explain how user inputs, questions and ideas connect to the theme? " "Try to be specific about quotations or examples from *Macbeth* that support your argument." "check for typos, style and creativity of the student's input so far." ) self.add_message("assistant", prompt) return self.get_response() if "tutor" not in st.session_state: st.session_state.tutor = None if "chat_history" not in st.session_state: st.session_state.chat_history = [] st.sidebar.title("Settings") selected_theme = st.sidebar.selectbox("Select a Theme", THEMES) selected_style = st.sidebar.selectbox("Select a Tutor Style", STYLES) st.title("Macbeth Essay Tutor") if st.sidebar.button("Start New Session"): st.session_state.tutor = EssayTutor(selected_theme, selected_style) st.session_state.chat_history = [{"role": "assistant", "content": st.session_state.tutor.conversation[1]["content"]}] st.success("Session started! The tutor is ready to help you.") if st.session_state.tutor is not None: for chat in st.session_state.chat_history: if chat["role"] == "assistant": st.markdown(f"**Tutor:** {chat['content']}") else: st.markdown(f"**You:** {chat['content']}") with st.form(key="input_form", clear_on_submit=True): user_input = st.text_area("Your response:", key="user_input", height=150) submitted = st.form_submit_button("Send") if submitted and user_input: analysis = st.session_state.tutor.analyze_student_response(user_input) st.session_state.tutor.student_profile.update_weaknesses(analysis.get("weaknesses", [])) for strength in analysis.get("strengths", []): st.session_state.tutor.student_profile.add_strength(strength) st.session_state.tutor.add_message("user", user_input) st.session_state.chat_history.append({"role": "user", "content": user_input}) tutor_reply = st.session_state.tutor.get_response() st.session_state.tutor.add_message("assistant", tutor_reply) st.session_state.chat_history.append({"role": "assistant", "content": tutor_reply}) #replace st.experimental_rerun() with this. st.rerun() if len(st.session_state.chat_history) > 2: if st.button("Get Personalized Feedback"): assessment_feedback = st.session_state.tutor.assess_progress() st.session_state.chat_history.append({"role": "assistant", "content": assessment_feedback}) #replace st.experimental_rerun() with this. st.rerun() st.sidebar.subheader("Your Writing Profile") if st.session_state.tutor.student_profile.identified_weaknesses: st.sidebar.warning("Areas to Improve:") for weakness in st.session_state.tutor.student_profile.identified_weaknesses: st.sidebar.write(f"- {WEAKNESSES[weakness]}") else: st.sidebar.success("No major weaknesses identified yet - keep going!") if st.session_state.tutor.student_profile.strengths: st.sidebar.info("Your Strengths:") for strength in st.session_state.tutor.student_profile.strengths: st.sidebar.write(f"- {strength}") else: st.info("Please start a new session using the sidebar.")