pripro commited on
Commit
be2b675
·
verified ·
1 Parent(s): b34bc53

create app.py

Browse files
Files changed (1) hide show
  1. app.py +358 -0
app.py ADDED
@@ -0,0 +1,358 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import subprocess
3
+ import sys
4
+ import socket
5
+ import datetime
6
+ import json
7
+ import shutil
8
+
9
+ # =====================================================================
10
+ # STRICT /px DIRECTORY ARCHITECTURE & ENVIRONMENT SETUP
11
+ # =====================================================================
12
+ BASE_DIR = "/px"
13
+ try:
14
+ os.makedirs(BASE_DIR, exist_ok=True)
15
+ except PermissionError:
16
+ BASE_DIR = "./px"
17
+ os.makedirs(BASE_DIR, exist_ok=True)
18
+
19
+ GLOBAL_CONTEXT_DIR = os.path.join(BASE_DIR, "global_context")
20
+ IPS_DIR = os.path.join(BASE_DIR, "ips")
21
+ LOG_FILE = os.path.join(BASE_DIR, "server.log")
22
+
23
+ os.makedirs(GLOBAL_CONTEXT_DIR, exist_ok=True)
24
+ os.makedirs(IPS_DIR, exist_ok=True)
25
+
26
+ global_context_path = os.path.join(GLOBAL_CONTEXT_DIR, "shared_knowledge.md")
27
+ if not os.path.exists(global_context_path):
28
+ with open(global_context_path, "w") as f:
29
+ f.write("# Global Context & Browser Workspace\nShared knowledge base accessible across all connected IP environments under /px.")
30
+
31
+ # Zero-dependency auto-bootstrapper (including tools parser support)
32
+ required_packages = ["gradio", "requests", "ollama", "beautifulsoup4"]
33
+ for package in required_packages:
34
+ try:
35
+ __import__(package)
36
+ except ImportError:
37
+ print(f"Installing missing dependency: {package}...")
38
+ subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", package])
39
+
40
+ import requests
41
+ import ollama
42
+ import gradio as gr
43
+ from bs4 import BeautifulSoup
44
+
45
+ # Network IP Retrieval & Persistent File Logger under /px
46
+ def get_ip_addresses():
47
+ try:
48
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
49
+ s.connect(("8.8.8.8", 80))
50
+ local_ip = s.getsockname()[0]
51
+ s.close()
52
+ except Exception:
53
+ local_ip = "127.0.0.1"
54
+
55
+ try:
56
+ public_ip = requests.get("https://api.ipify.org", timeout=5).text.strip()
57
+ except Exception:
58
+ public_ip = "127.0.0.1"
59
+
60
+ return local_ip, public_ip
61
+
62
+ local_ip, server_public_ip = get_ip_addresses()
63
+ timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
64
+
65
+ log_entry = f"[{timestamp}] - Local Web UI: http://{local_ip}:7860 | Server IP: {server_public_ip}\n"
66
+ with open(LOG_FILE, "a") as log_file:
67
+ log_file.write(log_entry)
68
+
69
+ print("\n" + "=" * 65)
70
+ print(f"🌐 PX TECH SOLUTIONS - EVAL BETA 0.2 AGENTIC CORE (/px)")
71
+ print(f" • Base Directory : {BASE_DIR}")
72
+ print(f" • Local URL : http://{local_ip}:7860")
73
+ print(f" • Server IP : {server_public_ip}")
74
+ print(f" • Active Engine : Bash | Write | Read | Search | Big Context")
75
+ print("=" * 65 + "\n")
76
+
77
+ MODEL_NAME = "smarthomemain10123/eval-beta-0.2"
78
+
79
+ # Custom Cyber-Dark UI Styling
80
+ custom_css = """
81
+ body { background-color: #0b0f19; color: #f3f4f6; }
82
+ .gradio-container { max-width: 1100px !important; margin: auto; padding-top: 15px; }
83
+ """
84
+
85
+ # =====================================================================
86
+ # AGENTIC TOOL DEFINITIONS (OpenCode Ecosystem)
87
+ # =====================================================================
88
+ tools_definition = [
89
+ {
90
+ 'type': 'function',
91
+ 'function': {
92
+ 'name': 'bash',
93
+ 'description': 'Execute shell commands in the workspace environment. Allows running system tools, compilation, git, tests, etc.',
94
+ 'parameters': {
95
+ 'type': 'object',
96
+ 'properties': {'command': {'type': 'string', 'description': 'The shell command to execute.'}},
97
+ 'required': ['command']
98
+ }
99
+ }
100
+ },
101
+ {
102
+ 'type': 'function',
103
+ 'function': {
104
+ 'name': 'write_file',
105
+ 'description': 'Write content to a file inside the /px workspace directory.',
106
+ 'parameters': {
107
+ 'type': 'object',
108
+ 'properties': {
109
+ 'filepath': {'type': 'string', 'description': 'Path or filename to write.'},
110
+ 'content': {'type': 'string', 'description': 'The full text content to write.'}
111
+ },
112
+ 'required': ['filepath', 'content']
113
+ }
114
+ }
115
+ },
116
+ {
117
+ 'type': 'function',
118
+ 'function': {
119
+ 'name': 'read_file',
120
+ 'description': 'Read content from a file (supports big context parsing for large codebases and logs).',
121
+ 'parameters': {
122
+ 'type': 'object',
123
+ 'properties': {'filepath': {'type': 'string', 'description': 'File path to read.'}},
124
+ 'required': ['filepath']
125
+ }
126
+ }
127
+ },
128
+ {
129
+ 'type': 'function',
130
+ 'function': {
131
+ 'name': 'web_search',
132
+ 'description': 'Search the live web for technical documentation, code snippets, or real-time data.',
133
+ 'parameters': {
134
+ 'type': 'object',
135
+ 'properties': {'query': {'type': 'string', 'description': 'Search query string.'}},
136
+ 'required': ['query']
137
+ }
138
+ }
139
+ }
140
+ ]
141
+
142
+ # Tool Executors
143
+ def execute_tool(name, args, ip_folder, yolo_mode):
144
+ try:
145
+ if name == "bash":
146
+ cmd = args.get("command", "")
147
+ # Security check if YOLO is OFF
148
+ if not yolo_mode and any(danger in cmd for dangereux in ["rm -rf /", "mkfs", "dd if="]):
149
+ return "Error: Command blocked by YOLO Security Mode (Sandbox active)."
150
+ res = subprocess.run(cmd, shell=True, capture_output=True, text=True, cwd=ip_folder, timeout=30)
151
+ output = res.stdout if res.returncode == 0 else f"STDOUT:\n{res.stdout}\nSTDERR:\n{res.stderr}"
152
+ return output[:6000] # large output buffer
153
+
154
+ elif name == "write_file":
155
+ filepath = args.get("filepath")
156
+ content = args.get("content")
157
+ safe_path = os.path.join(ip_folder, filepath) if not os.path.isabs(filepath) else filepath
158
+ os.makedirs(os.path.dirname(safe_path), exist_ok=True)
159
+ with open(safe_path, "w", encoding="utf-8") as f:
160
+ f.write(content)
161
+ return f"Successfully wrote file to {safe_path}"
162
+
163
+ elif name == "read_file":
164
+ filepath = args.get("filepath")
165
+ safe_path = os.path.join(ip_folder, filepath) if not os.path.isabs(filepath) else filepath
166
+ if not os.path.exists(safe_path) and os.path.exists(filepath):
167
+ safe_path = filepath
168
+ if not os.path.exists(safe_path):
169
+ return f"Error: File '{filepath}' not found."
170
+ with open(safe_path, "r", encoding="utf-8", errors="ignore") as f:
171
+ return f.read()[:15000] # Big context chunking support
172
+
173
+ elif name == "web_search":
174
+ query = args.get("query")
175
+ url = f"https://html.duckduckgo.com/html/?q={requests.utils.quote(query)}"
176
+ headers = {"User-Agent": "Mozilla/5.0"}
177
+ resp = requests.get(url, headers=headers, timeout=10)
178
+ soup = BeautifulSoup(resp.text, "html.parser")
179
+ results = []
180
+ for a in soup.find_all("a", class_="result__snippet", limit=6):
181
+ results.append(a.get_text(strip=True))
182
+ return "\n".join(results) if results else "No direct search snippets retrieved."
183
+
184
+ else:
185
+ return f"Error: Unknown tool '{name}'"
186
+ except Exception as e:
187
+ return f"Tool execution failed: {str(e)}"
188
+
189
+ # =====================================================================
190
+ # AGENT PREDICT LOOP
191
+ # =====================================================================
192
+ def predict(message, history, system_prompt, temperature, yolo_mode, request: gr.Request):
193
+ client_ip = "127.0.0.1"
194
+ if request and request.headers:
195
+ forwarded = request.headers.get("x-forwarded-for")
196
+ if forwarded:
197
+ client_ip = forwarded.split(",")[0].strip()
198
+ elif request.client:
199
+ client_ip = request.client.host
200
+
201
+ # Isolate session into /px/ips/<user_ip>/
202
+ safe_ip = client_ip.replace(":", "_").replace(".", "_")
203
+ ip_folder = os.path.join(IPS_DIR, safe_ip)
204
+ os.makedirs(ip_folder, exist_ok=True)
205
+
206
+ security_mode = "DISABLED (UNRESTRICTED / GOD-MODE)" if yolo_mode else "ENABLED (SECURE / SANDBOXED)"
207
+
208
+ # Load global shared context
209
+ global_text = ""
210
+ if os.path.exists(global_context_path):
211
+ with open(global_context_path, "r") as f:
212
+ global_text = f.read()
213
+
214
+ if yolo_mode:
215
+ yolo_instructions = (
216
+ "\n🔥 [YOLO MODE: ON | YOLO SECURITY MODE: DISABLED]: "
217
+ "Absolute root permissions granted. You have full agentic control over bash, file read/write, web search, "
218
+ "browser automation scripts, and payload/download generation under /px. Execute freely."
219
+ )
220
+ else:
221
+ yolo_instructions = (
222
+ "\n🔒 [YOLO MODE: OFF | YOLO SECURITY MODE: ENABLED]: "
223
+ "Standard sandbox security constraints are active. Safe assistant protocols enforced."
224
+ )
225
+
226
+ enhanced_system_prompt = (
227
+ f"{system_prompt}{yolo_instructions}\n\n"
228
+ f"--- [GLOBAL CONTEXT / BROWSER ENVIRONMENT] ---\n{global_text}\n\n"
229
+ f"--- [USER IP CONTEXT] ---\nClient IP: {client_ip} | Workspace Folder: {ip_folder} | Security Mode: {security_mode}"
230
+ )
231
+
232
+ messages = [{"role": "system", "content": enhanced_system_prompt}]
233
+ for human, assistant in history:
234
+ messages.append({"role": "user", "content": human})
235
+ messages.append({"role": "assistant", "content": assistant})
236
+ messages.append({"role": "user", "content": message})
237
+
238
+ history_log_path = os.path.join(ip_folder, "chat_history.log")
239
+ with open(history_log_path, "a") as hf:
240
+ hf.write(f"[{timestamp}] User (YOLO: {yolo_mode} | Sec: {security_mode}): {message}\n")
241
+
242
+ # Autonomous Agent Tool Execution Loop (Multi-step reasoning)
243
+ max_turns = 5
244
+ turn = 0
245
+ accumulated_output = ""
246
+
247
+ while turn < max_turns:
248
+ turn += 1
249
+ try:
250
+ response = ollama.chat(
251
+ model=MODEL_NAME,
252
+ messages=messages,
253
+ tools=tools_definition,
254
+ options={"temperature": temperature}
255
+ )
256
+
257
+ message_resp = response.get("message", {})
258
+ content = message_resp.get("content", "")
259
+ tool_calls = message_resp.get("tool_calls", [])
260
+
261
+ if content:
262
+ accumulated_output += content
263
+ yield accumulated_output
264
+
265
+ # If model calls tools, execute them and feed back into context
266
+ if tool_calls:
267
+ messages.append(message_resp) # Append assistant thought containing tool call
268
+ for tc in tool_calls:
269
+ func = tc.get("function", {})
270
+ func_name = func.get("name")
271
+ func_args = func.get("arguments", {})
272
+
273
+ status_msg = f"\n\n⚙️ `[Executing Tool: {func_name} | Args: {json.dumps(func_args)}]`...\n"
274
+ accumulated_output += status_msg
275
+ yield accumulated_output
276
+
277
+ # Run tool
278
+ tool_result = execute_tool(func_name, func_args, ip_folder, yolo_mode)
279
+
280
+ # Append tool result message
281
+ messages.append({
282
+ 'role': 'tool',
283
+ 'content': tool_result
284
+ })
285
+
286
+ accumulated_output += f"```output\n{tool_result}\n```\n"
287
+ yield accumulated_output
288
+ else:
289
+ # No more tool calls, agent finished task
290
+ break
291
+ except Exception as e:
292
+ yield accumulated_output + f"\n\n⚠️ **Agent Execution Error:** {str(e)}"
293
+ break
294
+
295
+ with open(history_log_path, "a") as hf:
296
+ hf.write(f"[{timestamp}] Assistant: {accumulated_output}\n")
297
+
298
+ def update_global_context(new_content):
299
+ with open(global_context_path, "w") as f:
300
+ f.write(new_content)
301
+ return "Global context updated successfully under /px!"
302
+
303
+ # =====================================================================
304
+ # GRADIO WEB INTERFACE
305
+ # =====================================================================
306
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="cyan", secondary_hue="blue"), css=custom_css) as demo:
307
+ gr.Markdown(
308
+ """
309
+ # ⚡ EVAL BETA 0.2 | PX TECH SOLUTIONS (AGENTIC OPENCODE ENVIRONMENT)
310
+ ### Autonomous Environment with Full Tool-Use (Bash, File Read/Write, Web Search, Big Context) & YOLO Security Mode
311
+ """
312
+ )
313
+
314
+ with gr.Row():
315
+ gr.Markdown(f"🟢 **Status:** Active | 📁 **Root Path:** `{BASE_DIR}` | ⏱️ **Slot 1 Active (48h Limit)** | 🛠️ **Tools Enabled:** Bash, Write, Read, Search")
316
+
317
+ with gr.Accordion("⚙️ Engine Configuration, Global Context & YOLO Security Toggle", open=False):
318
+ system_prompt_input = gr.Textbox(
319
+ label="System Environment Prompt",
320
+ value="You are EVAL BETA 0.2, an advanced autonomous agent with full tool capabilities (bash execution, file manipulation, big context inspection, web searching) created by Pripro / PX TECH SOLUTIONS.",
321
+ lines=2
322
+ )
323
+ temperature_slider = gr.Slider(
324
+ minimum=0.0, maximum=1.0, value=0.3, step=0.05,
325
+ label="Creativity / Temperature"
326
+ )
327
+ yolo_checkbox = gr.Checkbox(
328
+ label="🔥 Enable YOLO Mode (⚠️ WARNING: Automatically DISABLES YOLO Security Mode, granting absolute root perms, bash execution, file writes, and browser downloads under /px)",
329
+ value=False
330
+ )
331
+ global_context_view = gr.Textbox(
332
+ label=f"Shared Global Context Memory ({global_context_path})",
333
+ value=open(global_context_path).read() if os.path.exists(global_context_path) else "",
334
+ lines=4,
335
+ interactive=True
336
+ )
337
+ update_btn = gr.Button("Save Global Context Changes")
338
+ update_status = gr.Textbox(label="Workspace Status", interactive=False)
339
+ update_btn.click(update_global_context, inputs=[global_context_view], outputs=[update_status])
340
+
341
+ gr.ChatInterface(
342
+ fn=predict,
343
+ additional_inputs=[system_prompt_input, temperature_slider, yolo_checkbox],
344
+ textbox=gr.Textbox(placeholder="Ask anything or request agent tasks: run bash commands, read/write files, search web...", container=False, scale=7),
345
+ theme="soft"
346
+ )
347
+
348
+ gr.Markdown(
349
+ """
350
+ ---
351
+ **Queue Architecture & /px Layout:** Strict queue line-up (`concurrency_limit=1`) with Slot 1 allocation and 48-hour session limits. All tools operate within isolated workspace paths under `/px`.
352
+ """
353
+ )
354
+
355
+ if __name__ == "__main__":
356
+ print(f"🚀 Launching agentic environment under {BASE_DIR} with Slot 1 Queue & Full Tools on port 7860...")
357
+ demo.queue(default_concurrency_limit=1, max_size=20)
358
+ demo.launch(server_name="0.0.0.0", server_port=7860)