File size: 10,903 Bytes
3abcb23
c35d60a
 
 
 
 
 
 
 
3abcb23
 
c35d60a
 
 
 
 
3abcb23
c35d60a
 
 
 
 
8114a6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e5be686
 
8114a6a
e5be686
8114a6a
c35d60a
8114a6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c35d60a
8114a6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
898bb3c
8114a6a
 
 
 
898bb3c
8114a6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213b076
8114a6a
 
 
 
 
 
 
 
c35d60a
8114a6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12af1be
8114a6a
213b076
8114a6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271e143
8114a6a
 
 
 
 
 
12af1be
8114a6a
 
 
 
213b076
 
8114a6a
 
 
213b076
8114a6a
 
 
 
 
 
213b076
8114a6a
12af1be
8114a6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12af1be
8114a6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3abcb23
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
import gradio as gr
import os 
import re
import time 
import base64
from openai import OpenAI # access the open router api
from together import Together 
from PIL import Image
import io


def math_solution_openrouter(api_key, prob_text, history=None):
    if not api_key.strip():
        return "please enter your OpenRouter Key.",history
    if not prob_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 a very smart math tutor who can able to solve math and give proper explanations clearly and in a precise manner.
             You can analyze the math problem given to you and provide the details solution step by step.
             For every step:
             1. Show all the mathematical explanations.
             2. Explain each step and its necessity.
             3. Connect it to the relevant mathematical concept.
             Format your response with clear section of headers using markdown and comment if necessary.
             Begin with a section of analysis named "Initail step" and followed number of step and conclude with "Final step" section.
             """},
        ]

        if history:
            for exchange in history:
                messages.append({"role":"user","content":exchange[0]}) #@ task a math problem
                if exchange[1]: # check if there is a problem 
                    messages.append({"role": "assistant","content": exchange[1]})  # AI response with solution.

        messages.append({"role":"user","content":f"Solve the given math problem step-by-step: {prob_text}"}) # math problem 

        completion = client.chat.completions.create(
            model= "openai/gpt-4o",
            message= messages,
            extra_headers={
                "HTTP-Referer": "https://smartmathtutor.edu", # Optional. Site URL for rankings on openrouter.ai.
                "X-Title": "Smart Math Tutor", # Optional. Site title for rankings on openrouter.ai.
          }
            
        )

        solution = completion.choices[0].message.content

        #update history
        if history is None:
            history=[]
        history.append((prob_text, solution ))

        return solution, history
    
    except Exception as e:
        error_message= f"Error:{str(e)}"

        return error_message, history
         
        
#image processing 
def img_conv_base64(img_path):
    if img_path is None:
        return None

    try:
        with open(img_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


# function for a given math problem for image data[Togetherai]
def gen_math_sol_together(api_key, prob_text, img_path=None, history=None):
    if not api_key.strip():
        return "Please enter your Valid Together API key",history

    if not prob_text.strip() and img_path is None:
        return "please enter a valid math problem or upload an image of a math problem", history
        
    try:
        client= Together(api_key=api_key)
        messages=[{ "role": "system", "content":
             """You are a very smart math tutor who can able to solve math and give proper explanations clearly and in a precise manner.
             You can analyze the math problem from image given to you and provide the details solution step by step.
             For every step:
             1. Show all the mathematical explanations.
             2. Explain each step and its necessity.
             3. Connect it to the relevant mathematical concept.
             Format your response with clear section of headers using markdown and comment if necessary.
             Begin with a section of analysis named "Initail step" and followed number of step and conclude with "Final step" section.
             """},]

        if history:
            for exchange in history:
                messages.append({"role":"user","content":exchange[0]}) #@ task a math problem
                if exchange[1]: # check if there is a problem 
                    messages.append({"role": "assistant","content": exchange[1]})  # AI response with solution.



        user_message_content= [] # if we want to add some instructions regaring how to solve the math from given image


        if prob_text.strip(): # for text
            user_message_content.append({
                "type": "text",
                "text": f"Solve this math problem:{prob_text}"
            })
        else: #image
            user_message_content.append({
                "type": "text",
                "text": "Solve this math problem from the given image"
            })
        if img_path:
            base64_image= img_conv_base64(img_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", #conversation saved with image data
            "content": user_message_content
            
        })

        response = client.chat.completions.create(
            model= "meta-llama/Llama-Vision-Free",
            message= messages,
            stream= False
        )
        solution= response.choices[0].message.content

        if history is None:
            history=[]
        history.append(prob_text if prob_text.strip() else "Image problem ..", solution)

        return solution, history
        
    except Exception as e:
        error_msg= f"Error: {str(e)}"
        return error_msg, history


def create_demo():
    with gr.Blocks(theme=gr.themes.Ocean(primary_hue="blue")) as demo:
        gr.Markdown("# Smart Math Tutor")
        gr.Markdown("""This applications provide step by step solution to a math paroblem using AI Tools. 
        Choose between OpenPouter's Phi-4-reasoning-plus for text based analysis and Together AI's Llama-Vision for problem with images""")\



        with gr.Tabs():
            with gr.TabItem("Text problem solver (OpenRouter)"):
                with gr.Row():
                    with gr.Column(scale=1): #left side
                        openrouter_api_key= gr.Textbox(
                            label= "OpenRouter API key",
                            placeholder= "enter your API key here",
                            type= "password"
                        )
                        text_prob_input= gr.Textbox(
                            label="Math Problem",
                            placeholder= "Enter ypur 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²) = 5"]
                            ],
                            input=[text_prob_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): #right side
                        openrouter_solution_output= gr.Markdown(label="Solution")

                    openrouter_conversation_history= gr.State(value=None)
                    openrouter_submit_btn.click(
                        fn=math_solution_openrouter,
                        inputs=[openrouter_api_key, text_prob_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("Text problem solver (Together AI)"):
                with gr.Row():
                    with gr.Column(scale=1): #left side
                        together_api_key= gr.Textbox(
                            label= "Together API key",
                            placeholder= "enter your API key here",
                            type= "password"
                        )
                        together_prob_input= gr.Textbox(
                            label="Math Problem Description",
                            placeholder= "Enter additional math problem here..",
                            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)
                    # Button actions
                    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]
                    )

        # Footer
        gr.Markdown("""
        ---
        ### About
        This application uses Microsoft's Phi-4-reasoning-plus model via OpenRouter for text-based problems
        and Llama-Vision-Free via Together AI for image-based problems. 
        Your API keys are required but not stored permanently.
        """)

    return demo
# Launch the app
if __name__ == "__main__":
    demo = create_demo()
    demo.launch()