joshuarauh's picture
no conceptual questions, added download functionality
9682d40 verified
raw
history blame
8.8 kB
import os
import gradio as gr
from anthropic import Anthropic
from datetime import datetime, timedelta
from collections import deque
import random
import tempfile
import subprocess
from pathlib import Path
# 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 create_latex_document(content, questions_only=False):
"""Create a complete LaTeX document"""
latex_header = r"""\documentclass{article}
\usepackage{amsmath,amssymb}
\usepackage[margin=1in]{geometry}
\begin{document}
"""
latex_footer = r"\end{document}"
if questions_only:
# Extract only the questions (everything before "Solution:")
questions = []
for question in content.split('\n'):
if 'Solution:' in question:
continue
questions.append(question)
content = '\n'.join(questions)
return f"{latex_header}\n{content}\n{latex_footer}"
def latex_to_pdf(latex_content):
"""Convert LaTeX content to PDF"""
with tempfile.TemporaryDirectory() as tmpdir:
tex_path = Path(tmpdir) / "output.tex"
with open(tex_path, "w", encoding="utf-8") as f:
f.write(latex_content)
# Run pdflatex twice to resolve references
subprocess.run(["pdflatex", "-interaction=nonstopmode", str(tex_path)],
cwd=tmpdir, capture_output=True)
subprocess.run(["pdflatex", "-interaction=nonstopmode", str(tex_path)],
cwd=tmpdir, capture_output=True)
pdf_path = Path(tmpdir) / "output.pdf"
if pdf_path.exists():
return pdf_path.read_bytes()
return None
def generate_test_with_format(subject, output_format):
"""Generate a math test with specified output format"""
try:
check_api_key()
if not check_rate_limit():
return "Daily request limit reached. Please try again tomorrow."
request_history.append(datetime.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"],
# ... 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. ALL questions must be computational or proof-based problems. NO conceptual or explanation questions.
4. Each question must require mathematical work, calculations, or formal proofs
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: Every question must require mathematical computation or proof. Do not ask for explanations, descriptions, or concepts."""
temperature = 0.7
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}."
}]
)
if hasattr(message, 'content') and len(message.content) > 0:
response_text = message.content[0].text
return clean_latex(response_text)
else:
return "Error: No content in response"
except Exception as e:
return f"Error: {str(e)}"
def create_download_files(test_content):
"""Create downloadable files in different formats"""
# Full test (questions and solutions)
full_latex = create_latex_document(test_content, questions_only=False)
full_pdf = latex_to_pdf(full_latex)
# Questions only
questions_latex = create_latex_document(test_content, questions_only=True)
questions_pdf = latex_to_pdf(questions_latex)
return {
"full_latex": full_latex,
"full_pdf": full_pdf,
"questions_latex": questions_latex,
"questions_pdf": questions_pdf
}
subjects = [
"Single Variable Calculus",
"Multivariable Calculus",
"Linear Algebra",
"Differential Equations",
"Real Analysis",
"Complex Analysis",
"Abstract Algebra",
"Probability Theory",
"Numerical Analysis",
"Topology"
]
def download_handler(file_content, filename):
"""Handle file downloads"""
return file_content
# Create Gradio interface
with gr.Blocks() as interface:
gr.Markdown("# Advanced Mathematics Test Generator")
gr.Markdown("""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.""")
with gr.Row():
subject_dropdown = gr.Dropdown(
choices=subjects,
label="Select Mathematics Subject",
info="Choose a subject for the exam questions"
)
generate_btn = gr.Button("Generate Test")
output_text = gr.Markdown(
label="Generated Test",
latex_delimiters=[
{"left": "$$", "right": "$$", "display": True},
{"left": "$", "right": "$", "display": False}
]
)
with gr.Row():
with gr.Column():
gr.Markdown("### Download Questions Only")
questions_latex_btn = gr.Button("Download Questions (LaTeX)")
questions_pdf_btn = gr.Button("Download Questions (PDF)")
with gr.Column():
gr.Markdown("### Download Full Test with Solutions")
full_latex_btn = gr.Button("Download Full Test (LaTeX)")
full_pdf_btn = gr.Button("Download Full Test (PDF)")
# Hidden components for downloads
questions_latex_output = gr.File(label="Questions LaTeX", visible=False)
questions_pdf_output = gr.File(label="Questions PDF", visible=False)
full_latex_output = gr.File(label="Full LaTeX", visible=False)
full_pdf_output = gr.File(label="Full PDF", visible=False)
# Event handlers
def generate_and_prepare_downloads(subject):
test_content = generate_test_with_format(subject, "latex")
files = create_download_files(test_content)
return (
test_content,
(files["questions_latex"], "questions.tex"),
(files["questions_pdf"], "questions.pdf"),
(files["full_latex"], "full_test.tex"),
(files["full_pdf"], "full_test.pdf")
)
generate_btn.click(
generate_and_prepare_downloads,
inputs=[subject_dropdown],
outputs=[output_text, questions_latex_output, questions_pdf_output,
full_latex_output, full_pdf_output]
)
# Download button clicks
questions_latex_btn.click(lambda: questions_latex_output.value)
questions_pdf_btn.click(lambda: questions_pdf_output.value)
full_latex_btn.click(lambda: full_latex_output.value)
full_pdf_btn.click(lambda: full_pdf_output.value)
if __name__ == "__main__":
interface.launch()