File size: 6,026 Bytes
bfc1cf6
 
 
 
 
2f3d61a
bfc1cf6
2f3d61a
516fc47
 
 
 
 
2f3d61a
516fc47
 
 
 
 
 
bfc1cf6
516fc47
 
 
 
 
 
109daa0
516fc47
 
 
 
 
 
2f3d61a
bfc1cf6
516fc47
 
 
e6857f6
516fc47
bfc1cf6
2f3d61a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
516fc47
 
 
2f3d61a
 
 
 
 
 
 
 
 
 
 
 
bfc1cf6
 
 
 
2f3d61a
bfc1cf6
 
516fc47
bfc1cf6
 
 
516fc47
 
 
 
 
 
ef21c2f
bfc1cf6
 
516fc47
 
 
bfc1cf6
 
516fc47
 
 
bfc1cf6
 
516fc47
 
 
 
 
 
bfc1cf6
516fc47
 
bfc1cf6
 
 
2f3d61a
91aaf8c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2f3d61a
 
91aaf8c
 
 
 
 
2f3d61a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import os
import gradio as gr
from anthropic import Anthropic
from datetime import datetime, timedelta
from collections import deque
import random

# 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 check_api_key():
    """Verify API key is configured"""
    if not os.environ.get('ANTHROPIC_API_KEY'):
        raise ValueError("Anthropic API key not found. Please configure it in HuggingFace Spaces settings.")

def check_rate_limit():
    """Check if we're within rate limits"""
    now = datetime.now()
    while request_history and (now - request_history[0]) > timedelta(days=1):
        request_history.popleft()
    return len(request_history) < MAX_REQUESTS_PER_DAY

def clean_latex(text):
    """Simple LaTeX cleaning"""
    text = text.replace('\n', '\n\n')
    return text

def generate_test(subject):
    """Generate a math test with enhanced variety"""
    try:
        check_api_key()
        if not check_rate_limit():
            return "Daily request limit reached. Please try again tomorrow."
        
        request_history.append(datetime.now())
        
        # Randomly select focus areas and difficulty levels
        topics = {
            "Single Variable Calculus": ["limits", "derivatives", "integrals", "series", "applications"],
            "Multivariable Calculus": ["partial derivatives", "multiple integrals", "vector fields", "optimization", "surface integrals"],
            "Linear Algebra": ["matrices", "vector spaces", "eigenvalues", "linear transformations", "inner products"],
            # ... add topics for other subjects
        }
        
        selected_topics = random.sample(topics.get(subject, ["general"]), min(3, len(topics.get(subject, ["general"]))))
        difficulty_distribution = random.choice([
            "one easy, one medium, one challenging",
            "two medium, one very challenging",
            "one medium, two challenging"
        ])
        
        system_prompt = f"""You will write math exam questions. Follow these requirements EXACTLY:
        1. Write exactly 3 university-level questions focusing on these specific topics: {', '.join(selected_topics)}
        2. Make the questions {difficulty_distribution}
        3. For each question, use a different type of mathematical thinking (e.g., computation, proof, application, conceptual understanding)
        4. Ensure questions are unique and not commonly found in textbooks
        5. For LaTeX math formatting:
           - Use $ for simple inline math
           - For equations and solution steps, use $$ on separate lines
           - For multi-step solutions, put each step on its own line in $$ $$
           - DO NOT use \\begin{{aligned}} or any other environments
        6. Number each question as 1), 2), 3)
        7. Include detailed solutions after each question
        8. Keep formatting simple and clear
        
        Important: Make these questions distinct from standard textbook problems. Incorporate real-world applications, 
        interdisciplinary connections, or creative scenarios where appropriate."""
        
        # Vary temperature based on subject complexity
        base_temperature = 0.7
        complexity_adjustment = random.uniform(-0.1, 0.1)
        temperature = min(1.0, max(0.5, base_temperature + complexity_adjustment))
        
        message = anthropic.messages.create(
            model="claude-3-opus-20240229",
            max_tokens=1500,
            temperature=temperature,
            messages=[{
                "role": "user",
                "content": f"{system_prompt}\n\nWrite an exam for {subject}."
            }]
        )
        
        # Extract usage information
        input_tokens = message.usage.input_tokens
        output_tokens = message.usage.output_tokens
        input_cost = (input_tokens / 1000) * 0.015
        output_cost = (output_tokens / 1000) * 0.075
        total_cost = input_cost + output_cost
        
        usage_stats = f"""
        \n---\nUsage Statistics:
        • Input Tokens: {input_tokens:,}
        • Output Tokens: {output_tokens:,}
        • Total Tokens: {input_tokens + output_tokens:,}
        
        Cost Breakdown:
        • Input Cost: ${input_cost:.4f}
        • Output Cost: ${output_cost:.4f}
        • Total Cost: ${total_cost:.4f}
        """
        
        if hasattr(message, 'content') and len(message.content) > 0:
            response_text = message.content[0].text
            formatted_response = clean_latex(response_text) + usage_stats
            return formatted_response
        else:
            return "Error: No content in response"
            
    except ValueError as e:
        return f"Configuration Error: {str(e)}"
    except Exception as e:
        return f"Error: {str(e)}"

# Subject choices remain the same
subjects = [
    "Single Variable Calculus",
    "Multivariable Calculus", 
    "Linear Algebra",
    "Differential Equations",
    "Real Analysis",
    "Complex Analysis",
    "Abstract Algebra",
    "Probability Theory",
    "Numerical Analysis",
    "Topology"
]

# Create Gradio interface
interface = gr.Interface(
    fn=generate_test,
    inputs=gr.Dropdown(
        choices=subjects,
        label="Select Mathematics Subject",
        info="Choose a subject for the exam questions"
    ),
    outputs=gr.Markdown(
        label="Generated Test",
        latex_delimiters=[
            {"left": "$$", "right": "$$", "display": True},
            {"left": "$", "right": "$", "display": False}
        ]
    ),
    title="Advanced Mathematics Test Generator",
    description="""Generates unique university-level mathematics exam questions with solutions using Claude 3 Opus.
    Each test features different topics and difficulty levels. Limited to 25 requests per day.""",
    theme="default",
    allow_flagging="never"
)

if __name__ == "__main__":
    interface.launch()