Upload folder using huggingface_hub
Browse files- app.py +121 -0
- vm_data_server.py +50 -0
app.py
CHANGED
|
@@ -504,6 +504,46 @@ def refresh_raw_logs():
|
|
| 504 |
header = f"=== RAW CRON LOGS ===\nShowing last {showing_lines} of {total_lines} total lines\n\n"
|
| 505 |
return header + content
|
| 506 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 507 |
# Custom CSS for gorgeous design
|
| 508 |
custom_css = """
|
| 509 |
.gradio-container {
|
|
@@ -571,6 +611,16 @@ custom_css = """
|
|
| 571 |
.profit-positive { color: #00d647 !important; font-weight: 600 !important; }
|
| 572 |
.profit-negative { color: #ff0080 !important; font-weight: 600 !important; }
|
| 573 |
.profit-neutral { color: #8b949e !important; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 574 |
"""
|
| 575 |
|
| 576 |
def create_dashboard():
|
|
@@ -649,6 +699,39 @@ def create_dashboard():
|
|
| 649 |
)
|
| 650 |
refresh_investment_btn = gr.Button("π Refresh Investment Performance", variant="primary", size="lg")
|
| 651 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 652 |
# System Logs Tab
|
| 653 |
with gr.Tab("π System Logs"):
|
| 654 |
gr.Markdown("## π₯οΈ Trading Bot Activity")
|
|
@@ -722,6 +805,44 @@ def create_dashboard():
|
|
| 722 |
outputs=[investment_performance_table]
|
| 723 |
)
|
| 724 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 725 |
# Logs tab
|
| 726 |
refresh_logs_btn.click(
|
| 727 |
fn=refresh_system_logs,
|
|
|
|
| 504 |
header = f"=== RAW CRON LOGS ===\nShowing last {showing_lines} of {total_lines} total lines\n\n"
|
| 505 |
return header + content
|
| 506 |
|
| 507 |
+
def run_vm_command(command, current_output=""):
|
| 508 |
+
"""Execute command on VM and return output"""
|
| 509 |
+
try:
|
| 510 |
+
if not command.strip():
|
| 511 |
+
return current_output
|
| 512 |
+
|
| 513 |
+
response = requests.post(f"{VM_API_URL}/api/execute",
|
| 514 |
+
json={"command": command},
|
| 515 |
+
timeout=10)
|
| 516 |
+
|
| 517 |
+
if response.status_code == 200:
|
| 518 |
+
data = response.json()
|
| 519 |
+
output = data.get('output', '')
|
| 520 |
+
exit_code = data.get('exit_code', 0)
|
| 521 |
+
|
| 522 |
+
# Format terminal-style output
|
| 523 |
+
new_line = f"$ {command}\n{output}"
|
| 524 |
+
if exit_code != 0:
|
| 525 |
+
new_line += f"\n[Exit code: {exit_code}]"
|
| 526 |
+
new_line += "\n$ "
|
| 527 |
+
|
| 528 |
+
return current_output + new_line
|
| 529 |
+
else:
|
| 530 |
+
error_line = f"$ {command}\nError: VM API returned {response.status_code}\n$ "
|
| 531 |
+
return current_output + error_line
|
| 532 |
+
|
| 533 |
+
except Exception as e:
|
| 534 |
+
error_line = f"$ {command}\nError: {str(e)}\n$ "
|
| 535 |
+
return current_output + error_line
|
| 536 |
+
|
| 537 |
+
def clear_terminal():
|
| 538 |
+
"""Clear terminal output"""
|
| 539 |
+
return "π₯οΈ VM Terminal Ready\n$ "
|
| 540 |
+
|
| 541 |
+
def run_quick_command(cmd):
|
| 542 |
+
"""Helper for quick command buttons"""
|
| 543 |
+
def execute(current_output):
|
| 544 |
+
return run_vm_command(cmd, current_output)
|
| 545 |
+
return execute
|
| 546 |
+
|
| 547 |
# Custom CSS for gorgeous design
|
| 548 |
custom_css = """
|
| 549 |
.gradio-container {
|
|
|
|
| 611 |
.profit-positive { color: #00d647 !important; font-weight: 600 !important; }
|
| 612 |
.profit-negative { color: #ff0080 !important; font-weight: 600 !important; }
|
| 613 |
.profit-neutral { color: #8b949e !important; }
|
| 614 |
+
|
| 615 |
+
.terminal-output {
|
| 616 |
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace !important;
|
| 617 |
+
background: #1e1e1e !important;
|
| 618 |
+
color: #00ff00 !important;
|
| 619 |
+
border-radius: 8px !important;
|
| 620 |
+
padding: 1rem !important;
|
| 621 |
+
font-size: 14px !important;
|
| 622 |
+
line-height: 1.4 !important;
|
| 623 |
+
}
|
| 624 |
"""
|
| 625 |
|
| 626 |
def create_dashboard():
|
|
|
|
| 699 |
)
|
| 700 |
refresh_investment_btn = gr.Button("π Refresh Investment Performance", variant="primary", size="lg")
|
| 701 |
|
| 702 |
+
# VM Terminal Tab
|
| 703 |
+
with gr.Tab("π» VM Terminal"):
|
| 704 |
+
gr.Markdown("## π₯οΈ Remote VM Terminal")
|
| 705 |
+
gr.Markdown("### Execute commands directly on your trading VM")
|
| 706 |
+
|
| 707 |
+
with gr.Row():
|
| 708 |
+
with gr.Column(scale=4):
|
| 709 |
+
command_input = gr.Textbox(
|
| 710 |
+
label="Command",
|
| 711 |
+
placeholder="Enter command to run on VM...",
|
| 712 |
+
interactive=True,
|
| 713 |
+
elem_classes=["gr-textbox"]
|
| 714 |
+
)
|
| 715 |
+
with gr.Column(scale=1):
|
| 716 |
+
run_command_btn = gr.Button("βΆοΈ Run", variant="primary", size="lg")
|
| 717 |
+
clear_terminal_btn = gr.Button("ποΈ Clear", variant="secondary", size="lg")
|
| 718 |
+
|
| 719 |
+
terminal_output = gr.Textbox(
|
| 720 |
+
label="Terminal Output",
|
| 721 |
+
lines=20,
|
| 722 |
+
max_lines=20,
|
| 723 |
+
interactive=False,
|
| 724 |
+
elem_classes=["terminal-output"],
|
| 725 |
+
value="π₯οΈ VM Terminal Ready\n$ "
|
| 726 |
+
)
|
| 727 |
+
|
| 728 |
+
gr.Markdown("**Quick Commands:**")
|
| 729 |
+
with gr.Row():
|
| 730 |
+
quick_ls = gr.Button("π ls -la", size="sm")
|
| 731 |
+
quick_ps = gr.Button("π ps aux | grep python", size="sm")
|
| 732 |
+
quick_logs = gr.Button("π tail script.log", size="sm")
|
| 733 |
+
quick_vm_status = gr.Button("π₯οΈ VM Status", size="sm")
|
| 734 |
+
|
| 735 |
# System Logs Tab
|
| 736 |
with gr.Tab("π System Logs"):
|
| 737 |
gr.Markdown("## π₯οΈ Trading Bot Activity")
|
|
|
|
| 805 |
outputs=[investment_performance_table]
|
| 806 |
)
|
| 807 |
|
| 808 |
+
# VM Terminal tab
|
| 809 |
+
run_command_btn.click(
|
| 810 |
+
fn=run_vm_command,
|
| 811 |
+
inputs=[command_input, terminal_output],
|
| 812 |
+
outputs=[terminal_output]
|
| 813 |
+
)
|
| 814 |
+
command_input.submit(
|
| 815 |
+
fn=run_vm_command,
|
| 816 |
+
inputs=[command_input, terminal_output],
|
| 817 |
+
outputs=[terminal_output]
|
| 818 |
+
)
|
| 819 |
+
clear_terminal_btn.click(
|
| 820 |
+
fn=clear_terminal,
|
| 821 |
+
outputs=[terminal_output]
|
| 822 |
+
)
|
| 823 |
+
|
| 824 |
+
# Quick command buttons
|
| 825 |
+
quick_ls.click(
|
| 826 |
+
fn=lambda current: run_vm_command("ls -la", current),
|
| 827 |
+
inputs=[terminal_output],
|
| 828 |
+
outputs=[terminal_output]
|
| 829 |
+
)
|
| 830 |
+
quick_ps.click(
|
| 831 |
+
fn=lambda current: run_vm_command("ps aux | grep python", current),
|
| 832 |
+
inputs=[terminal_output],
|
| 833 |
+
outputs=[terminal_output]
|
| 834 |
+
)
|
| 835 |
+
quick_logs.click(
|
| 836 |
+
fn=lambda current: run_vm_command("tail -20 script.log", current),
|
| 837 |
+
inputs=[terminal_output],
|
| 838 |
+
outputs=[terminal_output]
|
| 839 |
+
)
|
| 840 |
+
quick_vm_status.click(
|
| 841 |
+
fn=lambda current: run_vm_command("uptime && df -h && free -h", current),
|
| 842 |
+
inputs=[terminal_output],
|
| 843 |
+
outputs=[terminal_output]
|
| 844 |
+
)
|
| 845 |
+
|
| 846 |
# Logs tab
|
| 847 |
refresh_logs_btn.click(
|
| 848 |
fn=refresh_system_logs,
|
vm_data_server.py
CHANGED
|
@@ -259,6 +259,55 @@ def get_raw_logs():
|
|
| 259 |
except Exception as e:
|
| 260 |
return jsonify({'error': str(e), 'content': ''})
|
| 261 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 262 |
if __name__ == '__main__':
|
| 263 |
print("π Starting VM Data Server...")
|
| 264 |
print("π‘ This exposes your trading bot data via API")
|
|
@@ -267,6 +316,7 @@ if __name__ == '__main__':
|
|
| 267 |
print(" β’ Raw cron logs with color coding")
|
| 268 |
print(" β’ Portfolio data from VM files")
|
| 269 |
print(" β’ Buy queue and system stats")
|
|
|
|
| 270 |
print("-" * 50)
|
| 271 |
|
| 272 |
# Run on all interfaces so dashboard can connect
|
|
|
|
| 259 |
except Exception as e:
|
| 260 |
return jsonify({'error': str(e), 'content': ''})
|
| 261 |
|
| 262 |
+
@app.route('/api/execute', methods=['POST'])
|
| 263 |
+
def execute_command():
|
| 264 |
+
"""Execute a command on the VM"""
|
| 265 |
+
try:
|
| 266 |
+
data = request.get_json()
|
| 267 |
+
command = data.get('command', '').strip()
|
| 268 |
+
|
| 269 |
+
if not command:
|
| 270 |
+
return jsonify({'error': 'No command provided', 'output': '', 'exit_code': 1})
|
| 271 |
+
|
| 272 |
+
# Security: only allow safe commands
|
| 273 |
+
dangerous_commands = ['rm', 'sudo', 'passwd', 'shutdown', 'reboot', 'mkfs', 'fdisk', 'dd']
|
| 274 |
+
if any(cmd in command.lower() for cmd in dangerous_commands):
|
| 275 |
+
return jsonify({
|
| 276 |
+
'error': 'Command not allowed for security reasons',
|
| 277 |
+
'output': f"β Command '{command}' contains restricted operations",
|
| 278 |
+
'exit_code': 1
|
| 279 |
+
})
|
| 280 |
+
|
| 281 |
+
# Execute command with timeout
|
| 282 |
+
import subprocess
|
| 283 |
+
result = subprocess.run(
|
| 284 |
+
command,
|
| 285 |
+
shell=True,
|
| 286 |
+
capture_output=True,
|
| 287 |
+
text=True,
|
| 288 |
+
timeout=30, # 30 second timeout
|
| 289 |
+
cwd='/home/jetpackjules/Stock-Trader' # Run in trading directory
|
| 290 |
+
)
|
| 291 |
+
|
| 292 |
+
return jsonify({
|
| 293 |
+
'output': result.stdout + result.stderr,
|
| 294 |
+
'exit_code': result.returncode,
|
| 295 |
+
'command': command
|
| 296 |
+
})
|
| 297 |
+
|
| 298 |
+
except subprocess.TimeoutExpired:
|
| 299 |
+
return jsonify({
|
| 300 |
+
'error': 'Command timed out',
|
| 301 |
+
'output': 'β° Command execution timed out (30s limit)',
|
| 302 |
+
'exit_code': 124
|
| 303 |
+
})
|
| 304 |
+
except Exception as e:
|
| 305 |
+
return jsonify({
|
| 306 |
+
'error': str(e),
|
| 307 |
+
'output': f'β Error executing command: {str(e)}',
|
| 308 |
+
'exit_code': 1
|
| 309 |
+
})
|
| 310 |
+
|
| 311 |
if __name__ == '__main__':
|
| 312 |
print("π Starting VM Data Server...")
|
| 313 |
print("π‘ This exposes your trading bot data via API")
|
|
|
|
| 316 |
print(" β’ Raw cron logs with color coding")
|
| 317 |
print(" β’ Portfolio data from VM files")
|
| 318 |
print(" β’ Buy queue and system stats")
|
| 319 |
+
print(" β’ Remote command execution")
|
| 320 |
print("-" * 50)
|
| 321 |
|
| 322 |
# Run on all interfaces so dashboard can connect
|