AptlyDigital commited on
Commit
2aeb870
·
verified ·
1 Parent(s): 738c1c1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +201 -853
app.py CHANGED
@@ -1,7 +1,6 @@
1
  """
2
  SEA Prep Pro - AI-Powered Tutor 🇹🇹
3
  FULLY FREE VERSION - No API Keys Required!
4
- Uses local models and open-source libraries
5
  """
6
  import gradio as gr
7
  import sqlite3
@@ -9,39 +8,16 @@ import json
9
  import os
10
  import re
11
  import random
12
- import requests
13
- from datetime import datetime, timedelta
14
- from typing import List, Dict, Optional, Tuple
15
- import threading
16
- import time
17
- import hashlib
18
  import math
 
 
19
 
20
- # ==================== FREE AI ALTERNATIVES ====================
21
- # We'll use rule-based AI and local models via Hugging Face's free inference API
22
- # No API key needed for public models!
23
-
24
  class FreeAITutor:
25
- """Free AI tutor using rule-based generation and public models"""
26
 
27
  def __init__(self):
28
- self.math_patterns = {
29
- "addition": r"(\d+)\s*\+\s*(\d+)",
30
- "subtraction": r"(\d+)\s*-\s*(\d+)",
31
- "multiplication": r"(\d+)\s*[x×]\s*(\d+)",
32
- "division": r"(\d+)\s*÷\s*(\d+)",
33
- "fraction": r"(\d+)/(\d+)"
34
- }
35
-
36
- self.grammar_rules = {
37
- "is_are": [("he is", "she is", "it is"), ("they are", "we are", "you are")],
38
- "was_were": [("i was", "he was", "she was"), ("they were", "we were")],
39
- "has_have": [("he has", "she has"), ("i have", "they have", "we have")]
40
- }
41
-
42
- def generate_math_question(self, topic, difficulty):
43
- """Generate math questions using templates"""
44
- templates = {
45
  "Fractions": [
46
  "Simplify the fraction {num}/{den}.",
47
  "Add {a}/{b} + {c}/{d}.",
@@ -49,42 +25,33 @@ class FreeAITutor:
49
  "What is {num}/{den} of {whole}?",
50
  "Convert {decimal} to a fraction."
51
  ],
52
- "Decimals": [
53
- "Add {a}.{b} + {c}.{d}",
54
- "Subtract {a}.{b} - {c}.{d}",
55
- "Multiply {a}.{b} × {c}",
56
- "Divide {a}.{b} ÷ {c}",
57
- "Round {num}.{dec} to the nearest {place}."
58
- ],
59
- "Percentages": [
60
- "What is {percent}% of {number}?",
61
- "{number} is what percent of {total}?",
62
- "Increase {number} by {percent}%.",
63
- "Decrease {number} by {percent}%.",
64
- "Find the percentage change from {old} to {new}."
65
- ],
66
  "Geometry": [
67
  "Find the area of a rectangle with length {l}cm and width {w}cm.",
68
  "Calculate the perimeter of a square with side {s}cm.",
69
  "Find the area of a triangle with base {b}cm and height {h}cm.",
70
  "Calculate the circumference of a circle with radius {r}cm (use π=3.14).",
71
  "Find the volume of a cube with side {s}cm."
72
- ],
73
- "Algebra": [
74
- "Solve for x: {a}x + {b} = {c}",
75
- "Simplify: {a}x + {b}y + {c}x - {d}y",
76
- "Expand: {a}(x + {b})",
77
- "Factor: {a}x + {b}",
78
- "Evaluate {a}x² + {b}x + {c} when x = {d}"
79
  ]
80
  }
81
 
82
- topic_templates = templates.get(topic, ["Practice {topic} problems."])
83
- template = random.choice(topic_templates)
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
- # Fill template with random values based on difficulty
86
- multipliers = {1: 10, 2: 20, 3: 50, 4: 100, 5: 500}
87
- max_val = multipliers.get(difficulty, 50)
88
 
89
  values = {
90
  'num': random.randint(1, max_val),
@@ -95,46 +62,28 @@ class FreeAITutor:
95
  'd': random.randint(2, max_val),
96
  'whole': random.randint(10, 100),
97
  'decimal': round(random.uniform(0.1, 0.9), 2),
98
- 'percent': random.randint(1, 100),
99
- 'number': random.randint(1, max_val),
100
- 'total': random.randint(10, 100),
101
- 'old': random.randint(10, 100),
102
- 'new': random.randint(10, 100),
103
  'l': random.randint(5, 20),
104
  'w': random.randint(3, 15),
105
  's': random.randint(4, 12),
106
  'r': random.randint(2, 10),
107
  'h': random.randint(3, 12),
108
  'b': random.randint(4, 16),
109
- 'x': random.randint(1, 10),
110
- 'y': random.randint(1, 10),
111
- 'place': random.choice(["whole number", "tenth", "hundredth"]),
112
  'topic': topic
113
  }
114
 
115
  question = template.format(**values)
116
-
117
- # Calculate answer
118
- answer = self._calculate_answer(question, topic, values)
119
 
120
  return question, answer
121
 
122
- def _calculate_answer(self, question, topic, values):
123
- """Calculate answer for math questions"""
124
  try:
125
  if "Simplify the fraction" in question:
126
  num, den = values['num'], values['den']
127
  gcd = math.gcd(num, den)
128
  return f"{num//gcd}/{den//gcd}"
129
 
130
- elif "Add" in question and "/" in question:
131
- # Fraction addition
132
- a, b, c, d = values['a'], values['b'], values['c'], values['d']
133
- lcm = b * d // math.gcd(b, d)
134
- num = a * (lcm // b) + c * (lcm // d)
135
- gcd = math.gcd(num, lcm)
136
- return f"{num//gcd}/{lcm//gcd}"
137
-
138
  elif "area of a rectangle" in question:
139
  return f"{values['l'] * values['w']} cm²"
140
 
@@ -145,270 +94,39 @@ class FreeAITutor:
145
  return f"{0.5 * values['b'] * values['h']} cm²"
146
 
147
  elif "circumference of a circle" in question:
148
- return f"{2 * 3.14 * values['r']} cm"
149
 
150
  elif "volume of a cube" in question:
151
  return f"{values['s'] ** 3} cm³"
152
 
153
- elif "Solve for x:" in question:
154
- a, b, c = values['a'], values['b'], values['c']
155
- return f"{(c - b) / a}"
156
-
157
- elif "What is" in question and "% of" in question:
158
- return f"{values['number'] * values['percent'] / 100}"
159
 
160
  else:
161
- # Try to evaluate mathematically
162
- expr = question.lower()
163
- expr = expr.replace("what is", "").replace("calculate", "").replace("find", "")
164
- expr = expr.replace("×", "*").replace("x", "*").replace("÷", "/")
165
-
166
- # Remove units and text
167
- expr = re.sub(r'[a-zA-Z\s]+', '', expr)
168
- expr = expr.strip(" .?")
169
 
170
- try:
171
- result = eval(expr)
172
- return str(round(result, 2))
173
- except:
174
- return "Calculate step by step"
175
-
176
- except Exception as e:
177
- print(f"Calculation error: {e}")
178
  return "Practice this concept"
179
 
180
- def generate_english_question(self, topic, difficulty):
181
- """Generate English questions using templates"""
182
- templates = {
183
- "Grammar": [
184
- "Correct the sentence: '{sentence}'",
185
- "Choose the correct word: '{sentence}'",
186
- "Identify the error: '{sentence}'",
187
- "Complete the sentence: '{sentence}'",
188
- "Rewrite in past tense: '{sentence}'"
189
- ],
190
- "Vocabulary": [
191
- "What is a synonym for '{word}'?",
192
- "What is the antonym of '{word}'?",
193
- "Use '{word}' in a sentence.",
194
- "What does '{word}' mean?",
195
- "Which word doesn't belong: '{words}'?"
196
- ],
197
- "Comprehension": [
198
- "Read this passage: '{passage}'. Answer: {question}",
199
- "What is the main idea? '{passage}'",
200
- "What can you infer from: '{passage}'?",
201
- "Who is the main character? '{passage}'",
202
- "What happened first? '{passage}'"
203
- ],
204
- "Writing": [
205
- "Write a paragraph about '{topic}'.",
206
- "Write a letter to your teacher about '{topic}'.",
207
- "Write a story that includes: '{elements}'",
208
- "Describe your favorite place in Trinidad.",
209
- "Write instructions for '{activity}'."
210
- ]
211
- }
212
-
213
- # Word banks
214
- vocabulary = {
215
- "easy": ["happy", "big", "small", "fast", "slow", "hot", "cold", "good", "bad"],
216
- "medium": ["excited", "enormous", "minuscule", "rapid", "gradual", "scorching", "freezing", "excellent", "terrible"],
217
- "hard": ["ecstatic", "colossal", "microscopic", "expeditious", "leisurely", "blistering", "glacial", "superb", "atrocious"]
218
- }
219
-
220
- grammar_sentences = {
221
- "easy": [
222
- "He go to school.",
223
- "They is happy.",
224
- "I has a book.",
225
- "She don't like it.",
226
- "We was playing."
227
- ],
228
- "medium": [
229
- "Neither of the boys have finished.",
230
- "Each of the students are here.",
231
- "The team are winning.",
232
- "One of the books were missing.",
233
- "Everybody know the answer."
234
- ],
235
- "hard": [
236
- "The data suggests that the hypothesis are correct.",
237
- "A number of students was absent.",
238
- "The committee have made their decision.",
239
- "Physics are my favorite subject.",
240
- "The police is investigating."
241
- ]
242
- }
243
-
244
- passages = [
245
- "The Caribbean sun shone brightly on the beaches of Trinidad. Children played in the sand while their parents watched from under colorful umbrellas. The sound of steelpan music floated on the breeze.",
246
- "In the rainforest, brightly colored birds flew between the trees. Monkeys chattered in the canopy, and exotic flowers bloomed everywhere. The air was filled with the sounds of nature.",
247
- "During Carnival, the streets of Port of Spain come alive with music and dancing. People in elaborate costumes parade through the streets, celebrating with joy and energy.",
248
- "The market was bustling with activity. Vendors sold fresh fruits, vegetables, and spices. The smell of curry and fresh bread filled the air as people shopped for their dinner ingredients."
249
- ]
250
-
251
- difficulty_key = ["easy", "medium", "hard", "hard", "hard"][difficulty-1]
252
-
253
- if topic in templates:
254
- template = random.choice(templates[topic])
255
-
256
- if topic == "Grammar":
257
- sentence = random.choice(grammar_sentences[difficulty_key])
258
- question = template.format(sentence=sentence)
259
- answer = self._correct_grammar(sentence)
260
-
261
- elif topic == "Vocabulary":
262
- word = random.choice(vocabulary[difficulty_key])
263
- question = template.format(word=word)
264
- answer = self._get_word_info(word, template)
265
-
266
- elif topic == "Comprehension":
267
- passage = random.choice(passages)
268
- questions = [
269
- "What is happening?",
270
- "Where does this take place?",
271
- "Who is mentioned?",
272
- "What time of day is it?",
273
- "What sounds are mentioned?"
274
- ]
275
- q = random.choice(questions)
276
- question = template.format(passage=passage, question=q)
277
- answer = self._comprehension_answer(passage, q)
278
-
279
- elif topic == "Writing":
280
- writing_topics = ["your family", "your school", "Carnival", "the beach", "a rainforest adventure"]
281
- topic_word = random.choice(writing_topics)
282
- question = template.format(topic=topic_word)
283
- answer = "Write a well-structured paragraph with complete sentences."
284
-
285
- else:
286
- question = f"Practice {topic}."
287
- answer = "Practice answer"
288
-
289
- return question, answer
290
-
291
- return f"Practice {topic} questions.", "Check your textbook."
292
-
293
- def _correct_grammar(self, sentence):
294
- """Correct grammar errors in sentences"""
295
- corrections = {
296
- "He go to school.": "He goes to school.",
297
- "They is happy.": "They are happy.",
298
- "I has a book.": "I have a book.",
299
- "She don't like it.": "She doesn't like it.",
300
- "We was playing.": "We were playing.",
301
- "Neither of the boys have finished.": "Neither of the boys has finished.",
302
- "Each of the students are here.": "Each of the students is here.",
303
- "The team are winning.": "The team is winning.",
304
- "One of the books were missing.": "One of the books was missing.",
305
- "Everybody know the answer.": "Everybody knows the answer."
306
- }
307
- return corrections.get(sentence, "Sentence appears to be correct.")
308
-
309
- def _get_word_info(self, word, template):
310
- """Get word synonyms/antonyms"""
311
- synonyms = {
312
- "happy": "joyful, cheerful",
313
- "big": "large, huge",
314
- "small": "little, tiny",
315
- "fast": "quick, rapid",
316
- "slow": "gradual, unhurried",
317
- "hot": "warm, boiling",
318
- "cold": "chilly, freezing",
319
- "good": "excellent, great",
320
- "bad": "poor, terrible"
321
- }
322
-
323
- antonyms = {
324
- "happy": "sad",
325
- "big": "small",
326
- "small": "big",
327
- "fast": "slow",
328
- "slow": "fast",
329
- "hot": "cold",
330
- "cold": "hot",
331
- "good": "bad",
332
- "bad": "good"
333
- }
334
-
335
- if "synonym" in template:
336
- return synonyms.get(word, "Look up in dictionary")
337
- elif "antonym" in template:
338
- return antonyms.get(word, "Look up in dictionary")
339
- else:
340
- return "Check dictionary for meaning"
341
-
342
- def _comprehension_answer(self, passage, question):
343
- """Generate comprehension answers"""
344
- if "What is happening" in question:
345
- return "People are enjoying outdoor activities in Trinidad."
346
- elif "Where" in question:
347
- if "beach" in passage.lower():
348
- return "At the beach in Trinidad"
349
- elif "rainforest" in passage.lower():
350
- return "In a rainforest"
351
- elif "Carnival" in passage.lower():
352
- return "In Port of Spain during Carnival"
353
- elif "market" in passage.lower():
354
- return "At a market"
355
- elif "Who" in question:
356
- return "People, children, parents, vendors (depending on passage)"
357
- elif "time of day" in question:
358
- return "During the day"
359
- elif "sounds" in question:
360
- return "Music, nature sounds, chatter"
361
-
362
- return "Read the passage carefully for the answer."
363
-
364
- def evaluate_answer(self, student_answer, correct_answer, question):
365
  """Evaluate student's answer"""
366
  student = str(student_answer).strip().lower()
367
  correct = str(correct_answer).strip().lower()
368
 
369
- # Basic matching
370
  if student == correct:
371
- return {
372
- "correct": True,
373
- "confidence": 1.0,
374
- "feedback": "✅ Perfect answer!",
375
- "score": 1
376
- }
377
-
378
- # For math: check numeric equivalence
379
- try:
380
- # Extract numbers
381
- s_num = re.findall(r"[-+]?\d*\.\d+|\d+", student)
382
- c_num = re.findall(r"[-+]?\d*\.\d+|\d+", correct)
383
-
384
- if s_num and c_num:
385
- if abs(float(s_num[0]) - float(c_num[0])) < 0.01:
386
- return {
387
- "correct": True,
388
- "confidence": 0.9,
389
- "feedback": "✅ Numerically correct!",
390
- "score": 0.9
391
- }
392
- except:
393
- pass
394
 
395
  # Partial credit for showing work
396
- if len(student) > 10 and any(word in student for word in ["step", "calculate", "solve", "answer"]):
397
- return {
398
- "correct": False,
399
- "confidence": 0.5,
400
- "feedback": "⚠️ Good attempt. The correct answer is: " + correct_answer,
401
- "score": 0.5
402
- }
403
 
404
- return {
405
- "correct": False,
406
- "confidence": 0.0,
407
- "feedback": "❌ Incorrect. The correct answer is: " + correct_answer,
408
- "score": 0
409
- }
410
 
411
- # ==================== DATABASE SETUP ====================
412
  class ThreadLocal(threading.local):
413
  def __init__(self):
414
  self.connections = {}
@@ -416,679 +134,309 @@ class ThreadLocal(threading.local):
416
  thread_local = ThreadLocal()
417
 
418
  def get_db_connection(db_name="questions"):
419
- """Get thread-local database connection"""
420
  if not hasattr(thread_local, 'connections'):
421
  thread_local.connections = {}
422
 
423
  if db_name not in thread_local.connections:
424
- db_dir = "/tmp/database"
425
- os.makedirs(db_dir, exist_ok=True)
426
-
427
- conn = sqlite3.connect(
428
- os.path.join(db_dir, f"{db_name}.db"),
429
- check_same_thread=False
430
- )
431
  thread_local.connections[db_name] = conn
432
 
433
  return thread_local.connections[db_name]
434
 
435
  def init_databases():
436
- """Initialize all databases"""
437
- # Questions database
438
- q_conn = get_db_connection("questions")
439
- q_cur = q_conn.cursor()
440
-
441
- q_cur.execute('''
442
  CREATE TABLE IF NOT EXISTS questions (
443
  id INTEGER PRIMARY KEY AUTOINCREMENT,
444
  subject TEXT,
445
  topic TEXT,
446
  question_text TEXT,
447
- question_type TEXT,
448
- difficulty INTEGER DEFAULT 3,
449
- options TEXT,
450
  correct_answer TEXT,
451
- explanation TEXT,
452
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
453
  )
454
  ''')
455
 
456
- # Student database
457
- s_conn = get_db_connection("students")
458
- s_cur = s_conn.cursor()
459
-
460
- s_cur.execute('''
461
  CREATE TABLE IF NOT EXISTS student_progress (
462
  id INTEGER PRIMARY KEY AUTOINCREMENT,
463
- student_id TEXT DEFAULT 'student_001',
464
  question_id INTEGER,
465
  student_answer TEXT,
466
  correct BOOLEAN,
467
  score REAL,
468
- feedback TEXT,
469
- topic TEXT,
470
- difficulty INTEGER,
471
- date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
472
  )
473
  ''')
474
 
475
- s_cur.execute('''
476
  CREATE TABLE IF NOT EXISTS student_stats (
477
  student_id TEXT PRIMARY KEY,
478
  total_questions INTEGER DEFAULT 0,
479
  correct_answers INTEGER DEFAULT 0,
480
  total_score REAL DEFAULT 0,
481
- current_streak INTEGER DEFAULT 0,
482
- best_streak INTEGER DEFAULT 0,
483
- level INTEGER DEFAULT 1,
484
- last_active TIMESTAMP DEFAULT CURRENT_TIMESTAMP
485
  )
486
  ''')
487
 
488
- # Add sample questions if empty
489
- q_cur.execute("SELECT COUNT(*) FROM questions")
490
- if q_cur.fetchone()[0] == 0:
491
- add_sample_questions()
492
-
493
- s_conn.commit()
494
- q_conn.commit()
495
-
496
- def add_sample_questions():
497
- """Add sample questions to database"""
498
- conn = get_db_connection("questions")
499
- cur = conn.cursor()
500
-
501
- sample_questions = [
502
- ("Mathematics", "Fractions", "Simplify 12/16", "Short Answer", 2, None, "3/4", "Divide numerator and denominator by 4"),
503
- ("Mathematics", "Geometry", "Find the area of a rectangle with length 8cm and width 5cm", "Short Answer", 2, None, "40 cm²", "Area = length × width = 8 × 5"),
504
- ("English", "Grammar", "Correct: He go to school every day", "Short Answer", 1, None, "He goes to school every day", "Use 'goes' for third person singular"),
505
- ("English", "Vocabulary", "What is a synonym for happy?", "Short Answer", 1, None, "joyful", "Synonyms are words with similar meanings"),
506
- ("Mathematics", "Percentages", "What is 20% of 50?", "Short Answer", 2, None, "10", "20% of 50 = 0.20 × 50 = 10")
507
- ]
508
-
509
- for q in sample_questions:
510
- cur.execute('''
511
- INSERT INTO questions (subject, topic, question_text, question_type, difficulty, options, correct_answer, explanation)
512
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
513
- ''', q)
514
-
515
  conn.commit()
516
 
517
- # ==================== MAIN TUTOR ENGINE ====================
518
  class SEAITutor:
519
  def __init__(self):
520
- self.free_ai = FreeAITutor()
521
  init_databases()
522
- print("🤖 FREE SEA AI Tutor Initialized - No API Keys Needed!")
523
 
524
  self.subjects = {
525
  "Mathematics": {
526
- "icon": "📐",
527
- "topics": ["Fractions", "Decimals", "Percentages", "Geometry", "Algebra", "Measurement", "Word Problems"],
528
- "description": "Practice SEA-level math problems"
529
  },
530
  "English": {
531
- "icon": "📚",
532
- "topics": ["Grammar", "Vocabulary", "Comprehension", "Writing", "Spelling", "Punctuation"],
533
- "description": "Improve English language skills"
534
  }
535
  }
536
 
537
  self.difficulty_levels = {
538
- 1: {"label": "Beginner", "color": "#4CAF50"},
539
- 2: {"label": "Easy", "color": "#8BC34A"},
540
- 3: {"label": "Medium", "color": "#FFC107"},
541
- 4: {"label": "Hard", "color": "#FF9800"},
542
- 5: {"label": "Expert", "color": "#F44336"}
543
  }
544
 
545
  self.student_id = "student_001"
546
 
547
- def generate_question(self, subject, topic, difficulty=3):
548
  """Generate a new question"""
549
- try:
550
- if subject == "Mathematics":
551
- question, answer = self.free_ai.generate_math_question(topic, difficulty)
552
- else:
553
- question, answer = self.free_ai.generate_english_question(topic, difficulty)
554
-
555
- # Store in database
556
- conn = get_db_connection("questions")
557
- cursor = conn.cursor()
558
- cursor.execute('''
559
- INSERT INTO questions
560
- (subject, topic, question_text, question_type, difficulty, correct_answer, explanation)
561
- VALUES (?, ?, ?, ?, ?, ?, ?)
562
- ''', (subject, topic, question, "Generated", difficulty, answer, f"Practice {topic} concepts."))
563
-
564
- question_id = cursor.lastrowid
565
- conn.commit()
566
-
567
- return {
568
- "id": question_id,
569
- "subject": subject,
570
- "topic": topic,
571
- "text": question,
572
- "difficulty": difficulty,
573
- "difficulty_label": self.difficulty_levels.get(difficulty, {}).get("label", "Medium"),
574
- "correct_answer": answer,
575
- "explanation": f"Practice {topic} to improve your skills."
576
- }
577
-
578
- except Exception as e:
579
- print(f"Error generating question: {e}")
580
- # Return a fallback question
581
- return {
582
- "id": None,
583
- "subject": subject,
584
- "topic": topic,
585
- "text": f"What is an example of a {topic.lower()} question in {subject}?",
586
- "difficulty": difficulty,
587
- "difficulty_label": self.difficulty_levels.get(difficulty, {}).get("label", "Medium"),
588
- "correct_answer": "Practice this topic regularly.",
589
- "explanation": "Keep practicing to improve!"
590
- }
591
 
592
  def submit_answer(self, question_id, student_answer):
593
- """Submit and evaluate an answer"""
594
- try:
595
- # Get question from database
596
- conn = get_db_connection("questions")
597
- cursor = conn.cursor()
598
- cursor.execute('''
599
- SELECT question_text, correct_answer, explanation, topic, difficulty
600
- FROM questions WHERE id = ?
601
- ''', (question_id,))
602
-
603
- result = cursor.fetchone()
604
- if not result:
605
- return {
606
- "correct": False,
607
- "feedback": "Question not found.",
608
- "score": 0,
609
- "correct_answer": ""
610
- }
611
-
612
- question_text, correct_answer, explanation, topic, difficulty = result
613
-
614
- # Evaluate using free AI
615
- evaluation = self.free_ai.evaluate_answer(student_answer, correct_answer, question_text)
616
-
617
- # Record progress
618
- self._record_progress(question_id, student_answer, evaluation["correct"],
619
- evaluation["score"], evaluation["feedback"], topic, difficulty)
620
-
621
- return {
622
- "correct": evaluation["correct"],
623
- "feedback": evaluation["feedback"],
624
- "score": evaluation["score"],
625
- "correct_answer": correct_answer,
626
- "explanation": explanation
627
- }
628
-
629
- except Exception as e:
630
- print(f"Error submitting answer: {e}")
631
- return {
632
- "correct": False,
633
- "feedback": "Error processing answer. Please try again.",
634
- "score": 0,
635
- "correct_answer": "",
636
- "explanation": ""
637
- }
638
-
639
- def _record_progress(self, question_id, student_answer, correct, score, feedback, topic, difficulty):
640
- """Record student progress"""
641
- conn = get_db_connection("students")
642
- cursor = conn.cursor()
643
 
644
- # Record answer
645
- cursor.execute('''
646
- INSERT INTO student_progress
647
- (student_id, question_id, student_answer, correct, score, feedback, topic, difficulty)
648
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
649
- ''', (self.student_id, question_id, student_answer, correct, score, feedback, topic, difficulty))
 
 
 
 
650
 
651
  # Update stats
652
- cursor.execute('''
653
- INSERT OR REPLACE INTO student_stats
654
- (student_id, total_questions, correct_answers, total_score, last_active)
655
  VALUES (?,
656
  COALESCE((SELECT total_questions FROM student_stats WHERE student_id = ?), 0) + 1,
657
  COALESCE((SELECT correct_answers FROM student_stats WHERE student_id = ?), 0) + ?,
658
- COALESCE((SELECT total_score FROM student_stats WHERE student_id = ?), 0) + ?,
659
- CURRENT_TIMESTAMP
660
  )
661
- ''', (self.student_id, self.student_id, self.student_id, 1 if correct else 0,
662
- self.student_id, score))
663
-
664
- # Update streak
665
- if correct:
666
- cursor.execute('''
667
- UPDATE student_stats
668
- SET current_streak = COALESCE(current_streak, 0) + 1,
669
- best_streak = MAX(best_streak, COALESCE(current_streak, 0) + 1)
670
- WHERE student_id = ?
671
- ''', (self.student_id,))
672
- else:
673
- cursor.execute('''
674
- UPDATE student_stats SET current_streak = 0 WHERE student_id = ?
675
- ''', (self.student_id,))
676
-
677
- # Update level based on total score
678
- cursor.execute('''
679
- UPDATE student_stats
680
- SET level = CAST(total_score / 100 AS INTEGER) + 1
681
- WHERE student_id = ? AND level < CAST(total_score / 100 AS INTEGER) + 1
682
- ''', (self.student_id,))
683
 
684
  conn.commit()
 
 
685
 
686
- def get_student_stats(self):
687
  """Get student statistics"""
688
  conn = get_db_connection("students")
689
- cursor = conn.cursor()
690
-
691
- cursor.execute('''
692
- SELECT total_questions, correct_answers, total_score, current_streak, best_streak, level
693
  FROM student_stats WHERE student_id = ?
694
  ''', (self.student_id,))
695
 
696
- row = cursor.fetchone()
697
  if not row:
698
- return {
699
- "total_questions": 0,
700
- "correct_answers": 0,
701
- "accuracy": 0,
702
- "total_score": 0,
703
- "current_streak": 0,
704
- "best_streak": 0,
705
- "level": 1,
706
- "level_progress": 0
707
- }
708
 
709
- total, correct, total_score, streak, best_streak, level = row
710
  accuracy = (correct / total * 100) if total > 0 else 0
711
- level_progress = (total_score % 100)
712
-
713
- # Get topic performance
714
- cursor.execute('''
715
- SELECT topic,
716
- COUNT(*) as total,
717
- AVG(score) as avg_score
718
- FROM student_progress
719
- WHERE student_id = ?
720
- GROUP BY topic
721
- ORDER BY avg_score ASC
722
- LIMIT 3
723
- ''', (self.student_id,))
724
-
725
- weak_topics = []
726
- for topic, total_q, avg_score in cursor.fetchall():
727
- weak_topics.append({
728
- "topic": topic,
729
- "accuracy": round((avg_score or 0) * 100, 1),
730
- "total": total_q
731
- })
732
 
733
  return {
734
  "total_questions": total,
735
  "correct_answers": correct,
736
  "accuracy": round(accuracy, 1),
737
- "total_score": round(total_score, 1),
738
- "current_streak": streak,
739
- "best_streak": best_streak,
740
- "level": level,
741
- "level_progress": level_progress,
742
- "weak_topics": weak_topics
743
  }
744
-
745
- def get_random_tip(self):
746
- """Get random study tip"""
747
- tips = [
748
- "🎯 Study a little every day instead of cramming before exams.",
749
- "📝 Practice past SEA exam papers regularly.",
750
- "⏰ Take short breaks during study sessions to stay focused.",
751
- "📚 Review your mistakes to learn from them.",
752
- "🧮 For math, show all your working steps.",
753
- "📖 Read every day to improve vocabulary and comprehension.",
754
- "✅ Check your work before submitting answers.",
755
- "🎨 Use colors and diagrams to remember concepts.",
756
- "🤔 Ask questions when you don't understand something.",
757
- "🎵 Study in a quiet place without distractions."
758
- ]
759
- return random.choice(tips)
760
-
761
- def get_leaderboard(self):
762
- """Get leaderboard data (simulated for demo)"""
763
- return [
764
- {"rank": 1, "name": "Aaliyah", "score": 1250, "level": 13},
765
- {"rank": 2, "name": "Brandon", "score": 1180, "level": 12},
766
- {"rank": 3, "name": "Chelsea", "score": 1050, "level": 11},
767
- {"rank": 4, "name": "David", "score": 980, "level": 10},
768
- {"rank": 5, "name": "Emily", "score": 920, "level": 10}
769
- ]
770
 
771
- # Initialize tutor
772
- ai_tutor = SEAITutor()
773
 
774
  # ==================== GRADIO UI ====================
775
- def create_app():
776
- """Create the Gradio interface"""
777
-
778
  with gr.Blocks(
779
- title="🤖 FREE SEA Prep AI Tutor | Trinidad & Tobago",
780
- theme=gr.themes.Soft(
781
- primary_hue="blue",
782
- secondary_hue="green"
783
- ),
784
- css="""
785
- .gradio-container {
786
- max-width: 1200px !important;
787
- margin: 0 auto;
788
- }
789
- .header {
790
- text-align: center;
791
- padding: 20px;
792
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
793
- color: white;
794
- border-radius: 10px;
795
- margin-bottom: 20px;
796
- }
797
- .free-badge {
798
- background: #4CAF50;
799
- color: white;
800
- padding: 5px 15px;
801
- border-radius: 20px;
802
- font-weight: bold;
803
- display: inline-block;
804
- margin: 5px;
805
- }
806
- .question-card {
807
- background: #f8f9fa;
808
- padding: 20px;
809
- border-radius: 10px;
810
- border-left: 5px solid #2196F3;
811
- margin: 15px 0;
812
- }
813
- .feedback-correct {
814
- background: #d4edda;
815
- padding: 15px;
816
- border-radius: 10px;
817
- border-left: 5px solid #28a745;
818
- }
819
- .feedback-incorrect {
820
- background: #f8d7da;
821
- padding: 15px;
822
- border-radius: 10px;
823
- border-left: 5px solid #dc3545;
824
- }
825
- .stat-card {
826
- text-align: center;
827
- padding: 15px;
828
- background: white;
829
- border-radius: 10px;
830
- box-shadow: 0 2px 10px rgba(0,0,0,0.1);
831
- margin: 10px 0;
832
- }
833
- .stat-value {
834
- font-size: 2em;
835
- font-weight: bold;
836
- color: #2196F3;
837
- }
838
- .tip-box {
839
- background: #e3f2fd;
840
- padding: 15px;
841
- border-radius: 10px;
842
- font-style: italic;
843
- margin: 10px 0;
844
- }
845
- """
846
  ) as demo:
847
 
848
  # Header
849
  gr.Markdown("""
850
- <div class="header">
851
- <h1>🤖 FREE SEA Prep AI Tutor 🇹🇹</h1>
852
- <h3>100% Free AI-Powered Secondary Entrance Assessment Preparation</h3>
853
- <span class="free-badge">NO API KEYS REQUIRED</span>
854
- <span class="free-badge">COMPLETELY FREE</span>
855
- <span class="free-badge">LOCAL PROCESSING</span>
856
- <p>Practice Mathematics and English questions for Trinidad & Tobago SEA exams</p>
857
- </div>
858
  """)
859
 
860
- # Main content
861
  with gr.Tabs():
862
- # Practice Tab
863
  with gr.TabItem("🎯 Practice"):
864
  with gr.Row():
865
  with gr.Column(scale=1):
866
- gr.Markdown("### 📝 Question Settings")
867
  subject = gr.Dropdown(
868
- choices=list(ai_tutor.subjects.keys()),
869
- label="Select Subject",
870
- value="Mathematics"
871
  )
872
  topic = gr.Dropdown(
873
- choices=ai_tutor.subjects["Mathematics"]["topics"],
874
- label="Select Topic",
875
- value="Fractions"
876
  )
877
  difficulty = gr.Slider(
878
- minimum=1, maximum=5, value=3, step=1,
879
  label="Difficulty Level"
880
  )
881
 
882
- # Update topics when subject changes
883
- def update_topics(subject):
884
- topics = ai_tutor.subjects.get(subject, {}).get("topics", [])
885
- return gr.Dropdown.update(choices=topics, value=topics[0] if topics else "")
886
-
887
- subject.change(update_topics, inputs=subject, outputs=topic)
888
-
889
- generate_btn = gr.Button("✨ Generate New Question", variant="primary", size="lg")
890
 
891
  gr.Markdown("---")
892
- gr.Markdown("### 📊 Quick Stats")
893
- stats_display = gr.JSON(label="Your Statistics")
894
- refresh_stats = gr.Button("🔄 Refresh Stats")
895
-
896
  with gr.Column(scale=2):
897
- gr.Markdown("### Your Question")
898
- question_text = gr.Markdown("", elem_classes="question-card")
899
-
900
- gr.Markdown("### ✏️ Your Answer")
901
- answer_input = gr.Textbox(
902
- label="Type your answer here:",
903
- placeholder="Enter your answer...",
904
- lines=3
905
- )
906
 
907
  with gr.Row():
908
  submit_btn = gr.Button("✅ Submit Answer", variant="primary")
909
- clear_btn = gr.Button("🗑️ Clear Answer")
910
 
911
- gr.Markdown("### 💬 Feedback")
912
- feedback_display = gr.Markdown("")
913
-
914
- gr.Markdown("### 📖 Explanation")
915
- explanation_display = gr.Markdown("")
916
 
917
- # Progress Tab
918
  with gr.TabItem("📈 Progress"):
919
- with gr.Row():
920
- with gr.Column():
921
- gr.Markdown("### 📊 Your Progress")
922
- progress_stats = gr.JSON(label="Detailed Statistics")
923
-
924
- gr.Markdown("### 🎯 Recommendations")
925
- recommendations = gr.Markdown("")
926
-
927
- with gr.Column():
928
- gr.Markdown("### 🏆 Leaderboard")
929
- leaderboard = gr.Dataframe(
930
- value=ai_tutor.get_leaderboard(),
931
- headers=["Rank", "Name", "Score", "Level"],
932
- interactive=False
933
- )
934
-
935
- gr.Markdown("### 💡 Study Tip")
936
- tip_display = gr.Markdown("")
937
- new_tip_btn = gr.Button("🎲 New Tip")
938
 
939
- # About Tab
940
  with gr.TabItem("ℹ️ About"):
941
  gr.Markdown("""
942
  ## About SEA Prep Pro
943
 
944
- **SEA Prep Pro** is a completely free AI-powered tutoring system designed specifically for
945
- Trinidad and Tobago students preparing for the Secondary Entrance Assessment (SEA) exam.
946
 
947
- ### 🎯 Features:
948
- - **100% Free** - No subscriptions, no API keys required
949
- - **AI-Powered** - Smart question generation and evaluation
950
- - **Adaptive Learning** - Questions adjust to your skill level
951
- - **Progress Tracking** - Monitor your improvement over time
952
- - **Trinidad & Tobago Focus** - Contextually relevant content
953
 
954
- ### 📚 Subjects Covered:
955
- - **Mathematics**: Fractions, Geometry, Algebra, Word Problems
956
- - **English**: Grammar, Vocabulary, Comprehension, Writing
957
 
958
- ### 🚀 How It Works:
959
  1. Select a subject and topic
960
- 2. Choose difficulty level (1-5)
961
- 3. Generate practice questions
962
- 4. Submit answers for instant feedback
963
- 5. Track your progress and improve!
964
-
965
- ### 💝 Why It's Free:
966
- This project was created to provide equal access to quality educational resources
967
- for all Trinidad and Tobago students, regardless of their financial situation.
968
 
969
- ### 👨‍💻 Developer:
970
- Created with ❤️ for Trinidad and Tobago students
971
-
972
- ***
973
-
974
- <center>
975
- <span class="free-badge">EDUCATION FOR ALL</span>
976
- <span class="free-badge">MADE IN TRINIDAD & TOBAGO</span>
977
- <span class="free-badge">OPEN SOURCE</span>
978
- </center>
979
  """)
980
 
981
- # State variables
982
- current_question = gr.State({"id": None})
983
 
984
- # Generate question function
985
- def generate_q(subject_val, topic_val, difficulty_val):
986
- question = ai_tutor.generate_question(subject_val, topic_val, difficulty_val)
987
-
 
 
 
988
  display = f"""
989
- **Subject:** {question['subject']}
990
- **Topic:** {question['topic']}
991
- **Difficulty:** {question['difficulty_label']} ({question['difficulty']}/5)
992
 
993
  ---
994
 
995
  **Question:**
996
- {question['text']}
997
  """
998
-
999
- return display, question, "", ""
1000
 
1001
- # Submit answer function
1002
- def submit_a(answer, question_state):
1003
- if not question_state or not question_state.get("id"):
1004
- return "Please generate a question first!", "", question_state
1005
-
1006
- result = ai_tutor.submit_answer(question_state["id"], answer)
1007
 
1008
- feedback_class = "feedback-correct" if result["correct"] else "feedback-incorrect"
1009
- feedback = f"""
1010
- <div class='{feedback_class}'>
1011
- **Result:** {result['feedback']}
1012
- **Score:** {result['score']:.1%}
1013
- **Correct Answer:** {result['correct_answer']}
1014
- </div>
1015
- """
1016
-
1017
- explanation = f"**Explanation:** {result['explanation']}"
1018
-
1019
- return feedback, explanation, question_state
1020
 
1021
- # Get stats function
1022
  def get_stats_func():
1023
- stats = ai_tutor.get_student_stats()
1024
- return stats
1025
-
1026
- # Get tip function
1027
- def get_tip():
1028
- return ai_tutor.get_random_tip()
1029
-
1030
- # Get recommendations
1031
- def get_recommendations():
1032
- stats = ai_tutor.get_student_stats()
1033
- if stats["weak_topics"]:
1034
- topic = stats["weak_topics"][0]["topic"]
1035
- return f"**Focus on:** {topic} \n**Reason:** Lower accuracy in this area \n**Action:** Practice 5-10 {topic} questions daily"
1036
- else:
1037
- return "**Great job!** Keep practicing all topics to maintain your skills."
1038
 
1039
- # Clear answer function
1040
- def clear_answer():
1041
  return "", ""
1042
 
1043
  # Event handlers
1044
- generate_btn.click(
1045
- generate_q,
1046
- inputs=[subject, topic, difficulty],
1047
- outputs=[question_text, current_question, feedback_display, explanation_display]
1048
- )
1049
-
1050
- submit_btn.click(
1051
- submit_a,
1052
- inputs=[answer_input, current_question],
1053
- outputs=[feedback_display, explanation_display, current_question]
1054
- )
1055
-
1056
- refresh_stats.click(
1057
- get_stats_func,
1058
- outputs=stats_display
1059
- )
1060
-
1061
- clear_btn.click(
1062
- clear_answer,
1063
- outputs=[answer_input, feedback_display]
1064
- )
1065
-
1066
- # Progress tab functions
1067
- demo.load(
1068
- lambda: [get_stats_func(), get_recommendations(), get_tip()],
1069
- outputs=[progress_stats, recommendations, tip_display]
1070
- )
1071
-
1072
- new_tip_btn.click(
1073
- get_tip,
1074
- outputs=tip_display
1075
- )
1076
 
1077
  # Initialize
1078
- demo.load(
1079
- get_stats_func,
1080
- outputs=stats_display
1081
- )
1082
 
1083
  return demo
1084
 
1085
- # Create and launch app
1086
  if __name__ == "__main__":
1087
- app = create_app()
1088
- app.launch(
1089
- server_name="0.0.0.0",
1090
- server_port=7860,
1091
- share=False,
1092
- show_error=True,
1093
- debug=True
1094
- )
 
1
  """
2
  SEA Prep Pro - AI-Powered Tutor 🇹🇹
3
  FULLY FREE VERSION - No API Keys Required!
 
4
  """
5
  import gradio as gr
6
  import sqlite3
 
8
  import os
9
  import re
10
  import random
 
 
 
 
 
 
11
  import math
12
+ import threading
13
+ from datetime import datetime
14
 
15
+ # ==================== FREE AI TUTOR ====================
 
 
 
16
  class FreeAITutor:
17
+ """Free AI tutor using rule-based generation"""
18
 
19
  def __init__(self):
20
+ self.math_templates = {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  "Fractions": [
22
  "Simplify the fraction {num}/{den}.",
23
  "Add {a}/{b} + {c}/{d}.",
 
25
  "What is {num}/{den} of {whole}?",
26
  "Convert {decimal} to a fraction."
27
  ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  "Geometry": [
29
  "Find the area of a rectangle with length {l}cm and width {w}cm.",
30
  "Calculate the perimeter of a square with side {s}cm.",
31
  "Find the area of a triangle with base {b}cm and height {h}cm.",
32
  "Calculate the circumference of a circle with radius {r}cm (use π=3.14).",
33
  "Find the volume of a cube with side {s}cm."
 
 
 
 
 
 
 
34
  ]
35
  }
36
 
37
+ self.english_templates = {
38
+ "Grammar": [
39
+ "Correct the sentence: '{sentence}'",
40
+ "Choose the correct word: '{sentence}'"
41
+ ],
42
+ "Vocabulary": [
43
+ "What is a synonym for '{word}'?",
44
+ "What is the antonym of '{word}'?"
45
+ ]
46
+ }
47
+
48
+ def generate_math_question(self, topic, difficulty):
49
+ """Generate math question"""
50
+ templates = self.math_templates.get(topic, ["Practice {topic}."])
51
+ template = random.choice(templates)
52
 
53
+ # Generate values based on difficulty
54
+ max_val = {1: 10, 2: 20, 3: 50, 4: 100, 5: 200}[difficulty]
 
55
 
56
  values = {
57
  'num': random.randint(1, max_val),
 
62
  'd': random.randint(2, max_val),
63
  'whole': random.randint(10, 100),
64
  'decimal': round(random.uniform(0.1, 0.9), 2),
 
 
 
 
 
65
  'l': random.randint(5, 20),
66
  'w': random.randint(3, 15),
67
  's': random.randint(4, 12),
68
  'r': random.randint(2, 10),
69
  'h': random.randint(3, 12),
70
  'b': random.randint(4, 16),
 
 
 
71
  'topic': topic
72
  }
73
 
74
  question = template.format(**values)
75
+ answer = self._calculate_answer(question, values)
 
 
76
 
77
  return question, answer
78
 
79
+ def _calculate_answer(self, question, values):
80
+ """Calculate answer for math question"""
81
  try:
82
  if "Simplify the fraction" in question:
83
  num, den = values['num'], values['den']
84
  gcd = math.gcd(num, den)
85
  return f"{num//gcd}/{den//gcd}"
86
 
 
 
 
 
 
 
 
 
87
  elif "area of a rectangle" in question:
88
  return f"{values['l'] * values['w']} cm²"
89
 
 
94
  return f"{0.5 * values['b'] * values['h']} cm²"
95
 
96
  elif "circumference of a circle" in question:
97
+ return f"{2 * 3.14 * values['r']:.2f} cm"
98
 
99
  elif "volume of a cube" in question:
100
  return f"{values['s'] ** 3} cm³"
101
 
102
+ elif "Add" in question and "/" in question:
103
+ a, b, c, d = values['a'], values['b'], values['c'], values['d']
104
+ lcm = b * d // math.gcd(b, d)
105
+ num = a * (lcm // b) + c * (lcm // d)
106
+ gcd = math.gcd(num, lcm)
107
+ return f"{num//gcd}/{lcm//gcd}"
108
 
109
  else:
110
+ return "Calculate step by step"
 
 
 
 
 
 
 
111
 
112
+ except Exception:
 
 
 
 
 
 
 
113
  return "Practice this concept"
114
 
115
+ def evaluate_answer(self, student_answer, correct_answer):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  """Evaluate student's answer"""
117
  student = str(student_answer).strip().lower()
118
  correct = str(correct_answer).strip().lower()
119
 
 
120
  if student == correct:
121
+ return {"correct": True, "score": 1.0, "feedback": "✅ Correct! Well done!"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
  # Partial credit for showing work
124
+ if len(student) > 10:
125
+ return {"correct": False, "score": 0.5, "feedback": "⚠️ Good attempt. Keep practicing!"}
 
 
 
 
 
126
 
127
+ return {"correct": False, "score": 0.0, "feedback": "❌ Incorrect. Try again!"}
 
 
 
 
 
128
 
129
+ # ==================== DATABASE ====================
130
  class ThreadLocal(threading.local):
131
  def __init__(self):
132
  self.connections = {}
 
134
  thread_local = ThreadLocal()
135
 
136
  def get_db_connection(db_name="questions"):
137
+ """Get database connection"""
138
  if not hasattr(thread_local, 'connections'):
139
  thread_local.connections = {}
140
 
141
  if db_name not in thread_local.connections:
142
+ conn = sqlite3.connect(f"/tmp/{db_name}.db", check_same_thread=False)
 
 
 
 
 
 
143
  thread_local.connections[db_name] = conn
144
 
145
  return thread_local.connections[db_name]
146
 
147
  def init_databases():
148
+ """Initialize databases"""
149
+ # Questions DB
150
+ conn = get_db_connection("questions")
151
+ cur = conn.cursor()
152
+ cur.execute('''
 
153
  CREATE TABLE IF NOT EXISTS questions (
154
  id INTEGER PRIMARY KEY AUTOINCREMENT,
155
  subject TEXT,
156
  topic TEXT,
157
  question_text TEXT,
158
+ difficulty INTEGER,
 
 
159
  correct_answer TEXT,
 
160
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
161
  )
162
  ''')
163
 
164
+ # Student DB
165
+ conn = get_db_connection("students")
166
+ cur = conn.cursor()
167
+ cur.execute('''
 
168
  CREATE TABLE IF NOT EXISTS student_progress (
169
  id INTEGER PRIMARY KEY AUTOINCREMENT,
170
+ student_id TEXT,
171
  question_id INTEGER,
172
  student_answer TEXT,
173
  correct BOOLEAN,
174
  score REAL,
175
+ timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
 
 
 
176
  )
177
  ''')
178
 
179
+ cur.execute('''
180
  CREATE TABLE IF NOT EXISTS student_stats (
181
  student_id TEXT PRIMARY KEY,
182
  total_questions INTEGER DEFAULT 0,
183
  correct_answers INTEGER DEFAULT 0,
184
  total_score REAL DEFAULT 0,
185
+ level INTEGER DEFAULT 1
 
 
 
186
  )
187
  ''')
188
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  conn.commit()
190
 
191
+ # ==================== MAIN APP ====================
192
  class SEAITutor:
193
  def __init__(self):
194
+ self.ai = FreeAITutor()
195
  init_databases()
196
+ print("🚀 SEA Prep Pro - Free AI Tutor Started!")
197
 
198
  self.subjects = {
199
  "Mathematics": {
200
+ "topics": ["Fractions", "Geometry", "Algebra", "Word Problems", "Percentages"],
201
+ "icon": "📐"
 
202
  },
203
  "English": {
204
+ "topics": ["Grammar", "Vocabulary", "Comprehension", "Writing"],
205
+ "icon": "📚"
 
206
  }
207
  }
208
 
209
  self.difficulty_levels = {
210
+ 1: "Beginner", 2: "Easy", 3: "Medium", 4: "Hard", 5: "Expert"
 
 
 
 
211
  }
212
 
213
  self.student_id = "student_001"
214
 
215
+ def generate_question(self, subject, topic, difficulty):
216
  """Generate a new question"""
217
+ if subject == "Mathematics":
218
+ question, answer = self.ai.generate_math_question(topic, difficulty)
219
+ else:
220
+ question = f"Practice {topic} in {subject}. Write your answer below."
221
+ answer = "Sample answer for practice."
222
+
223
+ # Store in DB
224
+ conn = get_db_connection("questions")
225
+ cur = conn.cursor()
226
+ cur.execute('''
227
+ INSERT INTO questions (subject, topic, question_text, difficulty, correct_answer)
228
+ VALUES (?, ?, ?, ?, ?)
229
+ ''', (subject, topic, question, difficulty, answer))
230
+
231
+ question_id = cur.lastrowid
232
+ conn.commit()
233
+
234
+ return {
235
+ "id": question_id,
236
+ "text": question,
237
+ "subject": subject,
238
+ "topic": topic,
239
+ "difficulty": self.difficulty_levels.get(difficulty, "Medium")
240
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
 
242
  def submit_answer(self, question_id, student_answer):
243
+ """Submit and evaluate answer"""
244
+ # Get question
245
+ conn = get_db_connection("questions")
246
+ cur = conn.cursor()
247
+ cur.execute('SELECT correct_answer FROM questions WHERE id = ?', (question_id,))
248
+ row = cur.fetchone()
249
+
250
+ if not row:
251
+ return {"feedback": "Question not found.", "score": 0}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
 
253
+ correct_answer = row[0]
254
+ evaluation = self.ai.evaluate_answer(student_answer, correct_answer)
255
+
256
+ # Record progress
257
+ conn = get_db_connection("students")
258
+ cur = conn.cursor()
259
+ cur.execute('''
260
+ INSERT INTO student_progress (student_id, question_id, student_answer, correct, score)
261
+ VALUES (?, ?, ?, ?, ?)
262
+ ''', (self.student_id, question_id, student_answer, evaluation["correct"], evaluation["score"]))
263
 
264
  # Update stats
265
+ cur.execute('''
266
+ INSERT OR REPLACE INTO student_stats (student_id, total_questions, correct_answers, total_score)
 
267
  VALUES (?,
268
  COALESCE((SELECT total_questions FROM student_stats WHERE student_id = ?), 0) + 1,
269
  COALESCE((SELECT correct_answers FROM student_stats WHERE student_id = ?), 0) + ?,
270
+ COALESCE((SELECT total_score FROM student_stats WHERE student_id = ?), 0) + ?
 
271
  )
272
+ ''', (self.student_id, self.student_id, self.student_id,
273
+ 1 if evaluation["correct"] else 0, self.student_id, evaluation["score"]))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
 
275
  conn.commit()
276
+
277
+ return evaluation
278
 
279
+ def get_stats(self):
280
  """Get student statistics"""
281
  conn = get_db_connection("students")
282
+ cur = conn.cursor()
283
+ cur.execute('''
284
+ SELECT total_questions, correct_answers, total_score, level
 
285
  FROM student_stats WHERE student_id = ?
286
  ''', (self.student_id,))
287
 
288
+ row = cur.fetchone()
289
  if not row:
290
+ return {"total_questions": 0, "correct_answers": 0, "accuracy": 0, "level": 1}
 
 
 
 
 
 
 
 
 
291
 
292
+ total, correct, score, level = row
293
  accuracy = (correct / total * 100) if total > 0 else 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
 
295
  return {
296
  "total_questions": total,
297
  "correct_answers": correct,
298
  "accuracy": round(accuracy, 1),
299
+ "total_score": round(score, 1),
300
+ "level": level
 
 
 
 
301
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302
 
303
+ # Initialize
304
+ tutor = SEAITutor()
305
 
306
  # ==================== GRADIO UI ====================
307
+ def create_ui():
 
 
308
  with gr.Blocks(
309
+ title="SEA Prep Pro - Free AI Tutor 🇹🇹",
310
+ theme=gr.themes.Soft(primary_hue="blue", secondary_hue="purple")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
  ) as demo:
312
 
313
  # Header
314
  gr.Markdown("""
315
+ # 🤖 SEA Prep Pro - Free AI Tutor 🇹🇹
316
+ ### 100% Free No API Keys • Trinidad & Tobago SEA Exam Preparation
 
 
 
 
 
 
317
  """)
318
 
 
319
  with gr.Tabs():
 
320
  with gr.TabItem("🎯 Practice"):
321
  with gr.Row():
322
  with gr.Column(scale=1):
 
323
  subject = gr.Dropdown(
324
+ choices=["Mathematics", "English"],
325
+ value="Mathematics",
326
+ label="Subject"
327
  )
328
  topic = gr.Dropdown(
329
+ choices=tutor.subjects["Mathematics"]["topics"],
330
+ value="Fractions",
331
+ label="Topic"
332
  )
333
  difficulty = gr.Slider(
334
+ 1, 5, value=3, step=1,
335
  label="Difficulty Level"
336
  )
337
 
338
+ generate_btn = gr.Button("✨ Generate Question", variant="primary")
 
 
 
 
 
 
 
339
 
340
  gr.Markdown("---")
341
+ stats = gr.JSON(label="📊 Your Stats")
342
+ refresh_btn = gr.Button("🔄 Refresh Stats")
343
+
 
344
  with gr.Column(scale=2):
345
+ question_display = gr.Markdown("### Your question will appear here")
346
+ answer_input = gr.Textbox(label="Your Answer", lines=3)
 
 
 
 
 
 
 
347
 
348
  with gr.Row():
349
  submit_btn = gr.Button("✅ Submit Answer", variant="primary")
350
+ clear_btn = gr.Button("🗑️ Clear")
351
 
352
+ feedback = gr.Markdown("### 💬 Feedback")
 
 
 
 
353
 
 
354
  with gr.TabItem("📈 Progress"):
355
+ gr.Markdown("### Your Learning Journey")
356
+ progress_stats = gr.JSON()
357
+ gr.Markdown("### 🎯 Tips for Success")
358
+ gr.Markdown("""
359
+ - Practice regularly
360
+ - Review your mistakes
361
+ - Ask for help when needed
362
+ - Stay consistent
363
+ """)
 
 
 
 
 
 
 
 
 
 
364
 
 
365
  with gr.TabItem("ℹ️ About"):
366
  gr.Markdown("""
367
  ## About SEA Prep Pro
368
 
369
+ **SEA Prep Pro** is a completely free AI-powered tutoring system for Trinidad and Tobago students.
 
370
 
371
+ ### Features:
372
+ - 100% Free - No payments ever
373
+ - 🔒 No API Keys Required
374
+ - 🤖 Smart Question Generation
375
+ - 📊 Progress Tracking
376
+ - 🇹🇹 Trinidad & Tobago Focus
377
 
378
+ ### Subjects:
379
+ - **Mathematics**: Fractions, Geometry, Algebra
380
+ - **English**: Grammar, Vocabulary, Comprehension
381
 
382
+ ### How to Use:
383
  1. Select a subject and topic
384
+ 2. Choose difficulty level
385
+ 3. Generate questions
386
+ 4. Submit answers
387
+ 5. Track your progress
 
 
 
 
388
 
389
+ **Made with ❤️ for Trinidad and Tobago students**
 
 
 
 
 
 
 
 
 
390
  """)
391
 
392
+ # State
393
+ current_q = gr.State()
394
 
395
+ # Functions
396
+ def update_topics(subject):
397
+ topics = tutor.subjects.get(subject, {}).get("topics", [])
398
+ return gr.Dropdown.update(choices=topics, value=topics[0] if topics else "")
399
+
400
+ def generate(subject, topic, difficulty):
401
+ q = tutor.generate_question(subject, topic, difficulty)
402
  display = f"""
403
+ **Subject:** {q['subject']}
404
+ **Topic:** {q['topic']}
405
+ **Difficulty:** {q['difficulty']}
406
 
407
  ---
408
 
409
  **Question:**
410
+ {q['text']}
411
  """
412
+ return display, q, ""
 
413
 
414
+ def submit(answer, question):
415
+ if not question:
416
+ return "Please generate a question first!", question
 
 
 
417
 
418
+ result = tutor.submit_answer(question["id"], answer)
419
+ return f"**{result['feedback']}** \n**Score:** {result['score']:.1%}", question
 
 
 
 
 
 
 
 
 
 
420
 
 
421
  def get_stats_func():
422
+ return tutor.get_stats()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
423
 
424
+ def clear():
 
425
  return "", ""
426
 
427
  # Event handlers
428
+ subject.change(update_topics, subject, topic)
429
+ generate_btn.click(generate, [subject, topic, difficulty], [question_display, current_q, feedback])
430
+ submit_btn.click(submit, [answer_input, current_q], [feedback, current_q])
431
+ refresh_btn.click(get_stats_func, outputs=stats)
432
+ clear_btn.click(clear, outputs=[answer_input, feedback])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
433
 
434
  # Initialize
435
+ demo.load(get_stats_func, outputs=stats)
 
 
 
436
 
437
  return demo
438
 
439
+ # Launch
440
  if __name__ == "__main__":
441
+ app = create_ui()
442
+ app.launch(debug=True)