|
|
import gradio as gr |
|
|
import os |
|
|
import re |
|
|
import time |
|
|
import base64 |
|
|
from openai import OpenAI |
|
|
from together import Together |
|
|
from PIL import Image |
|
|
import io |
|
|
|
|
|
|
|
|
|
|
|
def generate_math_solution_openrouter(api_key, problem_text, history=None): |
|
|
if not api_key.strip(): |
|
|
return "Please enter your OpenRouter API key.", history |
|
|
|
|
|
if not problem_text.strip(): |
|
|
return "Please enter a math problem so that I can solve it for you!", |
|
|
|
|
|
try: |
|
|
client=OpenAI( |
|
|
base_url="https://openrouter.ai/api/v1", |
|
|
api_key=api_key, |
|
|
) |
|
|
|
|
|
messages= [ |
|
|
{"role": "system", "content": |
|
|
"""You are an expert math tutor who explains concepts clearly and thoroughly. |
|
|
Analyze the given math problem and provide a detailed step-by-step solution. |
|
|
For each step: |
|
|
1. Show the mathematical operation |
|
|
2. Explain why this step is necessary |
|
|
3. Connect it to relevant mathematical concepts |
|
|
|
|
|
Format your response with clear section headers using markdown. |
|
|
Begin with an "Initial Analysis" section, follow with numbered steps, |
|
|
and conclude with a "Final Answer" section."""}, |
|
|
] |
|
|
|
|
|
if history: |
|
|
for exchange in history: |
|
|
messages.append({"role": "user", "content": exchange[0]}) |
|
|
if exchange[1]: |
|
|
messages.append({"role": "assistant", "content": exchange[1]}) |
|
|
|
|
|
|
|
|
messages.append({"role": "user", "content": f"Solve this math problem step-by-step: {problem_text}"}) |
|
|
|
|
|
|
|
|
completion = client.chat.completions.create( |
|
|
model="minimax/minimax-m2:free", |
|
|
messages=messages, |
|
|
extra_headers={ |
|
|
"HTTP-Referer": "https://advancedmathtutor.edu", |
|
|
"X-Title": "Advanced Math Tutor", |
|
|
} |
|
|
) |
|
|
|
|
|
solution=completion.choices[0].message.content |
|
|
|
|
|
|
|
|
if history is None: |
|
|
history = [] |
|
|
history.append((problem_text, solution)) |
|
|
|
|
|
return solution, history |
|
|
|
|
|
except Exception as e: |
|
|
error_message = f"Error: {str(e)}" |
|
|
return error_message, history |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def image_to_base64(image_path): |
|
|
if image_path is None: |
|
|
return None |
|
|
|
|
|
try: |
|
|
with open(image_path, "rb") as img_file: |
|
|
return base64.b64encode(img_file.read()).decode("utf-8") |
|
|
except Exception as e: |
|
|
print(f"Error converting image to base64: {str(e)}") |
|
|
return None |
|
|
|
|
|
|
|
|
|
|
|
def generate_math_solution_together(api_key, problem_text, image_path=None, history=None): |
|
|
if not api_key.strip(): |
|
|
return "Please enter your Together AI API key.", history |
|
|
|
|
|
if not problem_text.strip() and image_path is None: |
|
|
return "Please enter a math problem or upload an image of a math problem.", history |
|
|
|
|
|
try: |
|
|
client = Together(api_key=api_key) |
|
|
|
|
|
messages= [ |
|
|
{"role": "system", "content": |
|
|
"""You are an expert math tutor who explains concepts clearly and thoroughly. |
|
|
Analyze the given math problem and provide a detailed step-by-step solution. |
|
|
For each step: |
|
|
1. Show the mathematical operation |
|
|
2. Explain why this step is necessary |
|
|
3. Connect it to relevant mathematical concepts |
|
|
|
|
|
Format your response with clear section headers using markdown. |
|
|
Begin with an "Initial Analysis" section, follow with numbered steps, |
|
|
and conclude with a "Final Answer" section."""}, |
|
|
] |
|
|
|
|
|
|
|
|
if history: |
|
|
for exchange in history: |
|
|
messages.append({"role": "user", "content": exchange[0]}) |
|
|
if exchange[1]: |
|
|
messages.append({"role": "assistant", "content": exchange[1]}) |
|
|
|
|
|
|
|
|
user_message_content = [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if problem_text.strip(): |
|
|
user_message_content.append({ |
|
|
"type": "text", |
|
|
"text": f"Solve this math problem: {problem_text}" |
|
|
}) |
|
|
else: |
|
|
user_message_content.append({ |
|
|
"type": "text", |
|
|
"text": "Solve this math problem from the image:" |
|
|
}) |
|
|
|
|
|
|
|
|
if image_path: |
|
|
|
|
|
base64_image = image_to_base64(image_path) |
|
|
if base64_image: |
|
|
user_message_content.append({ |
|
|
"type": "image_url", |
|
|
"image_url": { |
|
|
"url": f"data:image/jpeg;base64,{base64_image}" |
|
|
} |
|
|
}) |
|
|
|
|
|
|
|
|
messages.append({ |
|
|
"role": "user", |
|
|
"content": user_message_content |
|
|
}) |
|
|
|
|
|
|
|
|
response=client.chat.completions.create( |
|
|
model="ServiceNow-AI/Apriel-1.5-15b-Thinker", |
|
|
messages=messages, |
|
|
stream=False |
|
|
) |
|
|
|
|
|
solution=response.choices[0].message.content |
|
|
|
|
|
|
|
|
if history is None: |
|
|
history = [] |
|
|
history.append((problem_text if problem_text.strip() else "Image problem", solution)) |
|
|
|
|
|
return solution, history |
|
|
|
|
|
except Exception as e: |
|
|
error_message = f"Error: {str(e)}" |
|
|
return error_message, history |
|
|
|
|
|
def create_demo(): |
|
|
with gr.Blocks(theme=gr.themes.Ocean(primary_hue="blue")) as demo: |
|
|
gr.Markdown("# 📚 Advanced Math Tutor") |
|
|
gr.Markdown(""" |
|
|
This application provides step-by-step solutions to math problems using advanced AI models. |
|
|
""") |
|
|
|
|
|
with gr.Tabs(): |
|
|
with gr.TabItem("Text Problem Solver (OpenRouter)"): |
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
openrouter_api_key = gr.Textbox( |
|
|
label="OpenRouter API Key", |
|
|
placeholder="Enter your OpenRouter API key (starts with sk-or-)", |
|
|
type="password" |
|
|
) |
|
|
text_problem_input = gr.Textbox( |
|
|
label="Math Problem", |
|
|
placeholder="Enter your math problem here...", |
|
|
lines=5 |
|
|
) |
|
|
example_problems = gr.Examples( |
|
|
examples=[ |
|
|
["Solve the quadratic equation: 3x² + 5x - 2 = 0"], |
|
|
["Find the derivative of f(x) = x³ln(x)"], |
|
|
["Calculate the area of a circle with radius 5 cm"], |
|
|
["Find all values of x that satisfy the equation: log₂(x-1) + log₂(x+3) = 5"] |
|
|
], |
|
|
inputs=[text_problem_input], |
|
|
label="Example Problems" |
|
|
) |
|
|
with gr.Row(): |
|
|
openrouter_submit_btn = gr.Button("Solve Problem", variant="primary") |
|
|
openrouter_clear_btn = gr.Button("Clear") |
|
|
|
|
|
with gr.Column(scale=2): |
|
|
openrouter_solution_output = gr.Markdown(label="Solution") |
|
|
|
|
|
|
|
|
openrouter_conversation_history = gr.State(value=None) |
|
|
|
|
|
|
|
|
openrouter_submit_btn.click( |
|
|
fn=generate_math_solution_openrouter, |
|
|
inputs=[openrouter_api_key, text_problem_input, openrouter_conversation_history], |
|
|
outputs=[openrouter_solution_output, openrouter_conversation_history] |
|
|
) |
|
|
|
|
|
openrouter_clear_btn.click( |
|
|
fn=lambda: ("", None), |
|
|
inputs=[], |
|
|
outputs=[openrouter_solution_output, openrouter_conversation_history] |
|
|
) |
|
|
|
|
|
with gr.TabItem("Image Problem Solver (Together AI)"): |
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
together_api_key = gr.Textbox( |
|
|
label="Together AI API Key", |
|
|
placeholder="Enter your Together AI API key", |
|
|
type="password" |
|
|
) |
|
|
together_problem_input = gr.Textbox( |
|
|
label="Problem Description/Instruction (Optional)", |
|
|
placeholder="Enter additional context for the image problem...", |
|
|
lines=3 |
|
|
) |
|
|
together_image_input = gr.Image( |
|
|
label="Upload Math Problem Image", |
|
|
type="filepath" |
|
|
) |
|
|
with gr.Row(): |
|
|
together_submit_btn = gr.Button("Solve Problem", variant="primary") |
|
|
together_clear_btn = gr.Button("Clear") |
|
|
|
|
|
with gr.Column(scale=2): |
|
|
together_solution_output = gr.Markdown(label="Solution") |
|
|
|
|
|
|
|
|
together_conversation_history = gr.State(value=None) |
|
|
|
|
|
|
|
|
together_submit_btn.click( |
|
|
fn=generate_math_solution_together, |
|
|
inputs=[together_api_key, together_problem_input, together_image_input, together_conversation_history], |
|
|
outputs=[together_solution_output, together_conversation_history] |
|
|
) |
|
|
|
|
|
together_clear_btn.click( |
|
|
fn=lambda: ("", None), |
|
|
inputs=[], |
|
|
outputs=[together_solution_output, together_conversation_history] |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
gr.Markdown(""" |
|
|
--- |
|
|
### About |
|
|
This application uses minimax-m2 model via OpenRouter for text-based problems |
|
|
and Apriel-1.5-15b-Thinker via Together AI for image-based problems. |
|
|
Your API keys are required but not stored permanently. |
|
|
""") |
|
|
|
|
|
return demo |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo = create_demo() |
|
|
demo.launch() |