tanjinadnanabir/Advanced-Math-Tutor-1
0
1import gradio as gr2import os3import re4import time5import base646from openai import OpenAI7from together import Together8from PIL import Image9import io10import markdown11from datetime import datetime12import tempfile13import weasyprint14from pathlib import Path15 16# Function to convert markdown to HTML with styling17def markdown_to_html(markdown_text, problem_text="", include_problem=True):18 """Convert markdown to styled HTML"""19 20 # Convert markdown to HTML21 html_content = markdown.markdown(markdown_text, extensions=['tables', 'fenced_code'])22 23 # Get current timestamp24 timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")25 26 # Create styled HTML document27 styled_html = f"""28 <!DOCTYPE html>29 <html lang="en">30 <head>31 <meta charset="UTF-8">32 <meta name="viewport" content="width=device-width, initial-scale=1.0">33 <title>Math Solution - Advanced Math Tutor</title>34 <style>35 body {{36 font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;37 line-height: 1.6;38 color: #333;39 max-width: 800px;40 margin: 0 auto;41 padding: 20px;42 background-color: #f9f9f9;43 }}44 .container {{45 background-color: white;46 padding: 40px;47 border-radius: 10px;48 box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);49 }}50 .header {{51 text-align: center;52 border-bottom: 3px solid #4CAF50;53 padding-bottom: 20px;54 margin-bottom: 30px;55 }}56 .header h1 {{57 color: #2c3e50;58 margin: 0;59 font-size: 2.5em;60 }}61 .header .subtitle {{62 color: #7f8c8d;63 font-style: italic;64 margin-top: 10px;65 }}66 .problem-section {{67 background-color: #e8f5e8;68 padding: 20px;69 border-radius: 8px;70 margin-bottom: 30px;71 border-left: 5px solid #4CAF50;72 }}73 .problem-section h2 {{74 color: #2c3e50;75 margin-top: 0;76 }}77 .solution-content {{78 background-color: #f8f9fa;79 padding: 25px;80 border-radius: 8px;81 border-left: 5px solid #007bff;82 }}83 h1, h2, h3, h4, h5, h6 {{84 color: #2c3e50;85 margin-top: 25px;86 margin-bottom: 15px;87 }}88 h2 {{89 border-bottom: 2px solid #eee;90 padding-bottom: 10px;91 }}92 code {{93 background-color: #f1f1f1;94 padding: 2px 6px;95 border-radius: 3px;96 font-family: 'Courier New', monospace;97 color: #d63384;98 }}99 pre {{100 background-color: #f8f8f8;101 padding: 15px;102 border-radius: 5px;103 overflow-x: auto;104 border: 1px solid #ddd;105 }}106 pre code {{107 background-color: transparent;108 padding: 0;109 color: inherit;110 }}111 .math-expression {{112 background-color: #fff3cd;113 padding: 10px;114 border-radius: 5px;115 border: 1px solid #ffeaa7;116 margin: 10px 0;117 font-family: 'Times New Roman', serif;118 font-size: 1.1em;119 }}120 .step {{121 margin: 20px 0;122 padding: 15px;123 background-color: #ffffff;124 border-radius: 8px;125 border: 1px solid #dee2e6;126 }}127 .final-answer {{128 background-color: #d4edda;129 border: 2px solid #4CAF50;130 padding: 20px;131 border-radius: 8px;132 margin-top: 30px;133 text-align: center;134 font-weight: bold;135 font-size: 1.2em;136 }}137 .timestamp {{138 text-align: right;139 color: #6c757d;140 font-size: 0.9em;141 margin-top: 30px;142 padding-top: 20px;143 border-top: 1px solid #eee;144 }}145 ul, ol {{146 padding-left: 25px;147 }}148 li {{149 margin: 8px 0;150 }}151 table {{152 border-collapse: collapse;153 width: 100%;154 margin: 20px 0;155 }}156 th, td {{157 border: 1px solid #ddd;158 padding: 12px;159 text-align: left;160 }}161 th {{162 background-color: #f8f9fa;163 font-weight: bold;164 }}165 .print-button {{166 background-color: #007bff;167 color: white;168 border: none;169 padding: 10px 20px;170 border-radius: 5px;171 cursor: pointer;172 font-size: 16px;173 margin: 10px 5px;174 display: inline-block;175 text-decoration: none;176 }}177 .print-button:hover {{178 background-color: #0056b3;179 }}180 @media print {{181 body {{182 background-color: white;183 }}184 .container {{185 box-shadow: none;186 border: none;187 }}188 .print-button {{189 display: none;190 }}191 }}192 </style>193 <script>194 function printPage() {{195 window.print();196 }}197 </script>198 </head>199 <body>200 <div class="container">201 <div class="header">202 <h1>๐ Advanced Math Tutor</h1>203 <div class="subtitle">Step-by-Step Mathematical Solution</div>204 </div>205 206 <button class="print-button" onclick="printPage()">๐จ๏ธ Print to PDF</button>207 208 {f'''209 <div class="problem-section">210 <h2>๐ Problem Statement</h2>211 <p><strong>{problem_text}</strong></p>212 </div>213 ''' if include_problem and problem_text.strip() else ''}214 215 <div class="solution-content">216 <h2>๐ Solution</h2>217 {html_content}218 </div>219 220 <div class="timestamp">221 Generated on: {timestamp}222 </div>223 </div>224 </body>225 </html>226 """227 228 return styled_html229 230# Function to save HTML to file231def save_html_to_file(html_content, filename_prefix="math_solution"):232 """Save HTML content to a temporary file and return the file path"""233 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")234 filename = f"{filename_prefix}_{timestamp}.html"235 236 # Create a temporary file237 temp_dir = tempfile.gettempdir()238 file_path = os.path.join(temp_dir, filename)239 240 with open(file_path, 'w', encoding='utf-8') as f:241 f.write(html_content)242 243 return file_path244 245# Function to convert HTML to PDF246def html_to_pdf(html_content, filename_prefix="math_solution"):247 """Convert HTML content to PDF and return the file path"""248 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")249 filename = f"{filename_prefix}_{timestamp}.pdf"250 251 # Create a temporary file for PDF252 temp_dir = tempfile.gettempdir()253 pdf_path = os.path.join(temp_dir, filename)254 255 try:256 # Convert HTML to PDF using WeasyPrint257 weasyprint.HTML(string=html_content).write_pdf(pdf_path)258 return pdf_path259 except Exception as e:260 print(f"Error converting to PDF: {str(e)}")261 return None262 263# Enhanced function to generate math solution using OpenRouter with HTML output264def generate_math_solution_openrouter(api_key, problem_text, history=None):265 if not api_key.strip():266 return "Please enter your OpenRouter API key.", None, None, history267 268 if not problem_text.strip():269 return "Please enter a math problem.", None, None, history270 271 try:272 client = OpenAI(273 base_url="https://openrouter.ai/api/v1",274 api_key=api_key,275 )276 277 messages = [278 {"role": "system", "content": 279 """You are an expert math tutor who explains concepts clearly and thoroughly.280 Analyze the given math problem and provide a detailed step-by-step solution.281 For each step:282 1. Show the mathematical operation283 2. Explain why this step is necessary284 3. Connect it to relevant mathematical concepts285 286 Format your response using markdown with clear section headers.287 Begin with an "Initial Analysis" section, follow with numbered steps,288 and conclude with a "Final Answer" section.289 290 Use proper markdown formatting including:291 - Headers (##, ###)292 - **Bold text** for important points293 - `Code blocks` for mathematical expressions294 - Lists and numbered steps295 - Tables if needed for comparisons or data"""},296 ]297 298 # Add conversation history if it exists299 if history:300 for exchange in history:301 messages.append({"role": "user", "content": exchange[0]})302 if len(exchange) > 1 and exchange[1]: # Check if there's a response303 messages.append({"role": "assistant", "content": exchange[1]})304 305 # Add the current problem306 messages.append({"role": "user", "content": f"Solve this math problem step-by-step: {problem_text}"})307 308 # Create the completion309 completion = client.chat.completions.create(310 model="deepseek/deepseek-r1-0528:free",311 messages=messages,312 extra_headers={313 "HTTP-Referer": "https://advancedmathtutor.edu",314 "X-Title": "Advanced Math Tutor",315 }316 )317 318 markdown_solution = completion.choices[0].message.content319 320 # Convert to HTML321 html_solution = markdown_to_html(markdown_solution, problem_text)322 323 # Save HTML file324 html_file_path = save_html_to_file(html_solution, "openrouter_solution")325 326 # Convert to PDF327 pdf_file_path = html_to_pdf(html_solution, "openrouter_solution")328 329 # Update history330 if history is None:331 history = []332 history.append((problem_text, markdown_solution))333 334 return html_solution, html_file_path, pdf_file_path, history335 336 except Exception as e:337 error_message = f"Error: {str(e)}"338 return error_message, None, None, history339 340# Enhanced function to generate math solution using Together AI with HTML output341def generate_math_solution_together(api_key, problem_text, image_path=None, history=None):342 if not api_key.strip():343 return "Please enter your Together AI API key.", None, None, history344 345 if not problem_text.strip() and image_path is None:346 return "Please enter a math problem or upload an image of a math problem.", None, None, history347 348 try:349 client = Together(api_key=api_key)350 351 # Create the base message structure352 messages = [353 {354 "role": "system",355 "content": """You are an expert math tutor who explains concepts clearly and thoroughly.356 Analyze the given math problem and provide a detailed step-by-step solution.357 For each step:358 1. Show the mathematical operation359 2. Explain why this step is necessary360 3. Connect it to relevant mathematical concepts361 362 Format your response using markdown with clear section headers.363 Begin with an "Initial Analysis" section, follow with numbered steps,364 and conclude with a "Final Answer" section.365 366 Use proper markdown formatting including:367 - Headers (##, ###)368 - **Bold text** for important points369 - `Code blocks` for mathematical expressions370 - Lists and numbered steps371 - Tables if needed for comparisons or data"""372 }373 ]374 375 # Add conversation history if it exists376 if history:377 for exchange in history:378 messages.append({"role": "user", "content": exchange[0]})379 if len(exchange) > 1 and exchange[1]: # Check if there's a response380 messages.append({"role": "assistant", "content": exchange[1]})381 382 # Prepare the user message content383 user_message_content = []384 385 # Add text content if provided386 if problem_text.strip():387 user_message_content.append({388 "type": "text",389 "text": f"Solve this math problem: {problem_text}"390 })391 else:392 user_message_content.append({393 "type": "text",394 "text": "Solve this math problem from the image:"395 })396 397 # Add image if provided398 if image_path:399 # Convert image to base64400 base64_image = image_to_base64(image_path)401 if base64_image:402 user_message_content.append({403 "type": "image_url",404 "image_url": {405 "url": f"data:image/jpeg;base64,{base64_image}"406 }407 })408 409 # Add the user message with content410 messages.append({411 "role": "user",412 "content": user_message_content413 })414 415 # Create the completion416 response = client.chat.completions.create(417 model="ServiceNow-AI/Apriel-1.5-15b-Thinker",418 messages=messages,419 stream=False420 )421 422 markdown_solution = response.choices[0].message.content423 424 # Convert to HTML425 problem_display = problem_text if problem_text.strip() else "Image-based problem"426 html_solution = markdown_to_html(markdown_solution, problem_display)427 428 # Save HTML file429 html_file_path = save_html_to_file(html_solution, "together_solution")430 431 # Convert to PDF432 pdf_file_path = html_to_pdf(html_solution, "together_solution")433 434 # Update history - for simplicity, just store the text problem435 if history is None:436 history = []437 history.append((problem_display, markdown_solution))438 439 return html_solution, html_file_path, pdf_file_path, history440 441 except Exception as e:442 error_message = f"Error: {str(e)}"443 return error_message, None, None, history444 445# Function to convert image to base64446def image_to_base64(image_path):447 if image_path is None:448 return None449 450 try:451 with open(image_path, "rb") as img_file:452 return base64.b64encode(img_file.read()).decode("utf-8")453 except Exception as e:454 print(f"Error converting image to base64: {str(e)}")455 return None456 457# Define the Gradio interface458def create_demo():459 with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue")) as demo:460 gr.Markdown("# ๐ Advanced Math Tutor")461 gr.Markdown("""462 This application provides step-by-step solutions to math problems using advanced AI models.463 Solutions are generated in **HTML format** with download and print-to-PDF capabilities.464 Choose between OpenRouter's Phi-4-reasoning-plus for text-based problems or Together AI's 465 Llama-Vision for problems with images.466 """)467 468 # Main tabs469 with gr.Tabs():470 # Text-based problem solver (OpenRouter)471 with gr.TabItem("Text Problem Solver (OpenRouter)"):472 with gr.Row():473 with gr.Column(scale=1):474 openrouter_api_key = gr.Textbox(475 label="OpenRouter API Key", 476 placeholder="Enter your OpenRouter API key (starts with sk-or-)",477 type="password"478 )479 text_problem_input = gr.Textbox(480 label="Math Problem", 481 placeholder="Enter your math problem here...",482 lines=5483 )484 example_problems = gr.Examples(485 examples=[486 ["Solve the quadratic equation: 3xยฒ + 5x - 2 = 0"],487 ["Find the derivative of f(x) = xยณln(x)"],488 ["Calculate the area of a circle with radius 5 cm"],489 ["Find all values of x that satisfy the equation: logโ(x-1) + logโ(x+3) = 5"]490 ],491 inputs=[text_problem_input],492 label="Example Problems"493 )494 with gr.Row():495 openrouter_submit_btn = gr.Button("Solve Problem", variant="primary")496 openrouter_clear_btn = gr.Button("Clear")497 498 with gr.Column(scale=2):499 openrouter_solution_output = gr.HTML(label="Solution (HTML Format)")500 501 with gr.Row():502 openrouter_html_download = gr.File(503 label="๐ Download HTML Solution",504 visible=False505 )506 openrouter_pdf_download = gr.File(507 label="๐ Download PDF Solution",508 visible=False509 )510 511 # Store conversation history (invisible to user)512 openrouter_conversation_history = gr.State(value=None)513 514 # Button actions515 def handle_openrouter_submit(api_key, problem_text, history):516 html_solution, html_file, pdf_file, updated_history = generate_math_solution_openrouter(517 api_key, problem_text, history518 )519 520 # Return outputs including file updates521 return (522 html_solution,523 updated_history,524 gr.update(value=html_file, visible=html_file is not None),525 gr.update(value=pdf_file, visible=pdf_file is not None)526 )527 528 openrouter_submit_btn.click(529 fn=handle_openrouter_submit,530 inputs=[openrouter_api_key, text_problem_input, openrouter_conversation_history],531 outputs=[532 openrouter_solution_output, 533 openrouter_conversation_history,534 openrouter_html_download,535 openrouter_pdf_download536 ]537 )538 539 def clear_openrouter():540 return (541 "",542 None,543 gr.update(value=None, visible=False),544 gr.update(value=None, visible=False)545 )546 547 openrouter_clear_btn.click(548 fn=clear_openrouter,549 inputs=[],550 outputs=[551 openrouter_solution_output, 552 openrouter_conversation_history,553 openrouter_html_download,554 openrouter_pdf_download555 ]556 )557 558 # Image-based problem solver (Together AI)559 with gr.TabItem("Image Problem Solver (Together AI)"):560 with gr.Row():561 with gr.Column(scale=1):562 together_api_key = gr.Textbox(563 label="Together AI API Key", 564 placeholder="Enter your Together AI API key",565 type="password"566 )567 together_problem_input = gr.Textbox(568 label="Problem Description (Optional)", 569 placeholder="Enter additional context for the image problem...",570 lines=3571 )572 together_image_input = gr.Image(573 label="Upload Math Problem Image",574 type="filepath"575 )576 with gr.Row():577 together_submit_btn = gr.Button("Solve Problem", variant="primary")578 together_clear_btn = gr.Button("Clear")579 580 with gr.Column(scale=2):581 together_solution_output = gr.HTML(label="Solution (HTML Format)")582 583 with gr.Row():584 together_html_download = gr.File(585 label="๐ Download HTML Solution",586 visible=False587 )588 together_pdf_download = gr.File(589 label="๐ Download PDF Solution",590 visible=False591 )592 593 # Store conversation history (invisible to user)594 together_conversation_history = gr.State(value=None)595 596 # Button actions597 def handle_together_submit(api_key, problem_text, image_path, history):598 html_solution, html_file, pdf_file, updated_history = generate_math_solution_together(599 api_key, problem_text, image_path, history600 )601 602 # Return outputs including file updates603 return (604 html_solution,605 updated_history,606 gr.update(value=html_file, visible=html_file is not None),607 gr.update(value=pdf_file, visible=pdf_file is not None)608 )609 610 together_submit_btn.click(611 fn=handle_together_submit,612 inputs=[together_api_key, together_problem_input, together_image_input, together_conversation_history],613 outputs=[614 together_solution_output, 615 together_conversation_history,616 together_html_download,617 together_pdf_download618 ]619 )620 621 def clear_together():622 return (623 "",624 None,625 gr.update(value=None, visible=False),626 gr.update(value=None, visible=False)627 )628 629 together_clear_btn.click(630 fn=clear_together,631 inputs=[],632 outputs=[633 together_solution_output, 634 together_conversation_history,635 together_html_download,636 together_pdf_download637 ]638 )639 640 # Help tab641 with gr.TabItem("Help"):642 gr.Markdown("""643 ## How to Use the Advanced Math Tutor644 645 ### New Features ๐646 - **HTML-formatted solutions**: All responses are now generated in beautiful HTML format647 - **Download HTML**: Download the complete solution as an HTML file648 - **Download PDF**: Convert and download solutions as PDF files649 - **Print functionality**: Use the "Print to PDF" button in the HTML output to print directly650 651 ### Getting Started652 653 #### For Text-Based Problems (OpenRouter)654 1. You'll need an API key from OpenRouter655 2. Sign up at [OpenRouter](https://openrouter.ai/) to get your API key656 3. Enter your API key in the designated field in the "Text Problem Solver" tab657 658 #### For Image-Based Problems (Together AI)659 1. You'll need an API key from Together AI660 2. Sign up at [Together AI](https://www.together.ai/) to get your API key661 3. Enter your API key in the designated field in the "Image Problem Solver" tab662 4. Upload an image of your math problem663 5. Optionally add text to provide additional context664 665 ### Solving Math Problems666 - For text problems: Type or paste your math problem in the input field667 - For image problems: Upload a clear image of the math problem668 - Click "Solve Problem" to get a detailed step-by-step solution in HTML format669 - Use the download buttons to save HTML or PDF versions670 - Click "Print to PDF" within the solution to print directly from your browser671 672 ### HTML Output Features673 - **Professional styling**: Clean, readable format with proper typography674 - **Mathematical expressions**: Highlighted math expressions and code blocks675 - **Step-by-step sections**: Clearly organized solution steps676 - **Print-friendly**: Optimized for printing and PDF conversion677 - **Timestamps**: Each solution includes generation timestamp678 679 ### Tips for Best Results680 - Be specific in your problem description681 - Include all necessary information682 - For complex equations, use clear notation683 - For algebraic expressions, use ^ for exponents (e.g., x^2 for xยฒ)684 - Use parentheses to group terms clearly685 - For images, ensure the math problem is clearly visible and well-lit686 687 ### Types of Problems You Can Solve688 - Algebra (equations, inequalities, systems of equations)689 - Calculus (derivatives, integrals, limits)690 - Trigonometry691 - Geometry692 - Statistics and Probability693 - Number Theory694 - And many more!695 696 ### Required Dependencies697 To run this application, you'll need to install:698 ```bash699 pip install gradio openai together pillow markdown weasyprint700 ```701 """)702 703 # Footer704 gr.Markdown("""705 ---706 ### About707 This enhanced application uses Microsoft's Phi-4-reasoning-plus model via OpenRouter for text-based problems708 and Llama-Vision-Free via Together AI for image-based problems. 709 710 **New Features:**711 - HTML-formatted responses with professional styling712 - Download solutions as HTML files713 - Convert and download solutions as PDF files714 - Print-to-PDF functionality715 - Enhanced formatting with mathematical expressions highlighting716 717 Your API keys are required but not stored permanently.718 """)719 720 return demo721 722# Launch the app723if __name__ == "__main__":724 demo = create_demo()725 demo.launch()