Spaces:
Running
Running
no conceptual questions, added download functionality
Browse filesModified the system prompt to explicitly require computational or proof-based problems only, and explicitly forbid conceptual questions
Added functionality to generate both LaTeX and PDF versions of the test
Created a new interface using Gradio Blocks that includes:
Download buttons for questions-only and full test versions
Both LaTeX and PDF format options
Added functions to handle LaTeX document creation and PDF conversion
Improved the UI layout with separate sections for different download options
app.py
CHANGED
@@ -4,6 +4,9 @@ from anthropic import Anthropic
|
|
4 |
from datetime import datetime, timedelta
|
5 |
from collections import deque
|
6 |
import random
|
|
|
|
|
|
|
7 |
|
8 |
# Initialize Anthropic client
|
9 |
anthropic = Anthropic(
|
@@ -31,8 +34,46 @@ def clean_latex(text):
|
|
31 |
text = text.replace('\n', '\n\n')
|
32 |
return text
|
33 |
|
34 |
-
def
|
35 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
try:
|
37 |
check_api_key()
|
38 |
if not check_rate_limit():
|
@@ -40,11 +81,10 @@ def generate_test(subject):
|
|
40 |
|
41 |
request_history.append(datetime.now())
|
42 |
|
43 |
-
# Randomly select focus areas and difficulty levels
|
44 |
topics = {
|
45 |
"Single Variable Calculus": ["limits", "derivatives", "integrals", "series", "applications"],
|
46 |
-
"Multivariable Calculus": ["partial derivatives", "multiple integrals", "vector fields", "optimization"
|
47 |
-
"Linear Algebra": ["matrices", "vector spaces", "eigenvalues", "linear transformations"
|
48 |
# ... add topics for other subjects
|
49 |
}
|
50 |
|
@@ -58,8 +98,8 @@ def generate_test(subject):
|
|
58 |
system_prompt = f"""You will write math exam questions. Follow these requirements EXACTLY:
|
59 |
1. Write exactly 3 university-level questions focusing on these specific topics: {', '.join(selected_topics)}
|
60 |
2. Make the questions {difficulty_distribution}
|
61 |
-
3.
|
62 |
-
4.
|
63 |
5. For LaTeX math formatting:
|
64 |
- Use $ for simple inline math
|
65 |
- For equations and solution steps, use $$ on separate lines
|
@@ -69,13 +109,9 @@ def generate_test(subject):
|
|
69 |
7. Include detailed solutions after each question
|
70 |
8. Keep formatting simple and clear
|
71 |
|
72 |
-
Important:
|
73 |
-
interdisciplinary connections, or creative scenarios where appropriate."""
|
74 |
|
75 |
-
|
76 |
-
base_temperature = 0.7
|
77 |
-
complexity_adjustment = random.uniform(-0.1, 0.1)
|
78 |
-
temperature = min(1.0, max(0.5, base_temperature + complexity_adjustment))
|
79 |
|
80 |
message = anthropic.messages.create(
|
81 |
model="claude-3-opus-20240229",
|
@@ -87,38 +123,32 @@ def generate_test(subject):
|
|
87 |
}]
|
88 |
)
|
89 |
|
90 |
-
# Extract usage information
|
91 |
-
input_tokens = message.usage.input_tokens
|
92 |
-
output_tokens = message.usage.output_tokens
|
93 |
-
input_cost = (input_tokens / 1000) * 0.015
|
94 |
-
output_cost = (output_tokens / 1000) * 0.075
|
95 |
-
total_cost = input_cost + output_cost
|
96 |
-
|
97 |
-
usage_stats = f"""
|
98 |
-
\n---\nUsage Statistics:
|
99 |
-
• Input Tokens: {input_tokens:,}
|
100 |
-
• Output Tokens: {output_tokens:,}
|
101 |
-
• Total Tokens: {input_tokens + output_tokens:,}
|
102 |
-
|
103 |
-
Cost Breakdown:
|
104 |
-
• Input Cost: ${input_cost:.4f}
|
105 |
-
• Output Cost: ${output_cost:.4f}
|
106 |
-
• Total Cost: ${total_cost:.4f}
|
107 |
-
"""
|
108 |
-
|
109 |
if hasattr(message, 'content') and len(message.content) > 0:
|
110 |
response_text = message.content[0].text
|
111 |
-
|
112 |
-
return formatted_response
|
113 |
else:
|
114 |
return "Error: No content in response"
|
115 |
|
116 |
-
except ValueError as e:
|
117 |
-
return f"Configuration Error: {str(e)}"
|
118 |
except Exception as e:
|
119 |
return f"Error: {str(e)}"
|
120 |
|
121 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
122 |
subjects = [
|
123 |
"Single Variable Calculus",
|
124 |
"Multivariable Calculus",
|
@@ -132,27 +162,73 @@ subjects = [
|
|
132 |
"Topology"
|
133 |
]
|
134 |
|
|
|
|
|
|
|
|
|
135 |
# Create Gradio interface
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
label="Generated Test",
|
145 |
latex_delimiters=[
|
146 |
{"left": "$$", "right": "$$", "display": True},
|
147 |
{"left": "$", "right": "$", "display": False}
|
148 |
]
|
149 |
-
)
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
156 |
|
157 |
if __name__ == "__main__":
|
158 |
interface.launch()
|
|
|
4 |
from datetime import datetime, timedelta
|
5 |
from collections import deque
|
6 |
import random
|
7 |
+
import tempfile
|
8 |
+
import subprocess
|
9 |
+
from pathlib import Path
|
10 |
|
11 |
# Initialize Anthropic client
|
12 |
anthropic = Anthropic(
|
|
|
34 |
text = text.replace('\n', '\n\n')
|
35 |
return text
|
36 |
|
37 |
+
def create_latex_document(content, questions_only=False):
|
38 |
+
"""Create a complete LaTeX document"""
|
39 |
+
latex_header = r"""\documentclass{article}
|
40 |
+
\usepackage{amsmath,amssymb}
|
41 |
+
\usepackage[margin=1in]{geometry}
|
42 |
+
\begin{document}
|
43 |
+
"""
|
44 |
+
latex_footer = r"\end{document}"
|
45 |
+
|
46 |
+
if questions_only:
|
47 |
+
# Extract only the questions (everything before "Solution:")
|
48 |
+
questions = []
|
49 |
+
for question in content.split('\n'):
|
50 |
+
if 'Solution:' in question:
|
51 |
+
continue
|
52 |
+
questions.append(question)
|
53 |
+
content = '\n'.join(questions)
|
54 |
+
|
55 |
+
return f"{latex_header}\n{content}\n{latex_footer}"
|
56 |
+
|
57 |
+
def latex_to_pdf(latex_content):
|
58 |
+
"""Convert LaTeX content to PDF"""
|
59 |
+
with tempfile.TemporaryDirectory() as tmpdir:
|
60 |
+
tex_path = Path(tmpdir) / "output.tex"
|
61 |
+
with open(tex_path, "w", encoding="utf-8") as f:
|
62 |
+
f.write(latex_content)
|
63 |
+
|
64 |
+
# Run pdflatex twice to resolve references
|
65 |
+
subprocess.run(["pdflatex", "-interaction=nonstopmode", str(tex_path)],
|
66 |
+
cwd=tmpdir, capture_output=True)
|
67 |
+
subprocess.run(["pdflatex", "-interaction=nonstopmode", str(tex_path)],
|
68 |
+
cwd=tmpdir, capture_output=True)
|
69 |
+
|
70 |
+
pdf_path = Path(tmpdir) / "output.pdf"
|
71 |
+
if pdf_path.exists():
|
72 |
+
return pdf_path.read_bytes()
|
73 |
+
return None
|
74 |
+
|
75 |
+
def generate_test_with_format(subject, output_format):
|
76 |
+
"""Generate a math test with specified output format"""
|
77 |
try:
|
78 |
check_api_key()
|
79 |
if not check_rate_limit():
|
|
|
81 |
|
82 |
request_history.append(datetime.now())
|
83 |
|
|
|
84 |
topics = {
|
85 |
"Single Variable Calculus": ["limits", "derivatives", "integrals", "series", "applications"],
|
86 |
+
"Multivariable Calculus": ["partial derivatives", "multiple integrals", "vector fields", "optimization"],
|
87 |
+
"Linear Algebra": ["matrices", "vector spaces", "eigenvalues", "linear transformations"],
|
88 |
# ... add topics for other subjects
|
89 |
}
|
90 |
|
|
|
98 |
system_prompt = f"""You will write math exam questions. Follow these requirements EXACTLY:
|
99 |
1. Write exactly 3 university-level questions focusing on these specific topics: {', '.join(selected_topics)}
|
100 |
2. Make the questions {difficulty_distribution}
|
101 |
+
3. ALL questions must be computational or proof-based problems. NO conceptual or explanation questions.
|
102 |
+
4. Each question must require mathematical work, calculations, or formal proofs
|
103 |
5. For LaTeX math formatting:
|
104 |
- Use $ for simple inline math
|
105 |
- For equations and solution steps, use $$ on separate lines
|
|
|
109 |
7. Include detailed solutions after each question
|
110 |
8. Keep formatting simple and clear
|
111 |
|
112 |
+
Important: Every question must require mathematical computation or proof. Do not ask for explanations, descriptions, or concepts."""
|
|
|
113 |
|
114 |
+
temperature = 0.7
|
|
|
|
|
|
|
115 |
|
116 |
message = anthropic.messages.create(
|
117 |
model="claude-3-opus-20240229",
|
|
|
123 |
}]
|
124 |
)
|
125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
if hasattr(message, 'content') and len(message.content) > 0:
|
127 |
response_text = message.content[0].text
|
128 |
+
return clean_latex(response_text)
|
|
|
129 |
else:
|
130 |
return "Error: No content in response"
|
131 |
|
|
|
|
|
132 |
except Exception as e:
|
133 |
return f"Error: {str(e)}"
|
134 |
|
135 |
+
def create_download_files(test_content):
|
136 |
+
"""Create downloadable files in different formats"""
|
137 |
+
# Full test (questions and solutions)
|
138 |
+
full_latex = create_latex_document(test_content, questions_only=False)
|
139 |
+
full_pdf = latex_to_pdf(full_latex)
|
140 |
+
|
141 |
+
# Questions only
|
142 |
+
questions_latex = create_latex_document(test_content, questions_only=True)
|
143 |
+
questions_pdf = latex_to_pdf(questions_latex)
|
144 |
+
|
145 |
+
return {
|
146 |
+
"full_latex": full_latex,
|
147 |
+
"full_pdf": full_pdf,
|
148 |
+
"questions_latex": questions_latex,
|
149 |
+
"questions_pdf": questions_pdf
|
150 |
+
}
|
151 |
+
|
152 |
subjects = [
|
153 |
"Single Variable Calculus",
|
154 |
"Multivariable Calculus",
|
|
|
162 |
"Topology"
|
163 |
]
|
164 |
|
165 |
+
def download_handler(file_content, filename):
|
166 |
+
"""Handle file downloads"""
|
167 |
+
return file_content
|
168 |
+
|
169 |
# Create Gradio interface
|
170 |
+
with gr.Blocks() as interface:
|
171 |
+
gr.Markdown("# Advanced Mathematics Test Generator")
|
172 |
+
gr.Markdown("""Generates unique university-level mathematics exam questions with solutions using Claude 3 Opus.
|
173 |
+
Each test features different topics and difficulty levels. Limited to 25 requests per day.""")
|
174 |
+
|
175 |
+
with gr.Row():
|
176 |
+
subject_dropdown = gr.Dropdown(
|
177 |
+
choices=subjects,
|
178 |
+
label="Select Mathematics Subject",
|
179 |
+
info="Choose a subject for the exam questions"
|
180 |
+
)
|
181 |
+
generate_btn = gr.Button("Generate Test")
|
182 |
+
|
183 |
+
output_text = gr.Markdown(
|
184 |
label="Generated Test",
|
185 |
latex_delimiters=[
|
186 |
{"left": "$$", "right": "$$", "display": True},
|
187 |
{"left": "$", "right": "$", "display": False}
|
188 |
]
|
189 |
+
)
|
190 |
+
|
191 |
+
with gr.Row():
|
192 |
+
with gr.Column():
|
193 |
+
gr.Markdown("### Download Questions Only")
|
194 |
+
questions_latex_btn = gr.Button("Download Questions (LaTeX)")
|
195 |
+
questions_pdf_btn = gr.Button("Download Questions (PDF)")
|
196 |
+
|
197 |
+
with gr.Column():
|
198 |
+
gr.Markdown("### Download Full Test with Solutions")
|
199 |
+
full_latex_btn = gr.Button("Download Full Test (LaTeX)")
|
200 |
+
full_pdf_btn = gr.Button("Download Full Test (PDF)")
|
201 |
+
|
202 |
+
# Hidden components for downloads
|
203 |
+
questions_latex_output = gr.File(label="Questions LaTeX", visible=False)
|
204 |
+
questions_pdf_output = gr.File(label="Questions PDF", visible=False)
|
205 |
+
full_latex_output = gr.File(label="Full LaTeX", visible=False)
|
206 |
+
full_pdf_output = gr.File(label="Full PDF", visible=False)
|
207 |
+
|
208 |
+
# Event handlers
|
209 |
+
def generate_and_prepare_downloads(subject):
|
210 |
+
test_content = generate_test_with_format(subject, "latex")
|
211 |
+
files = create_download_files(test_content)
|
212 |
+
return (
|
213 |
+
test_content,
|
214 |
+
(files["questions_latex"], "questions.tex"),
|
215 |
+
(files["questions_pdf"], "questions.pdf"),
|
216 |
+
(files["full_latex"], "full_test.tex"),
|
217 |
+
(files["full_pdf"], "full_test.pdf")
|
218 |
+
)
|
219 |
+
|
220 |
+
generate_btn.click(
|
221 |
+
generate_and_prepare_downloads,
|
222 |
+
inputs=[subject_dropdown],
|
223 |
+
outputs=[output_text, questions_latex_output, questions_pdf_output,
|
224 |
+
full_latex_output, full_pdf_output]
|
225 |
+
)
|
226 |
+
|
227 |
+
# Download button clicks
|
228 |
+
questions_latex_btn.click(lambda: questions_latex_output.value)
|
229 |
+
questions_pdf_btn.click(lambda: questions_pdf_output.value)
|
230 |
+
full_latex_btn.click(lambda: full_latex_output.value)
|
231 |
+
full_pdf_btn.click(lambda: full_pdf_output.value)
|
232 |
|
233 |
if __name__ == "__main__":
|
234 |
interface.launch()
|