Purge identity refs from desktop Comfy and keep them in the server stills library.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-08-27 08:12:54 -05:00
co-authored by Cursor
parent 1466762af4
commit 72f4909815
6 changed files with 48 additions and 6 deletions
+6 -3
View File
@@ -181,9 +181,12 @@ function readJson(req) {
function purgeDesktopFiles(body) { function purgeDesktopFiles(body) {
const deleted = [] const deleted = []
const imageName = String(body?.imageName || body?.filename || '') const names = [
String(body?.imageName || body?.filename || ''),
...(Array.isArray(body?.imageNames) ? body.imageNames : [])
].map(name => String(name || '').trim()).filter(Boolean)
const imageSub = String(body?.imageSubfolder || '') const imageSub = String(body?.imageSubfolder || '')
if (imageName) { for (const imageName of names) {
for (const root of inputRoots()) { for (const root of inputRoots()) {
if (!existsSync(root)) continue if (!existsSync(root)) continue
const nested = safeFile(root, imageSub, imageName) const nested = safeFile(root, imageSub, imageName)
@@ -220,7 +223,7 @@ function purgeDesktopFiles(body) {
} }
} }
} }
console.log(JSON.stringify({ src: 'comfy-host-agent', event: 'purge', deleted: deleted.length, files: deleted.map((path) => basename(path)), imageName })) console.log(JSON.stringify({ src: 'comfy-host-agent', event: 'purge', deleted: deleted.length, files: deleted.map((path) => basename(path)), imageNames: names }))
return { ok: true, deleted } return { ok: true, deleted }
} }
+17 -1
View File
@@ -152,6 +152,20 @@ export default defineEventHandler(async (event) => {
height, height,
hideInput hideInput
}) })
if (useIdentityRefs) {
for (const [index, ref] of referenceImages.entries()) {
if (!ref?.data?.length || isPipelineFrameFilename(ref.filename)) continue
await saveStill({
ownerKey,
folderId,
filename: ref.filename || `identity-ref-${index + 2}.png`,
data: ref.data,
width,
height,
hideInput
})
}
}
const chainTotal = 1 + extensions.length const chainTotal = 1 + extensions.length
const job = createJob() const job = createJob()
@@ -332,6 +346,7 @@ async function queueMiniMax(
if (job.library) { if (job.library) {
job.library.imageName = uploaded.name job.library.imageName = uploaded.name
job.library.imageSubfolder = uploaded.subfolder job.library.imageSubfolder = uploaded.subfolder
job.library.referenceImageNames = referenceNames.filter(Boolean)
} }
emitChainJob(job, { type: 'status', message: queueing, progress: 6 }) emitChainJob(job, { type: 'status', message: queueing, progress: 6 })
await waitForComfySocket(job, 4000) await waitForComfySocket(job, 4000)
@@ -390,7 +405,8 @@ async function queueMiniMax(
parentClipId: job.library.parentClipId, parentClipId: job.library.parentClipId,
chainIndex: job.library.chainIndex, chainIndex: job.library.chainIndex,
stillId: job.library.stillId, stillId: job.library.stillId,
sound: job.library.sound sound: job.library.sound,
referenceImageNames: job.library.referenceImageNames
}) })
} }
emitChainJob(job, { type: 'status', message: 'Job queued on ComfyUI', progress: 8 }) emitChainJob(job, { type: 'status', message: 'Job queued on ComfyUI', progress: 8 })
+7
View File
@@ -293,6 +293,7 @@ async function purgeOnDesktop(opts: {
video?: { filename: string; subfolder: string; type: string } video?: { filename: string; subfolder: string; type: string }
imageName?: string imageName?: string
imageSubfolder?: string imageSubfolder?: string
extraImageNames?: string[]
}) { }) {
const config = useRuntimeConfig() const config = useRuntimeConfig()
const controlUrl = String(config.comfyControlUrl || process.env.COMFY_CONTROL_URL || '').replace(/\/$/, '') const controlUrl = String(config.comfyControlUrl || process.env.COMFY_CONTROL_URL || '').replace(/\/$/, '')
@@ -309,6 +310,7 @@ async function purgeOnDesktop(opts: {
body: JSON.stringify({ body: JSON.stringify({
imageName: opts.imageName || '', imageName: opts.imageName || '',
imageSubfolder: opts.imageSubfolder || '', imageSubfolder: opts.imageSubfolder || '',
imageNames: (opts.extraImageNames || []).filter(Boolean),
video: opts.video || null video: opts.video || null
}), }),
signal: AbortSignal.timeout(8000) signal: AbortSignal.timeout(8000)
@@ -322,6 +324,7 @@ export async function purgeComfyArtifacts(opts: {
video?: { filename: string; subfolder: string; type: string } video?: { filename: string; subfolder: string; type: string }
imageName?: string imageName?: string
imageSubfolder?: string imageSubfolder?: string
extraImageNames?: string[]
promptId?: string promptId?: string
}) { }) {
if (!purgeComfyEnabled()) return if (!purgeComfyEnabled()) return
@@ -329,6 +332,10 @@ export async function purgeComfyArtifacts(opts: {
const files: { filename: string; subfolder: string; type: string }[] = [] const files: { filename: string; subfolder: string; type: string }[] = []
if (opts.video?.filename) files.push(opts.video) if (opts.video?.filename) files.push(opts.video)
if (opts.imageName) files.push({ filename: opts.imageName, subfolder: opts.imageSubfolder || '', type: 'input' }) if (opts.imageName) files.push({ filename: opts.imageName, subfolder: opts.imageSubfolder || '', type: 'input' })
for (const name of opts.extraImageNames || []) {
if (!name || name === opts.imageName) continue
files.push({ filename: name, subfolder: opts.imageSubfolder || '', type: 'input' })
}
for (const file of files) { for (const file of files) {
try { try {
await comfyFetch('/aigen/purge', { await comfyFetch('/aigen/purge', {
+1
View File
@@ -66,6 +66,7 @@ export interface Job {
imageSubfolder?: string imageSubfolder?: string
stillId?: string stillId?: string
stillFilename?: string stillFilename?: string
referenceImageNames?: string[]
duration?: number duration?: number
sound?: boolean sound?: boolean
draftId?: string draftId?: string
+8 -1
View File
@@ -27,6 +27,7 @@ export interface PendingJob {
chainIndex?: number chainIndex?: number
stillId?: string stillId?: string
sound?: boolean sound?: boolean
referenceImageNames?: string[]
} }
function pendingRoot() { function pendingRoot() {
@@ -148,7 +149,13 @@ export async function completePendingIfReady(pending: PendingJob) {
stillId: pending.stillId, stillId: pending.stillId,
sound: pending.sound sound: pending.sound
}) })
await purgeComfyArtifacts({ video, imageName: pending.imageName, imageSubfolder: pending.imageSubfolder, promptId: pending.promptId }) await purgeComfyArtifacts({
video,
imageName: pending.imageName,
imageSubfolder: pending.imageSubfolder,
extraImageNames: pending.referenceImageNames,
promptId: pending.promptId
})
deletePendingJob(pending.jobId) deletePendingJob(pending.jobId)
return { return {
type: 'complete' as const, type: 'complete' as const,
+9 -1
View File
@@ -132,6 +132,11 @@ export function watchComfyJob(job: Job, options: { persist?: boolean } = {}): Pr
emitChainJob(job, { type: 'error', error: job.error, message: job.error }) emitChainJob(job, { type: 'error', error: job.error, message: job.error })
if (job.id) deletePendingJob(job.id) if (job.id) deletePendingJob(job.id)
removeExtendTemp(job.library?.extendTmpDir) removeExtendTemp(job.library?.extendTmpDir)
await purgeComfyArtifacts({
imageName: job.library?.imageName,
imageSubfolder: job.library?.imageSubfolder,
extraImageNames: job.library?.referenceImageNames
})
resolve() resolve()
} }
@@ -209,6 +214,7 @@ export function watchComfyJob(job: Job, options: { persist?: boolean } = {}): Pr
video, video,
imageName: job.library.imageName, imageName: job.library.imageName,
imageSubfolder: job.library.imageSubfolder, imageSubfolder: job.library.imageSubfolder,
extraImageNames: job.library.referenceImageNames,
promptId: job.promptId promptId: job.promptId
}) })
if (!persist) { if (!persist) {
@@ -405,6 +411,7 @@ export function ensurePendingWatch(pending: {
chainIndex?: number chainIndex?: number
stillId?: string stillId?: string
sound?: boolean sound?: boolean
referenceImageNames?: string[]
}) { }) {
const existing = getJob(pending.jobId) const existing = getJob(pending.jobId)
if (existing) return existing if (existing) return existing
@@ -435,7 +442,8 @@ export function ensurePendingWatch(pending: {
parentClipId: pending.parentClipId, parentClipId: pending.parentClipId,
chainIndex: pending.chainIndex, chainIndex: pending.chainIndex,
stillId: pending.stillId, stillId: pending.stillId,
sound: pending.sound sound: pending.sound,
referenceImageNames: pending.referenceImageNames
} }
}) })
if (!pendingWatches.has(job.id)) { if (!pendingWatches.has(job.id)) {