Spaces:
Running
Running
# app.py | |
import os | |
import gradio as gr | |
from anthropic import Anthropic | |
from datetime import datetime, timedelta | |
from collections import deque | |
# Initialize Anthropic client - will use the secret key from HuggingFace | |
anthropic = Anthropic( | |
api_key=os.environ.get('ANTHROPIC_API_KEY') | |
) | |
# Request tracking | |
MAX_REQUESTS_PER_DAY = 25 # Conservative limit to start | |
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() | |
# Remove requests older than 24 hours | |
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 error handling and rate limiting""" | |
try: | |
# Check API key | |
check_api_key() | |
# Check rate limit | |
if not check_rate_limit(): | |
return "Daily request limit reached. Please try again tomorrow." | |
# Record request | |
request_history.append(datetime.now()) | |
system_prompt = """You will write math exam questions. Follow these requirements EXACTLY: | |
1. Write exactly 3 challenging university-level questions | |
2. 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 | |
3. Number each question as 1), 2), 3) | |
4. Include solutions after each question | |
5. Keep formatting simple and clear""" | |
message = anthropic.messages.create( | |
model="claude-3-opus-20240229", | |
max_tokens=1500, | |
temperature=0.7, | |
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 | |
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 university-level mathematics exam questions with solutions using Claude 3 Opus. | |
Limited to 25 requests per day. Please use responsibly.""", | |
theme="default", | |
allow_flagging="never" | |
) | |
# Launch the interface | |
if __name__ == "__main__": | |
interface.launch() |