akborana4 commited on
Commit
c638de1
·
verified ·
1 Parent(s): b7bea27

Create backend/routes_terminal.py

Browse files
Files changed (1) hide show
  1. backend/routes_terminal.py +109 -0
backend/routes_terminal.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import re
4
+ import asyncio
5
+ import subprocess
6
+ import traceback
7
+ import urllib.request
8
+ from fastapi import APIRouter, WebSocket, WebSocketDisconnect
9
+ from backend.database import get_user_dir, USERS_DIR
10
+ from backend.routes_ai import ask_openrouter
11
+
12
+ router = APIRouter()
13
+
14
+ SYSTEM_PROMPT = """You are DEVPORTAL AI, an advanced terminal assistant.
15
+ You are operating within a user's private Linux directory.
16
+ To execute a bash command, output it wrapped EXACTLY in <EXEC> and </EXEC> tags.
17
+ Wait for the system to provide the output before taking further action. Keep responses concise."""
18
+
19
+ @router.websocket("/ws/{token}")
20
+ async def websocket_endpoint(websocket: WebSocket, token: str):
21
+ await websocket.accept()
22
+ user_dir = get_user_dir(token)
23
+ if not user_dir:
24
+ await websocket.send_text(json.dumps({"type": "error", "content": "Authentication failed."}))
25
+ await websocket.close()
26
+ return
27
+
28
+ current_dir = user_dir
29
+ session_history = [{"role": "system", "content": SYSTEM_PROMPT}]
30
+
31
+ await websocket.send_text(json.dumps({"type": "system", "content": f"Secure DEVPORTAL environment established. Type 'debug net' to run network diagnostics."}))
32
+
33
+ def run_cmd(cmd):
34
+ nonlocal current_dir
35
+ if cmd.startswith("cd "):
36
+ target = cmd[3:].strip()
37
+ new_dir = os.path.abspath(os.path.join(current_dir, target))
38
+ if not new_dir.startswith(os.path.abspath(USERS_DIR)): return "Permission denied."
39
+ current_dir = new_dir
40
+ return f"Directory changed to {current_dir}"
41
+ else:
42
+ try:
43
+ result = subprocess.run(cmd, shell=True, capture_output=True, text=True, cwd=current_dir, timeout=25)
44
+ out = result.stdout + result.stderr
45
+ return out if out else "[Executed successfully with no output]"
46
+ except Exception as e: return f"[Execution Error: {str(e)}]"
47
+
48
+ try:
49
+ while True:
50
+ data = await websocket.receive_text()
51
+ payload = json.loads(data)
52
+ command = payload.get("command", "").strip()
53
+ if not command: continue
54
+
55
+ if command.lower() == "debug net":
56
+ debug_info = "=== NETWORK DIAGNOSTICS ===\n"
57
+ for k, v in os.environ.items():
58
+ if 'proxy' in k.lower(): debug_info += f" {k} = {v}\n"
59
+ debug_info += f"\n2. Python internal getproxies():\n {urllib.request.getproxies()}\n"
60
+ await websocket.send_text(json.dumps({"type": "output", "content": debug_info}))
61
+ continue
62
+
63
+ if command.lower().startswith("ai "):
64
+ prompt = command[3:].strip()
65
+ await websocket.send_text(json.dumps({"type": "ai_status", "status": "thinking"}))
66
+ session_history.append({"role": "user", "content": prompt})
67
+ if len(session_history) > 21: session_history = [session_history[0]] + session_history[-20:]
68
+
69
+ for _ in range(5):
70
+ ai_response = await ask_openrouter(session_history)
71
+ if "ERROR:" in ai_response:
72
+ await websocket.send_text(json.dumps({"type": "error", "content": ai_response}))
73
+ session_history.pop()
74
+ break
75
+
76
+ match = re.search(r'<EXEC>(.*?)</EXEC>', ai_response, re.DOTALL)
77
+ if match:
78
+ exec_cmd = match.group(1).strip()
79
+ text_before = ai_response[:match.start()].strip()
80
+
81
+ full_ai_message = ""
82
+ if text_before:
83
+ await websocket.send_text(json.dumps({"type": "ai", "content": text_before}))
84
+ full_ai_message += text_before + "\n"
85
+
86
+ await websocket.send_text(json.dumps({"type": "system", "content": f"⚙️ AI is running: {exec_cmd}"}))
87
+ await websocket.send_text(json.dumps({"type": "ai_status", "status": f"executing..."}))
88
+
89
+ full_ai_message += f"<EXEC>{exec_cmd}</EXEC>"
90
+ session_history.append({"role": "assistant", "content": full_ai_message})
91
+
92
+ output = run_cmd(exec_cmd)
93
+ await websocket.send_text(json.dumps({"type": "output", "content": output}))
94
+ session_history.append({"role": "user", "content": f"Command Output:\n{output}"})
95
+ await asyncio.sleep(1)
96
+ else:
97
+ await websocket.send_text(json.dumps({"type": "ai", "content": ai_response}))
98
+ session_history.append({"role": "assistant", "content": ai_response})
99
+ break
100
+ await websocket.send_text(json.dumps({"type": "ai_status", "status": "idle"}))
101
+ else:
102
+ if command.lower() == "clear":
103
+ await websocket.send_text(json.dumps({"type": "clear", "content": ""}))
104
+ else:
105
+ output = run_cmd(command)
106
+ await websocket.send_text(json.dumps({"type": "output", "content": output}))
107
+ except WebSocketDisconnect:
108
+ pass
109
+