Files
ComfyUI_Skills_OpenClaw/ui/open_ui.py

127 lines
3.8 KiB
Python

#!/usr/bin/env python3
from __future__ import annotations
import argparse
import json
import os
import subprocess
import sys
import time
import urllib.error
import urllib.request
import webbrowser
from pathlib import Path
SCRIPT_DIR = Path(__file__).resolve().parent
ROOT_DIR = SCRIPT_DIR.parent
if str(SCRIPT_DIR) not in sys.path:
sys.path.insert(0, str(SCRIPT_DIR))
if str(ROOT_DIR / "scripts") not in sys.path:
sys.path.insert(0, str(ROOT_DIR / "scripts"))
from settings import DEFAULT_HOST, DEFAULT_PORT # noqa: E402
def build_ui_url() -> str:
host = DEFAULT_HOST if DEFAULT_HOST not in {"0.0.0.0", "::"} else "127.0.0.1"
return f"http://{host}:{DEFAULT_PORT}"
def is_ui_ready(url: str, timeout: float = 1.0) -> bool:
try:
with urllib.request.urlopen(url, timeout=timeout) as response:
return 200 <= response.status < 500
except (urllib.error.URLError, TimeoutError, ValueError):
return False
def wait_until_ready(url: str, timeout_seconds: float) -> bool:
deadline = time.time() + timeout_seconds
while time.time() < deadline:
if is_ui_ready(url):
return True
time.sleep(0.5)
return False
def start_ui_process(python_bin: str) -> tuple[subprocess.Popen[bytes], Path]:
log_path = SCRIPT_DIR / "ui.log"
log_handle = log_path.open("ab")
launcher = SCRIPT_DIR / "run_ui.sh"
kwargs: dict[str, object] = {
"cwd": str(ROOT_DIR),
"stdin": subprocess.DEVNULL,
"stdout": log_handle,
"stderr": subprocess.STDOUT,
"close_fds": os.name != "nt",
}
# 使用独立会话启动,避免 Agent 进程退出时把 UI 一起带走。
if os.name == "nt":
detached = getattr(subprocess, "DETACHED_PROCESS", 0)
new_group = getattr(subprocess, "CREATE_NEW_PROCESS_GROUP", 0)
kwargs["creationflags"] = detached | new_group
else:
kwargs["start_new_session"] = True
if os.name == "nt":
process = subprocess.Popen([python_bin, str(SCRIPT_DIR / "app.py")], **kwargs)
else:
env = os.environ.copy()
env.setdefault("PYTHON_BIN", python_bin)
kwargs["env"] = env
process = subprocess.Popen([str(launcher)], **kwargs)
return process, log_path
def open_browser(url: str) -> bool:
try:
return bool(webbrowser.open(url, new=2, autoraise=True))
except webbrowser.Error:
return False
def main() -> int:
parser = argparse.ArgumentParser(description="Start the local OpenClaw ComfyUI UI and open it in a browser.")
parser.add_argument("--no-browser", action="store_true", help="Start the UI without opening a browser window.")
parser.add_argument("--timeout", type=float, default=20.0, help="Seconds to wait for the UI to become ready.")
args = parser.parse_args()
url = build_ui_url()
python_bin = sys.executable or "python3"
result = {
"status": "success",
"url": url,
"already_running": False,
"browser_opened": False,
"log_path": str(SCRIPT_DIR / "ui.log"),
}
if is_ui_ready(url):
result["already_running"] = True
else:
process, log_path = start_ui_process(python_bin)
result["log_path"] = str(log_path)
if not wait_until_ready(url, args.timeout):
print(json.dumps({
"status": "error",
"url": url,
"message": "UI did not become ready in time.",
"log_path": str(log_path),
"pid": process.pid,
}, ensure_ascii=False))
return 1
result["pid"] = process.pid
if not args.no_browser:
result["browser_opened"] = open_browser(url)
print(json.dumps(result, ensure_ascii=False))
return 0
if __name__ == "__main__":
raise SystemExit(main())