shukdevdatta123 commited on
Commit
4011f06
·
verified ·
1 Parent(s): 8e04214

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +31 -714
app.py CHANGED
@@ -1,725 +1,42 @@
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="microsoft/phi-4-reasoning-plus: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()
 
 
 
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