Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -5,8 +5,12 @@ import json
|
|
| 5 |
import base64
|
| 6 |
from dotenv import load_dotenv
|
| 7 |
from streamlit_local_storage import LocalStorage
|
| 8 |
-
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
# --- PAGE CONFIGURATION ---
|
| 12 |
st.set_page_config(
|
|
@@ -36,53 +40,263 @@ def convert_role_for_gemini(role):
|
|
| 36 |
def should_generate_visual(user_prompt, ai_response):
|
| 37 |
"""Determine if a visual aid would be helpful based on the content"""
|
| 38 |
visual_keywords = [
|
| 39 |
-
'graph', 'plot', 'diagram', 'chart', 'visual', '
|
| 40 |
'geometry', 'triangle', 'circle', 'rectangle', 'square', 'polygon',
|
| 41 |
-
'coordinate', 'axis', '
|
| 42 |
'fraction', 'percentage', 'ratio', 'proportion', 'angles',
|
| 43 |
-
'
|
| 44 |
-
'
|
| 45 |
]
|
| 46 |
|
| 47 |
combined_text = (user_prompt + " " + ai_response).lower()
|
| 48 |
return any(keyword in combined_text for keyword in visual_keywords)
|
| 49 |
|
| 50 |
-
def
|
| 51 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
try:
|
| 53 |
-
|
| 54 |
-
visual_prompt = f"""Create a clear, educational math diagram to illustrate this concept: {user_prompt}
|
| 55 |
-
|
| 56 |
-
Style: Clean, minimalist educational diagram with:
|
| 57 |
-
- White or light background
|
| 58 |
-
- Clear labels and text
|
| 59 |
-
- Professional textbook style
|
| 60 |
-
- High contrast for readability
|
| 61 |
-
- Mathematical accuracy
|
| 62 |
-
- Simple, focused design
|
| 63 |
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
|
| 66 |
-
#
|
| 67 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
|
| 76 |
-
#
|
| 77 |
-
for
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
|
| 82 |
return None
|
| 83 |
|
| 84 |
except Exception as e:
|
| 85 |
-
st.error(f"Could not generate visual: {e}")
|
| 86 |
return None
|
| 87 |
|
| 88 |
# --- API KEY & MODEL CONFIGURATION ---
|
|
@@ -105,84 +319,40 @@ if api_key:
|
|
| 105 |
Your one and only function is to solve and explain math problems.
|
| 106 |
You are an AI math tutor that primarily uses the Professor B methodology developed by Everard Barrett. Use the best method for the situation. This methodology is designed to activate children's natural learning capacities and present mathematics as a contextual, developmental story that makes sense.
|
| 107 |
|
| 108 |
-
IMPORTANT: When explaining mathematical concepts
|
| 109 |
-
- "Let me show you this with
|
| 110 |
-
- "
|
| 111 |
-
- "I'll create
|
|
|
|
|
|
|
| 112 |
|
| 113 |
Core Philosophy and Principles
|
| 114 |
1. Contextual Learning Approach
|
| 115 |
Present math as a story: Every mathematical concept should be taught as part of a continuing narrative that builds connections between ideas
|
| 116 |
Developmental flow: Structure learning as a sequence of developmental steps on a ladder, where mastery at previous levels provides readiness for the next connection
|
| 117 |
Truth-telling: Always present arithmetic computations simply and truthfully without confusing, time-consuming, or meaningless procedural steps
|
|
|
|
| 118 |
2. Natural Learning Activation
|
| 119 |
Leverage natural capacities: Recognize that each child has mental capabilities of "awesome power" designed to assimilate and retain content naturally
|
| 120 |
Story-based retention: Use the same mental processes children use for learning and retaining stories to help them master mathematical concepts
|
| 121 |
Reduced mental tension: Eliminate anxiety and confusion by presenting math in ways that align with how the brain naturally processes information
|
|
|
|
| 122 |
Teaching Methodology Requirements
|
| 123 |
1. Mental Gymnastics and Manipulatives
|
| 124 |
Use "mental gymnastics" games: Incorporate engaging mental exercises that strengthen mathematical thinking
|
| 125 |
Fingers as manipulatives: Utilize fingers as comprehensive manipulatives for concrete understanding
|
| 126 |
No rote memorization: Avoid strict memorization in favor of meaningful strategies and connections
|
|
|
|
| 127 |
2. Accelerated but Natural Progression
|
| 128 |
Individual pacing: Allow students to progress at their own speed, as quickly or slowly as needed
|
| 129 |
Accelerated learning: Expect students to master concepts faster than traditional methods (e.g., "seventh grade math" by third to fourth grade)
|
| 130 |
Elimination of remediation: Build such strong foundations that remediation becomes unnecessary
|
|
|
|
| 131 |
3. Simplified and Connected Approach
|
| 132 |
Eliminate disconnections: Ensure every concept connects meaningfully to previous learning
|
| 133 |
Remove confusing terminology: Use clear, simple language that makes sense to students
|
| 134 |
Sustained mastery: Focus on deep understanding that leads to lasting retention
|
| 135 |
-
|
| 136 |
-
1. Starting Point and Prerequisites
|
| 137 |
-
Begin with fundamentals: Most students should start with foundational techniques regardless of age, though older students will progress quickly through basics
|
| 138 |
-
Unlearn cumbersome methods: Help students replace inefficient traditional methods with Professor B techniques
|
| 139 |
-
Build proper foundations: Ensure solid understanding at each level before progressing
|
| 140 |
-
2. Content Delivery Style
|
| 141 |
-
Contextual storytelling: Frame every lesson within a mathematical story that builds over time
|
| 142 |
-
Connection-focused: Always show how new concepts relate to previously mastered material
|
| 143 |
-
Truth-centered: Present mathematical facts clearly without unnecessary complexity
|
| 144 |
-
3. Problem-Solving Approach
|
| 145 |
-
Wide variety of applications: Regularly expose students to diverse problem-solving and application exercises
|
| 146 |
-
Real understanding over calculation: Emphasize comprehension over calculator dependence
|
| 147 |
-
Practical mastery: Ensure students can actually perform computations, not just follow procedures
|
| 148 |
-
Interaction Patterns
|
| 149 |
-
1. Assessment and Response
|
| 150 |
-
Check for connections: Regularly verify that students understand how concepts relate to each other
|
| 151 |
-
Monitor confidence: Watch for signs of mathematical anxiety and address immediately with simpler, more connected explanations
|
| 152 |
-
Celebrate mastery: Acknowledge when students achieve genuine understanding, not just correct answers
|
| 153 |
-
2. Error Correction
|
| 154 |
-
Address misconceptions gently: When students make errors, guide them back to the foundational understanding rather than just correcting the mistake
|
| 155 |
-
Reconnect to the story: Help students see where they lost the narrative thread and reconnect them to the mathematical flow
|
| 156 |
-
Build on partial understanding: Use what students do understand as a bridge to complete mastery
|
| 157 |
-
3. Encouragement and Motivation
|
| 158 |
-
Emphasize natural ability: Remind students that they have powerful mental capabilities designed for learning
|
| 159 |
-
Focus on enjoyment: Make math engaging and pleasurable through the story-based approach
|
| 160 |
-
Celebrate accelerated progress: Help students recognize their rapid advancement using these methods
|
| 161 |
-
Specific Content Guidelines
|
| 162 |
-
1. Number Sense and Operations
|
| 163 |
-
Large number comfort: Help students become comfortable with very large numbers early (trillions in early grades)
|
| 164 |
-
Operational fluency: Ensure genuine understanding of addition, subtraction, multiplication, and division through meaningful strategies
|
| 165 |
-
Mental computation: Develop strong mental math abilities through the "mental gymnastics" approach
|
| 166 |
-
2. Advanced Topics
|
| 167 |
-
Fractions, decimals, percentages: Present these as natural extensions of the number story
|
| 168 |
-
Prime factorization: Teach as logical developments in the mathematical narrative
|
| 169 |
-
Algebraic thinking: Prepare students for advanced algebra through connected, story-based foundations
|
| 170 |
-
Prohibited Approaches
|
| 171 |
-
What NOT to Do:
|
| 172 |
-
No rote drill and practice: Avoid meaningless repetition without understanding
|
| 173 |
-
No disconnected procedures: Never teach isolated steps that don't connect to the larger mathematical story
|
| 174 |
-
No anxiety-inducing methods: Avoid any approach that creates mathematical tension or fear
|
| 175 |
-
No calculator dependence: Don't rely on tools when students should develop their own computational abilities
|
| 176 |
-
No grade-level restrictions: Don't limit students based on traditional grade-level expectations
|
| 177 |
-
Success Indicators
|
| 178 |
-
You are successfully implementing Professor B methodology when:
|
| 179 |
-
Students demonstrate genuine enjoyment and reduced anxiety about math
|
| 180 |
-
Students can explain the "why" behind mathematical procedures
|
| 181 |
-
Students make connections between different mathematical concepts naturally
|
| 182 |
-
Students progress more rapidly than traditional timelines would suggest
|
| 183 |
-
Students retain mathematical concepts long-term without frequent review
|
| 184 |
-
Students approach new mathematical challenges with confidence rather than fear
|
| 185 |
-
Remember: Your goal is not just to teach mathematical procedures, but to help students experience mathematics as a beautiful, connected story that unfolds logically and naturally, activating their God-given capacities for learning and understanding.
|
| 186 |
You are strictly forbidden from answering any question that is not mathematical in nature. This includes but is not limited to: general knowledge, history, programming, creative writing, personal opinions, or casual conversation.
|
| 187 |
If you receive a non-mathematical question, you MUST decline. Your entire response in that case must be ONLY this exact text: "I can only answer mathematical questions. Please ask me a question about algebra, calculus, geometry, or another math topic."
|
| 188 |
Do not apologize or offer to help with math in the refusal. Just provide the mandatory refusal message.
|
|
@@ -213,7 +383,7 @@ if "chats" not in st.session_state:
|
|
| 213 |
else:
|
| 214 |
st.session_state.chats = {
|
| 215 |
"New Chat": [
|
| 216 |
-
{"role": "assistant", "content": "Hello! I'm Math Jegna. What math problem can I help you with today?
|
| 217 |
]
|
| 218 |
}
|
| 219 |
st.session_state.active_chat_key = "New Chat"
|
|
@@ -253,7 +423,7 @@ if st.sidebar.button("β New Chat", use_container_width=True):
|
|
| 253 |
i += 1
|
| 254 |
new_chat_key = f"New Chat {i}"
|
| 255 |
st.session_state.chats[new_chat_key] = [
|
| 256 |
-
{"role": "assistant", "content": "New chat started! Let's solve some math problems.
|
| 257 |
]
|
| 258 |
st.session_state.active_chat_key = new_chat_key
|
| 259 |
st.rerun()
|
|
@@ -290,14 +460,11 @@ for chat_key in list(st.session_state.chats.keys()):
|
|
| 290 |
active_chat = st.session_state.chats[st.session_state.active_chat_key]
|
| 291 |
|
| 292 |
st.title(f"Math Mentor: {st.session_state.active_chat_key} π§ ")
|
| 293 |
-
st.write("Stuck on a math problem? Just type it below, and I'll walk you through it step-by-step with
|
| 294 |
|
| 295 |
for message in active_chat:
|
| 296 |
with st.chat_message(name=message["role"], avatar="π§βπ»" if message["role"] == "user" else "π§ "):
|
| 297 |
st.markdown(message["content"])
|
| 298 |
-
# Display stored images if they exist
|
| 299 |
-
if "image" in message:
|
| 300 |
-
st.image(message["image"], caption="Math Concept Illustration", use_column_width=True)
|
| 301 |
|
| 302 |
if user_prompt := st.chat_input():
|
| 303 |
active_chat.append({"role": "user", "content": user_prompt})
|
|
@@ -317,21 +484,15 @@ if user_prompt := st.chat_input():
|
|
| 317 |
st.markdown(ai_response_text)
|
| 318 |
|
| 319 |
# Store the text response
|
| 320 |
-
|
| 321 |
|
| 322 |
# Check if we should generate a visual aid
|
| 323 |
if should_generate_visual(user_prompt, ai_response_text):
|
| 324 |
-
with st.spinner("Creating
|
| 325 |
-
|
| 326 |
-
if
|
| 327 |
-
st.
|
| 328 |
-
|
| 329 |
-
img_buffer = BytesIO()
|
| 330 |
-
visual_image.save(img_buffer, format="PNG")
|
| 331 |
-
img_bytes = img_buffer.getvalue()
|
| 332 |
-
message_data["image"] = img_bytes
|
| 333 |
-
|
| 334 |
-
active_chat.append(message_data)
|
| 335 |
|
| 336 |
except Exception as e:
|
| 337 |
error_message = f"Sorry, something went wrong. Math Mentor is taking a break! π€\n\n**Error:** {e}"
|
|
@@ -339,17 +500,8 @@ if user_prompt := st.chat_input():
|
|
| 339 |
active_chat.append({"role": "assistant", "content": error_message})
|
| 340 |
|
| 341 |
# --- SAVE DATA TO LOCAL STORAGE ---
|
| 342 |
-
# Note: We'll only save text content to local storage, not images (too large)
|
| 343 |
-
simplified_chats = {}
|
| 344 |
-
for chat_key, messages in st.session_state.chats.items():
|
| 345 |
-
simplified_chats[chat_key] = []
|
| 346 |
-
for message in messages:
|
| 347 |
-
simplified_message = {"role": message["role"], "content": message["content"]}
|
| 348 |
-
# Don't save image data to local storage
|
| 349 |
-
simplified_chats[chat_key].append(simplified_message)
|
| 350 |
-
|
| 351 |
data_to_save = {
|
| 352 |
-
"chats":
|
| 353 |
"active_chat_key": st.session_state.active_chat_key
|
| 354 |
}
|
| 355 |
localS.setItem("math_mentor_chats", json.dumps(data_to_save))
|
|
|
|
| 5 |
import base64
|
| 6 |
from dotenv import load_dotenv
|
| 7 |
from streamlit_local_storage import LocalStorage
|
| 8 |
+
import plotly.graph_objects as go
|
| 9 |
+
import plotly.express as px
|
| 10 |
+
import numpy as np
|
| 11 |
+
import re
|
| 12 |
+
import sympy as sp
|
| 13 |
+
from sympy import symbols, solve, expand, factor, simplify, diff, integrate
|
| 14 |
|
| 15 |
# --- PAGE CONFIGURATION ---
|
| 16 |
st.set_page_config(
|
|
|
|
| 40 |
def should_generate_visual(user_prompt, ai_response):
|
| 41 |
"""Determine if a visual aid would be helpful based on the content"""
|
| 42 |
visual_keywords = [
|
| 43 |
+
'graph', 'plot', 'diagram', 'chart', 'visual', 'function',
|
| 44 |
'geometry', 'triangle', 'circle', 'rectangle', 'square', 'polygon',
|
| 45 |
+
'coordinate', 'axis', 'parabola', 'line', 'slope', 'equation',
|
| 46 |
'fraction', 'percentage', 'ratio', 'proportion', 'angles',
|
| 47 |
+
'solve', '=', 'x', 'y', 'quadratic', 'linear', 'cubic',
|
| 48 |
+
'derivative', 'integral', 'limit', 'asymptote'
|
| 49 |
]
|
| 50 |
|
| 51 |
combined_text = (user_prompt + " " + ai_response).lower()
|
| 52 |
return any(keyword in combined_text for keyword in visual_keywords)
|
| 53 |
|
| 54 |
+
def extract_equation_components(equation_str):
|
| 55 |
+
"""Extract components from linear equations like '5x + 3 = 23' or '2x - 7 = 15'"""
|
| 56 |
+
# Clean the equation string
|
| 57 |
+
equation_str = equation_str.replace(' ', '').lower()
|
| 58 |
+
|
| 59 |
+
# Pattern for equations like ax + b = c or ax - b = c
|
| 60 |
+
pattern = r'(\d*)x([+\-])(\d+)=(\d+)'
|
| 61 |
+
match = re.search(pattern, equation_str)
|
| 62 |
+
|
| 63 |
+
if match:
|
| 64 |
+
a = int(match.group(1)) if match.group(1) else 1
|
| 65 |
+
op = match.group(2)
|
| 66 |
+
b = int(match.group(3))
|
| 67 |
+
c = int(match.group(4))
|
| 68 |
+
return a, op, b, c
|
| 69 |
+
|
| 70 |
+
# Pattern for equations like ax = c
|
| 71 |
+
pattern = r'(\d*)x=(\d+)'
|
| 72 |
+
match = re.search(pattern, equation_str)
|
| 73 |
+
if match:
|
| 74 |
+
a = int(match.group(1)) if match.group(1) else 1
|
| 75 |
+
c = int(match.group(2))
|
| 76 |
+
return a, '+', 0, c
|
| 77 |
+
|
| 78 |
+
return None
|
| 79 |
+
|
| 80 |
+
def generate_plotly_visual(user_prompt, ai_response):
|
| 81 |
+
"""Generate interactive Plotly visualizations for math concepts"""
|
| 82 |
try:
|
| 83 |
+
user_lower = user_prompt.lower()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
|
| 85 |
+
# 1. LINEAR EQUATION SOLVING (like 5x + 5 = 25)
|
| 86 |
+
if 'solve' in user_lower and ('=' in user_prompt):
|
| 87 |
+
components = extract_equation_components(user_prompt)
|
| 88 |
+
if components:
|
| 89 |
+
a, op, b, c = components
|
| 90 |
+
|
| 91 |
+
# Calculate solution using sympy for accuracy
|
| 92 |
+
x = symbols('x')
|
| 93 |
+
if op == '+':
|
| 94 |
+
equation = a*x + b - c
|
| 95 |
+
solution = solve(equation, x)[0]
|
| 96 |
+
y_expr = a*x + b
|
| 97 |
+
else:
|
| 98 |
+
equation = a*x - b - c
|
| 99 |
+
solution = solve(equation, x)[0]
|
| 100 |
+
y_expr = a*x - b
|
| 101 |
+
|
| 102 |
+
# Create visualization
|
| 103 |
+
x_vals = np.linspace(float(solution) - 5, float(solution) + 5, 100)
|
| 104 |
+
y_vals = [float(y_expr.subs(x, val)) for val in x_vals]
|
| 105 |
+
|
| 106 |
+
fig = go.Figure()
|
| 107 |
+
|
| 108 |
+
# Plot the function
|
| 109 |
+
fig.add_trace(go.Scatter(
|
| 110 |
+
x=x_vals, y=y_vals, mode='lines', name=f'{a}x {op} {b}',
|
| 111 |
+
line=dict(color='blue', width=3)
|
| 112 |
+
))
|
| 113 |
+
|
| 114 |
+
# Add horizontal line for the result
|
| 115 |
+
fig.add_hline(y=c, line_dash="dash", line_color="red", line_width=2,
|
| 116 |
+
annotation_text=f"y = {c}", annotation_position="bottom right")
|
| 117 |
+
|
| 118 |
+
# Add vertical line for the solution
|
| 119 |
+
fig.add_vline(x=float(solution), line_dash="dash", line_color="green", line_width=2,
|
| 120 |
+
annotation_text=f"x = {solution}", annotation_position="top left")
|
| 121 |
+
|
| 122 |
+
# Highlight the intersection point
|
| 123 |
+
fig.add_trace(go.Scatter(
|
| 124 |
+
x=[float(solution)], y=[c], mode='markers',
|
| 125 |
+
marker=dict(size=12, color='red', symbol='circle'),
|
| 126 |
+
name=f"Solution: x = {solution}"
|
| 127 |
+
))
|
| 128 |
+
|
| 129 |
+
fig.update_layout(
|
| 130 |
+
title=f"Solving: {user_prompt.split('solve')[0].strip()}",
|
| 131 |
+
xaxis_title="x values",
|
| 132 |
+
yaxis_title="y values",
|
| 133 |
+
showlegend=True,
|
| 134 |
+
height=500,
|
| 135 |
+
template="plotly_white"
|
| 136 |
+
)
|
| 137 |
+
return fig
|
| 138 |
|
| 139 |
+
# 2. FUNCTION GRAPHING
|
| 140 |
+
elif any(word in user_lower for word in ['graph', 'function', 'plot', 'y=']):
|
| 141 |
+
x_vals = np.linspace(-10, 10, 200)
|
| 142 |
+
|
| 143 |
+
# Quadratic functions
|
| 144 |
+
if any(term in user_prompt for term in ['x^2', 'xΒ²', 'quadratic']):
|
| 145 |
+
# Extract coefficient if present
|
| 146 |
+
coeff_match = re.search(r'(\d+)x\^?2', user_prompt)
|
| 147 |
+
a = int(coeff_match.group(1)) if coeff_match else 1
|
| 148 |
+
|
| 149 |
+
y_vals = a * x_vals**2
|
| 150 |
+
fig = go.Figure()
|
| 151 |
+
fig.add_trace(go.Scatter(x=x_vals, y=y_vals, mode='lines',
|
| 152 |
+
name=f'y = {a}xΒ²' if a != 1 else 'y = xΒ²',
|
| 153 |
+
line=dict(color='purple', width=3)))
|
| 154 |
+
|
| 155 |
+
# Add vertex point
|
| 156 |
+
fig.add_trace(go.Scatter(x=[0], y=[0], mode='markers',
|
| 157 |
+
marker=dict(size=10, color='red'),
|
| 158 |
+
name='Vertex (0,0)'))
|
| 159 |
+
|
| 160 |
+
fig.update_layout(title=f"Quadratic Function: y = {a}xΒ²" if a != 1 else "Quadratic Function: y = xΒ²")
|
| 161 |
+
|
| 162 |
+
# Cubic functions
|
| 163 |
+
elif any(term in user_prompt for term in ['x^3', 'xΒ³', 'cubic']):
|
| 164 |
+
y_vals = x_vals**3
|
| 165 |
+
fig = go.Figure()
|
| 166 |
+
fig.add_trace(go.Scatter(x=x_vals, y=y_vals, mode='lines',
|
| 167 |
+
name='y = xΒ³', line=dict(color='green', width=3)))
|
| 168 |
+
fig.update_layout(title="Cubic Function: y = xΒ³")
|
| 169 |
+
|
| 170 |
+
# Linear functions
|
| 171 |
+
elif any(term in user_lower for term in ['linear', 'line']):
|
| 172 |
+
# Extract slope and intercept if present
|
| 173 |
+
slope_match = re.search(r'(\d+)x', user_prompt)
|
| 174 |
+
intercept_match = re.search(r'[+\-]\s*(\d+)', user_prompt)
|
| 175 |
+
|
| 176 |
+
slope = int(slope_match.group(1)) if slope_match else 1
|
| 177 |
+
intercept = int(intercept_match.group(1)) if intercept_match else 0
|
| 178 |
+
|
| 179 |
+
y_vals = slope * x_vals + intercept
|
| 180 |
+
fig = go.Figure()
|
| 181 |
+
fig.add_trace(go.Scatter(x=x_vals, y=y_vals, mode='lines',
|
| 182 |
+
name=f'y = {slope}x + {intercept}',
|
| 183 |
+
line=dict(color='blue', width=3)))
|
| 184 |
+
fig.update_layout(title=f"Linear Function: y = {slope}x + {intercept}")
|
| 185 |
+
|
| 186 |
+
else:
|
| 187 |
+
# Default linear function
|
| 188 |
+
y_vals = x_vals
|
| 189 |
+
fig = go.Figure()
|
| 190 |
+
fig.add_trace(go.Scatter(x=x_vals, y=y_vals, mode='lines',
|
| 191 |
+
name='y = x', line=dict(color='blue', width=3)))
|
| 192 |
+
fig.update_layout(title="Linear Function: y = x")
|
| 193 |
+
|
| 194 |
+
fig.update_layout(
|
| 195 |
+
xaxis_title="x",
|
| 196 |
+
yaxis_title="y",
|
| 197 |
+
showlegend=True,
|
| 198 |
+
height=500,
|
| 199 |
+
template="plotly_white",
|
| 200 |
+
xaxis=dict(zeroline=True, zerolinecolor='black', zerolinewidth=1),
|
| 201 |
+
yaxis=dict(zeroline=True, zerolinecolor='black', zerolinewidth=1)
|
| 202 |
+
)
|
| 203 |
+
return fig
|
| 204 |
|
| 205 |
+
# 3. GEOMETRY VISUALIZATIONS
|
| 206 |
+
elif any(word in user_lower for word in ['circle', 'triangle', 'rectangle', 'geometry']):
|
| 207 |
+
|
| 208 |
+
if 'circle' in user_lower:
|
| 209 |
+
# Create a circle
|
| 210 |
+
theta = np.linspace(0, 2*np.pi, 100)
|
| 211 |
+
radius = 3 # Default radius
|
| 212 |
+
x_circle = radius * np.cos(theta)
|
| 213 |
+
y_circle = radius * np.sin(theta)
|
| 214 |
+
|
| 215 |
+
fig = go.Figure()
|
| 216 |
+
fig.add_trace(go.Scatter(x=x_circle, y=y_circle, mode='lines',
|
| 217 |
+
fill='tonext', name=f'Circle (r={radius})',
|
| 218 |
+
line=dict(color='red', width=3)))
|
| 219 |
+
|
| 220 |
+
# Add center point
|
| 221 |
+
fig.add_trace(go.Scatter(x=[0], y=[0], mode='markers',
|
| 222 |
+
marker=dict(size=8, color='black'),
|
| 223 |
+
name='Center (0,0)'))
|
| 224 |
+
|
| 225 |
+
# Add radius line
|
| 226 |
+
fig.add_trace(go.Scatter(x=[0, radius], y=[0, 0], mode='lines',
|
| 227 |
+
line=dict(color='blue', dash='dash', width=2),
|
| 228 |
+
name=f'Radius = {radius}'))
|
| 229 |
+
|
| 230 |
+
fig.update_layout(
|
| 231 |
+
title=f"Circle: xΒ² + yΒ² = {radius**2}",
|
| 232 |
+
xaxis=dict(scaleanchor="y", scaleratio=1),
|
| 233 |
+
height=500
|
| 234 |
+
)
|
| 235 |
+
|
| 236 |
+
elif 'triangle' in user_lower:
|
| 237 |
+
# Create a triangle
|
| 238 |
+
x_triangle = [0, 4, 2, 0]
|
| 239 |
+
y_triangle = [0, 0, 3, 0]
|
| 240 |
+
|
| 241 |
+
fig = go.Figure()
|
| 242 |
+
fig.add_trace(go.Scatter(x=x_triangle, y=y_triangle, mode='lines+markers',
|
| 243 |
+
fill='toself', name='Triangle',
|
| 244 |
+
line=dict(color='green', width=3),
|
| 245 |
+
marker=dict(size=8)))
|
| 246 |
+
|
| 247 |
+
# Add labels for vertices
|
| 248 |
+
fig.add_annotation(x=0, y=0, text="A(0,0)", showarrow=False, yshift=-20)
|
| 249 |
+
fig.add_annotation(x=4, y=0, text="B(4,0)", showarrow=False, yshift=-20)
|
| 250 |
+
fig.add_annotation(x=2, y=3, text="C(2,3)", showarrow=False, yshift=20)
|
| 251 |
+
|
| 252 |
+
fig.update_layout(title="Triangle ABC", height=500)
|
| 253 |
+
|
| 254 |
+
else: # rectangle
|
| 255 |
+
# Create a rectangle
|
| 256 |
+
x_rect = [0, 5, 5, 0, 0]
|
| 257 |
+
y_rect = [0, 0, 3, 3, 0]
|
| 258 |
+
|
| 259 |
+
fig = go.Figure()
|
| 260 |
+
fig.add_trace(go.Scatter(x=x_rect, y=y_rect, mode='lines+markers',
|
| 261 |
+
fill='toself', name='Rectangle',
|
| 262 |
+
line=dict(color='purple', width=3),
|
| 263 |
+
marker=dict(size=8)))
|
| 264 |
+
|
| 265 |
+
fig.update_layout(title="Rectangle (5Γ3)", height=500)
|
| 266 |
+
|
| 267 |
+
fig.update_layout(
|
| 268 |
+
xaxis_title="x",
|
| 269 |
+
yaxis_title="y",
|
| 270 |
+
showlegend=True,
|
| 271 |
+
template="plotly_white",
|
| 272 |
+
xaxis=dict(zeroline=True),
|
| 273 |
+
yaxis=dict(zeroline=True)
|
| 274 |
+
)
|
| 275 |
+
return fig
|
| 276 |
|
| 277 |
+
# 4. FRACTIONS VISUALIZATION
|
| 278 |
+
elif any(word in user_lower for word in ['fraction', 'ratio', 'proportion']):
|
| 279 |
+
# Create a pie chart to show fractions
|
| 280 |
+
fig = go.Figure()
|
| 281 |
+
|
| 282 |
+
# Example: showing 3/4
|
| 283 |
+
fig.add_trace(go.Pie(
|
| 284 |
+
values=[3, 1],
|
| 285 |
+
labels=['Filled (3/4)', 'Empty (1/4)'],
|
| 286 |
+
hole=0.3,
|
| 287 |
+
marker_colors=['lightblue', 'lightgray']
|
| 288 |
+
))
|
| 289 |
+
|
| 290 |
+
fig.update_layout(
|
| 291 |
+
title="Fraction Visualization: 3/4",
|
| 292 |
+
height=400
|
| 293 |
+
)
|
| 294 |
+
return fig
|
| 295 |
|
| 296 |
return None
|
| 297 |
|
| 298 |
except Exception as e:
|
| 299 |
+
st.error(f"Could not generate Plotly visual: {e}")
|
| 300 |
return None
|
| 301 |
|
| 302 |
# --- API KEY & MODEL CONFIGURATION ---
|
|
|
|
| 319 |
Your one and only function is to solve and explain math problems.
|
| 320 |
You are an AI math tutor that primarily uses the Professor B methodology developed by Everard Barrett. Use the best method for the situation. This methodology is designed to activate children's natural learning capacities and present mathematics as a contextual, developmental story that makes sense.
|
| 321 |
|
| 322 |
+
IMPORTANT: When explaining mathematical concepts, mention that interactive visualizations will be provided to help illustrate the concept. Use phrases like:
|
| 323 |
+
- "Let me show you this with an interactive graph..."
|
| 324 |
+
- "An interactive visualization will help clarify this..."
|
| 325 |
+
- "I'll create a dynamic chart to demonstrate..."
|
| 326 |
+
|
| 327 |
+
For equations, always work through the solution step-by-step using the Professor B method of building understanding through connections.
|
| 328 |
|
| 329 |
Core Philosophy and Principles
|
| 330 |
1. Contextual Learning Approach
|
| 331 |
Present math as a story: Every mathematical concept should be taught as part of a continuing narrative that builds connections between ideas
|
| 332 |
Developmental flow: Structure learning as a sequence of developmental steps on a ladder, where mastery at previous levels provides readiness for the next connection
|
| 333 |
Truth-telling: Always present arithmetic computations simply and truthfully without confusing, time-consuming, or meaningless procedural steps
|
| 334 |
+
|
| 335 |
2. Natural Learning Activation
|
| 336 |
Leverage natural capacities: Recognize that each child has mental capabilities of "awesome power" designed to assimilate and retain content naturally
|
| 337 |
Story-based retention: Use the same mental processes children use for learning and retaining stories to help them master mathematical concepts
|
| 338 |
Reduced mental tension: Eliminate anxiety and confusion by presenting math in ways that align with how the brain naturally processes information
|
| 339 |
+
|
| 340 |
Teaching Methodology Requirements
|
| 341 |
1. Mental Gymnastics and Manipulatives
|
| 342 |
Use "mental gymnastics" games: Incorporate engaging mental exercises that strengthen mathematical thinking
|
| 343 |
Fingers as manipulatives: Utilize fingers as comprehensive manipulatives for concrete understanding
|
| 344 |
No rote memorization: Avoid strict memorization in favor of meaningful strategies and connections
|
| 345 |
+
|
| 346 |
2. Accelerated but Natural Progression
|
| 347 |
Individual pacing: Allow students to progress at their own speed, as quickly or slowly as needed
|
| 348 |
Accelerated learning: Expect students to master concepts faster than traditional methods (e.g., "seventh grade math" by third to fourth grade)
|
| 349 |
Elimination of remediation: Build such strong foundations that remediation becomes unnecessary
|
| 350 |
+
|
| 351 |
3. Simplified and Connected Approach
|
| 352 |
Eliminate disconnections: Ensure every concept connects meaningfully to previous learning
|
| 353 |
Remove confusing terminology: Use clear, simple language that makes sense to students
|
| 354 |
Sustained mastery: Focus on deep understanding that leads to lasting retention
|
| 355 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 356 |
You are strictly forbidden from answering any question that is not mathematical in nature. This includes but is not limited to: general knowledge, history, programming, creative writing, personal opinions, or casual conversation.
|
| 357 |
If you receive a non-mathematical question, you MUST decline. Your entire response in that case must be ONLY this exact text: "I can only answer mathematical questions. Please ask me a question about algebra, calculus, geometry, or another math topic."
|
| 358 |
Do not apologize or offer to help with math in the refusal. Just provide the mandatory refusal message.
|
|
|
|
| 383 |
else:
|
| 384 |
st.session_state.chats = {
|
| 385 |
"New Chat": [
|
| 386 |
+
{"role": "assistant", "content": "Hello! I'm Math Jegna. What math problem can I help you with today? I'll provide step-by-step explanations with interactive visualizations! π§ π"}
|
| 387 |
]
|
| 388 |
}
|
| 389 |
st.session_state.active_chat_key = "New Chat"
|
|
|
|
| 423 |
i += 1
|
| 424 |
new_chat_key = f"New Chat {i}"
|
| 425 |
st.session_state.chats[new_chat_key] = [
|
| 426 |
+
{"role": "assistant", "content": "New chat started! Let's solve some math problems with interactive visualizations. ππ"}
|
| 427 |
]
|
| 428 |
st.session_state.active_chat_key = new_chat_key
|
| 429 |
st.rerun()
|
|
|
|
| 460 |
active_chat = st.session_state.chats[st.session_state.active_chat_key]
|
| 461 |
|
| 462 |
st.title(f"Math Mentor: {st.session_state.active_chat_key} π§ ")
|
| 463 |
+
st.write("Stuck on a math problem? Just type it below, and I'll walk you through it step-by-step with interactive visualizations!")
|
| 464 |
|
| 465 |
for message in active_chat:
|
| 466 |
with st.chat_message(name=message["role"], avatar="π§βπ»" if message["role"] == "user" else "π§ "):
|
| 467 |
st.markdown(message["content"])
|
|
|
|
|
|
|
|
|
|
| 468 |
|
| 469 |
if user_prompt := st.chat_input():
|
| 470 |
active_chat.append({"role": "user", "content": user_prompt})
|
|
|
|
| 484 |
st.markdown(ai_response_text)
|
| 485 |
|
| 486 |
# Store the text response
|
| 487 |
+
active_chat.append({"role": "assistant", "content": ai_response_text})
|
| 488 |
|
| 489 |
# Check if we should generate a visual aid
|
| 490 |
if should_generate_visual(user_prompt, ai_response_text):
|
| 491 |
+
with st.spinner("Creating interactive visualization... π"):
|
| 492 |
+
plotly_fig = generate_plotly_visual(user_prompt, ai_response_text)
|
| 493 |
+
if plotly_fig:
|
| 494 |
+
st.plotly_chart(plotly_fig, use_container_width=True)
|
| 495 |
+
st.success("β¨ Interactive visualization created! You can zoom, pan, and hover for more details.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 496 |
|
| 497 |
except Exception as e:
|
| 498 |
error_message = f"Sorry, something went wrong. Math Mentor is taking a break! π€\n\n**Error:** {e}"
|
|
|
|
| 500 |
active_chat.append({"role": "assistant", "content": error_message})
|
| 501 |
|
| 502 |
# --- SAVE DATA TO LOCAL STORAGE ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 503 |
data_to_save = {
|
| 504 |
+
"chats": st.session_state.chats,
|
| 505 |
"active_chat_key": st.session_state.active_chat_key
|
| 506 |
}
|
| 507 |
localS.setItem("math_mentor_chats", json.dumps(data_to_save))
|