Nymbo commited on
Commit
5c66cbb
·
verified ·
1 Parent(s): 159b3ad

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +16 -147
app.py CHANGED
@@ -689,98 +689,16 @@ def Search_DuckDuckGo( # <-- MCP tool #2 (DDG Search)
689
  # Code Execution: Python (MCP tool #3)
690
  # ======================================
691
 
692
- import tempfile
693
- import base64
694
- from pathlib import Path
695
-
696
- def _detect_created_files(working_dir: str, before_files: set) -> list[str]:
697
- """
698
- Detect files created during code execution.
699
- Returns list of newly created file paths.
700
- """
701
- try:
702
- current_files = set()
703
- for file_path in Path(working_dir).rglob("*"):
704
- if file_path.is_file():
705
- current_files.add(str(file_path))
706
-
707
- new_files = current_files - before_files
708
- return list(new_files)
709
- except Exception:
710
- return []
711
-
712
-
713
- def _generate_file_url(file_path: str) -> dict:
714
- """
715
- Generate a data URL for small files or file info for larger files.
716
- Returns dict with file info and download URL.
717
- """
718
- try:
719
- path = Path(file_path)
720
- file_size = path.stat().st_size
721
-
722
- # For files under 1MB, create data URL
723
- if file_size < 1024 * 1024: # 1MB limit
724
- with open(file_path, 'rb') as f:
725
- file_data = f.read()
726
-
727
- # Determine MIME type based on extension
728
- mime_types = {
729
- '.csv': 'text/csv',
730
- '.txt': 'text/plain',
731
- '.json': 'application/json',
732
- '.png': 'image/png',
733
- '.jpg': 'image/jpeg',
734
- '.jpeg': 'image/jpeg',
735
- '.gif': 'image/gif',
736
- '.pdf': 'application/pdf',
737
- '.html': 'text/html',
738
- '.xml': 'text/xml',
739
- '.svg': 'image/svg+xml'
740
- }
741
-
742
- mime_type = mime_types.get(path.suffix.lower(), 'application/octet-stream')
743
- encoded_data = base64.b64encode(file_data).decode('utf-8')
744
- data_url = f"data:{mime_type};base64,{encoded_data}"
745
-
746
- return {
747
- 'name': path.name,
748
- 'size': file_size,
749
- 'type': mime_type,
750
- 'url': data_url,
751
- 'downloadable': True
752
- }
753
- else:
754
- # For larger files, just return file info
755
- return {
756
- 'name': path.name,
757
- 'size': file_size,
758
- 'type': 'file',
759
- 'url': None,
760
- 'downloadable': False,
761
- 'note': f'File too large ({file_size} bytes) for data URL'
762
- }
763
- except Exception as e:
764
- return {
765
- 'name': Path(file_path).name,
766
- 'error': str(e),
767
- 'downloadable': False
768
- }
769
-
770
-
771
  def Execute_Python(code: Annotated[str, "Python source code to run; stdout is captured and returned."]) -> str:
772
  """
773
- Execute arbitrary Python code and return captured stdout plus any created files.
774
-
775
- Supports creating downloadable artifacts like CSV files, images, etc. Files created
776
- during execution will be detected and made available as data URLs for download.
777
 
778
  Args:
779
  code (str): Python source code to run; stdout is captured and returned.
780
 
781
  Returns:
782
- str: Combined stdout produced by the code, plus information about any files
783
- created during execution with download links for small files.
784
  """
785
  _log_call_start("Execute_Python", code=_truncate_for_log(code or "", 300))
786
  if code is None:
@@ -788,63 +706,15 @@ def Execute_Python(code: Annotated[str, "Python source code to run; stdout is ca
788
  _log_call_end("Execute_Python", result)
789
  return result
790
 
791
- # Create a temporary working directory
792
- with tempfile.TemporaryDirectory() as temp_dir:
793
- # Change to temp directory and capture existing files
794
- original_cwd = os.getcwd()
795
- os.chdir(temp_dir)
796
-
797
- try:
798
- # Get initial file list
799
- before_files = set()
800
- for file_path in Path(temp_dir).rglob("*"):
801
- if file_path.is_file():
802
- before_files.add(str(file_path))
803
-
804
- # Execute code with stdout capture
805
- old_stdout = sys.stdout
806
- redirected_output = sys.stdout = StringIO()
807
-
808
- try:
809
- exec(code)
810
- stdout_result = redirected_output.getvalue()
811
- except Exception as e:
812
- stdout_result = f"Error: {str(e)}"
813
- finally:
814
- sys.stdout = old_stdout
815
-
816
- # Detect any files created during execution
817
- created_files = _detect_created_files(temp_dir, before_files)
818
-
819
- # Build result with stdout and file information
820
- result_parts = []
821
-
822
- if stdout_result.strip():
823
- result_parts.append("=== Output ===")
824
- result_parts.append(stdout_result.strip())
825
-
826
- if created_files:
827
- result_parts.append("\n=== Created Files ===")
828
- for file_path in created_files:
829
- file_info = _generate_file_url(file_path)
830
-
831
- if file_info.get('downloadable', False):
832
- result_parts.append(f"📁 {file_info['name']} ({file_info['size']} bytes)")
833
- result_parts.append(f" Type: {file_info['type']}")
834
- result_parts.append(f" Download: {file_info['url']}")
835
- elif file_info.get('error'):
836
- result_parts.append(f"❌ {file_info['name']} (error: {file_info['error']})")
837
- else:
838
- result_parts.append(f"📄 {file_info['name']} ({file_info.get('size', 'unknown')} bytes)")
839
- if 'note' in file_info:
840
- result_parts.append(f" Note: {file_info['note']}")
841
-
842
- result = "\n".join(result_parts) if result_parts else "No output or files generated."
843
-
844
- finally:
845
- # Restore original working directory
846
- os.chdir(original_cwd)
847
-
848
  _log_call_end("Execute_Python", _truncate_for_log(result))
849
  return result
850
 
@@ -1375,15 +1245,14 @@ code_interface = gr.Interface(
1375
  outputs=gr.Textbox(label="Output"),
1376
  title="Python Code Executor",
1377
  description=(
1378
- "<div style=\"text-align:center\">Execute Python code and create downloadable files. Supports CSV exports, image generation, and more.</div>"
1379
  ),
1380
  api_description=(
1381
- "Execute arbitrary Python code and return captured stdout plus any created files with download URLs. "
1382
  "Supports any valid Python code including imports, variables, functions, loops, and calculations. "
1383
- "Files created during execution (CSV, PNG, TXT, etc.) are automatically detected and made available as data URLs for download. "
1384
- "Examples: 'print(2+2)', 'import pandas as pd; df.to_csv(\"data.csv\")', 'import matplotlib.pyplot as plt; plt.savefig(\"plot.png\")'. "
1385
  "Parameters: code (str - Python source code to execute). "
1386
- "Returns: Combined stdout output and file information with download links for created artifacts."
1387
  ),
1388
  flagging_mode="never",
1389
  )
 
689
  # Code Execution: Python (MCP tool #3)
690
  # ======================================
691
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
692
  def Execute_Python(code: Annotated[str, "Python source code to run; stdout is captured and returned."]) -> str:
693
  """
694
+ Execute arbitrary Python code and return captured stdout or an error message.
 
 
 
695
 
696
  Args:
697
  code (str): Python source code to run; stdout is captured and returned.
698
 
699
  Returns:
700
+ str: Combined stdout produced by the code, or the exception text if
701
+ execution failed.
702
  """
703
  _log_call_start("Execute_Python", code=_truncate_for_log(code or "", 300))
704
  if code is None:
 
706
  _log_call_end("Execute_Python", result)
707
  return result
708
 
709
+ old_stdout = sys.stdout
710
+ redirected_output = sys.stdout = StringIO()
711
+ try:
712
+ exec(code)
713
+ result = redirected_output.getvalue()
714
+ except Exception as e:
715
+ result = str(e)
716
+ finally:
717
+ sys.stdout = old_stdout
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
718
  _log_call_end("Execute_Python", _truncate_for_log(result))
719
  return result
720
 
 
1245
  outputs=gr.Textbox(label="Output"),
1246
  title="Python Code Executor",
1247
  description=(
1248
+ "<div style=\"text-align:center\">Execute Python code and see the output.</div>"
1249
  ),
1250
  api_description=(
1251
+ "Execute arbitrary Python code and return captured stdout or an error message. "
1252
  "Supports any valid Python code including imports, variables, functions, loops, and calculations. "
1253
+ "Examples: 'print(2+2)', 'import math; print(math.sqrt(16))', 'for i in range(3): print(i)'. "
 
1254
  "Parameters: code (str - Python source code to execute). "
1255
+ "Returns: Combined stdout output or exception text if execution fails."
1256
  ),
1257
  flagging_mode="never",
1258
  )