shukdevdattaEX commited on
Commit
6e03e80
Β·
verified Β·
1 Parent(s): f06d607

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +714 -31
app.py CHANGED
@@ -1,42 +1,725 @@
1
- from Crypto.Cipher import AES
2
- from Crypto.Protocol.KDF import PBKDF2
3
  import os
 
 
 
 
 
 
 
 
 
4
  import tempfile
5
- from dotenv import load_dotenv
 
6
 
7
- load_dotenv() # Load all environment variables
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
- def unpad(data):
10
- return data[:-data[-1]]
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
- def decrypt_and_run():
13
- # Get password from Hugging Face Secrets environment variable
14
- password = os.getenv("PASSWORD")
15
- if not password:
16
- raise ValueError("PASSWORD secret not found in environment variables")
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
- password = password.encode()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
- with open("code.enc", "rb") as f:
21
- encrypted = f.read()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
- salt = encrypted[:16]
24
- iv = encrypted[16:32]
25
- ciphertext = encrypted[32:]
 
 
 
 
 
 
 
 
26
 
27
- key = PBKDF2(password, salt, dkLen=32, count=1000000)
28
- cipher = AES.new(key, AES.MODE_CBC, iv)
29
-
30
- plaintext = unpad(cipher.decrypt(ciphertext))
31
-
32
- with tempfile.NamedTemporaryFile(suffix=".py", delete=False, mode='wb') as tmp:
33
- tmp.write(plaintext)
34
- tmp.flush()
35
- print(f"[INFO] Running decrypted code from {tmp.name}")
36
- os.system(f"python {tmp.name}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
 
38
  if __name__ == "__main__":
39
- decrypt_and_run()
40
-
41
- # This script decrypts the encrypted code and runs it.
42
- # Ensure you have the PASSWORD secret set in your Hugging Face Secrets
 
1
+ import gradio as gr
 
2
  import os
3
+ import re
4
+ import time
5
+ import base64
6
+ from openai import OpenAI
7
+ from together import Together
8
+ from PIL import Image
9
+ import io
10
+ import markdown
11
+ from datetime import datetime
12
  import tempfile
13
+ import weasyprint
14
+ from pathlib import Path
15
 
16
+ # Function to convert markdown to HTML with styling
17
+ def markdown_to_html(markdown_text, problem_text="", include_problem=True):
18
+ """Convert markdown to styled HTML"""
19
+
20
+ # Convert markdown to HTML
21
+ html_content = markdown.markdown(markdown_text, extensions=['tables', 'fenced_code'])
22
+
23
+ # Get current timestamp
24
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
25
+
26
+ # Create styled HTML document
27
+ 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_html
229
 
230
+ # Function to save HTML to file
231
+ def 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 file
237
+ 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_path
244
 
245
+ # Function to convert HTML to PDF
246
+ def 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 PDF
252
+ temp_dir = tempfile.gettempdir()
253
+ pdf_path = os.path.join(temp_dir, filename)
254
+
255
+ try:
256
+ # Convert HTML to PDF using WeasyPrint
257
+ weasyprint.HTML(string=html_content).write_pdf(pdf_path)
258
+ return pdf_path
259
+ except Exception as e:
260
+ print(f"Error converting to PDF: {str(e)}")
261
+ return None
262
 
263
+ # Enhanced function to generate math solution using OpenRouter with HTML output
264
+ def 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, history
267
+
268
+ if not problem_text.strip():
269
+ return "Please enter a math problem.", None, None, history
270
+
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 operation
283
+ 2. Explain why this step is necessary
284
+ 3. Connect it to relevant mathematical concepts
285
+
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 points
293
+ - `Code blocks` for mathematical expressions
294
+ - Lists and numbered steps
295
+ - Tables if needed for comparisons or data"""},
296
+ ]
297
+
298
+ # Add conversation history if it exists
299
+ 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 response
303
+ messages.append({"role": "assistant", "content": exchange[1]})
304
+
305
+ # Add the current problem
306
+ messages.append({"role": "user", "content": f"Solve this math problem step-by-step: {problem_text}"})
307
+
308
+ # Create the completion
309
+ 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.content
319
+
320
+ # Convert to HTML
321
+ html_solution = markdown_to_html(markdown_solution, problem_text)
322
+
323
+ # Save HTML file
324
+ html_file_path = save_html_to_file(html_solution, "openrouter_solution")
325
+
326
+ # Convert to PDF
327
+ pdf_file_path = html_to_pdf(html_solution, "openrouter_solution")
328
+
329
+ # Update history
330
+ if history is None:
331
+ history = []
332
+ history.append((problem_text, markdown_solution))
333
+
334
+ return html_solution, html_file_path, pdf_file_path, history
335
+
336
+ except Exception as e:
337
+ error_message = f"Error: {str(e)}"
338
+ return error_message, None, None, history
339
 
340
+ # Enhanced function to generate math solution using Together AI with HTML output
341
+ def 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, history
344
+
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, history
347
+
348
+ try:
349
+ client = Together(api_key=api_key)
350
+
351
+ # Create the base message structure
352
+ 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 operation
359
+ 2. Explain why this step is necessary
360
+ 3. Connect it to relevant mathematical concepts
361
+
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 points
369
+ - `Code blocks` for mathematical expressions
370
+ - Lists and numbered steps
371
+ - Tables if needed for comparisons or data"""
372
+ }
373
+ ]
374
+
375
+ # Add conversation history if it exists
376
+ 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 response
380
+ messages.append({"role": "assistant", "content": exchange[1]})
381
+
382
+ # Prepare the user message content
383
+ user_message_content = []
384
+
385
+ # Add text content if provided
386
+ 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 provided
398
+ if image_path:
399
+ # Convert image to base64
400
+ 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 content
410
+ messages.append({
411
+ "role": "user",
412
+ "content": user_message_content
413
+ })
414
+
415
+ # Create the completion
416
+ response = client.chat.completions.create(
417
+ model="meta-llama/Llama-Vision-Free",
418
+ messages=messages,
419
+ stream=False
420
+ )
421
+
422
+ markdown_solution = response.choices[0].message.content
423
+
424
+ # Convert to HTML
425
+ 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 file
429
+ html_file_path = save_html_to_file(html_solution, "together_solution")
430
+
431
+ # Convert to PDF
432
+ pdf_file_path = html_to_pdf(html_solution, "together_solution")
433
+
434
+ # Update history - for simplicity, just store the text problem
435
+ if history is None:
436
+ history = []
437
+ history.append((problem_display, markdown_solution))
438
+
439
+ return html_solution, html_file_path, pdf_file_path, history
440
+
441
+ except Exception as e:
442
+ error_message = f"Error: {str(e)}"
443
+ return error_message, None, None, history
444
 
445
+ # Function to convert image to base64
446
+ def image_to_base64(image_path):
447
+ if image_path is None:
448
+ return None
449
+
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 None
456
 
457
+ # Define the Gradio interface
458
+ def 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 tabs
469
+ 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=5
483
+ )
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=False
505
+ )
506
+ openrouter_pdf_download = gr.File(
507
+ label="πŸ“„ Download PDF Solution",
508
+ visible=False
509
+ )
510
+
511
+ # Store conversation history (invisible to user)
512
+ openrouter_conversation_history = gr.State(value=None)
513
+
514
+ # Button actions
515
+ 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, history
518
+ )
519
+
520
+ # Return outputs including file updates
521
+ 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_download
536
+ ]
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_download
555
+ ]
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=3
571
+ )
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=False
587
+ )
588
+ together_pdf_download = gr.File(
589
+ label="πŸ“„ Download PDF Solution",
590
+ visible=False
591
+ )
592
+
593
+ # Store conversation history (invisible to user)
594
+ together_conversation_history = gr.State(value=None)
595
+
596
+ # Button actions
597
+ 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, history
600
+ )
601
+
602
+ # Return outputs including file updates
603
+ 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_download
618
+ ]
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_download
637
+ ]
638
+ )
639
+
640
+ # Help tab
641
+ with gr.TabItem("Help"):
642
+ gr.Markdown("""
643
+ ## How to Use the Advanced Math Tutor
644
+
645
+ ### New Features πŸŽ‰
646
+ - **HTML-formatted solutions**: All responses are now generated in beautiful HTML format
647
+ - **Download HTML**: Download the complete solution as an HTML file
648
+ - **Download PDF**: Convert and download solutions as PDF files
649
+ - **Print functionality**: Use the "Print to PDF" button in the HTML output to print directly
650
+
651
+ ### Getting Started
652
+
653
+ #### For Text-Based Problems (OpenRouter)
654
+ 1. You'll need an API key from OpenRouter
655
+ 2. Sign up at [OpenRouter](https://openrouter.ai/) to get your API key
656
+ 3. Enter your API key in the designated field in the "Text Problem Solver" tab
657
+
658
+ #### For Image-Based Problems (Together AI)
659
+ 1. You'll need an API key from Together AI
660
+ 2. Sign up at [Together AI](https://www.together.ai/) to get your API key
661
+ 3. Enter your API key in the designated field in the "Image Problem Solver" tab
662
+ 4. Upload an image of your math problem
663
+ 5. Optionally add text to provide additional context
664
+
665
+ ### Solving Math Problems
666
+ - For text problems: Type or paste your math problem in the input field
667
+ - For image problems: Upload a clear image of the math problem
668
+ - Click "Solve Problem" to get a detailed step-by-step solution in HTML format
669
+ - Use the download buttons to save HTML or PDF versions
670
+ - Click "Print to PDF" within the solution to print directly from your browser
671
+
672
+ ### HTML Output Features
673
+ - **Professional styling**: Clean, readable format with proper typography
674
+ - **Mathematical expressions**: Highlighted math expressions and code blocks
675
+ - **Step-by-step sections**: Clearly organized solution steps
676
+ - **Print-friendly**: Optimized for printing and PDF conversion
677
+ - **Timestamps**: Each solution includes generation timestamp
678
+
679
+ ### Tips for Best Results
680
+ - Be specific in your problem description
681
+ - Include all necessary information
682
+ - For complex equations, use clear notation
683
+ - For algebraic expressions, use ^ for exponents (e.g., x^2 for xΒ²)
684
+ - Use parentheses to group terms clearly
685
+ - For images, ensure the math problem is clearly visible and well-lit
686
+
687
+ ### Types of Problems You Can Solve
688
+ - Algebra (equations, inequalities, systems of equations)
689
+ - Calculus (derivatives, integrals, limits)
690
+ - Trigonometry
691
+ - Geometry
692
+ - Statistics and Probability
693
+ - Number Theory
694
+ - And many more!
695
+
696
+ ### Required Dependencies
697
+ To run this application, you'll need to install:
698
+ ```bash
699
+ pip install gradio openai together pillow markdown weasyprint
700
+ ```
701
+ """)
702
+
703
+ # Footer
704
+ gr.Markdown("""
705
+ ---
706
+ ### About
707
+ This enhanced application uses Microsoft's Phi-4-reasoning-plus model via OpenRouter for text-based problems
708
+ and Llama-Vision-Free via Together AI for image-based problems.
709
+
710
+ **New Features:**
711
+ - HTML-formatted responses with professional styling
712
+ - Download solutions as HTML files
713
+ - Convert and download solutions as PDF files
714
+ - Print-to-PDF functionality
715
+ - Enhanced formatting with mathematical expressions highlighting
716
+
717
+ Your API keys are required but not stored permanently.
718
+ """)
719
+
720
+ return demo
721
 
722
+ # Launch the app
723
  if __name__ == "__main__":
724
+ demo = create_demo()
725
+ demo.launch()