Op / app.py
Marvin Wiesner
Create app.py
ed71545 verified
import os
import re
import shlex
import subprocess
import gradio as gr
# ── 1. Commands dynamisch ermitteln ──────────────────────────────
def discover_commands() -> list[str]:
"""
Ruft `openclaw --help` auf und extrahiert die Sub-Commands.
FΓ€llt bei Problemen auf eine kleine Default-Liste zurΓΌck.
"""
try:
res = subprocess.run(
["openclaw", "--help"],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
timeout=30,
)
commands, parsing = [], False
for line in res.stdout.splitlines():
if re.match(r"^\s*Commands?:", line):
parsing = True
continue
if parsing:
m = re.match(r"^\s{2,}([a-zA-Z0-9_-]+)\s", line)
if m:
commands.append(m.group(1))
elif line.strip() == "":
break # Ende des Command-Blocks
return sorted(set(commands))
except Exception:
# Fallback, falls openclaw nicht installiert oder Help-Format unbekannt
return ["status", "onboard", "gateway", "tui", "dashboard"]
COMMANDS = discover_commands()
# ── 2. AusgewΓ€hlten Befehl ausfΓΌhren ─────────────────────────────
def run_cmd(command: str, extra_args: str) -> str:
"""
FΓΌhrt `openclaw <command> [extra_args]` aus und gibt formatierten Output zurΓΌck.
"""
cmd = ["openclaw", command] + shlex.split(extra_args or "")
try:
res = subprocess.run(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
timeout=120,
cwd="/app",
)
return f"$ {' '.join(cmd)}\n\nExit code: {res.returncode}\n\n{res.stdout}"
except FileNotFoundError:
return "Error: `openclaw` ist nicht im Container installiert."
except subprocess.TimeoutExpired:
return "Error: Befehl lief lΓ€nger als 120 s."
except Exception as e:
return f"Unerwarteter Fehler: {e}"
# ── 3. Minimales UI mit Gradio ───────────────────────────────────
with gr.Blocks() as demo:
gr.Markdown("# OpenClaw Docker Space – automatisiert")
with gr.Row():
cmd_dd = gr.Dropdown(
choices=COMMANDS,
value=COMMANDS[0] if COMMANDS else None,
label="OpenClaw-Command",
)
extra_tb = gr.Textbox(
label="Optionale Zusatz-Argumente",
placeholder="z. B. --help oder --verbose",
)
output_tb = gr.Textbox(lines=20, label="Ausgabe")
run_btn = gr.Button("AusfΓΌhren")
run_btn.click(run_cmd, inputs=[cmd_dd, extra_tb], outputs=output_tb)
# Hugging Face setzt $PORT automatisch; Fallback 7860 fΓΌr Lokaltests
demo.launch(server_name="0.0.0.0",
server_port=int(os.environ.get("PORT", 7860)))