Spaces:
Configuration error
Configuration error
| """ | |
| SEA Prep Pro - AI-Powered Tutor ๐น๐น | |
| FULLY FREE VERSION - No API Keys Required! | |
| """ | |
| import gradio as gr | |
| import sqlite3 | |
| import json | |
| import os | |
| import re | |
| import random | |
| import math | |
| import threading | |
| from datetime import datetime | |
| # ==================== FREE AI TUTOR ==================== | |
| class FreeAITutor: | |
| """Free AI tutor using rule-based generation""" | |
| def __init__(self): | |
| self.math_templates = { | |
| "Fractions": [ | |
| "Simplify the fraction {num}/{den}.", | |
| "Add {a}/{b} + {c}/{d}.", | |
| "Subtract {a}/{b} - {c}/{d}.", | |
| "What is {num}/{den} of {whole}?", | |
| "Convert {decimal} to a fraction." | |
| ], | |
| "Geometry": [ | |
| "Find the area of a rectangle with length {l}cm and width {w}cm.", | |
| "Calculate the perimeter of a square with side {s}cm.", | |
| "Find the area of a triangle with base {b}cm and height {h}cm.", | |
| "Calculate the circumference of a circle with radius {r}cm (use ฯ=3.14).", | |
| "Find the volume of a cube with side {s}cm." | |
| ] | |
| } | |
| self.english_templates = { | |
| "Grammar": [ | |
| "Correct the sentence: '{sentence}'", | |
| "Choose the correct word: '{sentence}'" | |
| ], | |
| "Vocabulary": [ | |
| "What is a synonym for '{word}'?", | |
| "What is the antonym of '{word}'?" | |
| ] | |
| } | |
| def generate_math_question(self, topic, difficulty): | |
| """Generate math question""" | |
| templates = self.math_templates.get(topic, ["Practice {topic}."]) | |
| template = random.choice(templates) | |
| # Generate values based on difficulty | |
| max_val = {1: 10, 2: 20, 3: 50, 4: 100, 5: 200}[difficulty] | |
| values = { | |
| 'num': random.randint(1, max_val), | |
| 'den': random.randint(2, max_val), | |
| 'a': random.randint(1, max_val), | |
| 'b': random.randint(2, max_val), | |
| 'c': random.randint(1, max_val), | |
| 'd': random.randint(2, max_val), | |
| 'whole': random.randint(10, 100), | |
| 'decimal': round(random.uniform(0.1, 0.9), 2), | |
| 'l': random.randint(5, 20), | |
| 'w': random.randint(3, 15), | |
| 's': random.randint(4, 12), | |
| 'r': random.randint(2, 10), | |
| 'h': random.randint(3, 12), | |
| 'b': random.randint(4, 16), | |
| 'topic': topic | |
| } | |
| question = template.format(**values) | |
| answer = self._calculate_answer(question, values) | |
| return question, answer | |
| def _calculate_answer(self, question, values): | |
| """Calculate answer for math question""" | |
| try: | |
| if "Simplify the fraction" in question: | |
| num, den = values['num'], values['den'] | |
| gcd = math.gcd(num, den) | |
| return f"{num//gcd}/{den//gcd}" | |
| elif "area of a rectangle" in question: | |
| return f"{values['l'] * values['w']} cmยฒ" | |
| elif "perimeter of a square" in question: | |
| return f"{4 * values['s']} cm" | |
| elif "area of a triangle" in question: | |
| return f"{0.5 * values['b'] * values['h']} cmยฒ" | |
| elif "circumference of a circle" in question: | |
| return f"{2 * 3.14 * values['r']:.2f} cm" | |
| elif "volume of a cube" in question: | |
| return f"{values['s'] ** 3} cmยณ" | |
| elif "Add" in question and "/" in question: | |
| a, b, c, d = values['a'], values['b'], values['c'], values['d'] | |
| lcm = b * d // math.gcd(b, d) | |
| num = a * (lcm // b) + c * (lcm // d) | |
| gcd = math.gcd(num, lcm) | |
| return f"{num//gcd}/{lcm//gcd}" | |
| else: | |
| return "Calculate step by step" | |
| except Exception: | |
| return "Practice this concept" | |
| def evaluate_answer(self, student_answer, correct_answer): | |
| """Evaluate student's answer""" | |
| student = str(student_answer).strip().lower() | |
| correct = str(correct_answer).strip().lower() | |
| if student == correct: | |
| return {"correct": True, "score": 1.0, "feedback": "โ Correct! Well done!"} | |
| # Partial credit for showing work | |
| if len(student) > 10: | |
| return {"correct": False, "score": 0.5, "feedback": "โ ๏ธ Good attempt. Keep practicing!"} | |
| return {"correct": False, "score": 0.0, "feedback": "โ Incorrect. Try again!"} | |
| # ==================== DATABASE ==================== | |
| class ThreadLocal(threading.local): | |
| def __init__(self): | |
| self.connections = {} | |
| thread_local = ThreadLocal() | |
| def get_db_connection(db_name="questions"): | |
| """Get database connection""" | |
| if not hasattr(thread_local, 'connections'): | |
| thread_local.connections = {} | |
| if db_name not in thread_local.connections: | |
| conn = sqlite3.connect(f"/tmp/{db_name}.db", check_same_thread=False) | |
| thread_local.connections[db_name] = conn | |
| return thread_local.connections[db_name] | |
| def init_databases(): | |
| """Initialize databases""" | |
| # Questions DB | |
| conn = get_db_connection("questions") | |
| cur = conn.cursor() | |
| cur.execute(''' | |
| CREATE TABLE IF NOT EXISTS questions ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| subject TEXT, | |
| topic TEXT, | |
| question_text TEXT, | |
| difficulty INTEGER, | |
| correct_answer TEXT, | |
| created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP | |
| ) | |
| ''') | |
| # Student DB | |
| conn = get_db_connection("students") | |
| cur = conn.cursor() | |
| cur.execute(''' | |
| CREATE TABLE IF NOT EXISTS student_progress ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| student_id TEXT, | |
| question_id INTEGER, | |
| student_answer TEXT, | |
| correct BOOLEAN, | |
| score REAL, | |
| timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP | |
| ) | |
| ''') | |
| cur.execute(''' | |
| CREATE TABLE IF NOT EXISTS student_stats ( | |
| student_id TEXT PRIMARY KEY, | |
| total_questions INTEGER DEFAULT 0, | |
| correct_answers INTEGER DEFAULT 0, | |
| total_score REAL DEFAULT 0, | |
| level INTEGER DEFAULT 1 | |
| ) | |
| ''') | |
| conn.commit() | |
| # ==================== MAIN APP ==================== | |
| class SEAITutor: | |
| def __init__(self): | |
| self.ai = FreeAITutor() | |
| init_databases() | |
| print("๐ SEA Prep Pro - Free AI Tutor Started!") | |
| self.subjects = { | |
| "Mathematics": { | |
| "topics": ["Fractions", "Geometry", "Algebra", "Word Problems", "Percentages"], | |
| "icon": "๐" | |
| }, | |
| "English": { | |
| "topics": ["Grammar", "Vocabulary", "Comprehension", "Writing"], | |
| "icon": "๐" | |
| } | |
| } | |
| self.difficulty_levels = { | |
| 1: "Beginner", 2: "Easy", 3: "Medium", 4: "Hard", 5: "Expert" | |
| } | |
| self.student_id = "student_001" | |
| def generate_question(self, subject, topic, difficulty): | |
| """Generate a new question""" | |
| if subject == "Mathematics": | |
| question, answer = self.ai.generate_math_question(topic, difficulty) | |
| else: | |
| question = f"Practice {topic} in {subject}. Write your answer below." | |
| answer = "Sample answer for practice." | |
| # Store in DB | |
| conn = get_db_connection("questions") | |
| cur = conn.cursor() | |
| cur.execute(''' | |
| INSERT INTO questions (subject, topic, question_text, difficulty, correct_answer) | |
| VALUES (?, ?, ?, ?, ?) | |
| ''', (subject, topic, question, difficulty, answer)) | |
| question_id = cur.lastrowid | |
| conn.commit() | |
| return { | |
| "id": question_id, | |
| "text": question, | |
| "subject": subject, | |
| "topic": topic, | |
| "difficulty": self.difficulty_levels.get(difficulty, "Medium") | |
| } | |
| def submit_answer(self, question_id, student_answer): | |
| """Submit and evaluate answer""" | |
| # Get question | |
| conn = get_db_connection("questions") | |
| cur = conn.cursor() | |
| cur.execute('SELECT correct_answer FROM questions WHERE id = ?', (question_id,)) | |
| row = cur.fetchone() | |
| if not row: | |
| return {"feedback": "Question not found.", "score": 0} | |
| correct_answer = row[0] | |
| evaluation = self.ai.evaluate_answer(student_answer, correct_answer) | |
| # Record progress | |
| conn = get_db_connection("students") | |
| cur = conn.cursor() | |
| cur.execute(''' | |
| INSERT INTO student_progress (student_id, question_id, student_answer, correct, score) | |
| VALUES (?, ?, ?, ?, ?) | |
| ''', (self.student_id, question_id, student_answer, evaluation["correct"], evaluation["score"])) | |
| # Update stats | |
| cur.execute(''' | |
| INSERT OR REPLACE INTO student_stats (student_id, total_questions, correct_answers, total_score) | |
| VALUES (?, | |
| COALESCE((SELECT total_questions FROM student_stats WHERE student_id = ?), 0) + 1, | |
| COALESCE((SELECT correct_answers FROM student_stats WHERE student_id = ?), 0) + ?, | |
| COALESCE((SELECT total_score FROM student_stats WHERE student_id = ?), 0) + ? | |
| ) | |
| ''', (self.student_id, self.student_id, self.student_id, | |
| 1 if evaluation["correct"] else 0, self.student_id, evaluation["score"])) | |
| conn.commit() | |
| return evaluation | |
| def get_stats(self): | |
| """Get student statistics""" | |
| conn = get_db_connection("students") | |
| cur = conn.cursor() | |
| cur.execute(''' | |
| SELECT total_questions, correct_answers, total_score, level | |
| FROM student_stats WHERE student_id = ? | |
| ''', (self.student_id,)) | |
| row = cur.fetchone() | |
| if not row: | |
| return {"total_questions": 0, "correct_answers": 0, "accuracy": 0, "level": 1} | |
| total, correct, score, level = row | |
| accuracy = (correct / total * 100) if total > 0 else 0 | |
| return { | |
| "total_questions": total, | |
| "correct_answers": correct, | |
| "accuracy": round(accuracy, 1), | |
| "total_score": round(score, 1), | |
| "level": level | |
| } | |
| # Initialize | |
| tutor = SEAITutor() | |
| # ==================== GRADIO UI ==================== | |
| def create_ui(): | |
| with gr.Blocks( | |
| title="SEA Prep Pro - Free AI Tutor ๐น๐น", | |
| theme=gr.themes.Soft(primary_hue="blue", secondary_hue="purple") | |
| ) as demo: | |
| # Header | |
| gr.Markdown(""" | |
| # ๐ค SEA Prep Pro - Free AI Tutor ๐น๐น | |
| ### 100% Free โข No API Keys โข Trinidad & Tobago SEA Exam Preparation | |
| """) | |
| with gr.Tabs(): | |
| with gr.TabItem("๐ฏ Practice"): | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| subject = gr.Dropdown( | |
| choices=["Mathematics", "English"], | |
| value="Mathematics", | |
| label="Subject" | |
| ) | |
| topic = gr.Dropdown( | |
| choices=tutor.subjects["Mathematics"]["topics"], | |
| value="Fractions", | |
| label="Topic" | |
| ) | |
| difficulty = gr.Slider( | |
| 1, 5, value=3, step=1, | |
| label="Difficulty Level" | |
| ) | |
| generate_btn = gr.Button("โจ Generate Question", variant="primary") | |
| gr.Markdown("---") | |
| stats = gr.JSON(label="๐ Your Stats") | |
| refresh_btn = gr.Button("๐ Refresh Stats") | |
| with gr.Column(scale=2): | |
| question_display = gr.Markdown("### Your question will appear here") | |
| answer_input = gr.Textbox(label="Your Answer", lines=3) | |
| with gr.Row(): | |
| submit_btn = gr.Button("โ Submit Answer", variant="primary") | |
| clear_btn = gr.Button("๐๏ธ Clear") | |
| feedback = gr.Markdown("### ๐ฌ Feedback") | |
| with gr.TabItem("๐ Progress"): | |
| gr.Markdown("### Your Learning Journey") | |
| progress_stats = gr.JSON() | |
| gr.Markdown("### ๐ฏ Tips for Success") | |
| gr.Markdown(""" | |
| - Practice regularly | |
| - Review your mistakes | |
| - Ask for help when needed | |
| - Stay consistent | |
| """) | |
| with gr.TabItem("โน๏ธ About"): | |
| gr.Markdown(""" | |
| ## About SEA Prep Pro | |
| **SEA Prep Pro** is a completely free AI-powered tutoring system for Trinidad and Tobago students. | |
| ### Features: | |
| - โ 100% Free - No payments ever | |
| - ๐ No API Keys Required | |
| - ๐ค Smart Question Generation | |
| - ๐ Progress Tracking | |
| - ๐น๐น Trinidad & Tobago Focus | |
| ### Subjects: | |
| - **Mathematics**: Fractions, Geometry, Algebra | |
| - **English**: Grammar, Vocabulary, Comprehension | |
| ### How to Use: | |
| 1. Select a subject and topic | |
| 2. Choose difficulty level | |
| 3. Generate questions | |
| 4. Submit answers | |
| 5. Track your progress | |
| **Made with โค๏ธ for Trinidad and Tobago students** | |
| """) | |
| # State | |
| current_q = gr.State() | |
| # Functions | |
| def update_topics(subject): | |
| topics = tutor.subjects.get(subject, {}).get("topics", []) | |
| return gr.Dropdown.update(choices=topics, value=topics[0] if topics else "") | |
| def generate(subject, topic, difficulty): | |
| q = tutor.generate_question(subject, topic, difficulty) | |
| display = f""" | |
| **Subject:** {q['subject']} | |
| **Topic:** {q['topic']} | |
| **Difficulty:** {q['difficulty']} | |
| --- | |
| **Question:** | |
| {q['text']} | |
| """ | |
| return display, q, "" | |
| def submit(answer, question): | |
| if not question: | |
| return "Please generate a question first!", question | |
| result = tutor.submit_answer(question["id"], answer) | |
| return f"**{result['feedback']}** \n**Score:** {result['score']:.1%}", question | |
| def get_stats_func(): | |
| return tutor.get_stats() | |
| def clear(): | |
| return "", "" | |
| # Event handlers | |
| subject.change(update_topics, subject, topic) | |
| generate_btn.click(generate, [subject, topic, difficulty], [question_display, current_q, feedback]) | |
| submit_btn.click(submit, [answer_input, current_q], [feedback, current_q]) | |
| refresh_btn.click(get_stats_func, outputs=stats) | |
| clear_btn.click(clear, outputs=[answer_input, feedback]) | |
| # Initialize | |
| demo.load(get_stats_func, outputs=stats) | |
| return demo | |
| # Launch | |
| if __name__ == "__main__": | |
| app = create_ui() | |
| app.launch(debug=True) |