DataMine commited on
Commit
c495b19
ยท
verified ยท
1 Parent(s): 35c48b2

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +1447 -38
src/streamlit_app.py CHANGED
@@ -1,40 +1,1449 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
  import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
 
 
 
1
  import streamlit as st
2
+ import os
3
+ from groq import Groq
4
+ import json
5
+ import re
6
+ from typing import List, Dict, Optional
7
+ import time
8
+ import plotly.express as px
9
+ import plotly.graph_objects as go
10
+ import pandas as pd
11
+ from datetime import datetime, timedelta
12
+ import streamlit.components.v1 as components
13
+
14
+ # Configure page
15
+ st.set_page_config(
16
+ page_title="๐Ÿงฎ MathGenius Academy",
17
+ page_icon="๐Ÿงฎ",
18
+ layout="wide",
19
+ initial_sidebar_state="expanded"
20
+ )
21
+
22
+ # Custom CSS for enhanced UI
23
+ def load_custom_css():
24
+ st.markdown("""
25
+ <style>
26
+ /* Comprehensive Streamlit branding removal */
27
+ #MainMenu {visibility: hidden !important;}
28
+ footer {visibility: hidden !important;}
29
+ header {visibility: hidden !important;}
30
+ .stDeployButton {display: none !important;}
31
+ .stDecoration {display: none !important;}
32
+ .stActionButton {display: none !important;}
33
+ [data-testid="stToolbar"] {display: none !important;}
34
+ [data-testid="stDecoration"] {display: none !important;}
35
+ [data-testid="stStatusWidget"] {display: none !important;}
36
+ [data-testid="manage-app-button"] {display: none !important;}
37
+ [data-testid="deployButton"] {display: none !important;}
38
+
39
+ /* Hide hamburger menu */
40
+ .css-14xtw13.e8zbici0 {display: none !important;}
41
+ .css-vk3wp9 {display: none !important;}
42
+ .css-1inwz65 {display: none !important;}
43
+
44
+ /* Hide footer */
45
+ .css-h5rgaw.egzxvld1 {display: none !important;}
46
+ .css-cio0dv.egzxvld1 {display: none !important;}
47
+ footer.css-164nlkn.egzxvld1 {display: none !important;}
48
+
49
+ /* Hide "Made with Streamlit" */
50
+ .viewerBadge_container__1QSob {display: none !important;}
51
+ .styles_viewerBadge__1yB5_ {display: none !important;}
52
+ .viewerBadge_link__1S137 {display: none !important;}
53
+ .viewerBadge_text__1JaDK {display: none !important;}
54
+
55
+ /* Hide deploy button and related elements */
56
+ .css-1rs6os {display: none !important;}
57
+ .css-17eq0hr {display: none !important;}
58
+ .css-1vbkxwb {display: none !important;}
59
+ .css-1dp5vir {display: none !important;}
60
+
61
+ /* Hide GitHub icon and deploy related buttons */
62
+ [title="View source on GitHub"] {display: none !important;}
63
+ [title="Deploy this app"] {display: none !important;}
64
+ .css-1avcm0n {display: none !important;}
65
+
66
+ /* Hide top padding */
67
+ #root > div:nth-child(1) > div > div > div > div > section > div {padding-top: 0rem !important;}
68
+
69
+ /* Import Google Fonts */
70
+ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&family=Nunito:wght@300;400;500;600;700&display=swap');
71
+
72
+ /* Global Styles */
73
+ .main {
74
+ font-family: 'Poppins', sans-serif;
75
+ }
76
+
77
+ /* Header Styling */
78
+ .hero-header {
79
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
80
+ padding: 2rem;
81
+ border-radius: 20px;
82
+ color: white;
83
+ text-align: center;
84
+ margin-bottom: 2rem;
85
+ box-shadow: 0 20px 40px rgba(102, 126, 234, 0.3);
86
+ position: relative;
87
+ overflow: hidden;
88
+ }
89
+
90
+ .hero-header::before {
91
+ content: '';
92
+ position: absolute;
93
+ top: -50%;
94
+ left: -50%;
95
+ width: 200%;
96
+ height: 200%;
97
+ background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%);
98
+ animation: float 6s ease-in-out infinite;
99
+ }
100
+
101
+ @keyframes float {
102
+ 0%, 100% { transform: translate(0, 0) rotate(0deg); }
103
+ 50% { transform: translate(20px, -20px) rotate(180deg); }
104
+ }
105
+
106
+ .hero-title {
107
+ font-size: 3.5rem;
108
+ font-weight: 700;
109
+ margin-bottom: 0.5rem;
110
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
111
+ position: relative;
112
+ z-index: 1;
113
+ }
114
+
115
+ .hero-subtitle {
116
+ font-size: 1.2rem;
117
+ opacity: 0.9;
118
+ margin-bottom: 1rem;
119
+ position: relative;
120
+ z-index: 1;
121
+ }
122
+
123
+ /* Card Styling */
124
+ .custom-card {
125
+ background: white;
126
+ padding: 2rem;
127
+ border-radius: 20px;
128
+ box-shadow: 0 15px 35px rgba(0,0,0,0.1);
129
+ border: 1px solid #e1e8ed;
130
+ transition: all 0.3s ease;
131
+ position: relative;
132
+ overflow: hidden;
133
+ color: #333;
134
+ }
135
+
136
+ .custom-card:hover {
137
+ transform: translateY(-10px);
138
+ box-shadow: 0 25px 50px rgba(0,0,0,0.15);
139
+ }
140
+
141
+ .custom-card::before {
142
+ content: '';
143
+ position: absolute;
144
+ top: 0;
145
+ left: 0;
146
+ width: 100%;
147
+ height: 4px;
148
+ background: linear-gradient(90deg, #667eea, #764ba2);
149
+ }
150
+
151
+ .custom-card h4 {
152
+ color: #667eea !important;
153
+ margin-bottom: 1rem;
154
+ font-weight: 600;
155
+ }
156
+
157
+ .custom-card p, .custom-card li {
158
+ color: #444 !important;
159
+ line-height: 1.6;
160
+ }
161
+
162
+ .custom-card ul {
163
+ padding-left: 1.5rem;
164
+ }
165
+
166
+ .custom-card ol {
167
+ padding-left: 1.5rem;
168
+ }
169
+
170
+ /* Question Card */
171
+ .question-card {
172
+ background: linear-gradient(145deg, #f8fafc 0%, #e2e8f0 100%);
173
+ border-radius: 20px;
174
+ padding: 2rem;
175
+ margin: 1rem 0;
176
+ border-left: 6px solid #667eea;
177
+ box-shadow: 0 10px 30px rgba(0,0,0,0.1);
178
+ transition: all 0.3s ease;
179
+ }
180
+
181
+ .question-card:hover {
182
+ transform: translateX(10px);
183
+ box-shadow: 0 15px 40px rgba(0,0,0,0.15);
184
+ }
185
+
186
+ /* Stats Cards */
187
+ .stat-card {
188
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
189
+ color: white;
190
+ padding: 1.5rem;
191
+ border-radius: 15px;
192
+ text-align: center;
193
+ box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3);
194
+ transition: all 0.3s ease;
195
+ }
196
+
197
+ .stat-card:hover {
198
+ transform: scale(1.05);
199
+ }
200
+
201
+ .stat-number {
202
+ font-size: 2.5rem;
203
+ font-weight: 700;
204
+ margin-bottom: 0.5rem;
205
+ }
206
+
207
+ .stat-label {
208
+ font-size: 0.9rem;
209
+ opacity: 0.9;
210
+ }
211
+
212
+ /* Buttons */
213
+ .custom-button {
214
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
215
+ color: white;
216
+ border: none;
217
+ padding: 0.75rem 2rem;
218
+ border-radius: 50px;
219
+ font-weight: 600;
220
+ font-size: 1rem;
221
+ cursor: pointer;
222
+ transition: all 0.3s ease;
223
+ box-shadow: 0 5px 15px rgba(102, 126, 234, 0.3);
224
+ }
225
+
226
+ .custom-button:hover {
227
+ transform: translateY(-3px);
228
+ box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
229
+ }
230
+
231
+ /* Progress Bar */
232
+ .progress-container {
233
+ background: #e2e8f0;
234
+ border-radius: 50px;
235
+ padding: 0.5rem;
236
+ margin: 1rem 0;
237
+ }
238
+
239
+ .progress-bar {
240
+ background: linear-gradient(90deg, #667eea, #764ba2);
241
+ height: 20px;
242
+ border-radius: 50px;
243
+ transition: width 1s ease;
244
+ display: flex;
245
+ align-items: center;
246
+ justify-content: center;
247
+ color: white;
248
+ font-weight: 600;
249
+ font-size: 0.8rem;
250
+ }
251
+
252
+ /* Animations */
253
+ @keyframes slideInUp {
254
+ from {
255
+ opacity: 0;
256
+ transform: translateY(30px);
257
+ }
258
+ to {
259
+ opacity: 1;
260
+ transform: translateY(0);
261
+ }
262
+ }
263
+
264
+ .slide-in-up {
265
+ animation: slideInUp 0.6s ease-out;
266
+ }
267
+
268
+ @keyframes pulse {
269
+ 0% { transform: scale(1); }
270
+ 50% { transform: scale(1.05); }
271
+ 100% { transform: scale(1); }
272
+ }
273
+
274
+ .pulse-animation {
275
+ animation: pulse 2s infinite;
276
+ }
277
+
278
+ /* Sidebar Styling */
279
+ .sidebar .sidebar-content {
280
+ background: linear-gradient(180deg, #667eea 0%, #764ba2 100%);
281
+ color: white;
282
+ }
283
+
284
+ /* Toast Notifications */
285
+ .toast {
286
+ position: fixed;
287
+ top: 20px;
288
+ right: 20px;
289
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
290
+ color: white;
291
+ padding: 1rem 2rem;
292
+ border-radius: 10px;
293
+ box-shadow: 0 10px 30px rgba(0,0,0,0.3);
294
+ z-index: 1000;
295
+ animation: slideInRight 0.5s ease;
296
+ }
297
+
298
+ @keyframes slideInRight {
299
+ from { transform: translateX(100%); }
300
+ to { transform: translateX(0); }
301
+ }
302
+
303
+ /* Mobile Responsive */
304
+ @media (max-width: 768px) {
305
+ .hero-title {
306
+ font-size: 2.5rem;
307
+ }
308
+
309
+ .custom-card {
310
+ padding: 1rem;
311
+ }
312
+
313
+ .question-card {
314
+ padding: 1rem;
315
+ }
316
+ }
317
+ body, .main, .block-container {
318
+ background: #f7f9fb !important;
319
+ }
320
+ .custom-card {
321
+ margin-bottom: 2rem;
322
+ padding: 2.5rem;
323
+ border-radius: 24px;
324
+ box-shadow: 0 8px 32px rgba(102, 126, 234, 0.08);
325
+ }
326
+ .question-card {
327
+ background: #fff;
328
+ border-radius: 20px;
329
+ box-shadow: 0 4px 24px rgba(102, 126, 234, 0.10);
330
+ margin-bottom: 2rem;
331
+ padding: 2rem 2.5rem;
332
+ }
333
+ .question-card:hover {
334
+ box-shadow: 0 8px 32px rgba(102, 126, 234, 0.15);
335
+ }
336
+ .question-card .stRadio > div {
337
+ gap: 1.5rem;
338
+ }
339
+ .stRadio label {
340
+ background: #f0f4fa;
341
+ border-radius: 16px;
342
+ padding: 0.75rem 1.5rem;
343
+ margin-bottom: 0.5rem;
344
+ font-size: 1.1rem;
345
+ transition: background 0.2s, color 0.2s;
346
+ cursor: pointer;
347
+ }
348
+ .stRadio label:hover {
349
+ background: #e3e9f7;
350
+ color: #667eea;
351
+ }
352
+ .stRadio input:checked + label {
353
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
354
+ color: #fff;
355
+ }
356
+ .stButton > button {
357
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
358
+ color: #fff;
359
+ border-radius: 30px;
360
+ font-weight: 600;
361
+ font-size: 1.1rem;
362
+ padding: 0.75rem 2.5rem;
363
+ margin: 0.5rem 0;
364
+ box-shadow: 0 4px 16px rgba(102, 126, 234, 0.10);
365
+ transition: background 0.2s, box-shadow 0.2s;
366
+ }
367
+ .stButton > button:hover {
368
+ background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
369
+ box-shadow: 0 8px 32px rgba(102, 126, 234, 0.15);
370
+ }
371
+ .stMarkdown h2, .stMarkdown h3, .stMarkdown h4 {
372
+ font-weight: 700;
373
+ margin-top: 2rem;
374
+ margin-bottom: 1rem;
375
+ color: #667eea;
376
+ }
377
+ .stMarkdown hr {
378
+ border: none;
379
+ border-top: 2px solid #e1e8ed;
380
+ margin: 2rem 0;
381
+ }
382
+ .progress-container {
383
+ margin-bottom: 1.5rem;
384
+ }
385
+ </style>
386
+ """, unsafe_allow_html=True)
387
+
388
+ class MathOlympiadExam:
389
+ def __init__(self):
390
+ self.client = self._initialize_groq_client()
391
+ self.grade_levels = {
392
+ 1: {"name": "Grade 1 (Ages 6-7)", "emoji": "๐ŸŒฑ", "color": "#FF6B6B"},
393
+ 2: {"name": "Grade 2 (Ages 7-8)", "emoji": "๐ŸŒฟ", "color": "#4ECDC4"},
394
+ 3: {"name": "Grade 3 (Ages 8-9)", "emoji": "๐Ÿƒ", "color": "#45B7D1"},
395
+ 4: {"name": "Grade 4 (Ages 9-10)", "emoji": "๐ŸŒณ", "color": "#96CEB4"},
396
+ 5: {"name": "Grade 5 (Ages 10-11)", "emoji": "๐ŸŽฏ", "color": "#FECA57"},
397
+ 6: {"name": "Grade 6 (Ages 11-12)", "emoji": "๐Ÿš€", "color": "#FF9FF3"},
398
+ 7: {"name": "Grade 7 (Ages 12-13)", "emoji": "โญ", "color": "#54A0FF"},
399
+ 8: {"name": "Grade 8 (Ages 13-14)", "emoji": "๐Ÿ’Ž", "color": "#5F27CD"},
400
+ 9: {"name": "Grade 9 (Ages 14-15)", "emoji": "๐Ÿ†", "color": "#00D2D3"},
401
+ 10: {"name": "Grade 10 (Ages 15-16)", "emoji": "๐Ÿ‘‘", "color": "#FF6348"}
402
+ }
403
+
404
+ def _initialize_groq_client(self) -> Optional[Groq]:
405
+ """Initialize Groq client with API key"""
406
+ try:
407
+ # Use Streamlit secrets for secure API key management
408
+ api_key = st.secrets["GROQ_API_KEY"]
409
+ if not api_key:
410
+ st.error("โš ๏ธ GROQ_API_KEY not found in secrets!")
411
+ return None
412
+ return Groq(api_key=api_key)
413
+ except Exception as e:
414
+ st.error(f"Failed to initialize Groq client: {e}")
415
+ return None
416
+
417
+ def generate_questions(self, grade: int, num_questions: int, difficulty: str = "medium") -> List[Dict]:
418
+ """Generate math olympiad questions with enhanced difficulty options"""
419
+ if not self.client:
420
+ return []
421
+
422
+ try:
423
+ difficulty_map = {
424
+ 1: "very basic arithmetic, counting 1-20, simple shapes recognition, basic patterns",
425
+ 2: "addition and subtraction within 100, simple word problems, basic time and money",
426
+ 3: "multiplication tables up to 10, basic division, simple fractions, pattern recognition",
427
+ 4: "advanced multiplication and division, fractions, basic decimals, area and perimeter",
428
+ 5: "advanced arithmetic, introduction to algebra, geometry, data interpretation",
429
+ 6: "pre-algebra, ratios and proportions, percentages, coordinate geometry, statistics",
430
+ 7: "algebra fundamentals, advanced geometry, probability, scientific notation",
431
+ 8: "linear equations, quadratic basics, trigonometry introduction, advanced geometry",
432
+ 9: "advanced algebra, geometry proofs, probability and statistics, trigonometry",
433
+ 10: "pre-calculus, advanced trigonometry, complex numbers, advanced problem solving"
434
+ }
435
+
436
+ difficulty_modifiers = {
437
+ "easy": "Make questions slightly easier than typical olympiad level, focusing on fundamental concepts",
438
+ "medium": "Standard olympiad difficulty with moderate complexity",
439
+ "hard": "Advanced olympiad level with complex multi-step problems"
440
+ }
441
+
442
+ topics = difficulty_map.get(grade, "general math concepts")
443
+ modifier = difficulty_modifiers.get(difficulty, "")
444
+
445
+ prompt = f"""Generate exactly {num_questions} Math Olympiad-style multiple choice questions for Grade {grade} students.
446
+
447
+ Topics focus: {topics}
448
+ Difficulty: {modifier}
449
+
450
+ Format each question EXACTLY as follows:
451
+ **Question X:** [Question text here]
452
+ A) [Option A]
453
+ B) [Option B]
454
+ C) [Option C]
455
+ D) [Option D]
456
+ **Correct Answer:** [Letter only - A, B, C, or D]
457
+ **Explanation:** [Clear step-by-step solution]
458
+ **Hint:** [Helpful hint for students]
459
+
460
+ Make questions engaging and educational. Include varied problem types: word problems, visual problems, logical reasoning, and computational challenges."""
461
+
462
+ response = self.client.chat.completions.create(
463
+ model="llama-3.3-70b-versatile",
464
+ messages=[
465
+ {"role": "system", "content": "You are an expert Math Olympiad coach creating engaging, educational questions."},
466
+ {"role": "user", "content": prompt}
467
+ ],
468
+ temperature=0.7,
469
+ max_tokens=3000
470
+ )
471
+
472
+ return self._parse_questions(response.choices[0].message.content)
473
+
474
+ except Exception as e:
475
+ st.error(f"Failed to generate questions: {e}")
476
+ return []
477
+
478
+ def _parse_questions(self, content: str) -> List[Dict]:
479
+ """Enhanced question parsing with hints"""
480
+ questions = []
481
+ question_blocks = re.split(r'\*\*Question \d+:\*\*', content)[1:]
482
+
483
+ for i, block in enumerate(question_blocks, 1):
484
+ try:
485
+ lines = [line.strip() for line in block.strip().split('\n') if line.strip()]
486
+
487
+ if len(lines) < 6:
488
+ continue
489
+
490
+ question_text = lines[0]
491
+ options = []
492
+ correct_answer = None
493
+ explanation = ""
494
+ hint = ""
495
+
496
+ for line in lines[1:]:
497
+ if line.startswith(('A)', 'B)', 'C)', 'D)')):
498
+ options.append(line)
499
+ elif line.startswith('**Correct Answer:**'):
500
+ correct_answer = line.replace('**Correct Answer:**', '').strip()
501
+ elif line.startswith('**Explanation:**'):
502
+ explanation = line.replace('**Explanation:**', '').strip()
503
+ elif line.startswith('**Hint:**'):
504
+ hint = line.replace('**Hint:**', '').strip()
505
+
506
+ if len(options) == 4 and correct_answer:
507
+ questions.append({
508
+ 'question_number': i,
509
+ 'question_text': question_text,
510
+ 'options': options,
511
+ 'correct_answer': correct_answer,
512
+ 'explanation': explanation,
513
+ 'hint': hint,
514
+ 'user_answer': None,
515
+ 'time_taken': 0,
516
+ 'difficulty': self._estimate_difficulty(question_text)
517
+ })
518
+
519
+ except Exception as e:
520
+ st.warning(f"Error parsing question {i}: {e}")
521
+ continue
522
+
523
+ return questions
524
+
525
+ def _estimate_difficulty(self, question_text: str) -> str:
526
+ """Estimate question difficulty based on content"""
527
+ hard_keywords = ['prove', 'complex', 'advanced', 'multiple steps', 'system of']
528
+ easy_keywords = ['basic', 'simple', 'find', 'calculate', 'what is']
529
+
530
+ text_lower = question_text.lower()
531
+
532
+ if any(keyword in text_lower for keyword in hard_keywords):
533
+ return "Hard"
534
+ elif any(keyword in text_lower for keyword in easy_keywords):
535
+ return "Easy"
536
+ else:
537
+ return "Medium"
538
+
539
+ # Initialize session state
540
+ def initialize_session_state():
541
+ if 'questions' not in st.session_state:
542
+ st.session_state.questions = []
543
+ if 'exam_completed' not in st.session_state:
544
+ st.session_state.exam_completed = False
545
+ if 'grade_selected' not in st.session_state:
546
+ st.session_state.grade_selected = None
547
+ if 'exam_history' not in st.session_state:
548
+ st.session_state.exam_history = []
549
+ if 'current_question' not in st.session_state:
550
+ st.session_state.current_question = 0
551
+ if 'exam_mode' not in st.session_state:
552
+ st.session_state.exam_mode = 'practice'
553
+ if 'start_time' not in st.session_state:
554
+ st.session_state.start_time = None
555
+ if 'user_profile' not in st.session_state:
556
+ st.session_state.user_profile = {
557
+ 'name': 'Math Explorer',
558
+ 'total_exams': 0,
559
+ 'total_questions': 0,
560
+ 'correct_answers': 0,
561
+ 'favorite_grade': 5,
562
+ 'badges': [],
563
+ 'streak': 0
564
+ }
565
+ if 'seen_questions' not in st.session_state:
566
+ st.session_state.seen_questions = set()
567
+
568
+ @st.cache_resource
569
+ def get_exam_system():
570
+ return MathOlympiadExam()
571
+
572
+ def render_hero_section():
573
+ """Render the hero section with animations"""
574
+ st.markdown("""
575
+ <div class="hero-header slide-in-up">
576
+ <div class="hero-title">๐Ÿงฎ MathGenius Academy</div>
577
+ <div class="hero-subtitle">Master Mathematics Through Interactive Olympiad Training</div>
578
+ <div style="margin-top: 1rem;">
579
+ <span style="background: rgba(255,255,255,0.2); padding: 0.5rem 1rem; border-radius: 25px; margin: 0 0.5rem;">๐ŸŽฏ Adaptive Learning</span>
580
+ <span style="background: rgba(255,255,255,0.2); padding: 0.5rem 1rem; border-radius: 25px; margin: 0 0.5rem;">๐Ÿ“Š Progress Tracking</span>
581
+ <span style="background: rgba(255,255,255,0.2); padding: 0.5rem 1rem; border-radius: 25px; margin: 0 0.5rem;">๐Ÿ† Achievement System</span>
582
+ </div>
583
+ </div>
584
+ """, unsafe_allow_html=True)
585
+
586
+ def render_dashboard():
587
+ """Render user dashboard with statistics"""
588
+ profile = st.session_state.user_profile
589
+
590
+ st.markdown("### ๐Ÿ“Š Your Learning Dashboard")
591
+
592
+ col1, col2, col3, col4 = st.columns(4)
593
+
594
+ with col1:
595
+ st.markdown(f"""
596
+ <div class="stat-card">
597
+ <div class="stat-number">{profile['total_exams']}</div>
598
+ <div class="stat-label">Exams Taken</div>
599
+ </div>
600
+ """, unsafe_allow_html=True)
601
+
602
+ with col2:
603
+ accuracy = (profile['correct_answers'] / max(profile['total_questions'], 1)) * 100
604
+ st.markdown(f"""
605
+ <div class="stat-card">
606
+ <div class="stat-number">{accuracy:.1f}%</div>
607
+ <div class="stat-label">Accuracy</div>
608
+ </div>
609
+ """, unsafe_allow_html=True)
610
+
611
+ with col3:
612
+ st.markdown(f"""
613
+ <div class="stat-card">
614
+ <div class="stat-number">{profile['streak']}</div>
615
+ <div class="stat-label">Day Streak</div>
616
+ </div>
617
+ """, unsafe_allow_html=True)
618
+
619
+ with col4:
620
+ st.markdown(f"""
621
+ <div class="stat-card">
622
+ <div class="stat-number">{len(profile['badges'])}</div>
623
+ <div class="stat-label">Badges Earned</div>
624
+ </div>
625
+ """, unsafe_allow_html=True)
626
+
627
+ # Progress Chart
628
+ if st.session_state.exam_history:
629
+ df = pd.DataFrame(st.session_state.exam_history)
630
+
631
+ col1, col2 = st.columns(2)
632
+
633
+ with col1:
634
+ st.markdown("#### ๐Ÿ“ˆ Performance Trend")
635
+ fig = px.line(df, x='date', y='percentage',
636
+ title='Your Progress Over Time',
637
+ color_discrete_sequence=['#667eea'])
638
+ fig.update_layout(
639
+ plot_bgcolor='rgba(0,0,0,0)',
640
+ paper_bgcolor='rgba(0,0,0,0)',
641
+ )
642
+ st.plotly_chart(fig, use_container_width=True)
643
+
644
+ with col2:
645
+ st.markdown("#### ๐ŸŽฏ Grade Distribution")
646
+ grade_counts = df['grade'].value_counts().sort_index()
647
+ fig = px.bar(x=grade_counts.index, y=grade_counts.values,
648
+ title='Exams by Grade Level',
649
+ color_discrete_sequence=['#764ba2'])
650
+ fig.update_layout(
651
+ plot_bgcolor='rgba(0,0,0,0)',
652
+ paper_bgcolor='rgba(0,0,0,0)',
653
+ )
654
+ st.plotly_chart(fig, use_container_width=True)
655
+
656
+ def render_question_card(question, question_index, total_questions):
657
+ """Render an individual question with enhanced UI"""
658
+ progress = ((question_index + 1) / total_questions) * 100
659
+
660
+ st.markdown(f"""
661
+ <div class="progress-container">
662
+ <div class="progress-bar" style="width: {progress}%;">
663
+ Question {question_index + 1} of {total_questions}
664
+ </div>
665
+ </div>
666
+ """, unsafe_allow_html=True)
667
+
668
+ st.markdown(f"""
669
+ <div class="question-card slide-in-up">
670
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
671
+ <h3 style="color: #667eea; margin: 0;">Question {question['question_number']}</h3>
672
+ <span style="background: linear-gradient(135deg, #667eea, #764ba2); color: white; padding: 0.25rem 0.75rem; border-radius: 15px; font-size: 0.8rem;">
673
+ {question.get('difficulty', 'Medium')} Level
674
+ </span>
675
+ </div>
676
+ <div style="font-size: 1.1rem; font-weight: 500; margin-bottom: 1.5rem; line-height: 1.6; color: #222;">
677
+ {question['question_text']}
678
+ </div>
679
+ </div>
680
+ """, unsafe_allow_html=True)
681
+
682
+ # Options with enhanced styling
683
+ option_labels = [opt.split(')', 1)[1].strip() for opt in question['options']]
684
+ option_keys = [opt.split(')', 1)[0].strip() for opt in question['options']]
685
+
686
+ selected = st.radio(
687
+ "Choose your answer:",
688
+ options=option_keys,
689
+ format_func=lambda x, labels=option_labels, keys=option_keys: f"{x}) {labels[keys.index(x)]}",
690
+ key=f"q_{question_index}",
691
+ index=None
692
+ )
693
+
694
+ # Hint system
695
+ if st.button(f"๐Ÿ’ก Need a hint?", key=f"hint_{question_index}"):
696
+ if question.get('hint'):
697
+ st.info(f"๐Ÿ’ก **Hint:** {question['hint']}")
698
+ else:
699
+ st.info("๐Ÿ’ก **Hint:** Try breaking down the problem step by step!")
700
+
701
+ return selected
702
+
703
+ def render_exam_interface():
704
+ """Render the main exam interface"""
705
+ questions = st.session_state.questions
706
+ total_questions = len(questions)
707
+
708
+ if st.session_state.exam_mode == 'timed':
709
+ # Timer display
710
+ if st.session_state.start_time:
711
+ elapsed = time.time() - st.session_state.start_time
712
+ remaining = max(0, (total_questions * 120) - elapsed) # 2 minutes per question
713
+
714
+ mins, secs = divmod(int(remaining), 60)
715
+ st.markdown(f"""
716
+ <div style="text-align: center; margin-bottom: 1rem;">
717
+ <div style="background: linear-gradient(135deg, #FF6B6B, #FF8E8E); color: white;
718
+ padding: 1rem; border-radius: 15px; display: inline-block; font-size: 1.5rem; font-weight: 600;">
719
+ โฐ {mins:02d}:{secs:02d}
720
+ </div>
721
+ </div>
722
+ """, unsafe_allow_html=True)
723
+
724
+ if remaining <= 0:
725
+ st.error("โฐ Time's up! Submitting your exam...")
726
+ st.session_state.exam_completed = True
727
+ st.rerun()
728
+
729
+ # Question navigation
730
+ if total_questions > 1:
731
+ st.markdown("#### ๐Ÿ“ Question Navigation")
732
+ cols = st.columns(min(10, total_questions))
733
+ for i in range(total_questions):
734
+ with cols[i % 10]:
735
+ status = "โœ…" if questions[i]['user_answer'] else "โญ•"
736
+ if st.button(f"{status} Q{i+1}", key=f"nav_{i}"):
737
+ st.session_state.current_question = i
738
+
739
+ # Current question
740
+ current_q = st.session_state.current_question
741
+ if current_q < total_questions:
742
+ selected = render_question_card(questions[current_q], current_q, total_questions)
743
+ questions[current_q]['user_answer'] = selected
744
+
745
+ # Navigation buttons
746
+ col1, col2, col3 = st.columns([1, 2, 1])
747
+
748
+ with col1:
749
+ if current_q > 0:
750
+ if st.button("โฌ…๏ธ Previous", key="prev_btn"):
751
+ st.session_state.current_question -= 1
752
+ st.rerun()
753
+
754
+ with col3:
755
+ if current_q < total_questions - 1:
756
+ if st.button("Next โžก๏ธ", key="next_btn"):
757
+ st.session_state.current_question += 1
758
+ st.rerun()
759
+ else:
760
+ if st.button("๐ŸŽฏ Submit Exam", key="submit_btn", type="primary"):
761
+ unanswered = [i+1 for i, q in enumerate(questions) if not q['user_answer']]
762
+
763
+ if unanswered:
764
+ st.error(f"โš ๏ธ Please answer all questions. Missing: {', '.join(map(str, unanswered))}")
765
+ else:
766
+ st.session_state.exam_completed = True
767
+ st.rerun()
768
+
769
+ def calculate_badges(score, total, grade):
770
+ """Calculate badges earned based on performance"""
771
+ percentage = (score / total) * 100
772
+ badges = []
773
+
774
+ if percentage == 100:
775
+ badges.append("๐Ÿ† Perfect Score")
776
+ elif percentage >= 90:
777
+ badges.append("โญ Excellence")
778
+ elif percentage >= 80:
779
+ badges.append("๐ŸŽฏ High Achiever")
780
+ elif percentage >= 70:
781
+ badges.append("๐Ÿ“š Good Progress")
782
+
783
+ if grade >= 8:
784
+ badges.append("๐Ÿš€ Advanced Level")
785
+
786
+ return badges
787
+
788
+ def render_results_section():
789
+ """Render enhanced results with animations and insights - REMOVED ACTION BUTTONS"""
790
+ st.markdown("---")
791
+ st.markdown("### ๐ŸŽ‰ Exam Results")
792
+
793
+ questions = st.session_state.questions
794
+ correct_count = sum(1 for q in questions if q['user_answer'] == q['correct_answer'])
795
+ total_questions = len(questions)
796
+ percentage = (correct_count / total_questions) * 100
797
+
798
+ # Update user profile
799
+ profile = st.session_state.user_profile
800
+ profile['total_exams'] += 1
801
+ profile['total_questions'] += total_questions
802
+ profile['correct_answers'] += correct_count
803
+
804
+ # Add to history
805
+ st.session_state.exam_history.append({
806
+ 'date': datetime.now(),
807
+ 'grade': st.session_state.grade_selected,
808
+ 'score': correct_count,
809
+ 'total': total_questions,
810
+ 'percentage': percentage
811
+ })
812
+
813
+ # Calculate badges
814
+ new_badges = calculate_badges(correct_count, total_questions, st.session_state.grade_selected)
815
+ profile['badges'].extend(new_badges)
816
+
817
+ # Animated score reveal
818
+ col1, col2, col3 = st.columns(3)
819
+
820
+ with col1:
821
+ st.markdown(f"""
822
+ <div class="stat-card pulse-animation">
823
+ <div class="stat-number">{correct_count}/{total_questions}</div>
824
+ <div class="stat-label">Final Score</div>
825
+ </div>
826
+ """, unsafe_allow_html=True)
827
+
828
+ with col2:
829
+ st.markdown(f"""
830
+ <div class="stat-card pulse-animation">
831
+ <div class="stat-number">{percentage:.1f}%</div>
832
+ <div class="stat-label">Accuracy</div>
833
+ </div>
834
+ """, unsafe_allow_html=True)
835
+
836
+ with col3:
837
+ if percentage >= 90:
838
+ grade_emoji = "๐Ÿ†"
839
+ grade_text = "Excellent!"
840
+ elif percentage >= 80:
841
+ grade_emoji = "โญ"
842
+ grade_text = "Great Job!"
843
+ elif percentage >= 70:
844
+ grade_emoji = "๐Ÿ‘"
845
+ grade_text = "Good Work!"
846
+ else:
847
+ grade_emoji = "๐Ÿ“š"
848
+ grade_text = "Keep Practicing!"
849
+
850
+ st.markdown(f"""
851
+ <div class="stat-card pulse-animation">
852
+ <div class="stat-number">{grade_emoji}</div>
853
+ <div class="stat-label">{grade_text}</div>
854
+ </div>
855
+ """, unsafe_allow_html=True)
856
+
857
+ # New badges notification
858
+ if new_badges:
859
+ st.success(f"๐ŸŽ‰ New badges earned: {', '.join(new_badges)}")
860
+
861
+ # Detailed question review
862
+ st.markdown("#### ๐Ÿ“ Question Review")
863
+
864
+ for i, question in enumerate(questions):
865
+ is_correct = question['user_answer'] == question['correct_answer']
866
+
867
+ with st.expander(f"Question {i+1} - {'โœ… Correct' if is_correct else 'โŒ Incorrect'} ({question.get('difficulty', 'Medium')} Level)"):
868
+ st.markdown(f"**Question:** {question['question_text']}")
869
+
870
+ col1, col2 = st.columns(2)
871
+ with col1:
872
+ st.markdown(f"**Your Answer:** {question['user_answer']}")
873
+ with col2:
874
+ st.markdown(f"**Correct Answer:** {question['correct_answer']}")
875
+
876
+ if question.get('explanation'):
877
+ st.markdown(f"**Explanation:** {question['explanation']}")
878
+
879
+ if not is_correct and question.get('hint'):
880
+ st.info(f"๐Ÿ’ก **Hint for next time:** {question['hint']}")
881
+
882
+ # Performance insights
883
+ exam_system = get_exam_system()
884
+ if exam_system.client:
885
+ st.markdown("#### ๐Ÿง  AI Performance Analysis")
886
+ with st.spinner("Generating personalized insights..."):
887
+ summary = generate_enhanced_summary(
888
+ st.session_state.grade_selected,
889
+ questions,
890
+ correct_count,
891
+ total_questions,
892
+ exam_system
893
+ )
894
+
895
+ st.markdown(f"""
896
+ <div class="custom-card">
897
+ {summary}
898
+ </div>
899
+ """, unsafe_allow_html=True)
900
+
901
+ # Show completion message instead of action buttons
902
+ st.markdown("#### ๐ŸŽ“ Exam Complete!")
903
+ st.info("Great job completing the exam! Use the sidebar to generate a new exam or check out the Dashboard tab to view your progress.")
904
+
905
+ def generate_enhanced_summary(grade, questions, score, total, exam_system):
906
+ """Generate enhanced AI-powered performance summary"""
907
+ try:
908
+ # Analyze performance patterns
909
+ correct_questions = [q for q in questions if q['user_answer'] == q['correct_answer']]
910
+ incorrect_questions = [q for q in questions if q['user_answer'] != q['correct_answer']]
911
+
912
+ difficulty_analysis = {}
913
+ for q in questions:
914
+ diff = q.get('difficulty', 'Medium')
915
+ if diff not in difficulty_analysis:
916
+ difficulty_analysis[diff] = {'correct': 0, 'total': 0}
917
+ difficulty_analysis[diff]['total'] += 1
918
+ if q['user_answer'] == q['correct_answer']:
919
+ difficulty_analysis[diff]['correct'] += 1
920
+
921
+ percentage = (score / total * 100) if total > 0 else 0
922
+
923
+ prompt = f"""Analyze this Math Olympiad performance for a Grade {grade} student:
924
+
925
+ PERFORMANCE SUMMARY:
926
+ - Score: {score}/{total} ({percentage:.1f}%)
927
+ - Difficulty Breakdown: {difficulty_analysis}
928
+
929
+ SAMPLE INCORRECT QUESTIONS:
930
+ {chr(10).join([f"- {q['question_text'][:100]}..." for q in incorrect_questions[:2]])}
931
+
932
+ Please provide a concise summary (max 4-5 sentences) with:
933
+ - 1-2 key strengths
934
+ - 1 main area to improve
935
+ - 1 motivational message
936
+ Use simple, encouraging language for a Grade {grade} student. Avoid long lists or detailed study plans."""
937
+
938
+ response = exam_system.client.chat.completions.create(
939
+ model="llama-3.3-70b-versatile",
940
+ messages=[
941
+ {"role": "system", "content": "You are an expert Math Olympiad mentor providing detailed, encouraging feedback to help students improve."},
942
+ {"role": "user", "content": prompt}
943
+ ],
944
+ temperature=0.3,
945
+ max_tokens=1000
946
+ )
947
+
948
+ return response.choices[0].message.content
949
+
950
+ except Exception as e:
951
+ return f"""
952
+ **Performance Summary:**
953
+ You scored {score} out of {total} ({percentage:.1f}%).
954
+ Great job! You showed strong skills in several areas. Focus on reviewing the questions you missed. Keep practicing and you'll get even better! ๐ŸŒŸ
955
+ """
956
+
957
+ def reset_exam():
958
+ """Reset exam state for new attempt"""
959
+ st.session_state.questions = []
960
+ st.session_state.exam_completed = False
961
+ st.session_state.current_question = 0
962
+ st.session_state.start_time = None
963
+ st.rerun()
964
+
965
+ def render_sidebar():
966
+ """Enhanced sidebar with user profile and settings"""
967
+ exam_system = get_exam_system()
968
+
969
+ with st.sidebar:
970
+ # User profile section
971
+ st.markdown(f"""
972
+ <div style="text-align: center; padding: 1rem; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
973
+ border-radius: 15px; color: white; margin-bottom: 1rem;">
974
+ <div style="font-size: 3rem; margin-bottom: 0.5rem;">๐Ÿ‘‹</div>
975
+ <div style="font-size: 1.2rem; font-weight: 600;">{st.session_state.user_profile['name']}</div>
976
+ <div style="font-size: 0.9rem; opacity: 0.9;">Level {st.session_state.user_profile['favorite_grade']} Explorer</div>
977
+ </div>
978
+ """, unsafe_allow_html=True)
979
+
980
+ st.markdown("### โš™๏ธ Exam Configuration")
981
+
982
+ # Grade selection with enhanced UI
983
+ grade_options = list(exam_system.grade_levels.keys())
984
+ grade_labels = [f"{exam_system.grade_levels[g]['emoji']} {exam_system.grade_levels[g]['name']}" for g in grade_options]
985
+
986
+ grade = st.selectbox(
987
+ "๐ŸŽฏ Select Grade Level:",
988
+ options=grade_options,
989
+ format_func=lambda x: f"{exam_system.grade_levels[x]['emoji']} {exam_system.grade_levels[x]['name']}",
990
+ key="grade_selector",
991
+ help="Choose your current grade level for appropriate difficulty"
992
+ )
993
+
994
+ # Exam mode
995
+ exam_mode = st.radio(
996
+ "๐Ÿ“ Exam Mode:",
997
+ ["practice", "timed", "challenge"],
998
+ format_func=lambda x: {
999
+ "practice": "๐ŸŽฏ Practice Mode",
1000
+ "timed": "โฐ Timed Mode",
1001
+ "challenge": "๐Ÿ”ฅ Challenge Mode"
1002
+ }[x],
1003
+ help="Practice: No time limit | Timed: 2 min/question | Challenge: Extra hard questions"
1004
+ )
1005
+ st.session_state.exam_mode = exam_mode
1006
+
1007
+ # Number of questions
1008
+ if exam_mode == "challenge":
1009
+ num_questions = st.slider("๐Ÿ“Š Questions:", 5, 20, 10, help="Challenge mode: 5-20 questions")
1010
+ else:
1011
+ num_questions = st.slider("๐Ÿ“Š Questions:", 3, 15, 5, help="Choose number of questions")
1012
+
1013
+ # Difficulty level
1014
+ difficulty = st.select_slider(
1015
+ "โšก Difficulty:",
1016
+ options=["easy", "medium", "hard"],
1017
+ value="medium",
1018
+ format_func=lambda x: {
1019
+ "easy": "๐ŸŸข Easy",
1020
+ "medium": "๐ŸŸก Medium",
1021
+ "hard": "๐Ÿ”ด Hard"
1022
+ }[x]
1023
+ )
1024
+
1025
+ # Generate exam button
1026
+ if st.button("๐Ÿš€ Generate New Exam", type="primary", use_container_width=True):
1027
+ if not exam_system.client:
1028
+ st.error("๐Ÿšซ API not available!")
1029
+ else:
1030
+ with st.spinner(f"๐ŸŽญ Creating your {exam_mode} exam..."):
1031
+ # Add loading animation
1032
+ progress_bar = st.progress(0)
1033
+ for i in range(100):
1034
+ time.sleep(0.01)
1035
+ progress_bar.progress(i + 1)
1036
+
1037
+ challenge_difficulty = "hard" if exam_mode == "challenge" else difficulty
1038
+ questions = exam_system.generate_questions(grade, num_questions, challenge_difficulty)
1039
+
1040
+ if questions:
1041
+ # Filter out previously seen questions
1042
+ if 'seen_questions' in st.session_state:
1043
+ new_questions = [q for q in questions if q['question_text'] not in st.session_state.seen_questions]
1044
+ st.session_state.questions = new_questions
1045
+ # Update seen_questions with the new questions
1046
+ st.session_state.seen_questions.update(q['question_text'] for q in new_questions)
1047
+ else:
1048
+ st.session_state.questions = questions
1049
+
1050
+ st.session_state.exam_completed = False
1051
+ st.session_state.grade_selected = grade
1052
+ st.session_state.current_question = 0
1053
+ st.session_state.start_time = time.time() if exam_mode == "timed" else None
1054
+
1055
+ st.success(f"โœจ Generated {len(st.session_state.questions)} questions!")
1056
+ st.balloons()
1057
+ else:
1058
+ st.error("โŒ Failed to generate exam. Try again!")
1059
+
1060
+ st.markdown("---")
1061
+
1062
+ # Quick stats
1063
+ profile = st.session_state.user_profile
1064
+ st.markdown("### ๐Ÿ“ˆ Quick Stats")
1065
+ st.metric("๐ŸŽฏ Total Exams", profile['total_exams'])
1066
+
1067
+ if profile['total_questions'] > 0:
1068
+ accuracy = (profile['correct_answers'] / profile['total_questions']) * 100
1069
+ st.metric("๐ŸŽช Accuracy", f"{accuracy:.1f}%")
1070
+
1071
+ st.metric("๐Ÿ”ฅ Streak", f"{profile['streak']} days")
1072
+
1073
+ # Recent badges
1074
+ if profile['badges']:
1075
+ st.markdown("### ๐Ÿ† Recent Badges")
1076
+ for badge in profile['badges'][-3:]:
1077
+ st.markdown(f"- {badge}")
1078
+
1079
+ st.markdown("---")
1080
+
1081
+ # Settings
1082
+ with st.expander("โš™๏ธ Settings"):
1083
+ new_name = st.text_input("Your Name:", value=profile['name'])
1084
+ if new_name != profile['name']:
1085
+ profile['name'] = new_name
1086
+ st.success("Name updated!")
1087
+
1088
+ if st.button("๐Ÿ—‘๏ธ Reset Progress"):
1089
+ if st.checkbox("I'm sure"):
1090
+ initialize_session_state()
1091
+ st.success("Progress reset!")
1092
+ st.rerun()
1093
+
1094
+ def render_welcome_screen():
1095
+ """Render welcome screen for new users"""
1096
+ # Main welcome container
1097
+ st.markdown("""
1098
+ <div class="custom-card slide-in-up" style="text-align: center; padding: 3rem;">
1099
+ <div style="font-size: 4rem; margin-bottom: 1rem;">๐ŸŒŸ</div>
1100
+ <h2 style="color: #667eea; margin-bottom: 1rem;">Welcome to MathGenius Academy!</h2>
1101
+ <p style="font-size: 1.2rem; color: #666; margin-bottom: 2rem;">
1102
+ Ready to embark on an exciting mathematical journey? Let's discover your potential!
1103
+ </p>
1104
+ </div>
1105
+ """, unsafe_allow_html=True)
1106
+
1107
+ # Feature cards using Streamlit columns for better compatibility
1108
+ st.markdown("### โœจ What Makes Us Special")
1109
+ col1, col2, col3 = st.columns(3)
1110
+
1111
+ with col1:
1112
+ st.markdown("""
1113
+ <div style="background: linear-gradient(135deg, #667eea, #764ba2); color: white; padding: 1.5rem; border-radius: 15px; text-align: center; height: 200px; display: flex; flex-direction: column; justify-content: center;">
1114
+ <div style="font-size: 3rem; margin-bottom: 1rem;">๐ŸŽฏ</div>
1115
+ <h4 style="margin: 0.5rem 0; color: white;">Adaptive Learning</h4>
1116
+ <p style="margin: 0; color: rgba(255,255,255,0.9);">Questions adjust to your skill level</p>
1117
+ </div>
1118
+ """, unsafe_allow_html=True)
1119
+
1120
+ with col2:
1121
+ st.markdown("""
1122
+ <div style="background: linear-gradient(135deg, #667eea, #764ba2); color: white; padding: 1.5rem; border-radius: 15px; text-align: center; height: 200px; display: flex; flex-direction: column; justify-content: center;">
1123
+ <div style="font-size: 3rem; margin-bottom: 1rem;">๐Ÿ“Š</div>
1124
+ <h4 style="margin: 0.5rem 0; color: white;">Progress Tracking</h4>
1125
+ <p style="margin: 0; color: rgba(255,255,255,0.9);">See your improvement over time</p>
1126
+ </div>
1127
+ """, unsafe_allow_html=True)
1128
+
1129
+ with col3:
1130
+ st.markdown("""
1131
+ <div style="background: linear-gradient(135deg, #667eea, #764ba2); color: white; padding: 1.5rem; border-radius: 15px; text-align: center; height: 200px; display: flex; flex-direction: column; justify-content: center;">
1132
+ <div style="font-size: 3rem; margin-bottom: 1rem;">๐Ÿ†</div>
1133
+ <h4 style="margin: 0.5rem 0; color: white;">Achievement System</h4>
1134
+ <p style="margin: 0; color: rgba(255,255,255,0.9);">Earn badges and unlock new levels</p>
1135
+ </div>
1136
+ """, unsafe_allow_html=True)
1137
+
1138
+ # Getting started message
1139
+ st.markdown("---")
1140
+ st.info("๐Ÿ‘ˆ Choose your grade level from the sidebar and click 'Generate New Exam' to begin your mathematical adventure!")
1141
+
1142
+ # Quick start tips
1143
+ with st.expander("๐Ÿš€ Quick Start Guide"):
1144
+ st.markdown("""
1145
+ **Ready to begin? Follow these simple steps:**
1146
+
1147
+ 1. **๐ŸŽฏ Choose Your Grade**: Select your current grade level from the sidebar
1148
+ 2. **๐Ÿ“ Pick Your Mode**:
1149
+ - ๐ŸŸข **Practice Mode**: No time pressure, perfect for learning
1150
+ - โฐ **Timed Mode**: Challenge yourself with time limits
1151
+ - ๐Ÿ”ฅ **Challenge Mode**: Extra difficult questions for advanced learners
1152
+ 3. **โšก Set Difficulty**: Easy, Medium, or Hard - pick what feels right
1153
+ 4. **๐Ÿ“Š Choose Questions**: 3-20 questions depending on your time
1154
+ 5. **๐Ÿš€ Generate & Start**: Hit the generate button and begin!
1155
+
1156
+ **๐Ÿ’ก Pro Tips:**
1157
+ - Start with Practice mode to get comfortable
1158
+ - Use hints when you're stuck - learning is the goal!
1159
+ - Review all explanations to understand concepts better
1160
+ - Track your progress in the Dashboard tab
1161
+ """)
1162
+
1163
+ # Motivational quote
1164
+ st.markdown("""
1165
+ <div style="text-align: center; margin: 2rem 0; padding: 2rem; background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); border-radius: 20px; color: white;">
1166
+ <h3 style="margin: 0; color: white;">"Mathematics is not about numbers, equations, or algorithms. It is about understanding." - William Paul Thurston</h3>
1167
+ </div>
1168
+ """, unsafe_allow_html=True)
1169
+
1170
+ def main():
1171
+ # Load custom CSS
1172
+ load_custom_css()
1173
+
1174
+ # Initialize session state
1175
+ initialize_session_state()
1176
+
1177
+ # Get exam system
1178
+ exam_system = get_exam_system()
1179
+
1180
+ # Render hero section
1181
+ render_hero_section()
1182
+
1183
+ # Main navigation
1184
+ tab1, tab2, tab3 = st.tabs(["๐ŸŽฏ Exam", "๐Ÿ“Š Dashboard", "โ„น๏ธ About"])
1185
+
1186
+ with tab1:
1187
+ # Render sidebar
1188
+ render_sidebar()
1189
+
1190
+ # Main exam interface
1191
+ if not st.session_state.questions:
1192
+ render_welcome_screen()
1193
+ elif st.session_state.exam_completed:
1194
+ render_results_section()
1195
+ else:
1196
+ st.markdown("### ๐Ÿงฎ Math Olympiad Challenge")
1197
+
1198
+ if st.session_state.exam_mode == "timed" and st.session_state.start_time:
1199
+ # Show exam info
1200
+ col1, col2, col3 = st.columns(3)
1201
+ with col1:
1202
+ st.info(f"๐Ÿ“š Grade {st.session_state.grade_selected}")
1203
+ with col2:
1204
+ st.info(f"โฑ๏ธ {st.session_state.exam_mode.title()} Mode")
1205
+ with col3:
1206
+ st.info(f"๐Ÿ“ {len(st.session_state.questions)} Questions")
1207
+
1208
+ render_exam_interface()
1209
+
1210
+ with tab2:
1211
+ render_dashboard()
1212
+
1213
+ # Additional dashboard features
1214
+ if st.session_state.exam_history:
1215
+ st.markdown("#### ๐ŸŽฏ Detailed Analytics")
1216
+
1217
+ df = pd.DataFrame(st.session_state.exam_history)
1218
+
1219
+ col1, col2 = st.columns(2)
1220
+
1221
+ with col1:
1222
+ st.markdown("##### ๐Ÿ“Š Score Distribution")
1223
+ fig = px.histogram(df, x='percentage', nbins=10,
1224
+ title='Score Distribution',
1225
+ color_discrete_sequence=['#667eea'])
1226
+ fig.update_layout(plot_bgcolor='rgba(0,0,0,0)', paper_bgcolor='rgba(0,0,0,0)')
1227
+ st.plotly_chart(fig, use_container_width=True)
1228
+
1229
+ with col2:
1230
+ st.markdown("##### ๐Ÿ“ˆ Improvement Trend")
1231
+ df_trend = df.copy()
1232
+ df_trend['moving_avg'] = df_trend['percentage'].rolling(window=3, min_periods=1).mean()
1233
+
1234
+ fig = go.Figure()
1235
+ fig.add_trace(go.Scatter(x=df_trend['date'], y=df_trend['percentage'],
1236
+ mode='markers+lines', name='Actual Score',
1237
+ line=dict(color='#667eea')))
1238
+ fig.add_trace(go.Scatter(x=df_trend['date'], y=df_trend['moving_avg'],
1239
+ mode='lines', name='Trend',
1240
+ line=dict(color='#764ba2', dash='dash')))
1241
+
1242
+ fig.update_layout(title='Performance Trend',
1243
+ plot_bgcolor='rgba(0,0,0,0)',
1244
+ paper_bgcolor='rgba(0,0,0,0)')
1245
+ st.plotly_chart(fig, use_container_width=True)
1246
+
1247
+ # Achievement showcase
1248
+ profile = st.session_state.user_profile
1249
+ if profile['badges']:
1250
+ st.markdown("#### ๐Ÿ† Your Achievements")
1251
+
1252
+ badge_cols = st.columns(min(4, len(profile['badges'])))
1253
+ for i, badge in enumerate(profile['badges'][-8:]): # Show last 8 badges
1254
+ with badge_cols[i % 4]:
1255
+ st.markdown(f"""
1256
+ <div style="text-align: center; background: linear-gradient(135deg, #667eea, #764ba2);
1257
+ color: white; padding: 1rem; border-radius: 15px; margin-bottom: 1rem;">
1258
+ <div style="font-size: 1.5rem; margin-bottom: 0.5rem;">{badge.split()[0]}</div>
1259
+ <div style="font-size: 0.8rem;">{' '.join(badge.split()[1:])}</div>
1260
+ </div>
1261
+ """, unsafe_allow_html=True)
1262
+
1263
+ with tab3:
1264
+ st.markdown("# ๐Ÿ“– About MathGenius Academy")
1265
+
1266
+ # Mission section
1267
+ with st.container():
1268
+ st.markdown("## ๐ŸŽฏ Our Mission")
1269
+ st.markdown("""
1270
+ <div class="custom-card">
1271
+ <p style="font-size: 1.1rem; line-height: 1.6; color: #444;">
1272
+ To make mathematics accessible, engaging, and fun for students of all levels through
1273
+ interactive Olympiad-style training. We believe every student can excel in mathematics
1274
+ with the right guidance and practice.
1275
+ </p>
1276
+ </div>
1277
+ """, unsafe_allow_html=True)
1278
+
1279
+ # Features section
1280
+ st.markdown("## โœจ Key Features")
1281
+
1282
+ col1, col2 = st.columns(2)
1283
+
1284
+ with col1:
1285
+ st.markdown(
1286
+ """
1287
+ <div class="custom-card">
1288
+ <h4 style="color: #667eea;">๐Ÿค– AI-Powered Learning</h4>
1289
+ <ul style="color: #444;">
1290
+ <li><strong>Adaptive Questions:</strong> Problems that match your skill level</li>
1291
+ <li><strong>Smart Difficulty:</strong> Automatic adjustment based on performance</li>
1292
+ <li><strong>Personalized Feedback:</strong> Detailed insights and recommendations</li>
1293
+ </ul>
1294
+ <h4 style="color: #667eea;">๐ŸŽฎ Multiple Game Modes</h4>
1295
+ <ul style="color: #444;">
1296
+ <li><strong>Practice Mode:</strong> Learn at your own pace</li>
1297
+ <li><strong>Timed Mode:</strong> Build speed and confidence</li>
1298
+ <li><strong>Challenge Mode:</strong> Push your limits with hard problems</li>
1299
+ </ul>
1300
+ </div>
1301
+ """,
1302
+ unsafe_allow_html=True
1303
+ )
1304
+
1305
+ with col2:
1306
+ st.markdown(
1307
+ """
1308
+ <div class="custom-card">
1309
+ <h4 style="color: #667eea;">๐Ÿ“Š Progress & Analytics</h4>
1310
+ <ul style="color: #444;">
1311
+ <li><strong>Performance Tracking:</strong> Monitor improvement over time</li>
1312
+ <li><strong>Detailed Statistics:</strong> Accuracy, trends, and insights</li>
1313
+ <li><strong>Visual Charts:</strong> Interactive graphs and analysis</li>
1314
+ </ul>
1315
+ <h4 style="color: #667eea;">๐Ÿ† Achievement System</h4>
1316
+ <ul style="color: #444;">
1317
+ <li><strong>Badges & Rewards:</strong> Celebrate your success</li>
1318
+ <li><strong>Streak Tracking:</strong> Build consistent study habits</li>
1319
+ <li><strong>Level Progression:</strong> Unlock new challenges</li>
1320
+ </ul>
1321
+ </div>
1322
+ """,
1323
+ unsafe_allow_html=True
1324
+ )
1325
+
1326
+ # Getting Started Guide
1327
+ st.markdown("## ๐Ÿš€ Getting Started")
1328
+
1329
+ steps_col1, steps_col2 = st.columns(2)
1330
+
1331
+ with steps_col1:
1332
+ st.markdown("""
1333
+ <div class="custom-card">
1334
+ <h4 style="color: #667eea;">๐Ÿ“‹ Setup Steps</h4>
1335
+ <ol style="color: #444;">
1336
+ <li><strong>Select Grade Level:</strong> Choose from Grade 1-10</li>
1337
+ <li><strong>Pick Exam Mode:</strong> Practice, Timed, or Challenge</li>
1338
+ <li><strong>Set Difficulty:</strong> Easy, Medium, or Hard</li>
1339
+ <li><strong>Choose Questions:</strong> 3-20 questions per exam</li>
1340
+ <li><strong>Generate Exam:</strong> Click the generate button</li>
1341
+ </ol>
1342
+ </div>
1343
+ """, unsafe_allow_html=True)
1344
+
1345
+ with steps_col2:
1346
+ st.markdown("""
1347
+ <div class="custom-card">
1348
+ <h4 style="color: #667eea;">๐Ÿ’ก Success Tips</h4>
1349
+ <ul style="color: #444;">
1350
+ <li><strong>Start Easy:</strong> Begin with Practice mode</li>
1351
+ <li><strong>Use Hints:</strong> Don't hesitate to ask for help</li>
1352
+ <li><strong>Review Mistakes:</strong> Learn from wrong answers</li>
1353
+ <li><strong>Track Progress:</strong> Check your Dashboard regularly</li>
1354
+ <li><strong>Stay Consistent:</strong> Practice a little each day</li>
1355
+ </ul>
1356
+ </div>
1357
+ """, unsafe_allow_html=True)
1358
+
1359
+ # Grade Level Guide
1360
+ st.markdown("## ๐ŸŽฏ Grade Level Guide")
1361
+
1362
+ grade_col1, grade_col2, grade_col3 = st.columns(3)
1363
+
1364
+ with grade_col1:
1365
+ st.markdown("""
1366
+ <div class="custom-card">
1367
+ <h4 style="color: #667eea;">๐ŸŒฑ Elementary (Grades 1-4)</h4>
1368
+ <ul style="color: #444;">
1369
+ <li>Basic arithmetic operations</li>
1370
+ <li>Simple word problems</li>
1371
+ <li>Pattern recognition</li>
1372
+ <li>Basic geometry shapes</li>
1373
+ <li>Counting and number sense</li>
1374
+ </ul>
1375
+ </div>
1376
+ """, unsafe_allow_html=True)
1377
+
1378
+ with grade_col2:
1379
+ st.markdown("""
1380
+ <div class="custom-card">
1381
+ <h4 style="color: #667eea;">๐Ÿš€ Middle School (Grades 5-8)</h4>
1382
+ <ul style="color: #444;">
1383
+ <li>Pre-algebra concepts</li>
1384
+ <li>Fractions and decimals</li>
1385
+ <li>Basic statistics</li>
1386
+ <li>Coordinate geometry</li>
1387
+ <li>Problem-solving strategies</li>
1388
+ </ul>
1389
+ </div>
1390
+ """, unsafe_allow_html=True)
1391
+
1392
+ with grade_col3:
1393
+ st.markdown("""
1394
+ <div class="custom-card">
1395
+ <h4 style="color: #667eea;">โญ High School (Grades 9-10)</h4>
1396
+ <ul style="color: #444;">
1397
+ <li>Advanced algebra</li>
1398
+ <li>Geometry proofs</li>
1399
+ <li>Trigonometry basics</li>
1400
+ <li>Complex problem solving</li>
1401
+ <li>Mathematical reasoning</li>
1402
+ </ul>
1403
+ </div>
1404
+ """, unsafe_allow_html=True)
1405
+
1406
+ # FAQ Section
1407
+ with st.expander("โ“ Frequently Asked Questions"):
1408
+ st.markdown("""
1409
+ **Q: How are the questions generated?**
1410
+
1411
+ A: We use advanced AI to create unique, grade-appropriate questions that follow Math Olympiad standards.
1412
+
1413
+ **Q: Can I retake exams?**
1414
+
1415
+ A: Yes! You can generate unlimited exams to practice and improve your skills.
1416
+
1417
+ **Q: How is my progress tracked?**
1418
+
1419
+ A: We track your accuracy, response times, difficulty preferences, and improvement trends over time.
1420
+
1421
+ **Q: What if I get stuck on a question?**
1422
+
1423
+ A: Use the hint feature! We provide helpful hints to guide your thinking without giving away the answer.
1424
+
1425
+ **Q: Is there a time limit?**
1426
+
1427
+ A: Only in Timed Mode. Practice and Challenge modes let you work at your own pace.
1428
+
1429
+ **Q: How do I earn badges?**
1430
+
1431
+ A: Badges are earned automatically based on your performance, consistency, and achievements.
1432
+ """)
1433
+
1434
+ # Footer
1435
+ st.markdown("---")
1436
+ st.markdown("""
1437
+ <div style="text-align: center; padding: 2rem; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 20px; color: white;">
1438
+ <h3 style="color: white; margin-bottom: 1rem;">Ready to become a Math Genius? ๐Ÿงฎ</h3>
1439
+ <p style="color: rgba(255,255,255,0.9); margin: 0;">
1440
+ Join thousands of students improving their mathematical skills every day!
1441
+ </p>
1442
+ </div>
1443
+ """, unsafe_allow_html=True)
1444
+
1445
+ st.markdown("<br>", unsafe_allow_html=True)
1446
+ st.markdown("**Made with โค๏ธ for young mathematicians everywhere!**")
1447
 
1448
+ if __name__ == "__main__":
1449
+ main()