Python-server / index.html
Srevarshan1502's picture
added
605b91b
Raw
History Blame Contribute Delete
9.93 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Interactive Python Executor</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Inter', sans-serif;
background-color: #1a202c; /* Dark background */
color: #e2e8f0; /* Light text */
display: flex;
justify-content: center;
align-items: flex-start;
min-height: 100vh;
padding: 2rem;
box-sizing: border-box;
}
.container {
background-color: #2d3748; /* Slightly lighter dark for container */
border-radius: 0.75rem; /* rounded-xl */
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.2); /* shadow-xl */
padding: 2rem;
max-width: 900px;
width: 100%;
display: flex;
flex-direction: column;
gap: 1.5rem;
}
textarea, input[type="text"] {
background-color: #1a202c; /* Even darker for input fields */
color: #e2e8f0;
border: 1px solid #4a5568; /* border-gray-600 */
border-radius: 0.5rem; /* rounded-lg */
padding: 0.75rem 1rem;
font-family: 'Fira Code', 'Cascadia Code', 'Consolas', monospace; /* Monospace for code */
font-size: 0.9rem;
resize: vertical;
}
button {
padding: 0.75rem 1.5rem;
border-radius: 0.5rem; /* rounded-lg */
font-weight: 600; /* font-semibold */
transition: background-color 0.2s, transform 0.1s;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
button:hover {
transform: translateY(-1px);
}
.btn-primary {
background-color: #4299e1; /* blue-500 */
color: white;
}
.btn-primary:hover {
background-color: #3182ce; /* blue-600 */
}
.btn-secondary {
background-color: #a0aec0; /* gray-400 */
color: #2d3748;
}
.btn-secondary:hover {
background-color: #718096; /* gray-500 */
}
.terminal-output {
background-color: #000; /* Black for terminal */
color: #0f0; /* Green text for terminal */
border-radius: 0.5rem;
padding: 1rem;
min-height: 200px;
max-height: 400px;
overflow-y: auto;
white-space: pre-wrap; /* Preserve whitespace and wrap text */
font-family: 'Fira Code', 'Cascadia Code', 'Consolas', monospace;
font-size: 0.85rem;
border: 1px solid #4a5568;
}
.input-area {
display: flex;
gap: 0.5rem;
margin-top: 1rem;
}
.hidden {
display: none;
}
.status-message {
font-size: 0.8rem;
color: #cbd5e0;
margin-top: 0.5rem;
}
</style>
</head>
<body class="antialiased">
<div class="container">
<h1 class="text-3xl font-bold text-center mb-4 text-blue-300">Interactive Python Interpreter</h1>
<p class="text-center text-gray-400 mb-6">Enter Python code and interact with it in real-time.</p>
<div class="flex flex-col gap-4">
<label for="code-input" class="text-lg font-semibold text-gray-200">Python Code:</label>
<textarea id="code-input" rows="15" class="focus:ring-blue-500 focus:border-blue-500">
# Example: Interactive input
n = int(input("Enter a number: "))
if n % 2 == 0:
print("Even")
else:
print("Odd")
# Example: Multiple inputs
name = input("What is your name? ")
age = int(input("How old are you? "))
print(f"Hello, {name}! You are {age} years old.")
</textarea>
<button id="run-button" class="btn-primary">Run Code</button>
</div>
<div class="flex flex-col gap-4">
<label for="terminal-output" class="text-lg font-semibold text-gray-200">Terminal Output:</label>
<div id="terminal-output" class="terminal-output"></div>
<div id="input-prompt-area" class="input-area hidden">
<input type="text" id="user-input" class="flex-grow" placeholder="Enter input here...">
<button id="send-input-button" class="btn-primary">Send Input</button>
</div>
<p id="status-message" class="status-message">Status: Not connected</p>
</div>
</div>
<script>
const codeInput = document.getElementById('code-input');
const runButton = document.getElementById('run-button');
const terminalOutput = document.getElementById('terminal-output');
const inputPromptArea = document.getElementById('input-prompt-area');
const userInput = document.getElementById('user-input');
const sendInputButton = document.getElementById('send-input-button');
const statusMessage = document.getElementById('status-message');
let ws;
let isAwaitingInput = false;
function connectWebSocket() {
let wsUrl;
if (window.location.protocol === 'https:') {
// For Hugging Face Spaces, always use wss:// when the page is loaded over HTTPS
// window.location.hostname is safer as it never includes the port
wsUrl = `wss://${window.location.hostname}/ws`;
} else {
// For local development (http://localhost:7860)
wsUrl = `ws://${window.location.host}/ws`;
}
console.log('Attempting to connect WebSocket to:', wsUrl);
console.log('Current page protocol:', window.location.protocol);
console.log('Current page hostname:', window.location.hostname);
console.log('Current page host (includes port):', window.location.host);
ws = new WebSocket(wsUrl);
ws.onopen = () => {
statusMessage.textContent = 'Status: Connected';
runButton.disabled = false;
console.log('WebSocket connected');
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'output') {
terminalOutput.textContent += data.content;
terminalOutput.scrollTop = terminalOutput.scrollHeight; // Auto-scroll
} else if (data.type === 'input_request') {
isAwaitingInput = true;
inputPromptArea.classList.remove('hidden');
userInput.focus();
terminalOutput.scrollTop = terminalOutput.scrollHeight; // Auto-scroll
} else if (data.type === 'execution_complete') {
isAwaitingInput = false;
inputPromptArea.classList.add('hidden');
userInput.value = '';
statusMessage.textContent = 'Status: Execution complete.';
console.log('Execution complete:', data.result);
} else if (data.type === 'pong') {
// console.log('Pong received');
}
};
ws.onclose = (event) => {
statusMessage.textContent = `Status: Disconnected (Code: ${event.code}, Reason: ${event.reason})`;
runButton.disabled = true;
inputPromptArea.classList.add('hidden');
console.log('WebSocket disconnected:', event);
// Attempt to reconnect after a delay
setTimeout(connectWebSocket, 3000);
};
ws.onerror = (error) => {
statusMessage.textContent = 'Status: Connection error';
console.error('WebSocket error:', error);
};
}
runButton.addEventListener('click', () => {
if (ws && ws.readyState === WebSocket.OPEN) {
terminalOutput.textContent = ''; // Clear previous output
statusMessage.textContent = 'Status: Running code...';
isAwaitingInput = false;
inputPromptArea.classList.add('hidden'); // Hide input area initially
userInput.value = ''; // Clear input field
const code = codeInput.value;
ws.send(JSON.stringify({ type: 'code', content: code }));
} else {
statusMessage.textContent = 'Status: Not connected. Please wait or refresh.';
}
});
sendInputButton.addEventListener('click', () => {
if (isAwaitingInput && ws && ws.readyState === WebSocket.OPEN) {
const inputContent = userInput.value;
ws.send(JSON.stringify({ type: 'input', content: inputContent }));
userInput.value = ''; // Clear input field after sending
inputPromptArea.classList.add('hidden'); // Hide input area until next prompt
isAwaitingInput = false;
}
});
userInput.addEventListener('keypress', (event) => {
if (event.key === 'Enter') {
sendInputButton.click();
}
});
// Start WebSocket connection when the page loads
document.addEventListener('DOMContentLoaded', connectWebSocket);
// Optional: Send a ping every 30 seconds to keep the WebSocket connection alive
setInterval(() => {
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'ping' }));
}
}, 30000); // 30 seconds
</script>
</body>
</html>