NavyDevilDoc/Writing_Tutor
0
1import streamlit as st2from openai import OpenAI3import os4 5# 1. Configuration6st.set_page_config(page_title="High School Writing Coach", layout="wide")7 8# Get the API key from Environment Variables (HF Spaces) OR st.secrets (Local)9api_key = os.environ.get("OPENAI_API_KEY")10 11if not api_key:12 try:13 # Fallback for local development if using secrets.toml14 api_key = st.secrets["OPENAI_API_KEY"]15 except (FileNotFoundError, KeyError):16 st.error("OpenAI API Key not found. Please add 'OPENAI_API_KEY' to your Hugging Face Space secrets.")17 st.stop()18 19# Initialize client with the found key20client = OpenAI(api_key=api_key)21 22# 2. System Prompt23# This enforces the "No Rewrite" rule.24# --- 1. DEFINE THE FEW-SHOT EXAMPLES FIRST ---25FEW_SHOT_EXAMPLES = """26<example_1>27USER_INPUT: "The Great Gatsby shows that money is bad. Gatsby has a lot of money but he is sad."28USER_GOAL: "Argument Analysis"29AI_RESPONSE:30**Critique:** Your point is valid, but the sentence 31structure is a bit simple and relies on "telling" 32rather than "showing." You are using two independent 33clauses joined loosely.34 35**Lesson - Complex Sentences:** Try using a subordinating 36conjunction (like "although," "while," or "despite") to 37show the relationship between wealth and happiness.38 39**Structural Example (Topic: Sports):** Instead of saying 40"The team won the game but they played bad," a stronger writer 41might say: *"Despite securing a victory on the scoreboard, the 42team's defensive breakdown revealed fundamental weaknesses in 43their strategy."*44 45**Try it:** Can you rewrite your sentence about Gatsby using the word "Although" or "Despite"?46</example_1>47 48<example_2>49USER_INPUT: "I think that climate change is a big problem because it makes the weather hot."50USER_GOAL: "Vocabulary & Tone"51AI_RESPONSE:52**Critique:** The phrase "big problem" is vague, 53and "I think" is unnecessary. Academic writing 54requires precision.55 56**Lesson - Precise Vocabulary:** Replace general 57words with specific terms that describe the 58*scale* or *nature* of the problem.59 60**Structural Example (Topic: Cooking):** Instead 61of saying "I think the soup was bad because it was 62too salty," a critic would write: *"The broth's 63overwhelming salinity completely masked the delicate 64flavors of the vegetables."*65 66**Try it:** Look at your sentence. How can you replace 67"big problem" with a word that describes *how* climate 68change affects the planet?69</example_2>70"""71 72# --- 2. DEFINE THE MASTER SYSTEM PROMPT ---73# We inject the few-shot examples at the end.74SYSTEM_PROMPT = f"""75You are an expert Writing Coach for high school students. 76Your goal is to teach writing mechanics, logic, and rhetoric without rewriting the student's essay for them.77 78CORE RULES:791. **ABSOLUTE PROHIBITION:** DO NOT rewrite the student's text. If they ask "Can you fix this?" or "Rewrite it for me", you must REFUSE and ask them to try applying the lesson themselves.802. If you see a grammatical error, quote the sentence and explain the grammar rule they broke.813. Structure your feedback in Markdown with clear headings: "General Feedback", "Strengths", and "Areas for Improvement".824. Be encouraging but rigorous. Treat them like smart young adults.83 84SOCRATIC INSTRUCTIONS (Use when critiquing logic/argument):851. Do not give the answer.862. Ask a question that exposes the gap in the student's reasoning.873. Use the "Counter-Factual" technique: "If X were true, wouldn't Y also happen?"884. Use the "Perspective Shift" technique: "How would a French soldier in 1812 respond to this claim?"89 90INSTRUCTIONS FOR EXAMPLES:911. Analyze the student's text based on their selected Focus Area.922. Identify the top 1-2 weaknesses.933. For every weakness you identify, you must provide a **"Structural Example"**.944. CRITICAL: The "Structural Example" must be about a COMPLETELY DIFFERENT TOPIC than the student's essay.955. Never rewrite their actual sentence. Only show them the *pattern* of a better sentence.96 97Here are examples of how you should respond (Few-Shot Training):98{FEW_SHOT_EXAMPLES}99"""100 101# 3. Sidebar: Settings & Reset102with st.sidebar:103 st.header("⚙️ Coach Settings")104 grade_level = st.select_slider("Grade Level", options=["9th", "10th", "11th", "12th"])105 focus_area = st.selectbox(106 "Current Focus",107 ["General Critique", "Grammar & Syntax", "Argument & Logic", "Tone & Voice"]108 )109 110 st.divider()111 112 # --- RESET BUTTON LOGIC ---113 # If clicked, we clear the session state list114 if st.button("🔄 Reset Conversation", type="primary"):115 st.session_state.messages = []116 st.rerun()117 118# 4. Initialize Session State (Memory)119if "messages" not in st.session_state:120 st.session_state.messages = []121 122# 5. Display Chat History123st.title("🎓 Digital Writing Coach")124if len(st.session_state.messages) == 0:125 st.markdown("👋 **Hello!** Paste your draft below to get started. I'm here to coach, not to copy-edit!")126 127for message in st.session_state.messages:128 with st.chat_message(message["role"]):129 st.markdown(message["content"])130 131# 6. Chat Input & Processing132if prompt := st.chat_input("Paste your text or ask a question..."):133 134 # A. Display User Message135 with st.chat_message("user"):136 st.markdown(prompt)137 138 # Add user message to history139 st.session_state.messages.append({"role": "user", "content": prompt})140 141 # B. Generate Response142 with st.chat_message("assistant"):143 message_placeholder = st.empty()144 full_response = ""145 146 # We inject the "Current Settings" into the System Prompt dynamically147 # This ensures if the user changes the "Focus Area" mid-chat, the AI knows.148 dynamic_system_prompt = SYSTEM_PROMPT + f"\n\nCURRENT CONTEXT: Student is in {grade_level} Grade. Focus on: {focus_area}."149 150 try:151 # Construct the full message history for the API152 # System prompt first, then the conversation history153 messages_payload = [{"role": "system", "content": dynamic_system_prompt}] + st.session_state.messages154 155 response = client.chat.completions.create(156 model="gpt-4o",157 messages=messages_payload,158 temperature=0.7,159 stream=True # Streaming makes it feel faster160 )161 162 # Stream the response chunk by chunk163 for chunk in response:164 if chunk.choices[0].delta.content is not None:165 full_response += chunk.choices[0].delta.content166 message_placeholder.markdown(full_response + "▌")167 168 message_placeholder.markdown(full_response)169 170 # Add AI response to history171 st.session_state.messages.append({"role": "assistant", "content": full_response})172 173 except Exception as e:174 st.error(f"Error: {e}")