BeastGokul's picture
Update app.py
4686307 verified
import gradio as gr
import torch
import numpy as np
import random
import pandas as pd
import matplotlib.pyplot as plt
import time
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
model_name = "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B"
model = AutoModelForCausalLM.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)
# Sample problems database (you would expand this)
sample_problems = {
"algebra": [
{
"problem": "Find all positive integers n such that n^2 + 20 is divisible by n + 5.",
"difficulty": "medium",
"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."
},
{
"problem": "Determine all real values of x such that log_(x-1)(x^2 - 5x + 7) = 2.",
"difficulty": "hard",
"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."
}
],
"geometry": [
{
"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?",
"difficulty": "medium",
"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°."
}
],
"number_theory": [
{
"problem": "Find the sum of all positive integers n such that n^2 + n + 1 is divisible by 7.",
"difficulty": "hard",
"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."
}
],
"combinatorics": [
{
"problem": "How many different 4-digit numbers can be formed using the digits 1, 2, 3, 4, 5 without repetition?",
"difficulty": "easy",
"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"
}
]
}
# Function to generate problem based on filters
def generate_problem(topic, difficulty):
filtered_problems = [p for p in sample_problems.get(topic, []) if p["difficulty"] == difficulty]
if filtered_problems:
return random.choice(filtered_problems)["problem"]
return "No problem found matching the criteria. Try a different combination."
# Function to solve problem using AI model
def solve_problem(problem_text):
if not problem_text.strip():
return "Please enter a problem first."
prompt = f"Solve this math olympiad problem step by step:\n\n{problem_text}\n\nSolution:"
# Add a small delay to simulate AI thinking (remove in production)
time.sleep(2)
inputs = tokenizer(prompt, return_tensors="pt")
# In a real system, you would use your AI model here
# outputs = model.generate(inputs["input_ids"], max_length=1024, temperature=0.7)
# solution = tokenizer.decode(outputs[0], skip_special_tokens=True).split("Solution:")[1].strip()
# For demo purposes, we'll provide a placeholder solution
for topic in sample_problems:
for problem in sample_problems[topic]:
if problem["problem"] == problem_text:
return problem["solution"]
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.)"
# Function to analyze student solution
def analyze_solution(problem, student_solution, ai_solution):
if not student_solution.strip():
return "Please enter your solution first."
# In a real system, you would compare the solutions more intelligently
# For demo purposes, we'll provide a placeholder analysis
feedback = "Solution Analysis:\n\n"
# Simple keyword checking (very basic, would be much more sophisticated in reality)
ai_keywords = set([word.lower() for word in ai_solution.split() if len(word) > 4])
student_keywords = set([word.lower() for word in student_solution.split() if len(word) > 4])
common_keywords = ai_keywords.intersection(student_keywords)
if len(common_keywords) / max(1, len(ai_keywords)) > 0.4:
feedback += "✓ Your approach seems correct and contains many of the key concepts needed.\n\n"
else:
feedback += "⚠ Your approach may be missing some key concepts or taking a different direction.\n\n"
# Check for solution steps
if student_solution.count("\n") < 3:
feedback += "⚠ Your solution could benefit from showing more steps and reasoning.\n\n"
else:
feedback += "✓ Good job showing your work step by step!\n\n"
# Give general encouragement
feedback += "Areas to focus on:\n"
feedback += "- Consider whether you've addressed all constraints in the problem\n"
feedback += "- Check if your solution is logically complete\n"
feedback += "- Verify any algebraic manipulations\n\n"
return feedback
# Function to generate practice schedule
def generate_schedule(topics, difficulty_level, hours_per_week, weeks):
if not topics or not difficulty_level or not hours_per_week or not weeks:
return "Please fill in all fields."
# Create a DataFrame for the schedule
schedule = []
days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
# Distribute topics across the schedule
topics_cycle = topics.copy()
random.shuffle(topics_cycle)
# Calculate hours per day (simple distribution)
hours_per_day = [hours_per_week // 5 if d in ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'] else
hours_per_week // 10 for d in days]
# Ensure the total equals hours per week
while sum(hours_per_day) < hours_per_week:
idx = random.randint(0, len(days)-1)
hours_per_day[idx] += 1
for week in range(1, weeks+1):
for day_idx, day in enumerate(days):
if hours_per_day[day_idx] > 0:
topic = topics_cycle[week % len(topics_cycle)]
schedule.append({
'Week': week,
'Day': day,
'Topic': topic,
'Hours': hours_per_day[day_idx],
'Difficulty': difficulty_level
})
df = pd.DataFrame(schedule)
# Create a visualization
fig, ax = plt.subplots(figsize=(10, 6))
topic_hours = df.groupby('Topic')['Hours'].sum().reset_index()
ax.bar(topic_hours['Topic'], topic_hours['Hours'])
ax.set_title('Hours by Topic in Training Schedule')
ax.set_xlabel('Topic')
ax.set_ylabel('Total Hours')
plt.xticks(rotation=45)
plt.tight_layout()
# Convert to HTML for display
schedule_html = df.to_html(index=False)
return fig, schedule_html
# Function to track progress
def update_progress(topic, correct, incorrect):
# This would connect to a database in a real implementation
# For now, we just return a visualization
topics = ['Algebra', 'Geometry', 'Number Theory', 'Combinatorics', 'Calculus']
correct_counts = [0, 0, 0, 0, 0]
incorrect_counts = [0, 0, 0, 0, 0]
# Update the counts based on input
try:
topic_idx = topics.index(topic)
correct_counts[topic_idx] = int(correct)
incorrect_counts[topic_idx] = int(incorrect)
except:
pass
# Create the progress chart
fig, ax = plt.subplots(figsize=(10, 6))
x = np.arange(len(topics))
width = 0.35
ax.bar(x - width/2, correct_counts, width, label='Correct')
ax.bar(x + width/2, incorrect_counts, width, label='Incorrect')
# Add labels and legend
ax.set_ylabel('Number of Problems')
ax.set_title('Progress by Topic')
ax.set_xticks(x)
ax.set_xticklabels(topics)
ax.legend()
plt.tight_layout()
# Calculate accuracy
total = sum(correct_counts) + sum(incorrect_counts)
accuracy = sum(correct_counts) / max(1, total) * 100
return fig, f"Overall Accuracy: {accuracy:.1f}%"
# Function for the competition simulator
def simulate_competition(num_problems, difficulty, time_limit):
if not num_problems or not difficulty or not time_limit:
return "Please fill in all fields."
# Generate a set of problems for the competition
competition_problems = []
for topic in sample_problems:
filtered = [p for p in sample_problems[topic] if p["difficulty"] == difficulty]
if filtered:
competition_problems.extend(filtered[:min(2, len(filtered))])
if len(competition_problems) > num_problems:
competition_problems = random.sample(competition_problems, num_problems)
# Format the problems
formatted_problems = ""
for i, p in enumerate(competition_problems, 1):
formatted_problems += f"Problem {i}: {p['problem']}\n\n"
# Calculate expected time per problem
time_per_problem = time_limit / max(1, len(competition_problems))
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}"
# Create the Gradio interface
with gr.Blocks(title="AI Math Olympiad Trainer") as demo:
gr.Markdown("# AI Math Olympiad Trainer System")
with gr.Tab("Problem Generator"):
gr.Markdown("### Generate and Solve Math Olympiad Problems")
with gr.Row():
with gr.Column():
topic_dropdown = gr.Dropdown(
choices=["algebra", "geometry", "number_theory", "combinatorics"],
label="Topic"
)
difficulty_dropdown = gr.Dropdown(
choices=["easy", "medium", "hard"],
label="Difficulty"
)
generate_btn = gr.Button("Generate Problem")
with gr.Column():
problem_output = gr.Textbox(label="Problem", lines=5)
with gr.Row():
with gr.Column():
solution_input = gr.Textbox(label="Your Solution", lines=10)
analyze_btn = gr.Button("Analyze My Solution")
with gr.Column():
ai_solution_btn = gr.Button("Get AI Solution")
ai_solution_output = gr.Textbox(label="AI Solution", lines=10)
analysis_output = gr.Textbox(label="Analysis", lines=8)
with gr.Tab("Training Schedule"):
gr.Markdown("### Create a Personalized Training Schedule")
with gr.Row():
with gr.Column():
topics_multiselect = gr.CheckboxGroup(
choices=["Algebra", "Geometry", "Number Theory", "Combinatorics", "Calculus"],
label="Select Topics"
)
difficulty_radio = gr.Radio(
choices=["easy", "medium", "hard", "mixed"],
label="Difficulty Level"
)
hours_slider = gr.Slider(
minimum=1, maximum=30, value=10, step=1,
label="Hours per Week"
)
weeks_slider = gr.Slider(
minimum=1, maximum=12, value=4, step=1,
label="Number of Weeks"
)
schedule_btn = gr.Button("Generate Schedule")
with gr.Column():
schedule_plot = gr.Plot(label="Hours Distribution")
schedule_output = gr.HTML(label="Your Schedule")
with gr.Tab("Progress Tracker"):
gr.Markdown("### Track Your Progress")
with gr.Row():
with gr.Column():
progress_topic = gr.Dropdown(
choices=["Algebra", "Geometry", "Number Theory", "Combinatorics", "Calculus"],
label="Topic"
)
correct_slider = gr.Slider(
minimum=0, maximum=50, value=0, step=1,
label="Correct Solutions"
)
incorrect_slider = gr.Slider(
minimum=0, maximum=50, value=0, step=1,
label="Incorrect Solutions"
)
update_btn = gr.Button("Update Progress")
with gr.Column():
progress_plot = gr.Plot(label="Progress Chart")
accuracy_output = gr.Textbox(label="Accuracy")
with gr.Tab("Competition Simulator"):
gr.Markdown("### Simulate a Math Competition")
with gr.Row():
with gr.Column():
problems_slider = gr.Slider(
minimum=1, maximum=10, value=3, step=1,
label="Number of Problems"
)
comp_difficulty = gr.Radio(
choices=["easy", "medium", "hard"],
label="Difficulty"
)
time_slider = gr.Slider(
minimum=15, maximum=180, value=60, step=15,
label="Time Limit (minutes)"
)
simulate_btn = gr.Button("Start Simulation")
with gr.Column():
simulation_output = gr.Textbox(label="Competition Problems", lines=15)
# Connect the functions
generate_btn.click(
generate_problem,
inputs=[topic_dropdown, difficulty_dropdown],
outputs=problem_output
)
ai_solution_btn.click(
solve_problem,
inputs=[problem_output],
outputs=ai_solution_output
)
analyze_btn.click(
analyze_solution,
inputs=[problem_output, solution_input, ai_solution_output],
outputs=analysis_output
)
schedule_btn.click(
generate_schedule,
inputs=[topics_multiselect, difficulty_radio, hours_slider, weeks_slider],
outputs=[schedule_plot, schedule_output]
)
update_btn.click(
update_progress,
inputs=[progress_topic, correct_slider, incorrect_slider],
outputs=[progress_plot, accuracy_output]
)
simulate_btn.click(
simulate_competition,
inputs=[problems_slider, comp_difficulty, time_slider],
outputs=simulation_output
)
# Launch the app
demo.launch()