Fix generation progress getting stuck at 1% after Comfy finishes.
Poll Comfy history and the job snapshot so the browser still gets the video when the live stream is buffered or the websocket misses completion. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+52
-17
@@ -68,28 +68,63 @@ export async function fetchHistory(promptId: string) {
|
||||
return (await res.json()) as Record<string, unknown>
|
||||
}
|
||||
|
||||
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, Record<string, unknown>> } | undefined
|
||||
const outputs = entry?.outputs || {}
|
||||
for (const node of Object.values(outputs)) {
|
||||
for (const key of ['videos', 'gifs', 'images', 'files']) {
|
||||
const items = node[key]
|
||||
if (!Array.isArray(items)) continue
|
||||
const match = items.find((item: { filename?: string }) => String(item.filename || '').toLowerCase().endsWith('.mp4'))
|
||||
|| items[0]
|
||||
if (match?.filename) {
|
||||
return {
|
||||
filename: String(match.filename),
|
||||
subfolder: String(match.subfolder || 'video'),
|
||||
type: String(match.type || 'output')
|
||||
}
|
||||
}
|
||||
function isVideoFile(item: { filename?: string; format?: string } | null | undefined) {
|
||||
if (!item) return false
|
||||
const name = String(item.filename || '').toLowerCase()
|
||||
const format = String(item.format || '').toLowerCase()
|
||||
return name.endsWith('.mp4') || name.endsWith('.webm') || format.includes('video') || format.includes('mp4')
|
||||
}
|
||||
|
||||
function normalizeVideo(item: { filename?: string; subfolder?: string; type?: string }) {
|
||||
return {
|
||||
filename: String(item.filename),
|
||||
subfolder: String(item.subfolder || ''),
|
||||
type: String(item.type || 'output')
|
||||
}
|
||||
}
|
||||
|
||||
function findVideo(value: unknown, depth = 0): { filename: string; subfolder: string; type: string } | null {
|
||||
if (!value || typeof value !== 'object' || depth > 8) return null
|
||||
if (Array.isArray(value)) {
|
||||
const files = value.filter((item): item is { filename?: string; format?: string; subfolder?: string; type?: string } => Boolean(item && typeof item === 'object'))
|
||||
const match = files.find(item => String(item.filename || '').toLowerCase().endsWith('.mp4'))
|
||||
|| files.find(isVideoFile)
|
||||
if (match?.filename) return normalizeVideo(match)
|
||||
for (const item of value) {
|
||||
const nested = findVideo(item, depth + 1)
|
||||
if (nested) return nested
|
||||
}
|
||||
return null
|
||||
}
|
||||
const record = value as { filename?: string; format?: string; subfolder?: string; type?: string }
|
||||
if (record.filename && isVideoFile(record)) return normalizeVideo(record)
|
||||
for (const nested of Object.values(value as Record<string, unknown>)) {
|
||||
const found = findVideo(nested, depth + 1)
|
||||
if (found) return found
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
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 || {})
|
||||
}
|
||||
|
||||
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'
|
||||
? 'ComfyUI reported an execution error'
|
||||
: null
|
||||
const completed = Boolean(video) || status?.completed === true || status?.status_str === 'success'
|
||||
return { video, completed, error }
|
||||
}
|
||||
|
||||
export async function probeComfy() {
|
||||
try {
|
||||
const res = await fetch(`${comfyBase()}/system_stats`, { signal: AbortSignal.timeout(2500) })
|
||||
|
||||
Reference in New Issue
Block a user