# đŸ“ĸ 1. ZeroGPU keepalive setup import spaces @spaces.GPU def _hf_zerogpu_keepalive(): return None import os import sys import time import subprocess import html # 2. Auto-install required packages for pkg in ["gradio", "psutil"]: try: __import__(pkg) except ImportError: subprocess.run([sys.executable, "-m", "pip", "install", pkg, "-q"], check=True) import gradio as gr import psutil # Global directory state current_working_dir = os.path.expanduser("~") initial_text = "
[TERNAL Terminal Is Ready...]
" # ========================================== # 3. Terminal Execution Engine # ========================================== def execute_terminal(cmd, current_history): global current_working_dir if not cmd or not cmd.strip(): return current_history, "" cmd_clean = cmd.strip() if cmd_clean == "clear": return initial_text, "" # Remove initial text on first command if current_history and initial_text in current_history: current_history = current_history.replace(initial_text, "") if cmd_clean.startswith("cd ") or cmd_clean == "cd": target = cmd_clean[3:].strip() if len(cmd_clean) > 2 else os.path.expanduser("~") if target == "~": target = os.path.expanduser("~") try: new_path = os.path.abspath(os.path.join(current_working_dir, target)) if os.path.isdir(new_path): current_working_dir = new_path output = f"[Dir: {current_working_dir}]" else: output = f"cd: {target}: No such directory" except Exception as e: output = f"cd error: {str(e)}" else: try: res = subprocess.run( cmd_clean, shell=True, cwd=current_working_dir, capture_output=True, text=True, timeout=180 ) out_html = "" if res.stdout: out_html += f"{html.escape(res.stdout)}" if res.stderr: out_html += f"{html.escape(res.stderr)}" if not res.stdout and not res.stderr: out_html = "[Process finished with exit code 0]" output = f"
{out_html}
" except subprocess.TimeoutExpired: output = "[Timeout: 180s limit exceeded!]" except Exception as e: output = f"[Error: {html.escape(str(e))}]" user_part = "user@hf" path_part = f":{os.path.basename(current_working_dir) or '/'}" cmd_part = f"$ {html.escape(cmd_clean)}" prompt_line = f"
{user_part}{path_part}{cmd_part}
" output_block = f"
{output}
" updated_history = (current_history if current_history else "") + prompt_line + output_block scroll_js = "" return updated_history + scroll_js, "" # ========================================== # 4. Live RAM & CPU Header # ========================================== def get_live_header(): used_gb = 0.0 try: if os.path.exists("/sys/fs/cgroup/memory.current"): with open("/sys/fs/cgroup/memory.current") as f: used_gb = round(int(f.read().strip()) / (1024**3), 1) else: used_gb = round(psutil.virtual_memory().used / (1024**3), 1) except: used_gb = round(psutil.virtual_memory().used / (1024**3), 1) if used_gb < 0.1 or used_gb > 96.0: used_gb = round(psutil.virtual_memory().used / (1024**3), 1) cpu_load = int(psutil.cpu_percent()) ram_svg = """""" cpu_svg = """""" return f"""
{ram_svg} RAM: {used_gb}/96GB
{cpu_svg} CPU: 16C ({cpu_load}%)
""" # ========================================== # 5. Bulletproof CSS (Hardware Engine Auto-Lock) # ========================================== custom_css = """ @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap'); footer { display: none !important; } html, body { height: 100dvh !important; width: 100vw !important; background-color: #05070a !important; overflow: hidden !important; margin: 0 !important; padding: 0 !important; position: fixed !important; } .gradio-container { padding: 0 !important; margin: 0 !important; max-width: 100% !important; width: 100vw !important; height: 100dvh !important; border: none !important; background-color: #05070a !important; } #main_wrapper { position: absolute !important; top: 0 !important; left: 0 !important; width: 100vw !important; height: 100dvh !important; background-color: #05070a !important; margin: 0 !important; padding: 0 !important; } /* Top Header */ #live_header { position: fixed !important; top: 0 !important; left: 0 !important; width: 100vw !important; height: 32px !important; background-color: #161b22 !important; border-bottom: 1px solid #30363d !important; padding: 0 15px !important; display: flex !important; align-items: center !important; box-sizing: border-box !important; z-index: 9999 !important; font-family: 'JetBrains Mono', monospace !important; font-size: 11px !important; } #live_header > div { width: 100% !important; } /* TERNAL Sub-header */ #ternal_branding { position: fixed !important; top: 32px !important; left: 0 !important; width: 100vw !important; height: 26px !important; background-color: #0d1117 !important; border-bottom: none !important; display: flex !important; justify-content: center !important; align-items: center !important; box-sizing: border-box !important; z-index: 9998 !important; } .ternal-text { font-family: 'JetBrains Mono', monospace; font-size: 11.5px; font-weight: bold; letter-spacing: 1.5px; background: linear-gradient(90deg, #ff007f, #79c0ff, #7ee787, #f2cc60, #ff007f); background-size: 200% auto; color: transparent !important; -webkit-background-clip: text !important; -webkit-text-fill-color: transparent !important; animation: shine 3s linear infinite; margin-right: 6px; } @keyframes shine { to { background-position: 200% center; } } /* Output screen */ #terminal_output { position: fixed !important; top: 58px !important; bottom: 75px !important; left: 0 !important; width: 100vw !important; overflow-y: auto !important; padding: 10px !important; font-family: 'JetBrains Mono', monospace !important; box-sizing: border-box !important; background-color: #05070a !important; } /* Bottom Bar */ #bottom_row { position: fixed !important; bottom: 0 !important; left: 0 !important; width: 100vw !important; height: 75px !important; background-color: #0b0e14 !important; border-top: 1px solid #30363d !important; display: flex !important; flex-direction: row !important; align-items: flex-start !important; padding: 8px 8px 25px 8px !important; box-sizing: border-box !important; z-index: 9999 !important; gap: 8px !important; } /* Clear button */ #btn_clear { background-color: #da3633 !important; color: #ffffff !important; min-width: 75px !important; max-width: 75px !important; height: 40px !important; font-size: 12px !important; border-radius: 6px !important; border: none !important; display: flex !important; justify-content: center !important; align-items: center !important; cursor: pointer !important; } #btn_clear::before { content: ""; display: inline-block; width: 14px; height: 14px; margin-right: 5px; background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNCIgaGVpZ2h0PSIxNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBvbHlsaW5lIHBvaW50cz0iMyA2IDUgNiAyMSA2Ij48L3BvbHlsaW5lPjxwYXRoIGQ9Ik0xOSA2djE0YTIgMiAwIDAgMS0yIDJIN2EyIDIgMCAwIDEtMi0yVjZtMyAwVjRhMiAyIDAgMCAxIDItMmg0YTIgMiAwIDAgMSAyIDJ2MiI+PC9wYXRoPjwvc3ZnPg=="); background-size: contain; background-repeat: no-repeat; } #cmd_input { flex-grow: 1 !important; height: 40px !important; } #cmd_input input, #cmd_input textarea { background-color: #161b22 !important; color: #58a6ff !important; font-family: 'JetBrains Mono', monospace !important; font-size: 14px !important; border: 1px solid #30363d !important; border-radius: 6px !important; height: 40px !important; padding: 0 10px !important; width: 100% !important; box-sizing: border-box !important; } /* Send button default active state */ #btn_send { background-color: #238636 !important; color: #ffffff !important; min-width: 75px !important; max-width: 75px !important; height: 40px !important; font-size: 12px !important; border-radius: 6px !important; border: none !important; display: flex !important; justify-content: center !important; align-items: center !important; cursor: pointer !important; transition: all 0.15s ease !important; } #btn_send::before { content: ""; display: inline-block; width: 14px; height: 14px; margin-right: 5px; background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNCIgaGVpZ2h0PSIxNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PGxpbmUgeDE9IjIyIiB5MT0iMiIgeDI9IjExIiB5Mj0iMTMiPjwvbGluZT48cG9seWdvbiBwb2ludHM9IjIyIDIgMTUgMjIgMTEgMTMgMiA5IDIyIDIiPjwvcG9seWdvbj48L3N2Zz4="); background-size: contain; background-repeat: no-repeat; } /* 🔒 1. CSS Engine Auto-Lock: āχāύāĻĒ⧁āϟ āĻ–āĻžāϞāĻŋ āĻĨāĻžāĻ•āϞ⧇ āĻŦāĻžāϟāύ ā§§ā§Ļā§Ļ% āϞāĻ• āĻ“ āϧ⧂āϏāϰ */ #bottom_row:has(#cmd_input input:placeholder-shown) #btn_send, #bottom_row:has(#cmd_input textarea:placeholder-shown) #btn_send { background-color: #21262d !important; color: #6e7681 !important; opacity: 0.35 !important; pointer-events: none !important; cursor: not-allowed !important; } #bottom_row:has(#cmd_input input:placeholder-shown) #btn_send::before, #bottom_row:has(#cmd_input textarea:placeholder-shown) #btn_send::before { opacity: 0.25 !important; } /* 🔒 2. Execution Lock: āĻ•āĻŽāĻžāĻ¨ā§āĻĄ āφāωāϟāĻĒ⧁āϟ āφāϏāĻžāϰ āφāĻ— āĻĒāĻ°ā§āϝāĻ¨ā§āϤ āϞāĻ• */ #btn_send.running-state, .pending #btn_send { background-color: #21262d !important; color: #6e7681 !important; opacity: 0.35 !important; pointer-events: none !important; cursor: not-allowed !important; } /* Hidden Action Button */ #btn_hidden_clear { position: absolute !important; top: -9999px !important; left: -9999px !important; opacity: 0 !important; width: 1px !important; height: 1px !important; pointer-events: none !important; } """ # HTML for in-app Dark Modal Dialog modal_html = """ """ # TERNAL Sub-header Branding ternal_html = """
TERNAL
""" # Client-side dynamic execution tracker client_js = """ () => { function initTracker() { const sendBtn = document.querySelector('#btn_send'); const term = document.querySelector('#terminal_output'); const inp = document.querySelector('#cmd_input input') || document.querySelector('#cmd_input textarea'); if (!sendBtn || !term || !inp) return; function lockButton() { sendBtn.classList.add('running-state'); } inp.addEventListener('keydown', (e) => { if (e.key === 'Enter' && inp.value.trim().length > 0) { lockButton(); } }); sendBtn.addEventListener('click', lockButton); // Unlock when output arrives on screen const observer = new MutationObserver(() => { sendBtn.classList.remove('running-state'); }); observer.observe(term, { childList: true, subtree: true, characterData: true }); } setTimeout(initTracker, 300); setTimeout(initTracker, 1000); } """ # ========================================== # 6. Gradio UI # ========================================== with gr.Blocks(title="Ternal", css=custom_css, js=client_js) as demo: with gr.Column(elem_id="main_wrapper"): # In-App Custom Modal modal_component = gr.HTML(value=modal_html) # Top Live Header (RAM & CPU) header_bar = gr.HTML(value=get_live_header, every=1.5, elem_id="live_header") # TERNAL Branding ternal_bar = gr.HTML(value=ternal_html) # Terminal Output Screen terminal_box = gr.HTML(value=initial_text, elem_id="terminal_output") # Bottom Controls with gr.Row(elem_id="bottom_row"): btn_clear = gr.Button("Clear", elem_id="btn_clear") cmd_input = gr.Textbox( label="", placeholder="Enter command (e.g. ls, free -h)...", elem_id="cmd_input", container=False, max_lines=1 ) btn_send = gr.Button("Send", elem_id="btn_send") # Hidden button for modal trigger btn_hidden_clear = gr.Button("HiddenClear", elem_id="btn_hidden_clear") # 1. Clear button opens modal btn_clear.click(fn=None, js="() => { document.getElementById('clear_modal').style.display = 'flex'; }") # 2. Modal's confirm button triggers clear action btn_hidden_clear.click(lambda: (initial_text, ""), outputs=[terminal_box, cmd_input]) # 3. Command execution cmd_input.submit(execute_terminal, inputs=[cmd_input, terminal_box], outputs=[terminal_box, cmd_input]) btn_send.click(execute_terminal, inputs=[cmd_input, terminal_box], outputs=[terminal_box, cmd_input]) if __name__ == "__main__": demo.launch()