theguywhosucks commited on
Commit
f313f73
·
verified ·
1 Parent(s): 59b5f3f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +70 -590
app.py CHANGED
@@ -1,599 +1,79 @@
1
  import gradio as gr
2
  from gradio_client import Client
3
- import json
4
- import random
5
  import time
6
- from datetime import datetime, timedelta
7
- import threading
8
 
9
- # Backend engines
10
- BACKEND_ENGINES = [
11
- "ChocoLaboratory/SANDBOXBACKEND2",
12
- "ChocoLaboratory/SANDBOX_BACKEND"
 
 
13
  ]
14
 
15
- class SandboxManager:
16
- def __init__(self):
17
- self.client = None
18
- self.current_engine = None
19
- self.is_connected = False
20
- self.sandbox_created = False
21
- self.creation_time = None
22
- self.time_limit_hours = 2
23
- self.auto_refresh_thread = None
24
- self.stop_auto_refresh = False
25
-
26
- def select_random_engine(self):
27
- """Select a random backend engine"""
28
- self.current_engine = random.choice(BACKEND_ENGINES)
29
- return self.current_engine
30
-
31
- def get_remaining_time(self):
32
- """Calculate remaining time for the sandbox"""
33
- if not self.creation_time:
34
- return "N/A"
35
-
36
- elapsed = datetime.now() - self.creation_time
37
- remaining = timedelta(hours=self.time_limit_hours) - elapsed
38
-
39
- if remaining.total_seconds() <= 0:
40
- return "EXPIRED"
41
-
42
- hours, remainder = divmod(int(remaining.total_seconds()), 3600)
43
- minutes, seconds = divmod(remainder, 60)
44
- return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
45
-
46
- def is_sandbox_expired(self):
47
- """Check if sandbox has exceeded the 2-hour limit"""
48
- if not self.creation_time:
49
- return False
50
-
51
- elapsed = datetime.now() - self.creation_time
52
- return elapsed.total_seconds() > (self.time_limit_hours * 3600)
53
-
54
- def connect(self):
55
- """Connect to a backend engine"""
56
- if self.sandbox_created:
57
- return "⚠️ Sandbox already created. You can only create one sandbox per session.", self.current_engine
58
-
59
- engine = self.select_random_engine()
60
- try:
61
- self.client = Client(engine)
62
- self.is_connected = True
63
- return f"✅ Connected to: {engine}", engine
64
- except Exception as e:
65
- self.is_connected = False
66
- self.current_engine = None
67
- return f"❌ Connection failed to {engine}: {str(e)}", "Connection Failed"
68
-
69
- def launch_sandbox(self, main_py_code, requirements_txt):
70
- """Launch the sandbox (only once per session)"""
71
- if self.sandbox_created:
72
- remaining = self.get_remaining_time()
73
- if remaining == "EXPIRED":
74
- return "⏰ Your sandbox has expired (2-hour limit reached). Please refresh the page to start a new session.", ""
75
- return f"⚠️ Sandbox already running. Remaining time: {remaining}", self.get_status()
76
-
77
- if not self.is_connected:
78
- return "❌ Not connected to backend. Please connect first.", ""
79
-
80
- try:
81
- result = self.client.predict(
82
- code=main_py_code,
83
- requirements=requirements_txt,
84
- api_name="/launch_sandbox"
85
- )
86
-
87
- # Mark sandbox as created and record creation time
88
- self.sandbox_created = True
89
- self.creation_time = datetime.now()
90
-
91
- # Start auto-refresh thread for time monitoring
92
- self.start_time_monitor()
93
-
94
- remaining = self.get_remaining_time()
95
- return (f"🚀 Sandbox deployed successfully on {self.current_engine}\n"
96
- f"⏱️ Time limit: 2 hours | Remaining: {remaining}\n\n"
97
- f"Response: {result}"), self.get_status()
98
- except Exception as e:
99
- return f"❌ Deployment failed: {str(e)}", ""
100
-
101
- def fetch_logs(self):
102
- """Fetch logs from the sandbox"""
103
- if not self.is_connected:
104
- return "❌ Not connected to backend"
105
-
106
- if self.is_sandbox_expired():
107
- return "⏰ Sandbox expired. Logs are no longer available."
108
-
109
- try:
110
- result = self.client.predict(api_name="/fetch_logs")
111
- timestamp = datetime.now().strftime("%H:%M:%S")
112
- remaining = self.get_remaining_time()
113
- return f"[{timestamp}] Remaining time: {remaining}\nLogs from {self.current_engine}:\n\n{result}"
114
- except Exception as e:
115
- return f"[ERROR] Failed to fetch logs: {str(e)}"
116
-
117
- def kill_sandbox(self):
118
- """Terminate the sandbox"""
119
- if not self.is_connected:
120
- return "❌ Not connected to backend", ""
121
-
122
- try:
123
- result = self.client.predict(api_name="/kill_sandbox")
124
- self.sandbox_created = False
125
- self.creation_time = None
126
- self.stop_auto_refresh = True
127
- return f"🛑 Sandbox terminated on {self.current_engine}\n\nResponse: {result}", "TERMINATED"
128
- except Exception as e:
129
- return f"❌ Termination failed: {str(e)}", ""
130
-
131
- def get_status(self):
132
- """Get current sandbox status"""
133
- if not self.is_connected:
134
- return "OFFLINE"
135
-
136
- if self.is_sandbox_expired():
137
- return "EXPIRED"
138
-
139
- try:
140
- result = self.client.predict(api_name="/status_sandbox")
141
- if "running" in str(result).lower():
142
- remaining = self.get_remaining_time()
143
- return f"RUNNING ({remaining} left) - {result}"
144
- else:
145
- remaining = self.get_remaining_time()
146
- return f"IDLE ({remaining} left) - {result}"
147
- except Exception as e:
148
- return f"ERROR - {str(e)}"
149
-
150
- def start_time_monitor(self):
151
- """Start monitoring thread for time limits"""
152
- def monitor():
153
- while not self.stop_auto_refresh and self.sandbox_created:
154
- if self.is_sandbox_expired():
155
- try:
156
- self.kill_sandbox()
157
- except:
158
- pass
159
- break
160
- time.sleep(60) # Check every minute
161
-
162
- self.auto_refresh_thread = threading.Thread(target=monitor, daemon=True)
163
- self.auto_refresh_thread.start()
164
-
165
- # Initialize sandbox manager
166
- sandbox = SandboxManager()
167
-
168
- # Sample files
169
- SAMPLE_MAIN_PY = """# Enterprise Python Application
170
- import os
171
- import time
172
- from datetime import datetime
173
-
174
- def main():
175
- print("🚀 Sandbox Compute Platform - Initialized")
176
- print(f"📅 Started at: {datetime.now()}")
177
- print("✅ Environment ready for development")
178
-
179
- # Your application code here
180
- while True:
181
- print(f"⏱️ Running... {datetime.now().strftime('%H:%M:%S')}")
182
- time.sleep(30)
183
-
184
- if __name__ == "__main__":
185
- main()
186
- """
187
-
188
- SAMPLE_REQUIREMENTS_TXT = """# Production Dependencies
189
- # Specify exact versions for reproducibility
190
-
191
- # Web framework
192
- flask==2.3.3
193
- requests==2.31.0
194
-
195
- # Data processing
196
- pandas==2.1.1
197
- numpy==1.24.3
198
-
199
- # Utilities
200
- python-dotenv==1.0.0
201
- """
202
-
203
- # Enhanced CSS with modern design
204
- industrial_css = """
205
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap');
206
-
207
- :root {
208
- --primary: #2563eb;
209
- --primary-hover: #1d4ed8;
210
- --secondary: #64748b;
211
- --success: #10b981;
212
- --warning: #f59e0b;
213
- --danger: #ef4444;
214
- --surface: #ffffff;
215
- --surface-elevated: #f8fafc;
216
- --border: #e2e8f0;
217
- --text: #0f172a;
218
- --text-muted: #64748b;
219
- --shadow: rgba(15, 23, 42, 0.1);
220
- }
221
-
222
- * {
223
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif !important;
224
- }
225
-
226
- .gradio-container {
227
- background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%) !important;
228
- min-height: 100vh;
229
- }
230
-
231
- /* Header */
232
- .platform-header {
233
- background: linear-gradient(135deg, var(--primary) 0%, var(--primary-hover) 100%) !important;
234
- color: white !important;
235
- padding: 2rem !important;
236
- border-radius: 0 0 1rem 1rem !important;
237
- margin-bottom: 1.5rem !important;
238
- box-shadow: 0 10px 25px var(--shadow) !important;
239
- }
240
-
241
- .platform-title {
242
- font-size: 2rem !important;
243
- font-weight: 800 !important;
244
- margin-bottom: 0.5rem !important;
245
- }
246
-
247
- .platform-subtitle {
248
- font-size: 1rem !important;
249
- opacity: 0.9 !important;
250
- font-weight: 400 !important;
251
- }
252
-
253
- .breadcrumb {
254
- background: var(--surface-elevated) !important;
255
- padding: 0.75rem 1.5rem !important;
256
- border-radius: 0.75rem !important;
257
- font-size: 0.875rem !important;
258
- color: var(--text-muted) !important;
259
- border: 1px solid var(--border) !important;
260
- margin-bottom: 1.5rem !important;
261
- }
262
-
263
- /* Cards */
264
- .card {
265
- background: var(--surface) !important;
266
- border: 1px solid var(--border) !important;
267
- border-radius: 1rem !important;
268
- box-shadow: 0 4px 6px -1px var(--shadow) !important;
269
- overflow: hidden !important;
270
- margin-bottom: 1.5rem !important;
271
- }
272
-
273
- .card-header {
274
- background: var(--surface-elevated) !important;
275
- padding: 1rem 1.5rem !important;
276
- border-bottom: 1px solid var(--border) !important;
277
- font-weight: 600 !important;
278
- font-size: 1.1rem !important;
279
- display: flex !important;
280
- align-items: center !important;
281
- gap: 0.5rem !important;
282
- }
283
-
284
- .card-content {
285
- padding: 1.5rem !important;
286
- }
287
-
288
- /* Buttons */
289
- .btn {
290
- padding: 0.75rem 1.5rem !important;
291
- border-radius: 0.5rem !important;
292
- font-weight: 500 !important;
293
- font-size: 0.875rem !important;
294
- transition: all 0.2s ease !important;
295
- border: none !important;
296
- }
297
-
298
- .btn-primary {
299
- background: linear-gradient(135deg, var(--primary), var(--primary-hover)) !important;
300
- color: white !important;
301
- box-shadow: 0 4px 14px 0 rgba(37, 99, 235, 0.25) !important;
302
- }
303
-
304
- .btn-primary:hover {
305
- transform: translateY(-2px) !important;
306
- box-shadow: 0 6px 20px 0 rgba(37, 99, 235, 0.35) !important;
307
- }
308
-
309
- .btn-secondary {
310
- background: var(--surface) !important;
311
- color: var(--text) !important;
312
- border: 1px solid var(--border) !important;
313
- }
314
-
315
- .btn-secondary:hover {
316
- background: var(--surface-elevated) !important;
317
- border-color: var(--secondary) !important;
318
- }
319
-
320
- .btn-danger {
321
- background: linear-gradient(135deg, var(--danger), #dc2626) !important;
322
- color: white !important;
323
- box-shadow: 0 4px 14px 0 rgba(239, 68, 68, 0.25) !important;
324
- }
325
-
326
- .btn-danger:hover {
327
- transform: translateY(-2px) !important;
328
- box-shadow: 0 6px 20px 0 rgba(239, 68, 68, 0.35) !important;
329
- }
330
-
331
- /* Status indicators */
332
- .status-badge {
333
- padding: 0.5rem 1rem !important;
334
- border-radius: 0.5rem !important;
335
- font-weight: 500 !important;
336
- font-size: 0.875rem !important;
337
- text-align: center !important;
338
- }
339
-
340
- .status-online {
341
- background: #d1fae5 !important;
342
- color: var(--success) !important;
343
- border: 1px solid #a7f3d0 !important;
344
- }
345
-
346
- .status-offline {
347
- background: #fee2e2 !important;
348
- color: var(--danger) !important;
349
- border: 1px solid #fecaca !important;
350
- }
351
-
352
- .status-warning {
353
- background: #fef3c7 !important;
354
- color: var(--warning) !important;
355
- border: 1px solid #fed7aa !important;
356
- }
357
-
358
- /* Code editors */
359
- .code-editor {
360
- font-family: 'JetBrains Mono', monospace !important;
361
- background: #1e293b !important;
362
- color: #e2e8f0 !important;
363
- border-radius: 0.75rem !important;
364
- border: 1px solid #334155 !important;
365
- }
366
-
367
- .requirements-editor {
368
- font-family: 'JetBrains Mono', monospace !important;
369
- background: #27272a !important;
370
- color: #f4f4f5 !important;
371
- border-radius: 0.75rem !important;
372
- border: 1px solid #3f3f46 !important;
373
- }
374
-
375
- .terminal {
376
- font-family: 'JetBrains Mono', monospace !important;
377
- background: #0f172a !important;
378
- color: #e2e8f0 !important;
379
- border-radius: 0.75rem !important;
380
- padding: 1rem !important;
381
- border: 1px solid #1e293b !important;
382
- }
383
-
384
- /* Form labels */
385
- .form-label {
386
- font-weight: 600 !important;
387
- color: var(--text) !important;
388
- margin-bottom: 0.5rem !important;
389
- font-size: 0.875rem !important;
390
- text-transform: uppercase !important;
391
- letter-spacing: 0.025em !important;
392
- }
393
-
394
- /* Monitoring panel */
395
- .monitor-panel {
396
- background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%) !important;
397
- border: 1px solid var(--border) !important;
398
- border-radius: 1rem !important;
399
- padding: 1.5rem !important;
400
- box-shadow: 0 4px 6px -1px var(--shadow) !important;
401
- }
402
-
403
- /* Animations */
404
- @keyframes pulse {
405
- 0%, 100% { opacity: 1; }
406
- 50% { opacity: 0.5; }
407
- }
408
-
409
- .pulse {
410
- animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
411
- }
412
- """
413
-
414
- def auto_refresh_status():
415
- return sandbox.get_status()
416
-
417
- def auto_refresh_logs():
418
- return sandbox.fetch_logs()
419
-
420
- def load_sample_files():
421
- return SAMPLE_MAIN_PY, SAMPLE_REQUIREMENTS_TXT
422
-
423
- def get_session_info():
424
- if sandbox.sandbox_created:
425
- remaining = sandbox.get_remaining_time()
426
- created = sandbox.creation_time.strftime("%H:%M:%S") if sandbox.creation_time else "N/A"
427
- return f"Created: {created} | Remaining: {remaining}"
428
- return "No active sandbox"
429
-
430
- # Build enhanced Gradio interface
431
- with gr.Blocks(css=industrial_css, title="Sandbox Compute Platform") as demo:
432
- gr.HTML("""
433
- <div class="platform-header">
434
- <div class="platform-title">🚀 Sandbox Compute Platform</div>
435
- <div class="platform-subtitle">Enterprise-grade cloud computing with 2-hour session limits</div>
436
- </div>
437
- <div class="breadcrumb">
438
- 🛠️ Sandbox Management Console
439
- </div>
440
- """)
441
-
442
- # Session Info Bar
443
  with gr.Row():
444
- with gr.Column():
445
- session_info = gr.Textbox(
446
- value=get_session_info(),
447
- label="📊 Session Information",
448
- interactive=False,
449
- elem_classes=["status-badge"]
450
- )
451
-
452
- with gr.Row():
453
- # Main Content
454
- with gr.Column(scale=2):
455
- # Connection Management
456
- with gr.Group(elem_classes=["card"]):
457
- gr.HTML('<div class="card-header">🔌 Connection Management</div>')
458
- with gr.Group(elem_classes=["card-content"]):
459
- gr.HTML('<div class="form-label">Initialize Backend Connection</div>')
460
- with gr.Row():
461
- connect_btn = gr.Button("🚀 Connect to Backend", elem_classes=["btn-primary"])
462
- load_samples_btn = gr.Button("📄 Load Templates", elem_classes=["btn-secondary"])
463
-
464
- gr.HTML('<div class="form-label">Active Engine</div>')
465
- current_engine_display = gr.Textbox(
466
- value="No engine selected",
467
- interactive=False,
468
- elem_classes=["status-badge"],
469
- show_label=False
470
- )
471
-
472
- gr.HTML('<div class="form-label">Connection Status</div>')
473
- connection_status = gr.Textbox(
474
- value="DISCONNECTED",
475
- interactive=False,
476
- elem_classes=["status-offline"],
477
- show_label=False
478
- )
479
-
480
- # Development Environment
481
- with gr.Group(elem_classes=["card"]):
482
- gr.HTML('<div class="card-header">💻 Development Environment</div>')
483
- with gr.Group(elem_classes=["card-content"]):
484
- with gr.Tab("📝 main.py"):
485
- gr.HTML('<div class="form-label">Application Source Code</div>')
486
- main_py_editor = gr.Code(
487
- value=SAMPLE_MAIN_PY,
488
- language="python",
489
- lines=15,
490
- elem_classes=["code-editor"],
491
- show_label=False
492
- )
493
-
494
- with gr.Tab("📦 requirements.txt"):
495
- gr.HTML('<div class="form-label">Dependency Specifications</div>')
496
- requirements_editor = gr.Textbox(
497
- value=SAMPLE_REQUIREMENTS_TXT,
498
- lines=15,
499
- elem_classes=["requirements-editor"],
500
- show_label=False,
501
- max_lines=20
502
- )
503
-
504
- gr.HTML('<hr style="margin: 1.5rem 0; border: 1px solid var(--border);">')
505
-
506
- with gr.Row():
507
- launch_btn = gr.Button("🚀 Deploy Sandbox", elem_classes=["btn-primary"], size="lg")
508
- kill_btn = gr.Button("🛑 Terminate Sandbox", elem_classes=["btn-danger"], size="lg")
509
-
510
- gr.HTML('<div class="form-label">Deployment Output</div>')
511
- launch_output = gr.Textbox(
512
- lines=6,
513
- interactive=False,
514
- placeholder="🚀 Deployment logs and status information will appear here...",
515
- elem_classes=["terminal"],
516
- show_label=False
517
- )
518
-
519
- # Monitoring Panel
520
  with gr.Column(scale=1):
521
- with gr.Group(elem_classes=["monitor-panel"]):
522
- gr.HTML('<div class="form-label">📊 System Monitor</div>')
523
-
524
- gr.HTML('<div class="form-label">Instance Status</div>')
525
- status_display = gr.Textbox(
526
- value="OFFLINE",
527
- interactive=False,
528
- elem_classes=["status-offline"],
529
- show_label=False
530
- )
531
-
532
- status_refresh_btn = gr.Button("🔄 Refresh Status", elem_classes=["btn-secondary"], size="sm")
533
-
534
- gr.HTML('<div class="form-label">⚠️ Session Limits</div>')
535
- gr.HTML("""
536
- <div style="background: #fef3c7; padding: 1rem; border-radius: 0.5rem; border: 1px solid #fed7aa;">
537
- <strong>Time Limit:</strong> 2 hours per sandbox<br>
538
- <strong>Sessions:</strong> 1 sandbox per browser session<br>
539
- <strong>Auto-cleanup:</strong> Sandbox terminates when expired
540
- </div>
541
- """)
542
-
543
- # Logs Section
544
- with gr.Group(elem_classes=["card"]):
545
- gr.HTML('<div class="card-header">📋 System Logs & Monitoring</div>')
546
- with gr.Group(elem_classes=["card-content"]):
547
- with gr.Row():
548
- fetch_logs_btn = gr.Button("📋 Fetch Application Logs", elem_classes=["btn-secondary"])
549
- auto_refresh_btn = gr.Button("🔄 Auto Refresh (30s)", elem_classes=["btn-secondary"])
550
-
551
- gr.HTML('<div class="form-label">Runtime Logs</div>')
552
- logs_display = gr.Textbox(
553
- lines=12,
554
- interactive=False,
555
- elem_classes=["terminal"],
556
- placeholder="[SYSTEM] 📋 Application logs will appear here...",
557
- show_label=False
558
- )
559
-
560
- # Event Handlers
561
- connect_btn.click(
562
- fn=sandbox.connect,
563
- outputs=[connection_status, current_engine_display]
564
- )
565
-
566
- load_samples_btn.click(
567
- fn=load_sample_files,
568
- outputs=[main_py_editor, requirements_editor]
569
- )
570
-
571
- launch_btn.click(
572
- fn=sandbox.launch_sandbox,
573
- inputs=[main_py_editor, requirements_editor],
574
- outputs=[launch_output, status_display]
575
- )
576
-
577
- kill_btn.click(
578
- fn=sandbox.kill_sandbox,
579
- outputs=[launch_output, status_display]
580
- )
581
-
582
- fetch_logs_btn.click(
583
- fn=sandbox.fetch_logs,
584
- outputs=logs_display
585
- )
586
-
587
- status_refresh_btn.click(
588
- fn=auto_refresh_status,
589
- outputs=status_display
590
- )
591
 
592
- # Launch the application
593
- if __name__ == "__main__":
594
- demo.launch(
595
- server_name="0.0.0.0",
596
- server_port=7860,
597
- share=False,
598
- debug=False
599
- )
 
1
  import gradio as gr
2
  from gradio_client import Client
 
 
3
  import time
4
+ import random
 
5
 
6
+ # -------------------------
7
+ # Backend HF clients
8
+ # -------------------------
9
+ backend_engines = [
10
+ Client("ChocoLaboratory/SANDBOX_BACKEND1"),
11
+ Client("ChocoLaboratory/SANDBOX_BACKEND2")
12
  ]
13
 
14
+ # -------------------------
15
+ # Helper functions
16
+ # -------------------------
17
+ def pick_engine():
18
+ # Simple load balancing (random for now)
19
+ return random.choice(backend_engines)
20
+
21
+ def launch_sandbox(code):
22
+ engine = pick_engine()
23
+ result = engine.predict(code=code, api_name="/launch_sandbox")
24
+ sandbox_id = result if isinstance(result, str) else result.get("sandbox_id", "unknown")
25
+ return f"Sandbox launched! ID: {sandbox_id}", sandbox_id, "120:00" # 2h TTL
26
+
27
+ def run_command(cmd, sandbox_id):
28
+ engine = pick_engine()
29
+ # Here we assume the backend runs the code immediately in the sandbox
30
+ # For demo, we send each command as a mini script
31
+ code = cmd
32
+ engine.predict(code=code, api_name="/launch_sandbox") # you could create a /run_command endpoint
33
+ logs = engine.predict(api_name="/fetch_logs")
34
+ return logs
35
+
36
+ def kill_sandbox(sandbox_id):
37
+ engine = pick_engine()
38
+ result = engine.predict(api_name="/kill_sandbox")
39
+ return result
40
+
41
+ def get_status(sandbox_id):
42
+ engine = pick_engine()
43
+ return engine.predict(api_name="/status_sandbox")
44
+
45
+ # -------------------------
46
+ # Gradio UI
47
+ # -------------------------
48
+ with gr.Blocks() as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  with gr.Row():
50
+ with gr.Column(scale=3):
51
+ gr.Markdown("## 🖥 Sandbox Cloud")
52
+ terminal_output = gr.Textbox(label="Terminal Output", lines=20, interactive=False, elem_classes=["terminal-box"])
53
+ command_input = gr.Textbox(label="Enter command", placeholder="ls -la", interactive=True)
54
+ run_btn = gr.Button("Run Command")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  with gr.Column(scale=1):
56
+ launch_btn = gr.Button("Launch Sandbox")
57
+ kill_btn = gr.Button("Kill Sandbox")
58
+ status_btn = gr.Button("Check Status")
59
+ sandbox_id_box = gr.Textbox(label="Sandbox ID", interactive=False)
60
+ time_remaining = gr.Textbox(label="Time Remaining", interactive=False)
61
+ gr.Markdown("💡 Note: Running on a Debian-based container!")
62
+
63
+ # Callbacks
64
+ launch_btn.click(launch_sandbox, inputs=command_input, outputs=[terminal_output, sandbox_id_box, time_remaining])
65
+ run_btn.click(run_command, inputs=[command_input, sandbox_id_box], outputs=terminal_output)
66
+ kill_btn.click(kill_sandbox, inputs=sandbox_id_box, outputs=terminal_output)
67
+ status_btn.click(get_status, inputs=sandbox_id_box, outputs=terminal_output)
68
+
69
+ # CSS for terminal look
70
+ css = """
71
+ .terminal-box textarea {
72
+ background-color: #1e1e1e;
73
+ color: #00ff00;
74
+ font-family: monospace;
75
+ font-size: 14px;
76
+ }
77
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
+ demo.launch(css=css)