CoolFace
Apppublic

tanjinadnanabir/Advanced-Math-Tutor-1

sourceHugging Facemitupdated 11mo agoView on Hugging Face
0likes
app.py725 linesDownload Raw Back to root
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()