# đĸ 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 = """
Clear Terminal?
This will clear all current screen logs. Are you sure?
"""
# TERNAL Sub-header Branding
ternal_html = """
"""
# 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()