CODER-IDE / app.py
diamond-in's picture
Update app.py
981a5e7 verified
"""
Universal IDE MCP Server - Hugging Face Spaces Compatible
No permission errors, no WebSockets
"""
import gradio as gr
import subprocess
import os
import json
import shutil
from pathlib import Path
import sys
import traceback
from typing import Dict, List, Optional, Tuple
import uuid
import tempfile
# Set matplotlib config to temp directory to avoid permission errors
os.environ['MPLCONFIGDIR'] = tempfile.gettempdir()
class CodeExecutor:
def __init__(self):
# Use temp directory - always writable in HF Spaces
self.work_dir = Path(tempfile.gettempdir()) / "code_executor"
try:
self.work_dir.mkdir(parents=True, exist_ok=True)
except:
# Fallback to system temp if mkdir fails
self.work_dir = Path(tempfile.mkdtemp())
def execute_code(self, code: str, language: str) -> Tuple[str, str, bool]:
"""Execute code in specified language"""
# Create unique session directory
session_id = str(uuid.uuid4())[:8]
# Use tempfile.mkdtemp() for guaranteed writable directory
session_dir = Path(tempfile.mkdtemp(prefix=f"session_{session_id}_"))
try:
if language == "python":
return self._execute_python(code, session_dir)
elif language == "javascript":
return self._execute_javascript(code, session_dir)
elif language == "bash":
return self._execute_bash(code, session_dir)
elif language == "html":
return self._preview_html(code, session_dir)
else:
return "", f"Language '{language}' not supported", False
except Exception as e:
return "", f"Error: {str(e)}", False
finally:
# Clean up session directory
try:
shutil.rmtree(session_dir, ignore_errors=True)
except:
pass
def _execute_python(self, code: str, session_dir: Path) -> Tuple[str, str, bool]:
"""Execute Python code"""
file_path = session_dir / "script.py"
file_path.write_text(code)
try:
result = subprocess.run(
[sys.executable, str(file_path)],
capture_output=True,
text=True,
timeout=30,
cwd=str(session_dir),
env={**os.environ, 'MPLCONFIGDIR': str(session_dir)}
)
return result.stdout, result.stderr, result.returncode == 0
except subprocess.TimeoutExpired:
return "", "Execution timeout (30 seconds)", False
except Exception as e:
return "", f"Python execution error: {str(e)}", False
def _execute_javascript(self, code: str, session_dir: Path) -> Tuple[str, str, bool]:
"""Execute JavaScript code if Node.js is available"""
# Check if Node.js is installed
try:
node_version = subprocess.run(
["node", "--version"],
capture_output=True,
text=True,
timeout=5
)
if node_version.returncode != 0:
return "", "Node.js is not available in this environment", False
except:
return "", "Node.js is not installed. Please use Python instead.", False
file_path = session_dir / "script.js"
file_path.write_text(code)
try:
result = subprocess.run(
["node", str(file_path)],
capture_output=True,
text=True,
timeout=30,
cwd=str(session_dir)
)
return result.stdout, result.stderr, result.returncode == 0
except subprocess.TimeoutExpired:
return "", "Execution timeout (30 seconds)", False
except Exception as e:
return "", f"JavaScript execution error: {str(e)}", False
def _execute_bash(self, code: str, session_dir: Path) -> Tuple[str, str, bool]:
"""Execute limited bash commands for security"""
# Whitelist safe commands
safe_commands = ['echo', 'date', 'pwd', 'ls', 'cat', 'head', 'tail', 'wc', 'sort', 'uniq']
first_cmd = code.strip().split()[0] if code.strip() else ""
if first_cmd not in safe_commands:
return "", f"Command '{first_cmd}' not allowed. Allowed: {', '.join(safe_commands)}", False
try:
result = subprocess.run(
code,
shell=True,
capture_output=True,
text=True,
timeout=10,
cwd=str(session_dir)
)
return result.stdout, result.stderr, result.returncode == 0
except subprocess.TimeoutExpired:
return "", "Execution timeout (10 seconds)", False
except Exception as e:
return "", f"Bash execution error: {str(e)}", False
def _preview_html(self, code: str, session_dir: Path) -> Tuple[str, str, bool]:
"""Generate HTML preview"""
file_path = session_dir / "index.html"
file_path.write_text(code)
# Extract basic info from HTML
import re
title = "Untitled"
title_match = re.search(r'<title>(.*?)</title>', code, re.IGNORECASE)
if title_match:
title = title_match.group(1)
# Count elements
elements = {
'divs': len(re.findall(r'<div', code, re.IGNORECASE)),
'links': len(re.findall(r'<a\s', code, re.IGNORECASE)),
'images': len(re.findall(r'<img\s', code, re.IGNORECASE)),
'scripts': len(re.findall(r'<script', code, re.IGNORECASE))
}
preview = f"πŸ“„ HTML Preview\n"
preview += f"Title: {title}\n"
preview += f"Elements: {elements['divs']} divs, {elements['links']} links, "
preview += f"{elements['images']} images, {elements['scripts']} scripts\n"
preview += f"Total size: {len(code)} bytes"
return preview, "", True
# Create Gradio Interface
def create_interface():
executor = CodeExecutor()
def run_code(code, language):
"""Execute code and return output"""
if not code.strip():
return "⚠️ Please enter some code to execute", "No code provided"
stdout, stderr, success = executor.execute_code(code, language)
# Format output
output = ""
if stdout:
output = "πŸ“€ Output:\n" + stdout
if stderr:
if output:
output += "\n"
output += "⚠️ Warnings/Errors:\n" + stderr
if not output:
output = "βœ… Code executed successfully (no output)"
status = "βœ… Success" if success else "❌ Failed"
return output, status
# Build Gradio interface
with gr.Blocks(
title="Universal IDE MCP Server",
theme=gr.themes.Soft()
) as app:
gr.Markdown("""
# πŸš€ Universal IDE MCP Server
**Multi-language code execution environment for Hugging Face Spaces**
Supported: Python βœ… | JavaScript ⚠️ | Bash πŸ”’ | HTML πŸ“„
""")
with gr.Row():
with gr.Column(scale=3):
code_input = gr.Code(
label="Code Editor",
language="python",
value="""# Welcome! Try running this Python code
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
# Calculate first 10 Fibonacci numbers
for i in range(10):
print(f"F({i}) = {fibonacci(i)}")
""",
lines=15
)
with gr.Row():
language_select = gr.Dropdown(
choices=["python", "javascript", "bash", "html"],
value="python",
label="Language",
interactive=True
)
run_button = gr.Button("▢️ Run Code", variant="primary", size="lg")
with gr.Column(scale=2):
output_text = gr.Textbox(
label="Output",
lines=12,
max_lines=20,
interactive=False,
show_copy_button=True
)
status_text = gr.Textbox(
label="Status",
lines=1,
interactive=False
)
# Examples
gr.Examples(
examples=[
["""# Python: Data Analysis
import json
from datetime import datetime
data = {
"name": "Sample Analysis",
"timestamp": str(datetime.now()),
"values": [10, 20, 30, 40, 50]
}
# Calculate statistics
values = data["values"]
total = sum(values)
average = total / len(values)
maximum = max(values)
minimum = min(values)
print(f"Analysis: {data['name']}")
print(f"Time: {data['timestamp']}")
print(f"\\nStatistics:")
print(f" Count: {len(values)}")
print(f" Sum: {total}")
print(f" Average: {average:.2f}")
print(f" Min: {minimum}")
print(f" Max: {maximum}")
""", "python"],
["""// JavaScript: Array Operations
const numbers = [1, 2, 3, 4, 5];
// Map, filter, reduce examples
const doubled = numbers.map(n => n * 2);
const evens = numbers.filter(n => n % 2 === 0);
const sum = numbers.reduce((a, b) => a + b, 0);
console.log('Original:', numbers);
console.log('Doubled:', doubled);
console.log('Even numbers:', evens);
console.log('Sum:', sum);
// Object manipulation
const user = {
name: 'Alice',
age: 30,
skills: ['Python', 'JavaScript']
};
console.log('\\nUser Info:');
console.log(JSON.stringify(user, null, 2));
""", "javascript"],
["""echo "System Information"
echo "=================="
date
echo ""
echo "Working Directory:"
pwd
echo ""
echo "Directory Contents:"
ls -la
echo ""
echo "Environment Sample:"
echo "USER: $USER"
echo "HOME: $HOME"
""", "bash"],
["""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sample Dashboard</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
}
h1 {
color: #333;
}
.card {
border: 1px solid #ddd;
padding: 15px;
margin: 10px 0;
border-radius: 5px;
}
</style>
</head>
<body>
<div class="container">
<h1>Dashboard</h1>
<div class="card">
<h2>Statistics</h2>
<p>Users: 1,234</p>
<p>Active: 89%</p>
</div>
<div class="card">
<h2>Recent Activity</h2>
<ul>
<li>User login: 10:30 AM</li>
<li>Data updated: 10:15 AM</li>
<li>Report generated: 9:45 AM</li>
</ul>
</div>
</div>
</body>
</html>""", "html"]
],
inputs=[code_input, language_select],
label="Example Code"
)
# Connect events
run_button.click(
run_code,
inputs=[code_input, language_select],
outputs=[output_text, status_text]
)
# Update code highlighting when language changes
def update_language(lang):
return gr.Code(language=lang)
language_select.change(
update_language,
inputs=[language_select],
outputs=[code_input]
)
gr.Markdown("""
---
### πŸ“ Features & Limitations
- **Python**: Full support with standard library
- **JavaScript**: Requires Node.js (may not be available)
- **Bash**: Limited to safe commands only
- **HTML**: Preview mode, shows structure analysis
### πŸ”’ Security
- Sandboxed execution with 30-second timeout
- Isolated sessions with automatic cleanup
- Restricted bash commands for safety
### πŸš€ MCP Integration
This server can be extended with MCP protocol support for AI assistants.
""")
return app
# Launch the app
if __name__ == "__main__":
app = create_interface()
app.launch(
server_name="0.0.0.0",
server_port=7860,
share=False
)