import os import gradio as gr from anthropic import Anthropic from datetime import datetime, timedelta from collections import deque import random import logging import tempfile from pathlib import Path # Set up logging logging.basicConfig( level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) # Initialize Anthropic client anthropic = Anthropic( api_key=os.environ.get('ANTHROPIC_API_KEY') ) # Request tracking MAX_REQUESTS_PER_DAY = 25 request_history = deque(maxlen=1000) def get_difficulty_parameters(difficulty_level): """Return specific parameters and constraints based on difficulty level""" parameters = { 1: { # Very Easy "description": "very easy, suitable for beginners", "constraints": [ "Use only basic concepts and straightforward calculations", "Break complex problems into smaller, guided steps", "Provide hints within the question when needed", "Use simple numbers and avoid complex algebraic expressions" ], "example_style": "Similar to standard homework problems", "model": "claude-3-5-sonnet-20241022" }, 2: { # Easy "description": "easy, but requiring some thought", "constraints": [ "Use basic concepts with minor complications", "Include two-step problems", "Minimal guidance provided", "Use moderately complex numbers or expressions" ], "example_style": "Similar to quiz questions", "model": "claude-3-5-sonnet-20241022" }, 3: { # Intermediate "description": "intermediate difficulty, testing deeper understanding", "constraints": [ "Combine 2-3 related concepts", "Include some non-obvious solution paths", "Require multi-step reasoning", "Use moderate algebraic complexity" ], "example_style": "Similar to midterm exam questions", "model": "claude-3-5-sonnet-20241022" }, 4: { # Difficult "description": "challenging, requiring strong mathematical maturity", "constraints": [ "Combine multiple concepts creatively", "Require insight and deep understanding", "Include non-standard approaches", "Use sophisticated mathematical reasoning" ], "example_style": "Similar to final exam questions", "model": "claude-3-5-sonnet-20241022" }, 5: { # Very Difficult "description": "very challenging, testing mastery and creativity at a graduate level", "constraints": [ "Create novel applications of theoretical concepts", "Require graduate-level mathematical reasoning", "Combine multiple advanced topics in unexpected ways", "Demand creative problem-solving approaches", "Include rigorous proof construction", "Require synthesis across mathematical domains", "Test deep theoretical understanding" ], "example_style": "Similar to graduate qualifying exams or advanced competition problems", "model": "claude-3-sonnet-20241022" } } return parameters.get(difficulty_level) def create_latex_document(content, questions_only=False): """Create a complete LaTeX document""" try: latex_header = r"""\documentclass{article} \usepackage{amsmath,amssymb} \usepackage[margin=1in]{geometry} \begin{document} \title{Mathematics Question} \maketitle """ latex_footer = r"\end{document}" if questions_only: # Modified to handle single question processed_content = content.split('Solution:')[0] content = processed_content full_document = f"{latex_header}\n{content}\n{latex_footer}" logger.debug(f"Created {'questions-only' if questions_only else 'full'} LaTeX document") return full_document except Exception as e: logger.error(f"Error creating LaTeX document: {str(e)}") raise def save_to_temp_file(content, filename): """Save content to a temporary file and return the path""" try: temp_dir = Path(tempfile.gettempdir()) / "math_test_files" temp_dir.mkdir(exist_ok=True) file_path = temp_dir / filename file_path.write_text(content, encoding='utf-8') logger.debug(f"Saved content to temporary file: {file_path}") return str(file_path) except Exception as e: logger.error(f"Error saving temporary file: {str(e)}") raise def generate_question(subject, difficulty, question_type): """Generate a single math question""" try: if not os.environ.get('ANTHROPIC_API_KEY'): logger.error("Anthropic API key not found") return "Error: Anthropic API key not configured", None, None logger.debug(f"Generating {question_type} question for subject: {subject} at difficulty level: {difficulty}") # Check rate limit now = datetime.now() while request_history and (now - request_history[0]) > timedelta(days=1): request_history.popleft() if len(request_history) >= MAX_REQUESTS_PER_DAY: return "Daily request limit reached. Please try again tomorrow.", None, None request_history.append(now) topics = { "Single Variable Calculus": ["limits", "derivatives", "integrals", "series", "applications"], "Multivariable Calculus": ["partial derivatives", "multiple integrals", "vector fields", "optimization"], "Linear Algebra": ["matrices", "vector spaces", "eigenvalues", "linear transformations"], "Differential Equations": ["first order equations", "second order equations", "systems", "stability analysis"], "Real Analysis": ["sequences", "series", "continuity", "differentiation", "integration"], "Complex Analysis": ["complex functions", "analyticity", "contour integration", "residues"], "Abstract Algebra": ["groups", "rings", "fields", "homomorphisms"], "Probability Theory": ["probability spaces", "random variables", "distributions", "limit theorems"], "Numerical Analysis": ["approximation", "interpolation", "numerical integration", "error analysis"], "Topology": ["metric spaces", "continuity", "compactness", "connectedness"] } selected_topic = random.choice(topics.get(subject, ["general"])) logger.debug(f"Selected topic: {selected_topic}") difficulty_params = get_difficulty_parameters(difficulty) if difficulty == 5: system_prompt = f"""You are an expert mathematics professor creating a graduate-level exam question. STRICT REQUIREMENTS: 1. Write exactly 1 graduate-level application question on {subject} covering {selected_topic}. 2. Advanced Difficulty Requirements: This question must be suitable for PhD qualifying exams or advanced competitions. MUST include: - Novel applications of theoretical concepts to complex real-world scenarios - Graduate-level mathematical reasoning in practical contexts - Sophisticated modeling of real situations - Creative problem-solving approaches - Multiple stages of mathematical modeling and analysis Follow these specific constraints: {chr(10).join(f' - {c}' for c in difficulty_params['constraints'])} 3. Style Reference: Question should be {difficulty_params['example_style']} 4. The question MUST: - Bridge multiple mathematical domains - Require deep theoretical understanding - Test mastery of advanced concepts - Demand innovative solution approaches 5. For LaTeX formatting: - Use $ for inline math - Use $$ on separate lines for equations and solutions - Put each solution step on its own line in $$ $$ - DO NOT use \\begin{{aligned}} or similar environments 6. Include a detailed solution with thorough explanations of: - How to model the situation - Why specific mathematical techniques were chosen - How to interpret the results 7. Maintain clear, precise formatting""" else: system_prompt = f"""You are an expert mathematics professor creating a {difficulty_params['description']} exam question. STRICT REQUIREMENTS: 1. Write exactly 1 application question on {subject} covering {selected_topic}. 2. Difficulty Level Guidelines: {difficulty_params['description'].upper()} Follow these specific constraints: {chr(10).join(f' - {c}' for c in difficulty_params['constraints'])} 3. Style Reference: Question should be {difficulty_params['example_style']} 4. For LaTeX formatting: - Use $ for inline math - Use $$ on separate lines for equations and solutions - Put each solution step on its own line in $$ $$ - DO NOT use \\begin{{aligned}} or similar environments 5. Include a detailed solution that explains: - How to model the situation - Why specific mathematical techniques were chosen - How to interpret the results 6. Maintain clear formatting""" else: # Standard prompts for computation and proof questions if difficulty == 5: system_prompt = f"""You are an expert mathematics professor creating a graduate-level exam question. STRICT REQUIREMENTS: 1. Write exactly 1 graduate-level {question_type} question on {subject} covering {selected_topic}. 2. Advanced Difficulty Requirements: This question must be suitable for PhD qualifying exams or advanced competitions. MUST include: - Novel applications of theoretical concepts - Graduate-level mathematical reasoning - Unexpected connections between different areas of {subject} - Creative problem-solving approaches - Rigorous proof requirements where applicable Follow these specific constraints: {chr(10).join(f' - {c}' for c in difficulty_params['constraints'])} 3. Style Reference: Question should be {difficulty_params['example_style']} 4. The question MUST: - Bridge multiple mathematical domains - Require deep theoretical understanding - Test mastery of advanced concepts - Demand innovative solution approaches 5. For LaTeX formatting: - Use $ for inline math - Use $$ on separate lines for equations and solutions - Put each solution step on its own line in $$ $$ - DO NOT use \\begin{{aligned}} or similar environments 6. Include a detailed solution with thorough explanations of advanced concepts used 7. Maintain clear, precise formatting""" else: system_prompt = f"""You are an expert mathematics professor creating a {difficulty_params['description']} exam question. STRICT REQUIREMENTS: 1. Write exactly 1 {question_type} question on {subject} covering {selected_topic}. 2. Difficulty Level Guidelines: {difficulty_params['description'].upper()} Follow these specific constraints: {chr(10).join(f' - {c}' for c in difficulty_params['constraints'])} 3. Style Reference: Question should be {difficulty_params['example_style']} 4. For LaTeX formatting: - Use $ for inline math - Use $$ on separate lines for equations and solutions - Put each solution step on its own line in $$ $$ - DO NOT use \\begin{{aligned}} or similar environments 5. Include a detailed solution 6. Maintain clear formatting""" logger.debug("Sending request to Anthropic API") message = anthropic.messages.create( model=difficulty_params['model'], max_tokens=4096, temperature=0.7, messages=[{ "role": "user", "content": f"{system_prompt}\n\nWrite a question for {subject}." }] ) if not hasattr(message, 'content') or not message.content: logger.error("No content received from Anthropic API") return "Error: No content received from API", None, None response_text = message.content[0].text logger.debug("Successfully received response from Anthropic API") # Create LaTeX content questions_latex = create_latex_document(response_text, questions_only=True) full_latex = create_latex_document(response_text, questions_only=False) # Save to temporary files questions_path = save_to_temp_file(questions_latex, "question.tex") full_path = save_to_temp_file(full_latex, "full_question.tex") logger.debug("Successfully created temporary files") return response_text, questions_path, full_path except Exception as e: logger.error(f"Error generating question: {str(e)}") return f"Error: {str(e)}", None, None # Create Gradio interface with gr.Blocks() as interface: gr.Markdown("# Advanced Mathematics Question Generator") gr.Markdown("""Generates a unique university-level mathematics question with solution using Claude 3. Each question features different topics and difficulty levels. Limited to 25 requests per day.""") with gr.Row(): with gr.Column(): subject_dropdown = gr.Dropdown( choices=[ "Single Variable Calculus", "Multivariable Calculus", "Linear Algebra", "Differential Equations", "Real Analysis", "Complex Analysis", "Abstract Algebra", "Probability Theory", "Numerical Analysis", "Topology" ], label="Select Mathematics Subject", info="Choose a subject for the question" ) difficulty_slider = gr.Slider( minimum=1, maximum=5, step=1, value=3, label="Difficulty Level", info="1: Very Easy, 2: Easy, 3: Moderate, 4: Difficult, 5: Very Difficult" ) question_type = gr.Radio( choices=["computation", "proof", "application"], label="Question Type", info="Select the type of question you want", value="computation" ) generate_btn = gr.Button("Generate Question") output_text = gr.Markdown( label="Generated Question Preview", latex_delimiters=[ {"left": "$$", "right": "$$", "display": True}, {"left": "$", "right": "$", "display": False} ] ) with gr.Row(): questions_file = gr.File(label="Question Only (LaTeX)") full_file = gr.File(label="Question with Solution (LaTeX)") generate_btn.click( generate_question, inputs=[ subject_dropdown, difficulty_slider, question_type ], outputs=[output_text, questions_file, full_file] ) if __name__ == "__main__": logger.info("Starting application") interface.launch()