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:
Towsty
2026-08-26 22:56:37 -05:00
co-authored by Cursor
parent f54e8da857
commit e334cb7a7a
28 changed files with 1125 additions and 293 deletions
+23 -22
View File
@@ -1,6 +1,7 @@
// Nitro bundles these JSON graphs into the production server output.
import workflowV1 from '../assets/workflow_minimax_video.json'
import workflowV2 from '../assets/workflow_minimax_video_v2.json'
import { buildIdentityPrompt } from '~/utils/identityPrompt'
export type VideoWorkflowId = 'v1' | 'v2'
@@ -69,8 +70,10 @@ export function buildWorkflow(params: GenerateParams) {
const graph = structuredClone(templateFor(version))
const width = snap32(params.width)
const height = snap32(params.height)
const refs = (params.referenceImageNames || []).map(name => String(name || '').trim()).filter(Boolean).slice(0, 4)
const useRefs = version === 'v2' && params.useIdentityRefs === true && refs.length > 0
const refs = Array.from({ length: 4 }, (_, index) => String(params.referenceImageNames?.[index] || '').trim())
const extraPictures = refs.flatMap((name, index) => name ? [index + 2] : [])
const useRefs = version === 'v2' && params.useIdentityRefs === true
const graphPrompt = useRefs ? buildIdentityPrompt(params.prompt, extraPictures) : params.prompt
for (const [id, node] of Object.entries(graph)) {
if (IMAGE_CLASSES.has(node.class_type) && 'image' in node.inputs && id === '114') {
@@ -78,19 +81,19 @@ export function buildWorkflow(params: GenerateParams) {
}
if (PROMPT_CLASSES.has(node.class_type) || node.class_type.includes('Qwen3')) {
if ('prompt' in node.inputs) node.inputs.prompt = params.prompt
if ('text' in node.inputs) node.inputs.text = params.prompt
if ('prompt' in node.inputs) node.inputs.prompt = graphPrompt
if ('text' in node.inputs) node.inputs.text = graphPrompt
}
if (node.class_type === 'MiniMaxH3ImageToVideo') {
node.inputs.prompt = params.prompt
node.inputs.prompt = graphPrompt
if (typeof node.inputs.width === 'number') node.inputs.width = width
if (typeof node.inputs.height === 'number') node.inputs.height = height
if (typeof node.inputs.length === 'number') node.inputs.length = params.length
}
if (node.class_type === 'MiniMaxH3ReferenceToVideo') {
node.inputs.prompt = params.prompt
node.inputs.prompt = graphPrompt
if (!Array.isArray(node.inputs.length)) node.inputs.length = ['174', 1]
}
@@ -190,7 +193,7 @@ export function buildWorkflow(params: GenerateParams) {
}
}
if (version === 'v2') applyV2IdentityPath(graph, params, useRefs, refs)
if (version === 'v2') applyV2IdentityPath(graph, params, useRefs, refs, graphPrompt)
if (params.sound === false) {
delete graph['105:23']
@@ -207,33 +210,31 @@ function applyV2IdentityPath(
graph: WorkflowGraph,
params: GenerateParams,
useRefs: boolean,
refs: string[]
refs: string[],
graphPrompt: string
) {
if (useRefs && graph['155'] && graph['167'] && graph['168']) {
graph['167'].inputs.latent_image = ['155', 1]
graph['168'].inputs.conditioning = ['155', 0]
graph['155'].inputs.prompt = params.prompt
graph['155'].inputs.prompt = graphPrompt
graph['155'].inputs.length = ['174', 1]
delete graph['173']
if (graph['169']?.inputs) {
graph['169'].inputs.unet_name = 'minimax_h3_ref2va_pruned_int8_convrot.safetensors'
}
if (params.turbo && graph['176']?.inputs) {
graph['176'].inputs.lora_name = 'minimax_h3_ref2v_turbo_4step_v0.1_comfyui_bf16.safetensors'
}
V2_REF_LOADERS.forEach((id, index) => {
const name = refs[index]
const inputKey = `ref_images.ref_image_${index + 1}`
if (name && graph[id]) {
graph[id].inputs.image = name
} else {
delete graph[id]
if (graph['155']?.inputs) delete graph['155'].inputs[inputKey]
return
}
delete graph[id]
if (graph['155']?.inputs) delete graph['155'].inputs[`ref_images.ref_image_${index + 1}`]
})
graph['v2:cfg'] = {
class_type: 'FluxGuidance',
inputs: {
guidance: params.cfg,
conditioning: ['155', 0]
},
_meta: { title: 'Guidance scale' }
}
graph['168'].inputs.conditioning = ['v2:cfg', 0]
if (graph['150']?.inputs) graph['150'].inputs.value = true
return
}