BeastGokul/AI-Math-Olympiad-Trainer
0
1import gradio as gr2import torch3import numpy as np4import random5import pandas as pd6import matplotlib.pyplot as plt7import time8from peft import PeftModel9from transformers import AutoModelForCausalLM, AutoTokenizer10 11model_name = "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B"12model = AutoModelForCausalLM.from_pretrained(model_name)13tokenizer = AutoTokenizer.from_pretrained(model_name)14 15 16# Sample problems database (you would expand this)17sample_problems = {18 "algebra": [19 {20 "problem": "Find all positive integers n such that n^2 + 20 is divisible by n + 5.",21 "difficulty": "medium",22 "solution": "Let's denote n^2 + 20 = k(n + 5) for some integer k.\nThis gives us n^2 + 20 = kn + 5k\nn^2 - kn - 5k + 20 = 0\nn^2 - kn = 5k - 20\nWe need to find values of n such that n^2 - kn = 5k - 20 has solutions.\nRearranging, we get n(n - k) = 5k - 20\nFor n > 0 and n + 5 to divide n^2 + 20, we need to check possible values.\nTrying n = 4: 4^2 + 20 = 36, 4 + 5 = 9, and 36 is divisible by 9. So n = 4 works.\nTrying n = 15: 15^2 + 20 = 245, 15 + 5 = 20, and 245 is not divisible by 20.\nAfter checking more values systematically, we find that n = 4 is the only positive integer solution."23 },24 {25 "problem": "Determine all real values of x such that log_(x-1)(x^2 - 5x + 7) = 2.",26 "difficulty": "hard",27 "solution": "For log_(x-1)(x^2 - 5x + 7) = 2 to be defined, we need:\n1) x - 1 > 0, so x > 1\n2) x - 1 ≠ 1, so x ≠ 2\n3) x^2 - 5x + 7 > 0\n\nNow, log_(x-1)(x^2 - 5x + 7) = 2 means (x^2 - 5x + 7) = (x-1)^2\n\nExpanding (x-1)^2 = (x-1)(x-1) = x^2 - 2x + 1\n\nSo we need to solve x^2 - 5x + 7 = x^2 - 2x + 1\n-5x + 7 = -2x + 1\n-3x = -6\nx = 2\n\nBut we already established x ≠ 2, so there are no solutions."28 }29 ],30 "geometry": [31 {32 "problem": "Points A, B, C, and D lie on a circle in that order. If AB = BC = CD and angle BAC = 30°, what is the measure of angle ADC in degrees?",33 "difficulty": "medium",34 "solution": "Since AB = BC = CD, we know that B divides arc AC into two equal parts, and C divides arc BD into two equal parts.\n\nLet's denote the center of the circle as O.\nSince AB = BC, triangles AOB and BOC are isosceles.\nThis means angle AOB = angle BOA and angle BOC = angle COB.\n\nWe know angle BAC = 30°.\nBy the inscribed angle theorem, angle BAC = (1/2) × (arc BC).\nSo arc BC = 60°.\n\nSince AB = BC = CD, arcs AB, BC, and CD all have the same length.\nThis means arc AB = arc BC = arc CD = 60°.\n\nBy the inscribed angle theorem, angle ADC = (1/2) × (arc AC).\nArc AC = arc AB + arc BC = 60° + 60° = 120°.\nTherefore, angle ADC = (1/2) × 120° = 60°."35 }36 ],37 "number_theory": [38 {39 "problem": "Find the sum of all positive integers n such that n^2 + n + 1 is divisible by 7.",40 "difficulty": "hard",41 "solution": "Let's consider n mod 7 and check when n^2 + n + 1 ≡ 0 (mod 7).\n\nFor n ≡ 0 (mod 7): 0^2 + 0 + 1 = 1 ≡ 1 (mod 7) ❌\nFor n ≡ 1 (mod 7): 1^2 + 1 + 1 = 3 ≡ 3 (mod 7) ❌\nFor n ≡ 2 (mod 7): 2^2 + 2 + 1 = 7 ≡ 0 (mod 7) ✓\nFor n ≡ 3 (mod 7): 3^2 + 3 + 1 = 13 ≡ 6 (mod 7) ❌\nFor n ≡ 4 (mod 7): 4^2 + 4 + 1 = 21 ≡ 0 (mod 7) ✓\nFor n ≡ 5 (mod 7): 5^2 + 5 + 1 = 31 ≡ 3 (mod 7) ❌\nFor n ≡ 6 (mod 7): 6^2 + 6 + 1 = 43 ≡ 1 (mod 7) ❌\n\nSo n^2 + n + 1 is divisible by 7 when n ≡ 2 (mod 7) or n ≡ 4 (mod 7).\n\nFor n ≤ 100, the positive integers that satisfy this are:\n2, 4, 9, 11, 16, 18, 23, 25, 30, 32, 37, 39, 44, 46, 51, 53, 58, 60, 65, 67, 72, 74, 79, 81, 86, 88, 93, 95, 100\n\nThe sum of these numbers is 1501."42 }43 ],44 "combinatorics": [45 {46 "problem": "How many different 4-digit numbers can be formed using the digits 1, 2, 3, 4, 5 without repetition?",47 "difficulty": "easy",48 "solution": "We need to create 4-digit numbers using 5 distinct digits without repetition.\n\nFor the first position, we have 5 choices (1, 2, 3, 4, or 5).\nFor the second position, we have 4 remaining choices.\nFor the third position, we have 3 remaining choices.\nFor the fourth position, we have 2 remaining choices.\n\nBy the multiplication principle, the total number of possible 4-digit numbers is:\n5 × 4 × 3 × 2 = 120"49 }50 ]51}52 53# Function to generate problem based on filters54def generate_problem(topic, difficulty):55 filtered_problems = [p for p in sample_problems.get(topic, []) if p["difficulty"] == difficulty]56 if filtered_problems:57 return random.choice(filtered_problems)["problem"]58 return "No problem found matching the criteria. Try a different combination."59 60# Function to solve problem using AI model61def solve_problem(problem_text):62 if not problem_text.strip():63 return "Please enter a problem first."64 65 prompt = f"Solve this math olympiad problem step by step:\n\n{problem_text}\n\nSolution:"66 67 # Add a small delay to simulate AI thinking (remove in production)68 time.sleep(2)69 70 inputs = tokenizer(prompt, return_tensors="pt")71 72 # In a real system, you would use your AI model here73 # outputs = model.generate(inputs["input_ids"], max_length=1024, temperature=0.7)74 # solution = tokenizer.decode(outputs[0], skip_special_tokens=True).split("Solution:")[1].strip()75 76 # For demo purposes, we'll provide a placeholder solution77 for topic in sample_problems:78 for problem in sample_problems[topic]:79 if problem["problem"] == problem_text:80 return problem["solution"]81 82 return "I'll solve this step-by-step:\n\n1. First, let's understand what the problem is asking...\n\n(This is a placeholder. In the actual implementation, the AI model would generate a detailed solution.)"83 84# Function to analyze student solution85def analyze_solution(problem, student_solution, ai_solution):86 if not student_solution.strip():87 return "Please enter your solution first."88 89 # In a real system, you would compare the solutions more intelligently90 # For demo purposes, we'll provide a placeholder analysis91 92 feedback = "Solution Analysis:\n\n"93 94 # Simple keyword checking (very basic, would be much more sophisticated in reality)95 ai_keywords = set([word.lower() for word in ai_solution.split() if len(word) > 4])96 student_keywords = set([word.lower() for word in student_solution.split() if len(word) > 4])97 98 common_keywords = ai_keywords.intersection(student_keywords)99 100 if len(common_keywords) / max(1, len(ai_keywords)) > 0.4:101 feedback += "✓ Your approach seems correct and contains many of the key concepts needed.\n\n"102 else:103 feedback += "⚠ Your approach may be missing some key concepts or taking a different direction.\n\n"104 105 # Check for solution steps106 if student_solution.count("\n") < 3:107 feedback += "⚠ Your solution could benefit from showing more steps and reasoning.\n\n"108 else:109 feedback += "✓ Good job showing your work step by step!\n\n"110 111 # Give general encouragement112 feedback += "Areas to focus on:\n"113 feedback += "- Consider whether you've addressed all constraints in the problem\n"114 feedback += "- Check if your solution is logically complete\n"115 feedback += "- Verify any algebraic manipulations\n\n"116 117 return feedback118 119# Function to generate practice schedule120def generate_schedule(topics, difficulty_level, hours_per_week, weeks):121 if not topics or not difficulty_level or not hours_per_week or not weeks:122 return "Please fill in all fields."123 124 # Create a DataFrame for the schedule125 schedule = []126 days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']127 128 # Distribute topics across the schedule129 topics_cycle = topics.copy()130 random.shuffle(topics_cycle)131 132 # Calculate hours per day (simple distribution)133 hours_per_day = [hours_per_week // 5 if d in ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'] else 134 hours_per_week // 10 for d in days]135 136 # Ensure the total equals hours per week137 while sum(hours_per_day) < hours_per_week:138 idx = random.randint(0, len(days)-1)139 hours_per_day[idx] += 1140 141 for week in range(1, weeks+1):142 for day_idx, day in enumerate(days):143 if hours_per_day[day_idx] > 0:144 topic = topics_cycle[week % len(topics_cycle)]145 schedule.append({146 'Week': week,147 'Day': day,148 'Topic': topic,149 'Hours': hours_per_day[day_idx],150 'Difficulty': difficulty_level151 })152 153 df = pd.DataFrame(schedule)154 155 # Create a visualization156 fig, ax = plt.subplots(figsize=(10, 6))157 topic_hours = df.groupby('Topic')['Hours'].sum().reset_index()158 ax.bar(topic_hours['Topic'], topic_hours['Hours'])159 ax.set_title('Hours by Topic in Training Schedule')160 ax.set_xlabel('Topic')161 ax.set_ylabel('Total Hours')162 plt.xticks(rotation=45)163 plt.tight_layout()164 165 # Convert to HTML for display166 schedule_html = df.to_html(index=False)167 168 return fig, schedule_html169 170# Function to track progress171def update_progress(topic, correct, incorrect):172 # This would connect to a database in a real implementation173 # For now, we just return a visualization174 topics = ['Algebra', 'Geometry', 'Number Theory', 'Combinatorics', 'Calculus']175 correct_counts = [0, 0, 0, 0, 0]176 incorrect_counts = [0, 0, 0, 0, 0]177 178 # Update the counts based on input179 try:180 topic_idx = topics.index(topic)181 correct_counts[topic_idx] = int(correct)182 incorrect_counts[topic_idx] = int(incorrect)183 except:184 pass185 186 # Create the progress chart187 fig, ax = plt.subplots(figsize=(10, 6))188 189 x = np.arange(len(topics))190 width = 0.35191 192 ax.bar(x - width/2, correct_counts, width, label='Correct')193 ax.bar(x + width/2, incorrect_counts, width, label='Incorrect')194 195 # Add labels and legend196 ax.set_ylabel('Number of Problems')197 ax.set_title('Progress by Topic')198 ax.set_xticks(x)199 ax.set_xticklabels(topics)200 ax.legend()201 202 plt.tight_layout()203 204 # Calculate accuracy205 total = sum(correct_counts) + sum(incorrect_counts)206 accuracy = sum(correct_counts) / max(1, total) * 100207 208 return fig, f"Overall Accuracy: {accuracy:.1f}%"209 210# Function for the competition simulator211def simulate_competition(num_problems, difficulty, time_limit):212 if not num_problems or not difficulty or not time_limit:213 return "Please fill in all fields."214 215 # Generate a set of problems for the competition216 competition_problems = []217 for topic in sample_problems:218 filtered = [p for p in sample_problems[topic] if p["difficulty"] == difficulty]219 if filtered:220 competition_problems.extend(filtered[:min(2, len(filtered))])221 222 if len(competition_problems) > num_problems:223 competition_problems = random.sample(competition_problems, num_problems)224 225 # Format the problems226 formatted_problems = ""227 for i, p in enumerate(competition_problems, 1):228 formatted_problems += f"Problem {i}: {p['problem']}\n\n"229 230 # Calculate expected time per problem231 time_per_problem = time_limit / max(1, len(competition_problems))232 233 return f"Competition Simulation\n\nDifficulty: {difficulty}\nTime Limit: {time_limit} minutes\nRecommended time per problem: {time_per_problem:.1f} minutes\n\n{formatted_problems}"234 235# Create the Gradio interface236with gr.Blocks(title="AI Math Olympiad Trainer") as demo:237 gr.Markdown("# AI Math Olympiad Trainer System")238 239 with gr.Tab("Problem Generator"):240 gr.Markdown("### Generate and Solve Math Olympiad Problems")241 242 with gr.Row():243 with gr.Column():244 topic_dropdown = gr.Dropdown(245 choices=["algebra", "geometry", "number_theory", "combinatorics"], 246 label="Topic"247 )248 difficulty_dropdown = gr.Dropdown(249 choices=["easy", "medium", "hard"], 250 label="Difficulty"251 )252 generate_btn = gr.Button("Generate Problem")253 254 with gr.Column():255 problem_output = gr.Textbox(label="Problem", lines=5)256 257 with gr.Row():258 with gr.Column():259 solution_input = gr.Textbox(label="Your Solution", lines=10)260 analyze_btn = gr.Button("Analyze My Solution")261 262 with gr.Column():263 ai_solution_btn = gr.Button("Get AI Solution")264 ai_solution_output = gr.Textbox(label="AI Solution", lines=10)265 analysis_output = gr.Textbox(label="Analysis", lines=8)266 267 with gr.Tab("Training Schedule"):268 gr.Markdown("### Create a Personalized Training Schedule")269 270 with gr.Row():271 with gr.Column():272 topics_multiselect = gr.CheckboxGroup(273 choices=["Algebra", "Geometry", "Number Theory", "Combinatorics", "Calculus"],274 label="Select Topics"275 )276 difficulty_radio = gr.Radio(277 choices=["easy", "medium", "hard", "mixed"],278 label="Difficulty Level"279 )280 hours_slider = gr.Slider(281 minimum=1, maximum=30, value=10, step=1,282 label="Hours per Week"283 )284 weeks_slider = gr.Slider(285 minimum=1, maximum=12, value=4, step=1,286 label="Number of Weeks"287 )288 schedule_btn = gr.Button("Generate Schedule")289 290 with gr.Column():291 schedule_plot = gr.Plot(label="Hours Distribution")292 schedule_output = gr.HTML(label="Your Schedule")293 294 with gr.Tab("Progress Tracker"):295 gr.Markdown("### Track Your Progress")296 297 with gr.Row():298 with gr.Column():299 progress_topic = gr.Dropdown(300 choices=["Algebra", "Geometry", "Number Theory", "Combinatorics", "Calculus"],301 label="Topic"302 )303 correct_slider = gr.Slider(304 minimum=0, maximum=50, value=0, step=1,305 label="Correct Solutions"306 )307 incorrect_slider = gr.Slider(308 minimum=0, maximum=50, value=0, step=1,309 label="Incorrect Solutions"310 )311 update_btn = gr.Button("Update Progress")312 313 with gr.Column():314 progress_plot = gr.Plot(label="Progress Chart")315 accuracy_output = gr.Textbox(label="Accuracy")316 317 with gr.Tab("Competition Simulator"):318 gr.Markdown("### Simulate a Math Competition")319 320 with gr.Row():321 with gr.Column():322 problems_slider = gr.Slider(323 minimum=1, maximum=10, value=3, step=1,324 label="Number of Problems"325 )326 comp_difficulty = gr.Radio(327 choices=["easy", "medium", "hard"],328 label="Difficulty"329 )330 time_slider = gr.Slider(331 minimum=15, maximum=180, value=60, step=15,332 label="Time Limit (minutes)"333 )334 simulate_btn = gr.Button("Start Simulation")335 336 with gr.Column():337 simulation_output = gr.Textbox(label="Competition Problems", lines=15)338 339 # Connect the functions340 generate_btn.click(341 generate_problem, 342 inputs=[topic_dropdown, difficulty_dropdown], 343 outputs=problem_output344 )345 346 ai_solution_btn.click(347 solve_problem,348 inputs=[problem_output],349 outputs=ai_solution_output350 )351 352 analyze_btn.click(353 analyze_solution,354 inputs=[problem_output, solution_input, ai_solution_output],355 outputs=analysis_output356 )357 358 schedule_btn.click(359 generate_schedule,360 inputs=[topics_multiselect, difficulty_radio, hours_slider, weeks_slider],361 outputs=[schedule_plot, schedule_output]362 )363 364 update_btn.click(365 update_progress,366 inputs=[progress_topic, correct_slider, incorrect_slider],367 outputs=[progress_plot, accuracy_output]368 )369 370 simulate_btn.click(371 simulate_competition,372 inputs=[problems_slider, comp_difficulty, time_slider],373 outputs=simulation_output374 )375 376# Launch the app377demo.launch()