mohammed978's picture
Update app.py
6716214 verified
Raw History Blame Contribute Delete
38.6 kB
import gradio as gr
import subprocess
import os
import sys
import json
import shutil
import signal
import psutil
import time
import threading
import traceback
from pathlib import Path
from datetime import datetime
# ===== ู…ุฌู„ุฏ ุงู„ุนู…ู„ ุงู„ุฑุฆูŠุณูŠ =====
WORKSPACE = os.path.join(os.path.expanduser("~"), "workspace")
os.makedirs(WORKSPACE, exist_ok=True)
os.chdir(WORKSPACE)
# ===== ุชุฎุฒูŠู† ุงู„ุนู…ู„ูŠุงุช ุงู„ุฌุงุฑูŠุฉ =====
running_processes = {}
process_lock = threading.Lock()
terminal_history = []
# ===== ุชู†ููŠุฐ ุฃูˆุงู…ุฑ ุงู„ุทุฑููŠุฉ =====
def execute_command(command, working_dir=None):
"""ุชู†ููŠุฐ ุฃู…ุฑ ููŠ ุงู„ุทุฑููŠุฉ ู…ุน ุฏุนู… ูƒุงู…ู„"""
if not command or not command.strip():
return "โš ๏ธ ุงูƒุชุจ ุฃู…ุฑุงู‹ ู„ู„ุชู†ููŠุฐ"
work_dir = working_dir if working_dir and os.path.isdir(working_dir) else WORKSPACE
# ุญูุธ ููŠ ุงู„ุณุฌู„
timestamp = datetime.now().strftime("%H:%M:%S")
terminal_history.append(f"[{timestamp}] $ {command}")
try:
# ุฃูˆุงู…ุฑ ุฎุงุตุฉ
cmd_parts = command.strip().split()
cmd_name = cmd_parts[0] if cmd_parts else ""
# ุฃู…ุฑ cd
if cmd_name == "cd":
target = cmd_parts[1] if len(cmd_parts) > 1 else WORKSPACE
if target == "~":
target = WORKSPACE
target_path = os.path.join(work_dir, target) if not os.path.isabs(target) else target
target_path = os.path.abspath(target_path)
if os.path.isdir(target_path):
os.chdir(target_path)
return f"๐Ÿ“‚ ุงู†ุชู‚ู„ุช ุฅู„ู‰: {target_path}"
else:
return f"โŒ ุงู„ู…ุฌู„ุฏ ุบูŠุฑ ู…ูˆุฌูˆุฏ: {target_path}"
# ุฃู…ุฑ clear
if cmd_name in ("clear", "cls"):
terminal_history.clear()
return "๐Ÿงน ุชู… ู…ุณุญ ุงู„ุดุงุดุฉ"
# ุชู†ููŠุฐ ุงู„ุฃู…ุฑ
env = os.environ.copy()
env['PYTHONUNBUFFERED'] = '1'
env['HOME'] = os.path.expanduser("~")
env['PATH'] = env.get('PATH', '') + ':/usr/local/bin:/usr/bin:/bin'
result = subprocess.run(
command,
shell=True,
capture_output=True,
text=True,
timeout=300,
cwd=work_dir,
env=env,
)
output_parts = []
if result.stdout:
output_parts.append(result.stdout)
if result.stderr:
# ุจุนุถ ุงู„ุจุฑุงู…ุฌ ุชุณุชุฎุฏู… stderr ู„ู„ู…ุนู„ูˆู…ุงุช ุงู„ุนุงุฏูŠุฉ
if result.returncode == 0:
output_parts.append(result.stderr)
else:
output_parts.append(f"โš ๏ธ STDERR:\n{result.stderr}")
if result.returncode != 0 and not output_parts:
output_parts.append(f"โŒ Exit code: {result.returncode}")
if not output_parts:
output_parts.append("โœ… ุชู… ุงู„ุชู†ููŠุฐ ุจู†ุฌุงุญ (ุจุฏูˆู† ู…ุฎุฑุฌุงุช)")
return '\n'.join(output_parts)
except subprocess.TimeoutExpired:
return "โฐ ุงู†ุชู‡ุช ุงู„ู…ู‡ู„ุฉ (5 ุฏู‚ุงุฆู‚). ุงุณุชุฎุฏู… 'ุชุดุบูŠู„ ููŠ ุงู„ุฎู„ููŠุฉ' ู„ู„ุนู…ู„ูŠุงุช ุงู„ุทูˆูŠู„ุฉ."
except FileNotFoundError:
return f"โŒ ุงู„ุฃู…ุฑ ุบูŠุฑ ู…ูˆุฌูˆุฏ: {cmd_name}\nุฌุฑุจ: pip install ุฃูˆ apt-get install"
except Exception as e:
return f"โŒ ุฎุทุฃ: {str(e)}"
# ===== ุชุดุบูŠู„ ููŠ ุงู„ุฎู„ููŠุฉ =====
def run_background(command, working_dir=None):
"""ุชุดุบูŠู„ ุฃู…ุฑ ููŠ ุงู„ุฎู„ููŠุฉ (ู„ู„ุจูˆุชุงุช ูˆุงู„ุณูŠุฑูุฑุงุช)"""
if not command or not command.strip():
return "โš ๏ธ ุงูƒุชุจ ุฃู…ุฑุงู‹ ู„ู„ุชุดุบูŠู„"
work_dir = working_dir if working_dir and os.path.isdir(working_dir) else WORKSPACE
try:
env = os.environ.copy()
env['PYTHONUNBUFFERED'] = '1'
# ุฅู†ุดุงุก ู…ู„ูุงุช ู„ู„ู…ุฎุฑุฌุงุช
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
log_file = os.path.join(WORKSPACE, f".logs/process_{timestamp}.log")
os.makedirs(os.path.dirname(log_file), exist_ok=True)
log_handle = open(log_file, 'w')
process = subprocess.Popen(
command,
shell=True,
stdout=log_handle,
stderr=subprocess.STDOUT,
cwd=work_dir,
env=env,
preexec_fn=os.setsid if os.name != 'nt' else None,
)
with process_lock:
running_processes[process.pid] = {
'command': command,
'pid': process.pid,
'start_time': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
'log_file': log_file,
'process': process,
'log_handle': log_handle,
}
return (
f"โœ… ุชู… ุงู„ุชุดุบูŠู„ ููŠ ุงู„ุฎู„ููŠุฉ!\n"
f"{'โ”€' * 40}\n"
f"๐Ÿ“‹ PID: {process.pid}\n"
f"๐Ÿ“ ุงู„ุฃู…ุฑ: {command}\n"
f"๐Ÿ“„ ู…ู„ู ุงู„ุณุฌู„: {log_file}\n"
f"{'โ”€' * 40}\n"
f"๐Ÿ’ก ู„ู…ุชุงุจุนุฉ ุงู„ู…ุฎุฑุฌุงุช: cat {log_file}\n"
f"๐Ÿ’ก ู„ุฅูŠู‚ุงู ุงู„ุนู…ู„ูŠุฉ: ุงุณุชุฎุฏู… ุฒุฑ ุฅุฏุงุฑุฉ ุงู„ุนู…ู„ูŠุงุช"
)
except Exception as e:
return f"โŒ ุฎุทุฃ ููŠ ุงู„ุชุดุบูŠู„: {str(e)}"
# ===== ุฅุฏุงุฑุฉ ุงู„ุนู…ู„ูŠุงุช =====
def list_processes():
"""ุนุฑุถ ุงู„ุนู…ู„ูŠุงุช ุงู„ุฌุงุฑูŠุฉ"""
output_parts = ["๐Ÿ”„ ุงู„ุนู…ู„ูŠุงุช ุงู„ุฌุงุฑูŠุฉ ููŠ ุงู„ุฎู„ููŠุฉ:", "โ•" * 50]
with process_lock:
if not running_processes:
output_parts.append("๐Ÿ“ญ ู„ุง ุชูˆุฌุฏ ุนู…ู„ูŠุงุช ุฌุงุฑูŠุฉ")
else:
for pid, info in list(running_processes.items()):
proc = info['process']
status = "๐ŸŸข ูŠุนู…ู„" if proc.poll() is None else f"๐Ÿ”ด ุงู†ุชู‡ู‰ (code: {proc.returncode})"
# ู…ุนู„ูˆู…ุงุช ุงู„ุฐุงูƒุฑุฉ
mem_info = ""
try:
p = psutil.Process(pid)
mem = p.memory_info().rss / 1024 / 1024
cpu = p.cpu_percent()
mem_info = f" ๐Ÿ’พ RAM: {mem:.1f}MB | CPU: {cpu:.1f}%"
except:
pass
output_parts.append(
f"\n๐Ÿ“‹ PID: {pid}\n"
f" ๐Ÿ“ ุงู„ุฃู…ุฑ: {info['command']}\n"
f" ๐Ÿ• ุจุฏุฃ: {info['start_time']}\n"
f" ๐Ÿ“Š ุงู„ุญุงู„ุฉ: {status}\n"
f"{mem_info}\n"
f" ๐Ÿ“„ ุงู„ุณุฌู„: {info['log_file']}"
)
# ุนู…ู„ูŠุงุช ุงู„ู†ุธุงู…
output_parts.append(f"\n{'โ•' * 50}")
output_parts.append("๐Ÿ“Š ู…ุนู„ูˆู…ุงุช ุงู„ู†ุธุงู…:")
output_parts.append(f" ๐Ÿ’พ RAM: {psutil.virtual_memory().percent}% ู…ุณุชุฎุฏู…")
output_parts.append(f" ๐Ÿ–ฅ๏ธ CPU: {psutil.cpu_percent()}%")
output_parts.append(f" ๐Ÿ’ฟ Disk: {psutil.disk_usage('/').percent}% ู…ุณุชุฎุฏู…")
return '\n'.join(output_parts)
def stop_process(pid_str):
"""ุฅูŠู‚ุงู ุนู…ู„ูŠุฉ"""
if not pid_str or not pid_str.strip():
return "โš ๏ธ ุฃุฏุฎู„ ุฑู‚ู… PID"
try:
pid = int(pid_str.strip())
except ValueError:
return "โŒ PID ูŠุฌุจ ุฃู† ูŠูƒูˆู† ุฑู‚ู…ุงู‹"
with process_lock:
if pid in running_processes:
info = running_processes[pid]
proc = info['process']
try:
if os.name != 'nt':
os.killpg(os.getpgid(pid), signal.SIGTERM)
else:
proc.terminate()
proc.wait(timeout=5)
info['log_handle'].close()
del running_processes[pid]
return f"โœ… ุชู… ุฅูŠู‚ุงู ุงู„ุนู…ู„ูŠุฉ {pid}"
except subprocess.TimeoutExpired:
if os.name != 'nt':
os.killpg(os.getpgid(pid), signal.SIGKILL)
else:
proc.kill()
info['log_handle'].close()
del running_processes[pid]
return f"โš ๏ธ ุชู… ู‚ุชู„ ุงู„ุนู…ู„ูŠุฉ {pid} ุจุงู„ู‚ูˆุฉ"
except Exception as e:
return f"โŒ ุฎุทุฃ: {str(e)}"
else:
# ู…ุญุงูˆู„ุฉ ุฅูŠู‚ุงู ุนู…ู„ูŠุฉ ู†ุธุงู…
try:
os.kill(pid, signal.SIGTERM)
return f"โœ… ุชู… ุฅุฑุณุงู„ SIGTERM ู„ู„ุนู…ู„ูŠุฉ {pid}"
except ProcessLookupError:
return f"โŒ ุงู„ุนู…ู„ูŠุฉ {pid} ุบูŠุฑ ู…ูˆุฌูˆุฏุฉ"
except Exception as e:
return f"โŒ ุฎุทุฃ: {str(e)}"
def view_process_log(pid_str):
"""ุนุฑุถ ุณุฌู„ ุนู…ู„ูŠุฉ"""
if not pid_str or not pid_str.strip():
return "โš ๏ธ ุฃุฏุฎู„ ุฑู‚ู… PID"
try:
pid = int(pid_str.strip())
except ValueError:
return "โŒ PID ูŠุฌุจ ุฃู† ูŠูƒูˆู† ุฑู‚ู…ุงู‹"
with process_lock:
if pid in running_processes:
log_file = running_processes[pid]['log_file']
try:
with open(log_file, 'r') as f:
content = f.read()
if not content:
return "๐Ÿ“„ ุงู„ุณุฌู„ ูุงุฑุบ ุญุงู„ูŠุงู‹..."
# ุขุฎุฑ 100 ุณุทุฑ
lines = content.split('\n')
if len(lines) > 100:
return f"... (ุนุฑุถ ุขุฎุฑ 100 ุณุทุฑ ู…ู† {len(lines)})\n\n" + '\n'.join(lines[-100:])
return content
except Exception as e:
return f"โŒ ุฎุทุฃ ููŠ ู‚ุฑุงุกุฉ ุงู„ุณุฌู„: {str(e)}"
else:
return f"โŒ ุงู„ุนู…ู„ูŠุฉ {pid} ุบูŠุฑ ู…ูˆุฌูˆุฏุฉ ููŠ ุงู„ู‚ุงุฆู…ุฉ"
# ===== ู…ุฏูŠุฑ ุงู„ู…ู„ูุงุช =====
def list_files(path=None):
"""ุนุฑุถ ู…ุญุชูˆูŠุงุช ู…ุฌู„ุฏ"""
target = path if path and os.path.isdir(path) else os.getcwd()
target = os.path.abspath(target)
try:
items = sorted(os.listdir(target))
output_parts = [
f"๐Ÿ“‚ ุงู„ู…ุฌู„ุฏ: {target}",
f"{'โ•' * 60}",
f"{'ุงู„ู†ูˆุน':<6} {'ุงู„ุญุฌู…':<12} {'ุงู„ุชุนุฏูŠู„':<20} {'ุงู„ุงุณู…'}",
f"{'โ”€' * 60}",
]
total_size = 0
dir_count = 0
file_count = 0
for item in items:
full_path = os.path.join(target, item)
try:
stat = os.stat(full_path)
mod_time = datetime.fromtimestamp(stat.st_mtime).strftime("%Y-%m-%d %H:%M")
if os.path.isdir(full_path):
output_parts.append(f"๐Ÿ“ {'<DIR>':<12} {mod_time:<20} {item}/")
dir_count += 1
else:
size = stat.st_size
total_size += size
size_str = format_size(size)
# ุฃูŠู‚ูˆู†ุฉ ุญุณุจ ู†ูˆุน ุงู„ู…ู„ู
icon = get_file_icon(item)
output_parts.append(f"{icon} {size_str:<12} {mod_time:<20} {item}")
file_count += 1
except PermissionError:
output_parts.append(f"๐Ÿ”’ {'N/A':<12} {'N/A':<20} {item}")
output_parts.append(f"{'โ”€' * 60}")
output_parts.append(f"๐Ÿ“Š {dir_count} ู…ุฌู„ุฏุงุช | {file_count} ู…ู„ูุงุช | ุงู„ุญุฌู…: {format_size(total_size)}")
return '\n'.join(output_parts)
except PermissionError:
return f"๐Ÿ”’ ู„ุง ูŠูˆุฌุฏ ุตู„ุงุญูŠุฉ ู„ู„ูˆุตูˆู„ ุฅู„ู‰: {target}"
except Exception as e:
return f"โŒ ุฎุทุฃ: {str(e)}"
def format_size(size):
"""ุชู†ุณูŠู‚ ุญุฌู… ุงู„ู…ู„ู"""
for unit in ['B', 'KB', 'MB', 'GB']:
if size < 1024:
return f"{size:.1f}{unit}"
size /= 1024
return f"{size:.1f}TB"
def get_file_icon(filename):
"""ุฃูŠู‚ูˆู†ุฉ ุญุณุจ ู†ูˆุน ุงู„ู…ู„ู"""
ext = filename.rsplit('.', 1)[-1].lower() if '.' in filename else ''
icons = {
'py': '๐Ÿ', 'js': '๐Ÿ“œ', 'ts': '๐Ÿ“˜', 'html': '๐ŸŒ', 'css': '๐ŸŽจ',
'json': '๐Ÿ“‹', 'yml': 'โš™๏ธ', 'yaml': 'โš™๏ธ', 'toml': 'โš™๏ธ',
'md': '๐Ÿ“', 'txt': '๐Ÿ“„', 'log': '๐Ÿ“ƒ', 'csv': '๐Ÿ“Š',
'jpg': '๐Ÿ–ผ๏ธ', 'png': '๐Ÿ–ผ๏ธ', 'gif': '๐Ÿ–ผ๏ธ', 'svg': '๐Ÿ–ผ๏ธ',
'mp3': '๐ŸŽต', 'mp4': '๐ŸŽฌ', 'zip': '๐Ÿ“ฆ', 'tar': '๐Ÿ“ฆ',
'gz': '๐Ÿ“ฆ', 'sh': 'โšก', 'bash': 'โšก', 'env': '๐Ÿ”',
'db': '๐Ÿ—„๏ธ', 'sqlite': '๐Ÿ—„๏ธ', 'sql': '๐Ÿ—„๏ธ',
'dockerfile': '๐Ÿณ', 'gitignore': '๐Ÿ“Œ',
}
return icons.get(ext, '๐Ÿ“„')
def read_file(filepath):
"""ู‚ุฑุงุกุฉ ู…ู„ู"""
if not filepath or not filepath.strip():
return "โš ๏ธ ุฃุฏุฎู„ ู…ุณุงุฑ ุงู„ู…ู„ู"
filepath = filepath.strip()
if not os.path.isabs(filepath):
filepath = os.path.join(os.getcwd(), filepath)
try:
if not os.path.exists(filepath):
return f"โŒ ุงู„ู…ู„ู ุบูŠุฑ ู…ูˆุฌูˆุฏ: {filepath}"
size = os.path.getsize(filepath)
if size > 5 * 1024 * 1024: # 5MB limit
return f"โš ๏ธ ุงู„ู…ู„ู ูƒุจูŠุฑ ุฌุฏุงู‹ ({format_size(size)}). ุงุณุชุฎุฏู… head ุฃูˆ tail"
# ูุญุต ุฅุฐุง ูƒุงู† ู…ู„ู ู†ุตูŠ
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
return f"๐Ÿ“„ {filepath} ({format_size(size)}):\n{'โ”€' * 40}\n{content}"
except UnicodeDecodeError:
return f"โš ๏ธ ู‡ุฐุง ู…ู„ู ุซู†ุงุฆูŠ (binary) ูˆู„ุง ูŠู…ูƒู† ุนุฑุถู‡ ูƒู†ุต. ุงู„ุญุฌู…: {format_size(size)}"
except PermissionError:
return f"๐Ÿ”’ ู„ุง ูŠูˆุฌุฏ ุตู„ุงุญูŠุฉ ู„ู‚ุฑุงุกุฉ: {filepath}"
except Exception as e:
return f"โŒ ุฎุทุฃ: {str(e)}"
def write_file(filepath, content):
"""ูƒุชุงุจุฉ ู…ู„ู"""
if not filepath or not filepath.strip():
return "โš ๏ธ ุฃุฏุฎู„ ู…ุณุงุฑ ุงู„ู…ู„ู"
filepath = filepath.strip()
if not os.path.isabs(filepath):
filepath = os.path.join(os.getcwd(), filepath)
try:
os.makedirs(os.path.dirname(filepath), exist_ok=True)
with open(filepath, 'w', encoding='utf-8') as f:
f.write(content or "")
size = os.path.getsize(filepath)
return f"โœ… ุชู… ุญูุธ ุงู„ู…ู„ู: {filepath} ({format_size(size)})"
except Exception as e:
return f"โŒ ุฎุทุฃ ููŠ ุงู„ุญูุธ: {str(e)}"
def delete_file(filepath):
"""ุญุฐู ู…ู„ู ุฃูˆ ู…ุฌู„ุฏ"""
if not filepath or not filepath.strip():
return "โš ๏ธ ุฃุฏุฎู„ ู…ุณุงุฑ ุงู„ู…ู„ู"
filepath = filepath.strip()
if not os.path.isabs(filepath):
filepath = os.path.join(os.getcwd(), filepath)
try:
if not os.path.exists(filepath):
return f"โŒ ุบูŠุฑ ู…ูˆุฌูˆุฏ: {filepath}"
if os.path.isdir(filepath):
shutil.rmtree(filepath)
return f"โœ… ุชู… ุญุฐู ุงู„ู…ุฌู„ุฏ: {filepath}"
else:
os.remove(filepath)
return f"โœ… ุชู… ุญุฐู ุงู„ู…ู„ู: {filepath}"
except Exception as e:
return f"โŒ ุฎุทุฃ: {str(e)}"
def create_directory(dirpath):
"""ุฅู†ุดุงุก ู…ุฌู„ุฏ"""
if not dirpath or not dirpath.strip():
return "โš ๏ธ ุฃุฏุฎู„ ู…ุณุงุฑ ุงู„ู…ุฌู„ุฏ"
dirpath = dirpath.strip()
if not os.path.isabs(dirpath):
dirpath = os.path.join(os.getcwd(), dirpath)
try:
os.makedirs(dirpath, exist_ok=True)
return f"โœ… ุชู… ุฅู†ุดุงุก ุงู„ู…ุฌู„ุฏ: {dirpath}"
except Exception as e:
return f"โŒ ุฎุทุฃ: {str(e)}"
def upload_file(file):
"""ุฑูุน ู…ู„ู"""
if file is None:
return "โš ๏ธ ุงุฎุชุฑ ู…ู„ูุงู‹ ู„ู„ุฑูุน", list_files()
try:
filename = os.path.basename(file.name) if hasattr(file, 'name') else "uploaded_file"
dest = os.path.join(os.getcwd(), filename)
if isinstance(file, str):
shutil.copy2(file, dest)
else:
shutil.copy2(file.name, dest)
size = os.path.getsize(dest)
return f"โœ… ุชู… ุฑูุน: {filename} ({format_size(size)})", list_files()
except Exception as e:
return f"โŒ ุฎุทุฃ ููŠ ุงู„ุฑูุน: {str(e)}", list_files()
# ===== ู…ุญุฑุฑ ุงู„ุฃูƒูˆุงุฏ =====
def save_and_run(filepath, code):
"""ุญูุธ ูˆุชุดุบูŠู„ ู…ู„ู"""
if not filepath or not filepath.strip():
return "โš ๏ธ ุฃุฏุฎู„ ุงุณู… ุงู„ู…ู„ู", ""
filepath = filepath.strip()
if not os.path.isabs(filepath):
filepath = os.path.join(os.getcwd(), filepath)
# ุญูุธ
save_result = write_file(filepath, code)
# ุชุดุบูŠู„ ุญุณุจ ู†ูˆุน ุงู„ู…ู„ู
ext = filepath.rsplit('.', 1)[-1].lower() if '.' in filepath else ''
run_commands = {
'py': f'python3 "{filepath}"',
'js': f'node "{filepath}"',
'sh': f'bash "{filepath}"',
'bash': f'bash "{filepath}"',
}
if ext in run_commands:
run_result = execute_command(run_commands[ext])
return save_result, run_result
else:
return save_result, "โ„น๏ธ ุชู… ุงู„ุญูุธ ูู‚ุท (ู†ูˆุน ุงู„ู…ู„ู ู„ุง ูŠุฏุนู… ุงู„ุชุดุบูŠู„ ุงู„ู…ุจุงุดุฑ)"
# ===== ุชุซุจูŠุช ุงู„ุญุฒู… =====
def install_package(package_name):
"""ุชุซุจูŠุช ุญุฒู…ุฉ ุจุงูŠุซูˆู†"""
if not package_name or not package_name.strip():
return "โš ๏ธ ุฃุฏุฎู„ ุงุณู… ุงู„ุญุฒู…ุฉ"
return execute_command(f"pip install {package_name.strip()}")
def system_info():
"""ู…ุนู„ูˆู…ุงุช ุงู„ู†ุธุงู…"""
try:
mem = psutil.virtual_memory()
disk = psutil.disk_usage('/')
cpu_count = psutil.cpu_count()
boot_time = datetime.fromtimestamp(psutil.boot_time()).strftime("%Y-%m-%d %H:%M:%S")
info = f"""
โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘ ๐Ÿ–ฅ๏ธ ู…ุนู„ูˆู…ุงุช ุงู„ู†ุธุงู… โ•‘
โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ
โ•‘ โ•‘
โ•‘ ๐Ÿ Python: {sys.version.split()[0]:<28}โ•‘
โ•‘ ๐Ÿ’ป OS: {os.uname().sysname} {os.uname().release[:20]:<20}โ•‘
โ•‘ ๐Ÿ—๏ธ Arch: {os.uname().machine:<28}โ•‘
โ•‘ ๐Ÿ• Boot: {boot_time:<28}โ•‘
โ•‘ โ•‘
โ•‘ ๐Ÿ–ฅ๏ธ CPU Cores: {cpu_count:<25}โ•‘
โ•‘ ๐Ÿ“Š CPU Usage: {psutil.cpu_percent():.1f}%{'':<23}โ•‘
โ•‘ โ•‘
โ•‘ ๐Ÿ’พ RAM Total: {format_size(mem.total):<25}โ•‘
โ•‘ ๐Ÿ’พ RAM Used: {format_size(mem.used)} ({mem.percent}%){'':<14}โ•‘
โ•‘ ๐Ÿ’พ RAM Free: {format_size(mem.available):<25}โ•‘
โ•‘ โ•‘
โ•‘ ๐Ÿ’ฟ Disk Total: {format_size(disk.total):<24}โ•‘
โ•‘ ๐Ÿ’ฟ Disk Used: {format_size(disk.used)} ({disk.percent}%){'':<13}โ•‘
โ•‘ ๐Ÿ’ฟ Disk Free: {format_size(disk.free):<24}โ•‘
โ•‘ โ•‘
โ•‘ ๐Ÿ“‚ CWD: {os.getcwd()[:30]:<30}โ•‘
โ•‘ ๐Ÿ‘ค User: {os.environ.get('USER', 'N/A'):<29}โ•‘
โ•‘ โ•‘
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
"""
return info
except Exception as e:
return f"โŒ ุฎุทุฃ: {str(e)}"
# ===== ุงู„ูˆุงุฌู‡ุฉ =====
CUSTOM_CSS = """
@import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500&family=Tajawal:wght@400;500;700&display=swap');
* { font-family: 'Tajawal', sans-serif !important; }
.terminal-output textarea,
.code-editor textarea {
font-family: 'Fira Code', 'Courier New', monospace !important;
font-size: 13px !important;
line-height: 1.5 !important;
}
.terminal-output textarea {
background-color: #0d1117 !important;
color: #58a6ff !important;
border: 2px solid #30363d !important;
}
.header-banner {
text-align: center;
background: linear-gradient(135deg, #0d1117 0%, #161b22 50%, #0d1117 100%);
padding: 20px;
border-radius: 16px;
margin-bottom: 15px;
border: 1px solid #30363d;
}
.header-banner h1 {
color: #58a6ff;
font-size: 2.2em;
margin: 0;
}
.header-banner p {
color: #8b949e;
margin: 5px 0 0;
}
.status-bar {
background: #161b22;
color: #58a6ff;
padding: 8px 16px;
border-radius: 8px;
font-family: 'Fira Code', monospace !important;
font-size: 12px;
border: 1px solid #30363d;
}
footer { display: none !important; }
"""
with gr.Blocks(
css=CUSTOM_CSS,
title="๐Ÿ–ฅ๏ธ Cloud VPS Terminal",
theme=gr.themes.Base(
primary_hue="blue",
secondary_hue="purple",
neutral_hue="gray",
font=gr.themes.GoogleFont("Tajawal"),
)
) as app:
gr.HTML("""
<div class="header-banner">
<h1>๐Ÿ–ฅ๏ธ Cloud VPS Terminal</h1>
<p>ู†ุธุงู… VPS ุณุญุงุจูŠ ูƒุงู…ู„ - ุทุฑููŠุฉ + ู…ุฏูŠุฑ ู…ู„ูุงุช + ู…ุญุฑุฑ ุฃูƒูˆุงุฏ + ุฅุฏุงุฑุฉ ุนู…ู„ูŠุงุช</p>
</div>
""")
with gr.Tabs():
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ุชุงุจ ุงู„ุทุฑููŠุฉ โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
with gr.TabItem("โšก Terminal"):
gr.HTML('<div class="status-bar">๐Ÿ“ Terminal | ุงูƒุชุจ ุฃูŠ ุฃู…ุฑ Linux ูˆุดุบู‘ู„ู‡</div>')
with gr.Row():
with gr.Column(scale=4):
cmd_input = gr.Textbox(
label="๐Ÿ’ป ุงู„ุฃู…ุฑ",
placeholder="ุงูƒุชุจ ุฃู…ุฑ Linux ู‡ู†ุง... ู…ุซู„: ls -la, pip install requests, python bot.py",
lines=1,
)
with gr.Column(scale=1):
work_dir = gr.Textbox(
label="๐Ÿ“‚ ู…ุฌู„ุฏ ุงู„ุนู…ู„",
value=WORKSPACE,
lines=1,
)
with gr.Row():
run_cmd_btn = gr.Button("โ–ถ๏ธ ุชู†ููŠุฐ", variant="primary", size="lg")
bg_run_btn = gr.Button("๐Ÿ”„ ุชุดุบูŠู„ ููŠ ุงู„ุฎู„ููŠุฉ", variant="secondary", size="lg")
sys_info_btn = gr.Button("โ„น๏ธ ู…ุนู„ูˆู…ุงุช ุงู„ู†ุธุงู…", size="lg")
terminal_output = gr.Textbox(
label="๐Ÿ“บ ุงู„ู…ุฎุฑุฌุงุช",
lines=25,
max_lines=50,
interactive=False,
elem_classes=["terminal-output"],
)
gr.HTML("<h4>โšก ุฃูˆุงู…ุฑ ุณุฑูŠุนุฉ:</h4>")
with gr.Row():
gr.Button("๐Ÿ“‹ ls -la").click(fn=lambda: execute_command("ls -la"), outputs=[terminal_output])
gr.Button("๐Ÿ“‚ pwd").click(fn=lambda: execute_command("pwd"), outputs=[terminal_output])
gr.Button("๐Ÿ’พ df -h").click(fn=lambda: execute_command("df -h"), outputs=[terminal_output])
gr.Button("๐Ÿ pip list").click(fn=lambda: execute_command("pip list"), outputs=[terminal_output])
gr.Button("๐Ÿ“ก curl ifconfig.me").click(fn=lambda: execute_command("curl -s ifconfig.me"), outputs=[terminal_output])
gr.Button("๐Ÿ” top (snapshot)").click(fn=lambda: execute_command("ps aux --sort=-%mem | head -20"), outputs=[terminal_output])
# ุฑุจุท ุงู„ุฃุญุฏุงุซ
run_cmd_btn.click(fn=execute_command, inputs=[cmd_input, work_dir], outputs=[terminal_output])
cmd_input.submit(fn=execute_command, inputs=[cmd_input, work_dir], outputs=[terminal_output])
bg_run_btn.click(fn=run_background, inputs=[cmd_input, work_dir], outputs=[terminal_output])
sys_info_btn.click(fn=system_info, outputs=[terminal_output])
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ุชุงุจ ู…ุฏูŠุฑ ุงู„ู…ู„ูุงุช โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
with gr.TabItem("๐Ÿ“ File Manager"):
gr.HTML('<div class="status-bar">๐Ÿ“ File Manager | ุฅุฏุงุฑุฉ ูƒุงู…ู„ุฉ ู„ู„ู…ู„ูุงุช ูˆุงู„ู…ุฌู„ุฏุงุช</div>')
with gr.Row():
with gr.Column(scale=2):
browse_path = gr.Textbox(label="๐Ÿ“‚ ุงู„ู…ุณุงุฑ", value=WORKSPACE, lines=1)
browse_btn = gr.Button("๐Ÿ” ุงุณุชุนุฑุงุถ", variant="primary")
file_list_output = gr.Textbox(
label="๐Ÿ“‹ ู…ุญุชูˆูŠุงุช ุงู„ู…ุฌู„ุฏ",
lines=20,
interactive=False,
elem_classes=["terminal-output"],
)
with gr.Column(scale=2):
with gr.Tabs():
with gr.TabItem("๐Ÿ“„ ู‚ุฑุงุกุฉ ู…ู„ู"):
read_path = gr.Textbox(label="ู…ุณุงุฑ ุงู„ู…ู„ู", lines=1)
read_btn = gr.Button("๐Ÿ“– ู‚ุฑุงุกุฉ", variant="primary")
file_content = gr.Textbox(label="ุงู„ู…ุญุชูˆู‰", lines=15, interactive=False)
with gr.TabItem("โœ๏ธ ุฅู†ุดุงุก/ุชุนุฏูŠู„"):
new_file_path = gr.Textbox(label="ู…ุณุงุฑ ุงู„ู…ู„ู", lines=1, placeholder="ู…ุซุงู„: bot.py")
new_file_content = gr.Code(label="ุงู„ู…ุญุชูˆู‰", language="python", lines=12)
save_btn = gr.Button("๐Ÿ’พ ุญูุธ", variant="primary")
save_status = gr.Textbox(label="ุงู„ุญุงู„ุฉ", lines=2, interactive=False)
with gr.TabItem("๐Ÿ“ ู…ุฌู„ุฏ ุฌุฏูŠุฏ"):
new_dir_path = gr.Textbox(label="ู…ุณุงุฑ ุงู„ู…ุฌู„ุฏ", lines=1)
mkdir_btn = gr.Button("๐Ÿ“ ุฅู†ุดุงุก", variant="primary")
mkdir_status = gr.Textbox(label="ุงู„ุญุงู„ุฉ", lines=2, interactive=False)
with gr.TabItem("๐Ÿ—‘๏ธ ุญุฐู"):
del_path = gr.Textbox(label="ู…ุณุงุฑ ุงู„ู…ู„ู/ุงู„ู…ุฌู„ุฏ", lines=1)
del_btn = gr.Button("๐Ÿ—‘๏ธ ุญุฐู", variant="stop")
del_status = gr.Textbox(label="ุงู„ุญุงู„ุฉ", lines=2, interactive=False)
with gr.TabItem("๐Ÿ“ค ุฑูุน ู…ู„ู"):
upload_input = gr.File(label="ุงุฎุชุฑ ู…ู„ูุงู‹", file_count="single")
upload_btn = gr.Button("๐Ÿ“ค ุฑูุน", variant="primary")
upload_status = gr.Textbox(label="ุงู„ุญุงู„ุฉ", lines=2, interactive=False)
# ุฑุจุท ุฃุญุฏุงุซ ู…ุฏูŠุฑ ุงู„ู…ู„ูุงุช
browse_btn.click(fn=list_files, inputs=[browse_path], outputs=[file_list_output])
browse_path.submit(fn=list_files, inputs=[browse_path], outputs=[file_list_output])
read_btn.click(fn=read_file, inputs=[read_path], outputs=[file_content])
save_btn.click(fn=write_file, inputs=[new_file_path, new_file_content], outputs=[save_status])
mkdir_btn.click(fn=create_directory, inputs=[new_dir_path], outputs=[mkdir_status])
del_btn.click(fn=delete_file, inputs=[del_path], outputs=[del_status])
upload_btn.click(fn=upload_file, inputs=[upload_input], outputs=[upload_status, file_list_output])
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ุชุงุจ ู…ุญุฑุฑ ุงู„ุฃูƒูˆุงุฏ โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
with gr.TabItem("โœ๏ธ Code Editor"):
gr.HTML('<div class="status-bar">โœ๏ธ Code Editor | ูƒุชุงุจุฉ ูˆุชุดุบูŠู„ ุงู„ุฃูƒูˆุงุฏ ู…ุจุงุดุฑุฉ</div>')
with gr.Row():
editor_filepath = gr.Textbox(
label="๐Ÿ“„ ุงุณู… ุงู„ู…ู„ู",
value="script.py",
lines=1,
scale=2,
)
editor_lang = gr.Dropdown(
label="๐ŸŒ ุงู„ู„ุบุฉ",
choices=["python", "javascript", "shell", "json", "yaml", "markdown", "html", "css"],
value="python",
scale=1,
)
with gr.Row():
load_file_btn = gr.Button("๐Ÿ“‚ ุชุญู…ูŠู„ ู…ู† ู…ู„ู", variant="secondary")
save_file_btn = gr.Button("๐Ÿ’พ ุญูุธ", variant="primary")
save_run_btn = gr.Button("โ–ถ๏ธ ุญูุธ ูˆุชุดุบูŠู„", variant="primary")
code_editor = gr.Code(
label="โœ๏ธ ุงู„ูƒูˆุฏ",
language="python",
lines=25,
value='# ุงูƒุชุจ ุงู„ูƒูˆุฏ ู‡ู†ุง\nprint("ู…ุฑุญุจุงู‹! ๐Ÿ")',
)
editor_output = gr.Textbox(
label="๐Ÿ“ค ุงู„ู…ุฎุฑุฌุงุช",
lines=12,
interactive=False,
elem_classes=["terminal-output"],
)
# ู‚ูˆุงู„ุจ ุฌุงู‡ุฒุฉ
gr.HTML("<h4>๐Ÿ“ฆ ู‚ูˆุงู„ุจ ุฌุงู‡ุฒุฉ:</h4>")
with gr.Row():
def template_telegram_bot():
return """# Telegram Bot Template
# pip install python-telegram-bot
import asyncio
from telegram import Update
from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes
TOKEN = "YOUR_BOT_TOKEN_HERE"
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text("ู…ุฑุญุจุงู‹! ุฃู†ุง ุจูˆุช ุชู„ุฌุฑุงู… ๐Ÿค–")
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
text = update.message.text
await update.message.reply_text(f"ู‚ู„ุช: {text}")
def main():
app = Application.builder().token(TOKEN).build()
app.add_handler(CommandHandler("start", start))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
print("๐Ÿค– ุงู„ุจูˆุช ูŠุนู…ู„...")
app.run_polling()
if __name__ == "__main__":
main()
""", "telegram_bot.py"
def template_flask_server():
return """# Flask Web Server
# pip install flask
from flask import Flask, jsonify, request
app = Flask(__name__)
@app.route('/')
def home():
return jsonify({"message": "ู…ุฑุญุจุงู‹ ุจุงู„ุนุงู„ู…! ๐ŸŒ", "status": "running"})
@app.route('/api/hello/<name>')
def hello(name):
return jsonify({"message": f"ู…ุฑุญุจุงู‹ {name}! ๐Ÿ‘‹"})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
""", "server.py"
def template_discord_bot():
return """# Discord Bot Template
# pip install discord.py
import discord
from discord.ext import commands
TOKEN = "YOUR_DISCORD_TOKEN_HERE"
bot = commands.Bot(command_prefix="!", intents=discord.Intents.all())
@bot.event
async def on_ready():
print(f"๐Ÿค– Bot is ready: {bot.user}")
@bot.command()
async def hello(ctx):
await ctx.send(f"ู…ุฑุญุจุงู‹ {ctx.author.name}! ๐Ÿ‘‹")
@bot.command()
async def ping(ctx):
await ctx.send(f"๐Ÿ“ Pong! {round(bot.latency * 1000)}ms")
bot.run(TOKEN)
""", "discord_bot.py"
def template_scraper():
return """# Web Scraper Template
# pip install requests beautifulsoup4
import requests
from bs4 import BeautifulSoup
import json
def scrape_website(url):
print(f"๐Ÿ” ุฌุงุฑูŠ ุฌู„ุจ: {url}")
headers = {'User-Agent': 'Mozilla/5.0'}
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
title = soup.title.string if soup.title else "N/A"
links = [a.get('href') for a in soup.find_all('a', href=True)]
print(f"๐Ÿ“„ ุงู„ุนู†ูˆุงู†: {title}")
print(f"๐Ÿ”— ุนุฏุฏ ุงู„ุฑูˆุงุจุท: {len(links)}")
return {
'title': title,
'links_count': len(links),
'links': links[:10]
}
if __name__ == '__main__':
result = scrape_website("https://example.com")
print(json.dumps(result, indent=2, ensure_ascii=False))
""", "scraper.py"
tg_btn = gr.Button("๐Ÿค– ุจูˆุช ุชู„ุฌุฑุงู…")
flask_btn = gr.Button("๐ŸŒ Flask Server")
discord_btn = gr.Button("๐ŸŽฎ ุจูˆุช ุฏูŠุณูƒูˆุฑุฏ")
scraper_btn = gr.Button("๐Ÿ” Web Scraper")
# ุฑุจุท ุงู„ู‚ูˆุงู„ุจ
tg_btn.click(fn=template_telegram_bot, outputs=[code_editor, editor_filepath])
flask_btn.click(fn=template_flask_server, outputs=[code_editor, editor_filepath])
discord_btn.click(fn=template_discord_bot, outputs=[code_editor, editor_filepath])
scraper_btn.click(fn=template_scraper, outputs=[code_editor, editor_filepath])
# ุฑุจุท ุฃุญุฏุงุซ ุงู„ู…ุญุฑุฑ
def load_file_to_editor(filepath):
if not filepath:
return "โš ๏ธ ุฃุฏุฎู„ ู…ุณุงุฑ ุงู„ู…ู„ู", ""
content = read_file(filepath)
if content.startswith("โŒ") or content.startswith("โš ๏ธ") or content.startswith("๐Ÿ”’"):
return content, ""
# ุฅุฒุงู„ุฉ ุงู„ุณุทุฑ ุงู„ุฃูˆู„ (ู…ุนู„ูˆู…ุงุช ุงู„ู…ู„ู)
lines = content.split('\n')
if lines and lines[0].startswith("๐Ÿ“„"):
actual_content = '\n'.join(lines[2:]) # ุชุฌุงูˆุฒ ุงู„ุณุทุฑ ุงู„ุฃูˆู„ ูˆุงู„ูุงุตู„
return "โœ… ุชู… ุงู„ุชุญู…ูŠู„", actual_content
return "โœ… ุชู… ุงู„ุชุญู…ูŠู„", content
load_file_btn.click(
fn=load_file_to_editor,
inputs=[editor_filepath],
outputs=[editor_output, code_editor]
)
save_file_btn.click(
fn=write_file,
inputs=[editor_filepath, code_editor],
outputs=[editor_output]
)
save_run_btn.click(
fn=save_and_run,
inputs=[editor_filepath, code_editor],
outputs=[editor_output, editor_output]
)
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ุชุงุจ ุฅุฏุงุฑุฉ ุงู„ุนู…ู„ูŠุงุช โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
with gr.TabItem("๐Ÿ”„ Processes"):
gr.HTML('<div class="status-bar">๐Ÿ”„ Process Manager | ุฅุฏุงุฑุฉ ุงู„ุนู…ู„ูŠุงุช ุงู„ุฌุงุฑูŠุฉ</div>')
with gr.Row():
refresh_proc_btn = gr.Button("๐Ÿ”„ ุชุญุฏูŠุซ", variant="primary", size="lg")
list_all_btn = gr.Button("๐Ÿ“‹ ูƒู„ ุนู…ู„ูŠุงุช ุงู„ู†ุธุงู…", size="lg")
processes_output = gr.Textbox(
label="๐Ÿ“Š ุงู„ุนู…ู„ูŠุงุช",
lines=20,
interactive=False,
elem_classes=["terminal-output"],
)
with gr.Row():
with gr.Column():
pid_input = gr.Textbox(label="๐Ÿ”ข ุฑู‚ู… PID", lines=1)
with gr.Row():
stop_btn = gr.Button("โน๏ธ ุฅูŠู‚ุงู", variant="stop")
log_btn = gr.Button("๐Ÿ“„ ุนุฑุถ ุงู„ุณุฌู„", variant="secondary")
with gr.Column():
proc_action_output = gr.Textbox(
label="๐Ÿ“‹ ุงู„ู†ุชูŠุฌุฉ",
lines=10,
interactive=False,
elem_classes=["terminal-output"],
)
# ุฑุจุท ุงู„ุฃุญุฏุงุซ
refresh_proc_btn.click(fn=list_processes, outputs=[processes_output])
list_all_btn.click(
fn=lambda: execute_command("ps aux --sort=-%mem | head -30"),
outputs=[processes_output]
)
stop_btn.click(fn=stop_process, inputs=[pid_input], outputs=[proc_action_output])
log_btn.click(fn=view_process_log, inputs=[pid_input], outputs=[proc_action_output])
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ุชุงุจ ุงู„ุญุฒู… โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
with gr.TabItem("๐Ÿ“ฆ Packages"):
gr.HTML('<div class="status-bar">๐Ÿ“ฆ Package Manager | ุชุซุจูŠุช ูˆุฅุฏุงุฑุฉ ุงู„ุญุฒู…</div>')
with gr.Row():
pkg_input = gr.Textbox(
label="๐Ÿ“ฆ ุงุณู… ุงู„ุญุฒู…ุฉ",
placeholder="ู…ุซุงู„: requests ุฃูˆ flask ุฃูˆ python-telegram-bot",
lines=1,
scale=3,
)
install_btn = gr.Button("๐Ÿ“ฅ ุชุซุจูŠุช", variant="primary", scale=1, size="lg")
pkg_output = gr.Textbox(
label="๐Ÿ“‹ ุงู„ู†ุชูŠุฌุฉ",
lines=15,
interactive=False,
elem_classes=["terminal-output"],
)
gr.HTML("<h4>๐Ÿ“ฆ ุญุฒู… ุดุงุฆุนุฉ - ุงุถุบุท ู„ู„ุชุซุจูŠุช:</h4>")
with gr.Row():
gr.Button("๐Ÿค– python-telegram-bot").click(
fn=lambda: install_package("python-telegram-bot"), outputs=[pkg_output])
gr.Button("๐ŸŒ flask").click(
fn=lambda: install_package("flask"), outputs=[pkg_output])
gr.Button("๐Ÿ“ก requests").click(
fn=lambda: install_package("requests"), outputs=[pkg_output])
gr.Button("๐ŸŽฎ discord.py").click(
fn=lambda: install_package("discord.py"), outputs=[pkg_output])
with gr.Row():
gr.Button("๐Ÿ—„๏ธ sqlalchemy").click(
fn=lambda: install_package("sqlalchemy"), outputs=[pkg_output])
gr.Button("๐Ÿ” beautifulsoup4").click(
fn=lambda: install_package("beautifulsoup4"), outputs=[pkg_output])
gr.Button("๐Ÿ“Š pandas").click(
fn=lambda: install_package("pandas"), outputs=[pkg_output])
gr.Button("๐Ÿ”ง aiohttp").click(
fn=lambda: install_package("aiohttp"), outputs=[pkg_output])
with gr.Row():
gr.Button("๐Ÿ“‹ ุนุฑุถ ุงู„ุญุฒู… ุงู„ู…ุซุจุชุฉ").click(
fn=lambda: execute_command("pip list --format=columns"), outputs=[pkg_output])
gr.Button("๐Ÿ”„ ุชุญุฏูŠุซ pip").click(
fn=lambda: execute_command("pip install --upgrade pip"), outputs=[pkg_output])
install_btn.click(fn=install_package, inputs=[pkg_input], outputs=[pkg_output])
pkg_input.submit(fn=install_package, inputs=[pkg_input], outputs=[pkg_output])
gr.HTML("""
<div style="text-align:center; padding:10px; color:#8b949e; font-size:0.8em; margin-top:10px;">
๐Ÿ–ฅ๏ธ Cloud VPS Terminal | โšก Powered by ู…ุญู…ุฏ ุนู„ูŠ
</div>
""")
if __name__ == "__main__":
app.launch(
server_name="0.0.0.0",
server_port=7860,
)