Movie Editor: Restart ComfyUI button
FunPack menu -> 'Restart ComfyUI' relaunches the server process in place (POST /funpack/movie/api/restart -> os.execv, mirroring ComfyUI-Manager's reboot incl. the comfy-cli session case; no Manager dependency). Restart is deferred 0.7s so the 200 flushes first. UI shows a blocking spinner overlay, polls /health, and auto-reloads when ComfyUI is back. Confirms first. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
7f479a6a2d
commit
8b278c9515
@@ -45,6 +45,7 @@
|
||||
getModels: () => j("GET", API("/models")),
|
||||
saveModels: (data) => j("PUT", API("/models"), data),
|
||||
refreshModels: () => j("POST", API("/models/refresh")),
|
||||
restart: () => j("POST", API("/restart")),
|
||||
|
||||
// generate
|
||||
generate: (id, onlyScene) => j("POST", API(`/projects/${id}/generate`), { only_scene: onlyScene || null }),
|
||||
|
||||
@@ -9,6 +9,26 @@
|
||||
function sel() { return S.get().selectedSceneId; }
|
||||
function hasProject() { return !!S.get().project; }
|
||||
|
||||
async function restartComfy() {
|
||||
if (!confirm("Restart ComfyUI now?\n\nThe server will be down for ~10–40s and any running generation will be lost. This page reloads automatically when it's back.")) return;
|
||||
const ov = el("div", "restart-overlay");
|
||||
const card = el("div", "restart-card");
|
||||
card.append(el("div", "restart-spin"));
|
||||
const msg = el("div", "restart-msg", "Restarting ComfyUI…\nThis page will reload when it's back.");
|
||||
card.append(msg); ov.append(card); document.body.append(ov);
|
||||
try { await window.MovieEditorAPI.restart(); } catch (_) { /* connection drops as it execv's — expected */ }
|
||||
const start = Date.now();
|
||||
const tick = async () => {
|
||||
try {
|
||||
const h = await window.MovieEditorAPI.health();
|
||||
if (h && h.ok) { location.reload(); return; }
|
||||
} catch (_) { /* still down */ }
|
||||
if (Date.now() - start > 90000) msg.textContent = "Still waiting on ComfyUI…\nIt may need a manual restart — check the console.";
|
||||
setTimeout(tick, 2000);
|
||||
};
|
||||
setTimeout(tick, 3500); // give it a moment to actually go down first
|
||||
}
|
||||
|
||||
function menuSpec() {
|
||||
const st = S.get();
|
||||
const recent = (st.projects || []).slice(0, 8).map((p) => ({
|
||||
@@ -53,6 +73,7 @@
|
||||
FunPack: [
|
||||
{ menulabel: "Libraries (in ComfyUI Studio)" },
|
||||
{ label: "Open ComfyUI", hint: "↗", action: () => window.open("/", "_blank") },
|
||||
{ label: "Restart ComfyUI", hint: "⟳", danger: true, action: restartComfy },
|
||||
{ sep: true },
|
||||
{ label: st.health?.reference_loaded ? "Pipeline reference: loaded" : "Pipeline reference: missing", disabled: true },
|
||||
{ label: `Configured nodes: ${st.health?.configured_slots ?? 0}`, disabled: true },
|
||||
|
||||
@@ -293,6 +293,16 @@ input[type=number] { font-family: var(--font-mono); }
|
||||
.wire-arrow { color: var(--teal); }
|
||||
.wire-select { flex: 1; }
|
||||
|
||||
/* restart overlay */
|
||||
.restart-overlay { position: fixed; inset: 0; z-index: 9999; display: flex; align-items: center; justify-content: center;
|
||||
background: color-mix(in srgb, var(--ink-0) 88%, transparent); backdrop-filter: blur(3px); }
|
||||
.restart-card { display: flex; flex-direction: column; align-items: center; gap: 16px; padding: 30px 40px;
|
||||
background: var(--ink-1); border: 1px solid var(--line); border-radius: 14px; }
|
||||
.restart-msg { color: var(--muted); text-align: center; white-space: pre-line; font-size: 13px; line-height: 1.5; }
|
||||
.restart-spin { width: 30px; height: 30px; border-radius: 50%; border: 3px solid var(--line);
|
||||
border-top-color: var(--amber); animation: spin .8s linear infinite; }
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
|
||||
/* staggered zone reveal on load */
|
||||
.zone { animation: rise .5s both; }
|
||||
.media { animation-delay: .02s; }
|
||||
|
||||
@@ -25,6 +25,37 @@ from .backend.timeline import Project, build_combined_prompt
|
||||
UI_PREFIX = "/funpack/movie"
|
||||
|
||||
|
||||
def _restart_comfy() -> None:
|
||||
"""Relaunch the ComfyUI process in place. Mirrors ComfyUI-Manager's reboot so it
|
||||
works the same whether launched directly, as a module, or via comfy-cli."""
|
||||
import os
|
||||
import sys
|
||||
try:
|
||||
sys.stdout.close_log() # type: ignore[attr-defined] # Manager's tee logger, if present
|
||||
except Exception:
|
||||
pass
|
||||
# comfy-cli watches for a .reboot file and relaunches us itself.
|
||||
if "__COMFY_CLI_SESSION__" in os.environ:
|
||||
try:
|
||||
open(os.environ["__COMFY_CLI_SESSION__"] + ".reboot", "w").close()
|
||||
except Exception:
|
||||
pass
|
||||
print("\n[FunPack] Restarting ComfyUI...\n", flush=True)
|
||||
os._exit(0)
|
||||
sys_argv = sys.argv.copy()
|
||||
if "--windows-standalone-build" in sys_argv:
|
||||
sys_argv.remove("--windows-standalone-build")
|
||||
if sys_argv and sys_argv[0].endswith("__main__.py"): # python -m comfy
|
||||
module_name = os.path.basename(os.path.dirname(sys_argv[0]))
|
||||
cmds = [sys.executable, "-m", module_name] + sys_argv[1:]
|
||||
elif sys.platform.startswith("win32"):
|
||||
cmds = ['"' + sys.executable + '"', '"' + sys_argv[0] + '"'] + sys_argv[1:]
|
||||
else:
|
||||
cmds = [sys.executable] + sys_argv
|
||||
print(f"\n[FunPack] Restarting ComfyUI... {cmds}\n", flush=True)
|
||||
os.execv(sys.executable, cmds)
|
||||
|
||||
|
||||
# ── helpers ──────────────────────────────────────────────────────────────────
|
||||
|
||||
def _media_from_history(hist_entry: dict) -> list[dict]:
|
||||
@@ -267,6 +298,13 @@ if web is not None and PromptServer is not None:
|
||||
raise web.HTTPNotFound(reason="Unknown node class")
|
||||
return web.json_response(spec)
|
||||
|
||||
@routes.post(UI_PREFIX + "/api/restart")
|
||||
async def _restart(_req):
|
||||
import asyncio
|
||||
# defer so this 200 flushes to the browser before the process is replaced
|
||||
asyncio.get_event_loop().call_later(0.7, _restart_comfy)
|
||||
return web.json_response({"restarting": True})
|
||||
|
||||
@routes.post(UI_PREFIX + "/api/models/refresh")
|
||||
async def _models_refresh(_req):
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user