NSamson1 commited on
Commit
d5683db
ยท
verified ยท
1 Parent(s): b52ba89

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +138 -232
src/streamlit_app.py CHANGED
@@ -1,273 +1,179 @@
 
1
  import streamlit as st
2
  import pandas as pd
3
  import os
4
  import zipfile
5
  from PIL import Image
 
6
  import time
7
- import io
8
- import atexit
9
- import shutil
10
 
11
- # -------------------- PAGE CONFIG --------------------
12
- st.set_page_config(
13
- page_title="Smart Math Teacher",
14
- page_icon="๐Ÿงฎ",
15
- layout="wide",
16
- initial_sidebar_state="expanded"
17
- )
18
 
19
- # -------------------- CUSTOM THEME --------------------
20
  st.markdown("""
21
  <style>
22
- .main-title {
23
- font-size: 3rem;
24
- font-weight: 700;
25
- color: #FF4B4B;
26
- text-align: center;
27
- margin-bottom: 1rem;
28
- text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
29
- }
30
- .question-box {
31
- background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
32
- padding: 2rem;
33
- border-radius: 20px;
34
- box-shadow: 0 10px 20px rgba(0,0,0,0.1);
35
- margin: 1rem 0;
36
- font-size: 1.2rem;
37
- border-left: 5px solid #FF4B4B;
38
- }
39
- .hint-box {
40
- background-color: #fff3cd;
41
- border-left: 5px solid #ffc107;
42
- padding: 1rem;
43
  border-radius: 10px;
44
- margin: 1rem 0;
45
- }
46
- .stButton > button {
47
- transition: all 0.3s ease;
48
- }
49
- .stButton > button:hover {
50
- transform: translateY(-2px);
51
- box-shadow: 0 5px 15px rgba(0,0,0,0.2);
52
  }
53
  </style>
54
  """, unsafe_allow_html=True)
55
 
56
- # -------------------- SESSION STATE INIT --------------------
57
- if 'score' not in st.session_state:
58
- st.session_state.score = 0
59
- if 'total_attempted' not in st.session_state:
60
- st.session_state.total_attempted = 0
61
- if 'hint_used' not in st.session_state:
62
- st.session_state.hint_used = False
63
 
64
- # -------------------- DATA LOADING WITH CACHE --------------------
65
- @st.cache_data
66
- def load_age_groups():
67
- return {
68
- "4-6 Years (Beginner)": {
69
- "dataset": "src/Datase_of_4-6_Age_Group.xlsx",
70
- "zip_file": "src/Image_for_group_4-6.zip"
71
- },
72
- "7-9 Years (Intermediate)": {
73
- "dataset": "src/Datase_of_7-9_Age_Group.xlsx",
74
- "zip_file": "src/Image_for_group_7-9.zip"
75
- },
76
- "13-15 Years (Advanced)": {
77
- "dataset": "src/Datase_of_13-15_Age_Group.xlsx",
78
- "zip_file": "src/Image_for_group_13-15.zip"
79
- },
80
- }
81
-
82
- @st.cache_data
83
- def load_dataset(dataset_path):
84
- return pd.read_excel(dataset_path)
85
-
86
- age_groups = load_age_groups()
87
-
88
- # -------------------- SIDEBAR --------------------
89
- with st.sidebar:
90
- st.image("https://img.icons8.com/fluency/96/math.png", width=80)
91
- st.title("๐Ÿงฎ Smart Math Teacher")
92
- st.markdown("---")
93
 
94
- # Age group selection
95
- selected_age = st.selectbox(
96
- "๐Ÿ“š Select Age Group",
97
- options=list(age_groups.keys()),
98
- index=0
99
- )
100
 
101
- # Load dataset for selected age group
102
- group_info = age_groups[selected_age]
103
- dataset_path = group_info["dataset"]
104
- zip_path = group_info["zip_file"]
 
 
105
 
106
- if not os.path.exists(dataset_path):
107
- st.error(f"Dataset not found: {dataset_path}")
108
- st.stop()
109
 
110
- df = load_dataset(dataset_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  df['category'] = df['category'].astype(str).str.strip()
112
- categories = sorted(df['category'].dropna().unique())
113
-
114
- selected_category = st.selectbox(
115
- "๐Ÿ“– Choose Category",
116
- options=categories,
117
- key="category_select"
118
- )
119
-
120
- st.markdown("---")
121
-
122
- # Stats
123
- st.subheader("๐Ÿ“Š Your Stats")
124
- col1, col2 = st.columns(2)
125
- with col1:
126
- st.metric("Score", st.session_state.score)
127
- with col2:
128
- st.metric("Attempted", st.session_state.total_attempted)
129
 
130
- if st.session_state.total_attempted > 0:
131
- accuracy = (st.session_state.score / st.session_state.total_attempted) * 100
132
- st.progress(accuracy/100, text=f"Accuracy: {accuracy:.1f}%")
133
 
134
- st.markdown("---")
135
- st.caption("Made with โค๏ธ by Your Math Teacher")
136
-
137
- # -------------------- MAIN CONTENT --------------------
138
- st.markdown("<h1 class='main-title'>โœจ Smart Math Teacher โœจ</h1>", unsafe_allow_html=True)
139
-
140
- # Guide section (collapsible)
141
- with st.expander("๐Ÿ“˜ How to Use This App", expanded=False):
142
- st.markdown("""
143
- 1. **Choose your age group** from the sidebar.
144
- 2. **Pick a math category** you want to practice.
145
- 3. **Read the question** and type your answer.
146
- 4. **Submit** to check your answer.
147
- 5. Use **Hint** if you need help.
148
- 6. Track your progress in the sidebar stats!
149
- """)
150
-
151
- # Filter questions by selected category
152
- subset_df = df[df['category'] == selected_category].reset_index(drop=True)
153
-
154
- # Initialize question index in session state if needed
155
- if 'question_index' not in st.session_state or st.session_state.get('last_category') != selected_category:
156
  st.session_state.question_index = 0
157
- st.session_state.last_category = selected_category
158
- st.session_state.hint_used = False
 
159
 
160
- # Function to load image from zip on demand
161
- @st.cache_data(show_spinner=False)
162
- def load_image_from_zip(zip_path, image_name):
163
- try:
164
- with zipfile.ZipFile(zip_path, 'r') as zf:
165
- # Find the file in the zip (case-insensitive)
166
- for filename in zf.namelist():
167
- if filename.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp')):
168
- base = os.path.splitext(os.path.basename(filename))[0]
169
- if base.lower() == image_name.lower():
170
- with zf.open(filename) as f:
171
- img_data = f.read()
172
- img = Image.open(io.BytesIO(img_data))
173
- return img
174
- except Exception as e:
175
- st.warning(f"Error loading image: {e}")
176
- return None
177
 
178
  if not subset_df.empty and st.session_state.question_index < len(subset_df):
179
  question = subset_df.iloc[st.session_state.question_index]
 
 
180
 
181
- # Progress bar
182
- progress = (st.session_state.question_index / len(subset_df))
183
- st.progress(progress, text=f"Question {st.session_state.question_index + 1} of {len(subset_df)}")
184
-
185
- # Question box
186
- st.markdown(f"""
187
- <div class='question-box'>
188
- <h3>โ“ Question {st.session_state.question_index + 1}</h3>
189
- <p>{question['problem']}</p>
190
- </div>
191
- """, unsafe_allow_html=True)
192
 
193
- # Display image if exists
194
  if pd.notna(question.get('image')):
195
  image_name = str(question['image']).strip()
196
- img = load_image_from_zip(zip_path, image_name)
197
- if img:
198
- st.image(img, use_column_width=True, caption="Question Image")
199
- else:
200
- st.info("๐Ÿ“ท No image for this question.")
201
-
202
- # Answer input
203
- user_answer = st.text_input("โœ๏ธ Your Answer:", key="answer_input", placeholder="Type your answer here...")
204
-
205
- # Buttons layout
206
- col1, col2, col3, col4 = st.columns([1,1,1,1])
207
- with col1:
208
- submitted = st.button("โœ… Submit", use_container_width=True)
209
- with col2:
210
- hint_clicked = st.button("๐Ÿ’ก Hint", use_container_width=True)
211
- with col3:
212
- skip_clicked = st.button("โญ๏ธ Skip", use_container_width=True)
213
- with col4:
214
- if st.button("๐Ÿ”„ Reset Progress", use_container_width=True):
215
- st.session_state.question_index = 0
216
- st.session_state.score = 0
217
- st.session_state.total_attempted = 0
218
- st.rerun()
219
-
220
- # Hint logic
221
- if hint_clicked:
222
- st.session_state.hint_used = True
223
- # Check if dataset has hints column, else provide generic
224
- if 'hint' in question and pd.notna(question['hint']):
225
- hint_text = question['hint']
226
- else:
227
- hint_text = "Think step by step. Try to break the problem into smaller parts."
228
- st.markdown(f"<div class='hint-box'>๐Ÿ’ก <b>Hint:</b> {hint_text}</div>", unsafe_allow_html=True)
229
-
230
- # Submission logic
231
- if submitted:
232
- st.session_state.total_attempted += 1
233
- correct_answer = str(question['answer']).strip().lower()
234
- user_ans = str(user_answer).strip().lower()
235
-
236
- if user_ans == correct_answer:
237
- st.success("๐ŸŽ‰ Correct! Great job!")
238
  st.balloons()
239
- # Award points
240
- points = 10 if not st.session_state.hint_used else 5
241
- st.session_state.score += points
242
- # Move to next question after a short delay
243
  time.sleep(2)
244
  st.session_state.question_index += 1
245
- st.session_state.hint_used = False
 
246
  st.rerun()
247
  else:
248
- st.error("โŒ Not quite right. Try again or use a hint.")
249
-
250
- if skip_clicked:
 
 
 
 
 
 
 
 
 
 
251
  st.session_state.question_index += 1
252
- st.session_state.hint_used = False
 
253
  st.rerun()
254
-
255
- # Show answer and steps if user requests (optional)
256
- with st.expander("๐Ÿ” Show Answer & Steps"):
257
- st.markdown(f"**Correct Answer:** {question['answer']}")
258
- if 'steps' in question and pd.notna(question['steps']):
259
- st.markdown(f"**Step-by-Step:**\n{question['steps']}")
260
- else:
261
- st.info("No steps provided for this question.")
262
-
263
  else:
264
- # No more questions
265
- st.success("๐ŸŽฏ You've completed all questions in this category!")
266
- st.balloons()
267
- if st.button("๐Ÿ”„ Start Over in This Category"):
268
- st.session_state.question_index = 0
269
- st.session_state.score = 0
270
- st.session_state.total_attempted = 0
271
- st.rerun()
272
 
273
- # No cleanup needed because we never extracted files
 
 
 
 
 
 
 
 
1
+ import altair as alt
2
  import streamlit as st
3
  import pandas as pd
4
  import os
5
  import zipfile
6
  from PIL import Image
7
+ import sympy as sp
8
  import time
9
+ import tempfile
 
 
10
 
11
+ # Page config
12
+ st.set_page_config(page_title="๐ŸŽ“ Smart Math Teacher", layout="centered")
 
 
 
 
 
13
 
14
+ # Custom CSS
15
  st.markdown("""
16
  <style>
17
+ .fun-title { font-size: 40px; color: #ff3399; text-align: center; font-family: 'Comic Sans MS', cursive; }
18
+ .question-box { border: 4px dotted #ffcc00; padding: 20px; border-radius: 20px; background-color: #fff7e6; font-size: 20px; }
19
+ .stButton > button { font-size: 18px; background-color: #00cc99; color: white; border-radius: 10px; padding: 10px; }
20
+ .stTextInput > div > input { font-size: 18px; }
21
+
22
+ /* Guide styling */
23
+ .guide-box {
24
+ background-color: #e8f5e8;
25
+ padding: 15px;
 
 
 
 
 
 
 
 
 
 
 
 
26
  border-radius: 10px;
27
+ border: 2px solid #4CAF50;
28
+ margin: 10px 0;
 
 
 
 
 
 
29
  }
30
  </style>
31
  """, unsafe_allow_html=True)
32
 
33
+ # Welcome title
34
+ st.markdown("<div class='fun-title'>๐Ÿง โœจ Welcome to the Smart Math Teacher! โœจ๐Ÿง </div>", unsafe_allow_html=True)
 
 
 
 
 
35
 
36
+ # USER GUIDE - Always visible at the top
37
+ st.markdown("""
38
+ <div class="guide-box">
39
+ <h3>๐Ÿ“– How to Use This App:</h3>
40
+
41
+ **1. Select Your Age Group** - Choose your learning level (4-6, 7-9, or 13-15 years)<br>
42
+ **2. Choose Math Category** - Pick what type of math to practice<br>
43
+ **3. Solve Questions** - Read each question and type your answer<br>
44
+ **4. Get Help** - Use hints or skip if needed<br>
45
+ **5. Learn** - See correct answers and step-by-step solutions
46
+ </div>
47
+ """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
+ # Initialize session state for temp directory
50
+ if 'temp_dir' not in st.session_state:
51
+ st.session_state.temp_dir = tempfile.mkdtemp()
 
 
 
52
 
53
+ # Age group setup
54
+ age_groups = {
55
+ "4-6 Age Group": {"dataset": "src/Datase_of_4-6_Age_Group.xlsx", "zip_file": "src/Image_for_group_4-6.zip", "image_folder": "Image_for_group_4-6"},
56
+ "7-9 Age Group": {"dataset": "src/Datase_of_7-9_Age_Group.xlsx", "zip_file": "src/Image_for_group_7-9.zip", "image_folder": "Image_for_group_7-9"},
57
+ "13-15 Age Group": {"dataset": "src/Datase_of_13-15_Age_Group.xlsx", "zip_file": "src/Image_for_group_13-15.zip", "image_folder": "Image_for_group_13-15"},
58
+ }
59
 
60
+ selected_age_group = st.selectbox("๐Ÿง’ Select your Age Group:", list(age_groups.keys()))
 
 
61
 
62
+ # Initialize session
63
+ if "session_initialized" not in st.session_state or st.session_state.age_group != selected_age_group:
64
+ st.session_state.age_group = selected_age_group
65
+ st.session_state.category = None
66
+ st.session_state.question_index = 0
67
+ st.session_state.show_answer = False
68
+ st.session_state.show_steps = False
69
+ st.session_state.session_initialized = True
70
+
71
+ # Load dataset
72
+ group_info = age_groups[selected_age_group]
73
+ dataset_path = group_info["dataset"]
74
+ zip_path = group_info["zip_file"]
75
+ image_folder = group_info["image_folder"]
76
+
77
+ # Create image folder in temp directory
78
+ temp_image_folder = os.path.join(st.session_state.temp_dir, image_folder)
79
+ os.makedirs(temp_image_folder, exist_ok=True)
80
+
81
+ # Extract images if zip exists
82
+ try:
83
+ if os.path.exists(zip_path):
84
+ with zipfile.ZipFile(zip_path, "r") as zip_ref:
85
+ zip_ref.extractall(temp_image_folder)
86
+ except Exception as e:
87
+ st.warning(f"Error extracting images: {e}")
88
+
89
+ if not os.path.exists(dataset_path):
90
+ st.error(f"Dataset not found: {dataset_path}")
91
+ st.stop()
92
+
93
+ try:
94
+ df = pd.read_excel(dataset_path)
95
  df['category'] = df['category'].astype(str).str.strip()
96
+ except Exception as e:
97
+ st.error(f"Error loading dataset: {e}")
98
+ st.stop()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
 
100
+ # Category selection
101
+ categories = sorted(df['category'].dropna().unique())
102
+ selected_category = st.selectbox("๐Ÿ“š Choose a Math Category:", options=categories)
103
 
104
+ # Update session if category changes
105
+ if st.session_state.category != selected_category:
106
+ st.session_state.category = selected_category
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  st.session_state.question_index = 0
108
+ st.session_state.show_answer = False
109
+ st.session_state.show_steps = False
110
+ st.rerun()
111
 
112
+ # Filter questions by selected category only
113
+ subset_df = df[df['category'] == selected_category].reset_index(drop=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
  if not subset_df.empty and st.session_state.question_index < len(subset_df):
116
  question = subset_df.iloc[st.session_state.question_index]
117
+ progress = int((st.session_state.question_index / len(subset_df)) * 100)
118
+ st.progress(progress)
119
 
120
+ st.markdown(f"<div class='question-box'>๐Ÿ“˜ <b>Question {st.session_state.question_index + 1}:</b><br><br>{question['problem']}</div>", unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
121
 
122
+ # Display image with error handling
123
  if pd.notna(question.get('image')):
124
  image_name = str(question['image']).strip()
125
+ image_found = False
126
+ for root, _, files in os.walk(temp_image_folder):
127
+ for file in files:
128
+ if file.lower().startswith(image_name.lower()) or os.path.splitext(file)[0].lower() == image_name.lower():
129
+ try:
130
+ st.image(Image.open(os.path.join(root, file)), use_column_width=True)
131
+ image_found = True
132
+ break
133
+ except:
134
+ pass
135
+ if not image_found:
136
+ st.warning("โŒ Image not found.")
137
+
138
+ user_ans = st.text_input("๐Ÿ“ Your Answer:", key=f"ans_{st.session_state.question_index}")
139
+
140
+ if st.button("โœ… Submit Answer"):
141
+ if str(user_ans).strip().lower() == str(question['answer']).strip().lower():
142
+ st.success("๐ŸŽ‰ Correct! Well done!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  st.balloons()
 
 
 
 
144
  time.sleep(2)
145
  st.session_state.question_index += 1
146
+ st.session_state.show_answer = False
147
+ st.session_state.show_steps = False
148
  st.rerun()
149
  else:
150
+ st.error("โŒ Try again or view the correct answer below.")
151
+ st.session_state.show_answer = True
152
+ st.session_state.show_steps = False
153
+
154
+ if st.session_state.show_answer:
155
+ st.info(f"โœ… Correct Answer: **{question['answer']}**")
156
+ if selected_age_group in ["7-9 Age Group", "13-15 Age Group"]:
157
+ if st.button("๐Ÿ” Show Steps"):
158
+ st.session_state.show_steps = True
159
+ if st.session_state.show_steps and pd.notna(question.get("steps", None)):
160
+ st.success(f"### ๐Ÿช„ Steps:\n{question['steps']}")
161
+
162
+ if st.button("โญ๏ธ Skip"):
163
  st.session_state.question_index += 1
164
+ st.session_state.show_answer = False
165
+ st.session_state.show_steps = False
166
  st.rerun()
167
+ elif subset_df.empty:
168
+ st.warning("โš ๏ธ No questions available in this category. Try another one.")
 
 
 
 
 
 
 
169
  else:
170
+ st.success("๐Ÿ You've completed all questions in this category!")
 
 
 
 
 
 
 
171
 
172
+ # Cleanup function
173
+ def cleanup():
174
+ import shutil
175
+ if 'temp_dir' in st.session_state and os.path.exists(st.session_state.temp_dir):
176
+ shutil.rmtree(st.session_state.temp_dir)
177
+
178
+ import atexit
179
+ atexit.register(cleanup)