Move library collections as a group and map v2 identity refs.
Collapsed collection actions now move, rename, delete, and rerun every part so chains stay together. Identity mode follows the v2u3 Ref2VA picture wiring. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+33
-20
@@ -83,13 +83,20 @@ export default defineEventHandler(async (event) => {
|
||||
|
||||
const fields: Record<string, string> = {}
|
||||
let image: { filename: string; data: Buffer; type?: string } | null = null
|
||||
const referenceImages: { filename: string; data: Buffer; type?: string }[] = []
|
||||
const referenceImages: Array<{ filename: string; data: Buffer; type?: string } | null> = [null, null, null, null]
|
||||
let compactRefSlot = 0
|
||||
for (const part of form) {
|
||||
if (part.name === 'image' && part.filename && part.data?.length) {
|
||||
image = { filename: part.filename, data: part.data, type: part.type }
|
||||
} else if (part.name && /^refImage(\d)$/.test(part.name) && part.filename && part.data?.length) {
|
||||
const slot = Number(part.name.replace('refImage', ''))
|
||||
if (slot >= 0 && slot < 4) {
|
||||
referenceImages[slot] = { filename: part.filename, data: part.data, type: part.type }
|
||||
}
|
||||
} else if (part.name === 'refImage' && part.filename && part.data?.length) {
|
||||
if (referenceImages.length < 4) {
|
||||
referenceImages.push({ filename: part.filename, data: part.data, type: part.type })
|
||||
if (compactRefSlot < 4) {
|
||||
referenceImages[compactRefSlot] = { filename: part.filename, data: part.data, type: part.type }
|
||||
compactRefSlot += 1
|
||||
}
|
||||
} else if (part.name && part.data) {
|
||||
fields[part.name] = part.data.toString('utf8')
|
||||
@@ -105,7 +112,7 @@ export default defineEventHandler(async (event) => {
|
||||
}
|
||||
const extensions = parseExtensions(fields.extensions)
|
||||
const workflow = parseVideoWorkflow(fields.workflow)
|
||||
const useIdentityRefs = workflow === 'v2' && fields.useIdentityRefs === 'true' && referenceImages.length > 0
|
||||
const useIdentityRefs = workflow === 'v2' && fields.useIdentityRefs === 'true'
|
||||
|
||||
const { width, height } = resolveOutputSize(fields.aspect, image.data, Number(fields.width), Number(fields.height))
|
||||
const turbo = fields.turbo !== 'false'
|
||||
@@ -134,15 +141,17 @@ export default defineEventHandler(async (event) => {
|
||||
const destFolder = library.folders.find(folder => folder.id === folderId)
|
||||
const folderLocked = Boolean(destFolder?.protected && !destFolder.unlocked)
|
||||
assertFolderExists(event, folderId)
|
||||
const still = await saveStill({
|
||||
ownerKey,
|
||||
folderId,
|
||||
filename: image.filename,
|
||||
data: image.data,
|
||||
width,
|
||||
height,
|
||||
hideInput
|
||||
})
|
||||
const still = isPipelineFrameFilename(image.filename)
|
||||
? null
|
||||
: await saveStill({
|
||||
ownerKey,
|
||||
folderId,
|
||||
filename: image.filename,
|
||||
data: image.data,
|
||||
width,
|
||||
height,
|
||||
hideInput
|
||||
})
|
||||
|
||||
const chainTotal = 1 + extensions.length
|
||||
const job = createJob()
|
||||
@@ -167,9 +176,9 @@ export default defineEventHandler(async (event) => {
|
||||
fps,
|
||||
samplerName,
|
||||
scheduler,
|
||||
thumb: image.data,
|
||||
stillId: still.id,
|
||||
stillFilename: still.filename,
|
||||
thumb: isPipelineFrameFilename(image.filename) ? undefined : image.data,
|
||||
stillId: still?.id,
|
||||
stillFilename: still?.filename,
|
||||
duration: durationSeconds,
|
||||
sound,
|
||||
draftId: (fields.draftId || '').trim() || undefined,
|
||||
@@ -285,7 +294,7 @@ type GenerateParams = {
|
||||
workflow: 'v1' | 'v2'
|
||||
duration: number
|
||||
useIdentityRefs: boolean
|
||||
referenceImages: { filename: string; data: Buffer; type?: string }[]
|
||||
referenceImages: Array<{ filename: string; data: Buffer; type?: string } | null>
|
||||
}
|
||||
|
||||
async function queueMiniMax(
|
||||
@@ -308,15 +317,16 @@ async function queueMiniMax(
|
||||
: 'Queueing MiniMax H3 job...'
|
||||
emitChainJob(job, { type: 'status', message: uploading, progress: 4 })
|
||||
const uploaded = await uploadImage(params.image, job.id)
|
||||
const referenceNames: string[] = []
|
||||
const referenceNames: string[] = ['', '', '', '']
|
||||
const chainIndex = job.library?.chainIndex || 0
|
||||
if (chainIndex === 0) {
|
||||
for (const [index, ref] of (params.referenceImages || []).entries()) {
|
||||
if (!ref?.data?.length) continue
|
||||
const next = await uploadImage({
|
||||
...ref,
|
||||
filename: `ref${index + 1}_${ref.filename || 'identity.png'}`
|
||||
}, job.id)
|
||||
referenceNames.push(next.name)
|
||||
referenceNames[index] = next.name
|
||||
}
|
||||
}
|
||||
if (job.library) {
|
||||
@@ -378,7 +388,9 @@ async function queueMiniMax(
|
||||
extendPart1Path: job.library.extendPart1Path,
|
||||
familyId: job.library.familyId,
|
||||
parentClipId: job.library.parentClipId,
|
||||
chainIndex: job.library.chainIndex
|
||||
chainIndex: job.library.chainIndex,
|
||||
stillId: job.library.stillId,
|
||||
sound: job.library.sound
|
||||
})
|
||||
}
|
||||
emitChainJob(job, { type: 'status', message: 'Job queued on ComfyUI', progress: 8 })
|
||||
@@ -430,6 +442,7 @@ async function runGeneration(
|
||||
job.library.chainStep = i + 2
|
||||
job.library.chainLabel = `Extension ${i + 1}`
|
||||
job.library.extendPart1Path = undefined
|
||||
job.library.thumb = undefined
|
||||
|
||||
emitChainJob(job, { type: 'status', message: 'Waiting 3s buffer...', progress: 1 })
|
||||
await sleep(3000)
|
||||
|
||||
Reference in New Issue
Block a user