abc1181 commited on
Commit
8a8c3ce
·
verified ·
1 Parent(s): 8b26e86

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +183 -0
app.py CHANGED
@@ -243,6 +243,189 @@ print('File written to /tmp/{filename}')
243
  result = execute_code(kc, code)
244
  return jsonify({"output": result["stdout"], "path": f"/tmp/{filename}"})
245
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
  if __name__ == "__main__":
247
  print("[SANDBOX] Pre-warming default kernel...")
248
  get_or_create_kernel("default")
 
243
  result = execute_code(kc, code)
244
  return jsonify({"output": result["stdout"], "path": f"/tmp/{filename}"})
245
 
246
+ # 1. Terminal command execution
247
+ @app.route('/terminal', methods=['POST'])
248
+ def terminal():
249
+ if not check_auth(): return jsonify({"error": "Unauthorized"}), 401
250
+ data = request.json or {}
251
+ cmd = data.get("command", "")
252
+ session_id = data.get("session_id", "default")
253
+ if not cmd:
254
+ return jsonify({"error": "No command"}), 400
255
+ safe_code = f"""
256
+ import subprocess, shlex
257
+ result = subprocess.run(
258
+ shlex.split({repr(cmd)}),
259
+ capture_output=True, text=True, timeout=30, cwd='/tmp'
260
+ )
261
+ print(result.stdout)
262
+ if result.stderr: print("STDERR:", result.stderr)
263
+ print("Exit code:", result.returncode)
264
+ """
265
+ kc = get_or_create_kernel(session_id)
266
+ return jsonify(execute_code(kc, safe_code))
267
+
268
+
269
+ # 2. File download — return file from /tmp/ as base64
270
+ @app.route('/download', methods=['POST'])
271
+ def download_file():
272
+ if not check_auth(): return jsonify({"error": "Unauthorized"}), 401
273
+ data = request.json or {}
274
+ filename = data.get("filename", "")
275
+ session_id = data.get("session_id", "default")
276
+ code = f"""
277
+ import base64, os
278
+ path = '/tmp/{filename}'
279
+ if os.path.exists(path):
280
+ with open(path, 'rb') as f:
281
+ b64 = base64.b64encode(f.read()).decode()
282
+ print(f"FILE_B64_START:{{b64}}:FILE_B64_END")
283
+ print(f"Size: {{os.path.getsize(path)}} bytes")
284
+ else:
285
+ print("File not found:", path)
286
+ """
287
+ kc = get_or_create_kernel(session_id)
288
+ result = execute_code(kc, code)
289
+ # Extract b64 from output
290
+ import re
291
+ m = re.search(r'FILE_B64_START:(.+?):FILE_B64_END', result.get("stdout",""))
292
+ if m:
293
+ return jsonify({"filename": filename, "base64": m.group(1), "found": True})
294
+ return jsonify({"found": False, "output": result.get("stdout","")})
295
+
296
+
297
+ # 3. List /tmp files
298
+ @app.route('/files', methods=['GET', 'POST'])
299
+ def list_files():
300
+ if not check_auth(): return jsonify({"error": "Unauthorized"}), 401
301
+ data = (request.json or {}) if request.method == 'POST' else {}
302
+ session_id = data.get("session_id", "default")
303
+ code = """
304
+ import os, json
305
+ files = []
306
+ for f in os.listdir('/tmp'):
307
+ path = f'/tmp/{f}'
308
+ if os.path.isfile(path):
309
+ files.append({"name": f, "size": os.path.getsize(path),
310
+ "modified": os.path.getmtime(path)})
311
+ print(json.dumps(sorted(files, key=lambda x: x['modified'], reverse=True)))
312
+ """
313
+ kc = get_or_create_kernel(session_id)
314
+ result = execute_code(kc, code)
315
+ try:
316
+ return jsonify({"files": __import__('json').loads(result.get("stdout","[]"))})
317
+ except Exception:
318
+ return jsonify({"files": [], "raw": result.get("stdout","")})
319
+
320
+
321
+ # 4. Audio output endpoint
322
+ @app.route('/audio', methods=['POST'])
323
+ def generate_audio():
324
+ """Generate audio via TTS or synthesis in the kernel."""
325
+ if not check_auth(): return jsonify({"error": "Unauthorized"}), 401
326
+ data = request.json or {}
327
+ session_id = data.get("session_id", "default")
328
+ code = data.get("code", "")
329
+ kc = get_or_create_kernel(session_id)
330
+ result = execute_code(kc, code, timeout=120)
331
+ # Collect audio artifacts specifically
332
+ audio_artifacts = [a for a in result.get("artifacts", [])
333
+ if a.get("type","").startswith("audio/")]
334
+ return jsonify({**result, "audio_artifacts": audio_artifacts})
335
+
336
+
337
+ # 5. Browser actions endpoint (structured)
338
+ @app.route('/browser', methods=['POST'])
339
+ def browser_action():
340
+ """
341
+ Execute structured browser actions without raw code.
342
+ action: screenshot | navigate | click | type | extract | pdf
343
+ """
344
+ if not check_auth(): return jsonify({"error": "Unauthorized"}), 401
345
+ data = request.json or {}
346
+ action = data.get("action", "screenshot")
347
+ url = data.get("url", "")
348
+ session_id = data.get("session_id", "browser")
349
+
350
+ if action == "screenshot":
351
+ code = f"""
352
+ from playwright.sync_api import sync_playwright
353
+ with sync_playwright() as p:
354
+ browser = p.chromium.launch(args=['--no-sandbox'])
355
+ page = browser.new_page(viewport={{'width':1280,'height':720}})
356
+ page.goto('{url}', wait_until='networkidle', timeout=30000)
357
+ screenshot = page.screenshot(full_page={data.get('full_page', False)})
358
+ title = page.title()
359
+ browser.close()
360
+ import IPython.display as d
361
+ d.display(d.Image(data=screenshot))
362
+ print(f"URL: {url}")
363
+ print(f"Title: {{title}}")
364
+ """
365
+ elif action == "extract":
366
+ selector = data.get("selector", "body")
367
+ code = f"""
368
+ from playwright.sync_api import sync_playwright
369
+ with sync_playwright() as p:
370
+ browser = p.chromium.launch(args=['--no-sandbox'])
371
+ page = browser.new_page()
372
+ page.goto('{url}', wait_until='networkidle', timeout=30000)
373
+ text = page.inner_text('{selector}')
374
+ browser.close()
375
+ print(text[:5000])
376
+ """
377
+ elif action == "pdf":
378
+ code = f"""
379
+ from playwright.sync_api import sync_playwright
380
+ with sync_playwright() as p:
381
+ browser = p.chromium.launch(args=['--no-sandbox'])
382
+ page = browser.new_page()
383
+ page.goto('{url}', wait_until='networkidle', timeout=30000)
384
+ pdf_bytes = page.pdf(format='A4')
385
+ browser.close()
386
+ import base64
387
+ print("PDF_B64:" + base64.b64encode(pdf_bytes).decode())
388
+ print(f"PDF size: {{len(pdf_bytes)}} bytes")
389
+ """
390
+ else:
391
+ return jsonify({"error": f"Unknown action: {action}"}), 400
392
+
393
+ kc = get_or_create_kernel(session_id)
394
+ return jsonify(execute_code(kc, code, timeout=60))
395
+
396
+
397
+ # 6. Health endpoint with capabilities list
398
+ @app.route('/capabilities')
399
+ def capabilities():
400
+ return jsonify({
401
+ "python": True,
402
+ "playwright": True,
403
+ "packages": [
404
+ "pandas","numpy","matplotlib","seaborn","scipy","plotly",
405
+ "requests","beautifulsoup4","pillow","openpyxl",
406
+ "PyPDF2","python-docx","fpdf2","reportlab","kaleido"
407
+ ],
408
+ "endpoints": [
409
+ "/execute","/install","/upload","/download",
410
+ "/terminal","/files","/browser","/audio",
411
+ "/sessions","/capabilities"
412
+ ]
413
+ })
414
+
415
+
416
+ # 7. Interrupt running kernel (for long loops)
417
+ @app.route('/interrupt/<session_id>', methods=['POST'])
418
+ def interrupt_kernel(session_id):
419
+ if not check_auth(): return jsonify({"error": "Unauthorized"}), 401
420
+ with sessions_lock:
421
+ if session_id not in sessions:
422
+ return jsonify({"error": "Session not found"}), 404
423
+ try:
424
+ sessions[session_id]["km"].interrupt_kernel()
425
+ return jsonify({"message": f"Kernel {session_id} interrupted"})
426
+ except Exception as e:
427
+ return jsonify({"error": str(e)}), 500
428
+
429
  if __name__ == "__main__":
430
  print("[SANDBOX] Pre-warming default kernel...")
431
  get_or_create_kernel("default")