Lisman / app.py
Aqso's picture
Update app.py
3c12f48 verified
import os, subprocess, threading, time, shutil
from flask import Flask, render_template_string, request, Response, jsonify
app = Flask(__name__)
log_queue = []
# PATH TETAP: Semua bot ditaruh di sini
BOT_ROOT = os.path.join(os.getcwd(), "bot_workdir")
# UI Dashboard v6 - Ultimate Terminal Edition
HTML_TEMPLATE = """
<!DOCTYPE html>
<html>
<head>
<title>AQSO DEPLOYER v6</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body { background: #0b0f1a; color: #cbd5e1; font-family: 'Fira Code', monospace; }
.terminal { background: #000; color: #10b981; padding: 12px; border-radius: 8px 8px 0 0; height: 350px; overflow-y: auto; font-size: 11px; border: 1px solid #1e293b; }
.term-input { background: #000; color: #fff; border: 1px solid #1e293b; border-top: none; width: 100%; padding: 10px; font-size: 11px; border-radius: 0 0 8px 8px; outline: none; }
.btn-gacor { transition: all 0.2s; font-weight: bold; border-radius: 8px; }
.btn-gacor:active { transform: scale(0.95); }
</style>
</head>
<body class="p-4 md:p-10">
<div class="max-w-4xl mx-auto">
<div class="flex justify-between items-center mb-6">
<h1 class="text-2xl font-bold text-blue-500">AQSO CLOUD v6 ⚡</h1>
<div class="text-[10px] bg-slate-800 px-3 py-1 rounded text-slate-400">PATH: /bot_workdir</div>
</div>
<div class="bg-slate-900 p-6 rounded-2xl border border-slate-800 shadow-2xl space-y-4">
<div class="flex gap-2">
<button onclick="setLang('node')" id="tag-node" class="flex-1 py-2 rounded bg-green-900 text-green-300 border border-green-500">NODE JS MODE</button>
<button onclick="setLang('python')" id="tag-py" class="flex-1 py-2 rounded bg-slate-800 text-slate-500">PYTHON MODE</button>
</div>
<div class="flex gap-2">
<input id="repo" type="text" class="flex-1 p-3 bg-black rounded-lg border border-slate-700 text-xs outline-none focus:border-blue-500" placeholder="Paste URL Github Lu...">
<button onclick="runCmd('clone')" class="bg-blue-600 px-6 rounded-lg text-xs btn-gacor">CLONE</button>
</div>
<div class="terminal" id="logs">Sistem Siap. Terminal manual di bawah otomatis jalan di folder bot lu.</div>
<input type="text" id="term-box" class="term-input" placeholder="Ketik command manual (contoh: ls -la atau npm install) lalu Enter..." onkeypress="handleTerm(event)">
<div class="grid grid-cols-3 gap-3 mt-4">
<button onclick="runCmd('install')" class="bg-purple-700 py-3 text-xs btn-gacor">INSTALL DEPS</button>
<button onclick="runCmd('start')" class="bg-red-600 py-3 text-xs btn-gacor text-white">START BOT</button>
<button onclick="runCmd('clear')" class="bg-slate-700 py-3 text-xs btn-gacor">WIPE & RESET</button>
</div>
</div>
</div>
<script>
let lang = 'node';
function setLang(l) {
lang = l;
document.getElementById('tag-node').className = l === 'node' ? 'flex-1 py-2 rounded bg-green-900 text-green-300 border border-green-500' : 'flex-1 py-2 rounded bg-slate-800 text-slate-500';
document.getElementById('tag-py').className = l === 'python' ? 'flex-1 py-2 rounded bg-yellow-900 text-yellow-300 border border-yellow-500' : 'flex-1 py-2 rounded bg-slate-800 text-slate-500';
}
function handleTerm(e) {
if (e.key === 'Enter') {
const cmd = e.target.value;
runCmd('manual', cmd);
e.target.value = '';
}
}
function runCmd(type, manualCmd = '') {
const repo = document.getElementById('repo').value;
fetch('/execute', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({type, repo, lang, manual: manualCmd})
});
}
const source = new EventSource("/stream");
source.onmessage = (e) => {
const logDiv = document.getElementById('logs');
logDiv.innerHTML += e.data + '<br>';
logDiv.scrollTop = logDiv.scrollHeight;
};
</script>
</body>
</html>
"""
def run_command(command, cwd=None):
global log_queue
if not os.path.exists(cwd): os.makedirs(cwd)
# Gunakan bash -c agar 'exec -a' bisa jalan
full_cmd = f"bash -c \"{command}\""
process = subprocess.Popen(full_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, cwd=cwd)
for line in process.stdout:
log_queue.append(f"> {line.strip()}")
process.wait()
@app.route('/')
def index(): return render_template_string(HTML_TEMPLATE)
@app.route('/execute', methods=['POST'])
def execute():
data = request.json
cmd_type, repo, lang, manual = data['type'], data['repo'], data['lang'], data.get('manual', '')
if cmd_type == 'manual':
log_queue.append(f"<span class='text-blue-400'>[MANUAL] {manual}</span>")
threading.Thread(target=run_command, args=(manual, BOT_ROOT)).start()
elif cmd_type == 'clear':
if os.path.exists(BOT_ROOT): shutil.rmtree(BOT_ROOT)
log_queue.append("<span class='text-orange-400'>[SYSTEM] Workspace Cleaned.</span>")
elif cmd_type == 'clone':
if os.path.exists(BOT_ROOT): shutil.rmtree(BOT_ROOT)
os.makedirs(BOT_ROOT)
log_queue.append(f"[SYSTEM] Cloning ke folder khusus...")
threading.Thread(target=run_command, args=(f"git clone {repo} .", BOT_ROOT)).start()
elif cmd_type == 'install':
cmd = "npm install" if lang == 'node' else "pip install -r requirements.txt"
threading.Thread(target=run_command, args=(cmd, BOT_ROOT)).start()
elif cmd_type == 'start':
# FIX: Pakai bash -c biar 'exec -a' gak error lagi
cmd = "exec -a 'python3_inference' node ." if lang == 'node' else "exec -a 'python3_inference' python3 main.py"
log_queue.append(f"<span class='text-red-400'>[SYSTEM] Menjalankan bot (Masking Bash)...</span>")
threading.Thread(target=run_command, args=(cmd, BOT_ROOT)).start()
return {"status": "ok"}
@app.route('/stream')
def stream():
def generate():
while True:
if log_queue: yield f"data: {log_queue.pop(0)}\n\n"
else: time.sleep(0.5)
return Response(generate(), mimetype='text/event-stream')
if __name__ == "__main__":
app.run(host='0.0.0.0', port=7860)