ubuntu / app.py
proti0070's picture
Upload 2 files
35dc940 verified
import gradio as gr
import subprocess
import os
import sys
class Terminal:
def __init__(self):
self.current_dir = "/app"
self.history = []
self.output_history = []
self.max_history = 100
def execute(self, command):
"""执行命令并返回结果"""
if not command.strip():
return {"output": "", "success": True, "dir": self.current_dir}
cmd = command.strip()
self.history.append(cmd)
if len(self.history) > self.max_history:
self.history.pop(0)
# 处理 cd 命令
if cmd.startswith("cd "):
try:
target = cmd[3:].strip()
if not target:
target = os.path.expanduser("~")
if not os.path.isabs(target):
target = os.path.join(self.current_dir, target)
target = os.path.normpath(target)
if os.path.isdir(target):
os.chdir(target)
self.current_dir = os.getcwd()
output = f"Changed directory to: {self.current_dir}"
self.output_history.append(f"$ {cmd}\n{output}")
return {"output": output, "success": True, "dir": self.current_dir}
else:
output = f"cd: {target}: No such directory"
self.output_history.append(f"$ {cmd}\n{output}")
return {"output": output, "success": False, "dir": self.current_dir}
except Exception as e:
output = f"cd error: {str(e)}"
self.output_history.append(f"$ {cmd}\n{output}")
return {"output": output, "success": False, "dir": self.current_dir}
# 处理 clear 命令
if cmd == "clear" or cmd == "cls":
self.output_history = []
return {"output": "", "success": True, "dir": self.current_dir, "clear": True}
# 执行其他命令
try:
original_dir = os.getcwd()
os.chdir(self.current_dir)
process = subprocess.run(
["bash", "-c", cmd],
capture_output=True,
text=True,
timeout=30,
env=os.environ
)
os.chdir(original_dir)
# 构建输出
output_lines = []
if process.stdout:
output_lines.append(process.stdout.rstrip())
if process.stderr:
output_lines.append(process.stderr.rstrip())
if process.returncode != 0 and not process.stderr:
output_lines.append(f"[Exit code: {process.returncode}]")
output = "\n".join(output_lines)
# 保存到历史
self.output_history.append(f"$ {cmd}\n{output}" if output else f"$ {cmd}")
return {
"output": output,
"success": process.returncode == 0,
"dir": self.current_dir
}
except subprocess.TimeoutExpired:
output = "Error: Command timed out after 30 seconds"
self.output_history.append(f"$ {cmd}\n{output}")
return {"output": output, "success": False, "dir": self.current_dir}
except Exception as e:
output = f"Error: {str(e)}"
self.output_history.append(f"$ {cmd}\n{output}")
return {"output": output, "success": False, "dir": self.current_dir}
def get_full_output(self):
"""获取完整的终端输出"""
if not self.output_history:
return f"{self.current_dir}$ "
# 只保留最近20条命令以避免过长
recent_history = self.output_history[-20:]
full_output = "\n\n".join(recent_history)
full_output += f"\n\n{self.current_dir}$ "
return full_output
# 创建终端实例
terminal = Terminal()
# 自定义CSS(现在放在launch()方法中)
custom_css = """
#terminal-output textarea {
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace !important;
font-size: 14px !important;
background-color: #1e1e1e !important;
color: #e0e0e0 !important;
border: 1px solid #444 !important;
}
#terminal-output {
max-height: 500px;
overflow-y: auto;
}
.prompt-text {
color: #4CAF50;
font-weight: bold;
}
.command-text {
color: #64B5F6;
}
.error-text {
color: #f44336;
}
#cmd-input input {
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
font-size: 14px;
}
.quick-btn {
font-family: monospace;
font-size: 12px;
margin: 2px;
padding: 4px 8px;
}
"""
# 创建界面(移除了css参数)
with gr.Blocks(title="Ubuntu Terminal") as demo:
gr.Markdown("# 🐧 Ubuntu 22.04 Terminal")
gr.Markdown(f"**Current directory:** `{terminal.current_dir}`")
# 使用 Textbox 显示终端输出
terminal_output = gr.Textbox(
label="",
value=terminal.get_full_output(),
lines=25,
elem_id="terminal-output",
interactive=False,
show_label=False
)
# 命令输入
with gr.Row():
cmd_input = gr.Textbox(
label="",
placeholder="Enter command (press Enter to execute)...",
scale=8,
elem_id="cmd-input",
show_label=False
)
execute_btn = gr.Button("Run", variant="primary", scale=1)
clear_btn = gr.Button("Clear", variant="secondary", scale=1)
# 快速命令按钮
gr.Markdown("### 🚀 Quick Commands")
with gr.Row():
quick_commands = [
("pwd", "Show path"),
("ls -la", "List files"),
("python3 --version", "Python"),
("wget --version", "Wget"),
("curl --version", "Curl"),
("git --version", "Git"),
("sudo whoami", "Sudo test"),
("uname -a", "System info"),
]
for cmd, desc in quick_commands:
btn = gr.Button(cmd, size="sm", min_width=100)
btn.click(
fn=lambda c=cmd: c,
outputs=[cmd_input]
)
# 信息面板
with gr.Accordion("📋 System Information", open=False):
# 安全地获取用户信息
try:
user = os.environ.get('USER') or os.environ.get('USERNAME') or 'ubuntu'
uid = os.getuid()
except:
user = 'ubuntu'
uid = 1000
gr.Markdown(f"""
**Available Tools:**
- ✅ Python 3, pip
- ✅ sudo (passwordless for 'ubuntu' user)
- ✅ wget, curl, git
- ✅ vim, nano, htop
- ✅ build-essential
**Current User:** `{user}` (uid: {uid})
**Home Directory:** `{os.path.expanduser('~')}`
**Try these commands:**
```bash
# File operations
echo "Hello" > test.txt
cat test.txt
rm test.txt
# System info
df -h
free -h
ps aux | head -20
# Network test
curl -s https://httpbin.org/ip
ping -c 1 8.8.8.8 2>/dev/null || echo "ping not available"
```
""")
# 事件处理函数
def execute_command(cmd, current_output):
"""执行命令并更新输出"""
result = terminal.execute(cmd)
new_output = terminal.get_full_output()
return new_output, ""
def clear_terminal():
"""清空终端"""
terminal.output_history = []
return terminal.get_full_output()
# 绑定事件
execute_btn.click(
execute_command,
inputs=[cmd_input, terminal_output],
outputs=[terminal_output, cmd_input]
)
cmd_input.submit(
execute_command,
inputs=[cmd_input, terminal_output],
outputs=[terminal_output, cmd_input]
)
clear_btn.click(
clear_terminal,
outputs=[terminal_output]
)
if __name__ == "__main__":
print("=" * 60)
print("🚀 Starting Terminal Application")
print("📁 Current directory:", terminal.current_dir)
# 安全地获取用户信息
try:
user = os.environ.get('USER') or os.environ.get('USERNAME') or 'ubuntu'
except:
user = 'ubuntu'
print("👤 User:", user)
print("=" * 60)
# 启动应用(css参数现在在这里)
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
css=custom_css # CSS参数移到这里
)