Recover finished Comfy videos after relay restarts.
Persist queued jobs to disk, import leftover MP4s from Comfy history, and do not mark a run complete until the saved video exists. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+31
-9
@@ -68,6 +68,12 @@ export async function fetchHistory(promptId: string) {
|
||||
return (await res.json()) as Record<string, unknown>
|
||||
}
|
||||
|
||||
export async function fetchHistoryAll() {
|
||||
const res = await comfyFetch('/history')
|
||||
if (!res.ok) return {}
|
||||
return (await res.json()) as Record<string, unknown>
|
||||
}
|
||||
|
||||
function isVideoFile(item: { filename?: string; format?: string } | null | undefined) {
|
||||
if (!item) return false
|
||||
const name = String(item.filename || '').toLowerCase()
|
||||
@@ -107,22 +113,38 @@ function findVideo(value: unknown, depth = 0): { filename: string; subfolder: st
|
||||
|
||||
export function extractVideo(history: Record<string, unknown> | null, promptId: string) {
|
||||
if (!history) return null
|
||||
const entry = (history[promptId] || Object.values(history)[0]) as { outputs?: Record<string, unknown> } | undefined
|
||||
return findVideo(entry?.outputs || {})
|
||||
const wrapped = history[promptId] as { outputs?: Record<string, unknown> } | undefined
|
||||
if (wrapped) {
|
||||
return findVideo(wrapped.outputs || {}) || findVideo(wrapped)
|
||||
}
|
||||
if ((history as { outputs?: unknown }).outputs) {
|
||||
return findVideo((history as { outputs?: unknown }).outputs) || findVideo(history)
|
||||
}
|
||||
return findVideo(history)
|
||||
}
|
||||
|
||||
export function extractPromptFromHistory(entry: unknown) {
|
||||
const prompt = (entry as { prompt?: unknown[] })?.prompt
|
||||
const graph = Array.isArray(prompt) ? prompt[2] : null
|
||||
if (!graph || typeof graph !== 'object') return ''
|
||||
for (const node of Object.values(graph as Record<string, { class_type?: string; inputs?: Record<string, unknown> }>)) {
|
||||
if (node?.class_type === 'MiniMaxH3ImageToVideo') {
|
||||
return String(node.inputs?.prompt || node.inputs?.text || '').trim()
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
export function inspectHistory(history: Record<string, unknown> | null, promptId: string) {
|
||||
const video = extractVideo(history, promptId)
|
||||
if (!history) return { video: null, completed: false, error: null as string | null }
|
||||
const entry = (history[promptId] || Object.values(history)[0]) as {
|
||||
status?: { status_str?: string; completed?: boolean; messages?: unknown[] }
|
||||
} | undefined
|
||||
const status = entry?.status
|
||||
const error = status?.status_str === 'error'
|
||||
const entry = (history[promptId] || history) as {
|
||||
status?: { status_str?: string; completed?: boolean }
|
||||
}
|
||||
const error = entry?.status?.status_str === 'error'
|
||||
? 'ComfyUI reported an execution error'
|
||||
: null
|
||||
const completed = Boolean(video) || status?.completed === true || status?.status_str === 'success'
|
||||
return { video, completed, error }
|
||||
return { video, completed: Boolean(video), error }
|
||||
}
|
||||
|
||||
export async function probeComfy() {
|
||||
|
||||
Reference in New Issue
Block a user