import os import subprocess import threading import time import sys import queue from flask import Flask, Response, render_template_string # ============================================================================== # 📟 KIYENGINE COMMAND CENTER (TERMINAL UI) # ============================================================================== app = Flask(__name__) # Hàng đợi để chứa log từ bot (giữ lại 100 dòng cuối cùng) log_queue = queue.Queue() MAX_LOG_LINES = 200 recent_logs = [] def enqueue_output(out, queue): """Đọc output từ process và đẩy vào hàng đợi""" for line in iter(out.readline, b''): line = line.decode('utf-8').rstrip() if line: print(f"[BOT] {line}") # In ra console thật của Docker queue.put(line) # Lưu vào bộ nhớ đệm để người mới vào xem được lịch sử recent_logs.append(line) if len(recent_logs) > MAX_LOG_LINES: recent_logs.pop(0) out.close() def prepare_config(): """Inject Token vào config.yml""" token = os.getenv("LICHESS_TOKEN") config_path = "config.yml" if not os.path.exists(config_path): log_queue.put("❌ ERROR: config.yml not found!") return False if token: try: with open(config_path, "r", encoding="utf-8") as f: content = f.read() if "REPLACE_ME_WITH_LICHESS_TOKEN" in content: log_queue.put("🔑 System: Injecting Lichess Token...") new_content = content.replace("REPLACE_ME_WITH_LICHESS_TOKEN", token) with open(config_path, "w", encoding="utf-8") as f: f.write(new_content) except Exception as e: log_queue.put(f"❌ Config Error: {e}") return False else: log_queue.put("⚠️ Warning: No LICHESS_TOKEN found in env.") return True def run_bot_process(): """Chạy Lichess-bot trong subprocess""" if not prepare_config(): return log_queue.put("🚀 System: Starting KiyEngine v6 Assassin...") log_queue.put("Target: Lichess.org | Mode: Hunter") log_queue.put("--------------------------------------------------") # Chạy bot với chế độ unbuffered (-u) để log ra ngay lập tức process = subprocess.Popen( ["python3", "-u", "lichess-bot.py"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, # Gộp lỗi vào log chính bufsize=1 # Line buffered ) # Tạo thread đọc log t = threading.Thread(target=enqueue_output, args=(process.stdout, log_queue)) t.daemon = True t.start() process.wait() log_queue.put("🛑 System: Bot process terminated.") # --- GIAO DIỆN WEB TERMINAL --- HTML_TEMPLATE = """ KiyEngine v6 Control Center
KiyEngine v6 Assassin [BitNet 1.58-bit]
SYSTEM ONLINE
""" @app.route('/') def index(): return render_template_string(HTML_TEMPLATE) @app.route('/stream_logs') def stream_logs(): def generate(): # Gửi lại các log cũ trước for line in recent_logs: yield f"data: {line}\n\n" # Gửi log mới realtime while True: try: # Chờ log mới trong 5s, nếu không có thì gửi heartbeat comment line = log_queue.get(timeout=5) yield f"data: {line}\n\n" except queue.Empty: yield ": keep-alive\n\n" # Comment để giữ kết nối không bị đóng return Response(generate(), mimetype='text/event-stream') if __name__ == "__main__": # 1. Chạy Bot ở thread riêng threading.Thread(target=run_bot_process, daemon=True).start() # 2. Chạy Web Server (Port 7860 bắt buộc cho HF Spaces) port = int(os.environ.get("PORT", 7860)) app.run(host='0.0.0.0', port=port, threaded=True)