Ship duration control, hidden previews, job resume, and desktop file purge.

The slider never left this machine, so deploy the generate UI with separate input/output hide toggles, reconnect in-progress jobs after refresh, and delete Comfy input/output files after they are saved to the library.
This commit is contained in:
2026-08-25 20:25:36 -05:00
parent 1a271c05a4
commit c5ed4d7ac4
16 changed files with 651 additions and 104 deletions
+44 -6
View File
@@ -1,5 +1,6 @@
import { execFile, spawn } from 'node:child_process'
import { promisify } from 'node:util'
import { getComfyHost, setComfyHostOverride } from '~/server/utils/comfy'
const execFileAsync = promisify(execFile)
@@ -40,15 +41,14 @@ function settings() {
controlUrl: String(config.comfyControlUrl || process.env.COMFY_CONTROL_URL || '').replace(/\/$/, ''),
controlToken: String(config.comfyControlToken || process.env.COMFY_CONTROL_TOKEN || ''),
healthTimeoutMs: 2500,
bootPollAttempts: 5,
bootPollDelayMs: 2000,
startTimeoutMs: 30_000,
bootPollAttempts: Number(process.env.COMFY_BOOT_POLL_ATTEMPTS || 20),
bootPollDelayMs: 3000,
startTimeoutMs: Number(process.env.COMFY_START_TIMEOUT_MS || 180_000),
busyWaitMs: Number(process.env.COMFY_BUSY_WAIT_MS || 180_000)
}
}
export async function checkComfyHttp(timeoutMs = 2500) {
const host = getComfyHost()
export async function checkComfyHttp(timeoutMs = 2500, host = getComfyHost()) {
try {
const res = await fetch(`${host}/system_stats`, { signal: AbortSignal.timeout(timeoutMs) })
if (!res.ok) return { ok: false as const, host, status: res.status, stats: null }
@@ -93,6 +93,9 @@ async function controlRequest(path: string, method = 'GET') {
process?: boolean
pid?: number
started?: boolean
already?: boolean
port?: number | null
proxyPort?: number | null
}
} catch {
return null
@@ -200,6 +203,16 @@ async function waitWhileBusy(onStatus: StatusFn) {
})
}
function hostWithPort(host: string, port: number) {
try {
const url = new URL(host)
url.port = String(port)
return url.origin
} catch {
return host
}
}
async function ensureUnlocked(onStatus: StatusFn) {
const cfg = settings()
const host = cfg.host
@@ -214,6 +227,31 @@ async function ensureUnlocked(onStatus: StatusFn) {
}
log('http-fail', { host })
const remote = await controlRequest('/status')
if (remote?.http && remote.proxyPort) {
const proxyUrl = hostWithPort(host, remote.proxyPort)
onStatus({
state: 'booting',
message: `Configured Comfy port is blocked. Trying the desktop LAN proxy on ${remote.proxyPort}...`,
host: proxyUrl,
processRunning: true
})
const viaProxy = await checkComfyHttp(cfg.healthTimeoutMs, proxyUrl)
if (viaProxy.ok) {
setComfyHostOverride(proxyUrl)
log('http-ok-proxy', { host: proxyUrl, localPort: remote.port || null })
await waitWhileBusy(onStatus)
onStatus({ state: 'online', message: 'ComfyUI online', host: proxyUrl, processRunning: true })
return
}
}
if (remote?.http) {
const localPort = remote.port ? ` Port ${remote.port} is healthy on the desktop.` : ''
throw createError({
statusCode: 503,
statusMessage: `Comfy Desktop is open and the local API is up, but this server cannot reach ${host}.${localPort} Open the MiniMax instance “ComfyUI (1)” and wait until the graph editor loads — the instance picker is not enough.`
})
}
const running = await processRunning()
if (running) {
onStatus({
@@ -273,7 +311,7 @@ async function ensureUnlocked(onStatus: StatusFn) {
throw createError({
statusCode: 503,
statusMessage: 'Started ComfyUI but it did not become healthy within 30 seconds.'
statusMessage: 'Started Comfy Desktop but the API never answered. If the instance picker is showing, click “ComfyUI (1)” (MiniMax) and wait until the graph editor is loaded. Cold start can take a couple of minutes.'
})
}