Add Image Iterate: nested multi-prompt still families.
Iterate runs a series of prompts as generate (no still), edit (still A), or compose (A+B), saves each output under one library collection like video extensions, and defaults to iterating from the original still.
This commit is contained in:
+120
-38
@@ -24,6 +24,12 @@
|
||||
<p class="text-sm text-zinc-400">{{ studioMode === 'editv2'
|
||||
? (v2Mode === 'generate'
|
||||
? 'Generate: no reference image. Prompt only.'
|
||||
: v2Mode === 'iterate'
|
||||
? (file
|
||||
? (editRefFile
|
||||
? 'Iterate: each prompt runs as Compose from stills A and B (or chain from the last output). All results nest in one library collection.'
|
||||
: 'Iterate: each prompt runs from still A (batch) or from the last output (chain). All results nest in one library collection.')
|
||||
: 'Iterate: each prompt is a separate generate. All results nest in one library collection like video extensions.')
|
||||
: v2Mode === 'refine'
|
||||
? 'Refine: paint a mask on Still A. Prompt only what should change in the painted area. Strength is denoise in that region.'
|
||||
: v2Mode === 'compose'
|
||||
@@ -35,7 +41,7 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="!(studioMode === 'editv2' && v2Mode === 'generate')"
|
||||
v-if="!(studioMode === 'editv2' && (v2Mode === 'generate' || (v2Mode === 'iterate' && !file && !inputStillId)))"
|
||||
class="relative cursor-pointer rounded-2xl border border-dashed border-white/15 bg-zinc-950/50 p-4 transition hover:border-amber-300/50"
|
||||
:class="{ 'border-amber-300/70 bg-amber-400/5': dragging }"
|
||||
@dragover.prevent="dragging = true"
|
||||
@@ -71,7 +77,14 @@
|
||||
v-else-if="studioMode === 'editv2' && v2Mode === 'generate' && (file || inputStillId)"
|
||||
class="rounded-2xl border border-white/10 bg-zinc-950/40 px-4 py-3 text-sm text-zinc-400"
|
||||
>
|
||||
Still A is loaded for Edit / Compose / Refine. Generate ignores it and uses the prompt only.
|
||||
Still A is loaded for Edit / Compose / Refine / Iterate. Generate ignores it and uses the prompt only.
|
||||
</div>
|
||||
<div
|
||||
v-else-if="studioMode === 'editv2' && v2Mode === 'iterate'"
|
||||
class="rounded-2xl border border-dashed border-white/15 bg-zinc-950/40 px-4 py-3 text-sm text-zinc-400"
|
||||
>
|
||||
<button type="button" class="font-medium text-amber-100 hover:underline" @click="openPicker('main')">Optional · add still A</button>
|
||||
<span class="mt-1 block text-zinc-500">No still = text generate iterations. With a still = edit (or compose if you add still B).</span>
|
||||
</div>
|
||||
|
||||
<div v-if="file || inputStillId" class="mt-2 flex min-w-0 items-center gap-2">
|
||||
@@ -144,7 +157,17 @@
|
||||
>
|
||||
Generate
|
||||
</button>
|
||||
<label v-if="v2Mode === 'compose'" class="ml-auto text-xs">
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-full border px-3 py-1 text-xs font-medium disabled:cursor-not-allowed disabled:opacity-40"
|
||||
:class="v2Mode === 'iterate' ? 'border-amber-300/70 bg-amber-400/10 text-amber-100' : 'border-white/10 text-zinc-400 hover:text-white'"
|
||||
:disabled="v2ModeLocked && v2Mode !== 'iterate'"
|
||||
:title="v2ModeLocked && v2Mode !== 'iterate' ? 'Remove extra passes to change graphs' : ''"
|
||||
@click="setV2Mode('iterate')"
|
||||
>
|
||||
Iterate
|
||||
</button>
|
||||
<label v-if="v2Mode === 'compose' || (v2Mode === 'iterate' && editRefFile)" class="ml-auto text-xs">
|
||||
<span class="mr-2 text-zinc-500">Task</span>
|
||||
<select
|
||||
v-model="v2Task"
|
||||
@@ -158,9 +181,9 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div v-if="studioMode === 'edit' || (studioMode === 'editv2' && v2Mode === 'compose')" class="rounded-2xl border border-dashed border-white/15 bg-zinc-950/50 p-4">
|
||||
<div v-if="studioMode === 'edit' || (studioMode === 'editv2' && (v2Mode === 'compose' || (v2Mode === 'iterate' && file)))" class="rounded-2xl border border-dashed border-white/15 bg-zinc-950/50 p-4">
|
||||
<div class="mb-2 flex items-center justify-between gap-2">
|
||||
<p class="text-sm font-medium text-zinc-300">{{ studioMode === 'editv2' ? 'Still B · required' : 'Image 2 · optional' }}</p>
|
||||
<p class="text-sm font-medium text-zinc-300">{{ studioMode === 'editv2' && v2Mode === 'compose' ? 'Still B · required' : studioMode === 'editv2' ? 'Still B · optional' : 'Image 2 · optional' }}</p>
|
||||
<button
|
||||
v-if="editRefFile"
|
||||
type="button"
|
||||
@@ -203,7 +226,7 @@
|
||||
|
||||
<div>
|
||||
<div class="mb-2 flex flex-wrap items-center justify-between gap-2">
|
||||
<label class="text-sm font-medium text-zinc-300">{{ studioMode === 'editv2' && v2Mode === 'generate' ? 'Generate prompt' : studioMode === 'editv2' && v2Mode === 'refine' ? 'Refine prompt' : studioMode === 'edit' || studioMode === 'editv2' ? 'Edit prompt' : 'Motion & scene prompt' }}</label>
|
||||
<label class="text-sm font-medium text-zinc-300">{{ studioMode === 'editv2' && v2Mode === 'generate' ? 'Generate prompt' : studioMode === 'editv2' && v2Mode === 'iterate' ? 'Iteration 1' : studioMode === 'editv2' && v2Mode === 'refine' ? 'Refine prompt' : studioMode === 'edit' || studioMode === 'editv2' ? 'Edit prompt' : 'Motion & scene prompt' }}</label>
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<button
|
||||
v-if="identityPrompting"
|
||||
@@ -292,6 +315,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<p v-if="studioMode === 'editv2' && v2Mode === 'generate'" class="mt-3 text-xs text-zinc-500">No reference image. Prompt only.</p>
|
||||
<p v-else-if="studioMode === 'editv2' && v2Mode === 'iterate'" class="mt-3 text-xs text-zinc-500">Add more iterations below. Everything saves as one nested library collection.</p>
|
||||
<div v-if="studioMode === 'editv2' && v2Mode === 'refine'" class="mt-3 space-y-2">
|
||||
<p class="text-xs text-zinc-500">Prompt only what should change in the painted area.</p>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
@@ -345,14 +369,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="studioMode === 'edit' || v2PassChaining" class="mt-3 space-y-3">
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<div v-if="!(v2Mode === 'iterate' && !file)" class="grid grid-cols-2 gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-xl border px-3 py-2 text-left text-sm transition"
|
||||
:class="imagePassMode === 'batch' ? 'border-amber-300 bg-amber-400/10 text-amber-100' : 'border-white/10 hover:border-white/20'"
|
||||
@click="imagePassMode = 'batch'"
|
||||
>
|
||||
<span class="block font-semibold">Batch</span>
|
||||
<span class="block font-semibold">{{ v2Mode === 'iterate' ? 'From original' : 'Batch' }}</span>
|
||||
<span class="text-[11px] leading-snug text-zinc-400">Each prompt from the start still</span>
|
||||
</button>
|
||||
<button
|
||||
@@ -361,7 +385,7 @@
|
||||
:class="imagePassMode === 'chain' ? 'border-amber-300 bg-amber-400/10 text-amber-100' : 'border-white/10 hover:border-white/20'"
|
||||
@click="imagePassMode = 'chain'"
|
||||
>
|
||||
<span class="block font-semibold">Chain</span>
|
||||
<span class="block font-semibold">{{ v2Mode === 'iterate' ? 'From last' : 'Chain' }}</span>
|
||||
<span class="text-[11px] leading-snug text-zinc-400">Each pass from the last output</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -383,7 +407,7 @@
|
||||
class="rounded-2xl border border-white/10 bg-zinc-950/50 p-4"
|
||||
>
|
||||
<div class="mb-3 flex items-center justify-between gap-2">
|
||||
<p class="text-sm font-medium text-zinc-200">{{ imagePassMode === 'batch' ? 'Prompt' : 'Pass' }} {{ index + 2 }}</p>
|
||||
<p class="text-sm font-medium text-zinc-200">{{ v2Mode === 'iterate' ? 'Iteration' : imagePassMode === 'batch' ? 'Prompt' : 'Pass' }} {{ index + 2 }}</p>
|
||||
<button
|
||||
type="button"
|
||||
class="text-xs text-red-300 hover:text-red-200"
|
||||
@@ -844,7 +868,7 @@
|
||||
compact
|
||||
:disabled="v2Turbo"
|
||||
/>
|
||||
<template v-if="v2Mode !== 'generate'">
|
||||
<template v-if="v2Mode !== 'generate' && !(v2Mode === 'iterate' && !file)">
|
||||
<LampToggle :model-value="v2ScaleOn" label="Scale to MP" @update:model-value="setV2ScaleOn" />
|
||||
<Thumbwheel
|
||||
v-model="v2Megapixels"
|
||||
@@ -1982,7 +2006,7 @@
|
||||
<p class="truncate text-xs text-zinc-500">{{ stillMetaLine(entry.stillGroup.head) }}</p>
|
||||
<div class="mt-2 flex flex-wrap items-center gap-3">
|
||||
<button v-if="entry.stillGroup.parts.length > 1" type="button" class="text-xs text-amber-200" @click="toggleFamily(entry.stillGroup.key)">
|
||||
{{ expandedFamilies[entry.stillGroup.key] ? 'Collapse' : `Expand ${entry.stillGroup.parts.length} passes` }}
|
||||
{{ expandedFamilies[entry.stillGroup.key] ? 'Collapse' : `Expand ${entry.stillGroup.parts.length} ${entry.stillGroup.head.settings?.mode === 'iterate' ? 'iterations' : 'passes'}` }}
|
||||
</button>
|
||||
<button type="button" class="text-xs text-amber-300" @click="openStill(entry.stillGroup.head)">Open</button>
|
||||
<button type="button" class="text-xs text-amber-300" @click="useStillAsInput(entry.stillGroup.head)">Use as input</button>
|
||||
@@ -3198,38 +3222,52 @@ const stillBHint = computed(() => {
|
||||
const editV2Blocked = computed(() => {
|
||||
if (!folderId.value) return true
|
||||
if (!prompt.value.trim() && !imageFillWithoutPrompt.value) return true
|
||||
if (v2Mode.value !== 'generate' && !file.value) return true
|
||||
if (v2Mode.value !== 'generate' && v2Mode.value !== 'iterate' && !file.value) return true
|
||||
if (v2Mode.value === 'compose' && !editRefFile.value) return true
|
||||
if (v2Mode.value === 'refine' && !refineMaskDirty.value) return true
|
||||
if (v2PassChaining.value && editPassQueue.value.some(item => !item.prompt.trim())) return true
|
||||
if (v2Mode.value === 'iterate' && !editPassQueue.value.length) return true
|
||||
return false
|
||||
})
|
||||
const editV2BlockReason = computed(() => {
|
||||
if (v2Mode.value !== 'generate' && !file.value) return 'Load still A first.'
|
||||
if (v2Mode.value !== 'generate' && v2Mode.value !== 'iterate' && !file.value) return 'Load still A first.'
|
||||
if (v2Mode.value === 'compose' && !editRefFile.value) return 'Compose requires still B. This will not fall back to one-image generation.'
|
||||
if (v2Mode.value === 'refine' && !refineMaskDirty.value) return 'Paint a mask on Still A first. Refine will not fall back to Edit.'
|
||||
if (!prompt.value.trim() && !imageFillWithoutPrompt.value) {
|
||||
return v2Mode.value === 'generate'
|
||||
return v2Mode.value === 'generate' || (v2Mode.value === 'iterate' && !file.value)
|
||||
? 'Write a prompt first.'
|
||||
: 'Write a prompt, or pick Landscape / Portrait / Square to fill the frame.'
|
||||
}
|
||||
if (v2Mode.value === 'iterate' && !editPassQueue.value.length) return 'Add at least one more iteration prompt.'
|
||||
if (v2PassChaining.value && editPassQueue.value.some(item => !item.prompt.trim())) return 'Each extra pass needs a prompt.'
|
||||
if (!folderId.value) return 'Choose a library folder before generating.'
|
||||
if (!imageComfyConfigured.value && !comfyOk.value) return 'Image v2 is not configured. Set COMFY_HOST.'
|
||||
return ''
|
||||
})
|
||||
const v2PassChaining = computed(() => studioMode.value === 'editv2' && (v2Mode.value === 'edit' || v2Mode.value === 'compose'))
|
||||
const v2PassChaining = computed(() => studioMode.value === 'editv2' && (v2Mode.value === 'edit' || v2Mode.value === 'compose' || v2Mode.value === 'iterate'))
|
||||
const v2ModeLocked = computed(() => v2PassChaining.value && editPassQueue.value.length > 0)
|
||||
const extraPassButtonLabel = computed(() => {
|
||||
if (v2Mode.value === 'iterate') return '+ Iteration'
|
||||
if (imagePassMode.value === 'batch') return '+ Prompt'
|
||||
return studioMode.value === 'editv2' && v2Mode.value === 'compose' ? '+ Compose pass' : '+ Edit pass'
|
||||
})
|
||||
const imageBatchButtonHint = computed(() => {
|
||||
const n = 1 + editPassQueue.value.length
|
||||
if (imageBatchScript.value.trim() && n > 1) return `${n} prompts on the start still. Same format as a video shot list.`
|
||||
return 'Paste shot 1, shot 2, shot 3. Each image is a new prompt on the original still.'
|
||||
if (imageBatchScript.value.trim() && n > 1) {
|
||||
return v2Mode.value === 'iterate'
|
||||
? `${n} iterations. Same format as a video shot list.`
|
||||
: `${n} prompts on the start still. Same format as a video shot list.`
|
||||
}
|
||||
return v2Mode.value === 'iterate'
|
||||
? 'Paste shot 1, shot 2, shot 3. Each line becomes one nested still.'
|
||||
: 'Paste shot 1, shot 2, shot 3. Each image is a new prompt on the original still.'
|
||||
})
|
||||
const extraPassHint = computed(() => {
|
||||
if (v2Mode.value === 'iterate') {
|
||||
if (!file.value) return 'Each prompt is a separate generate. Outputs nest under one library collection.'
|
||||
if (imagePassMode.value === 'batch') return 'Every prompt runs from the start still. Outputs nest under one library collection.'
|
||||
return 'Each prompt runs from the last output. Outputs nest under one library collection.'
|
||||
}
|
||||
if (imagePassMode.value === 'batch') {
|
||||
return 'Every prompt runs from the start still. Paste a shot list, or add prompts one at a time. Outputs do not feed the next prompt.'
|
||||
}
|
||||
@@ -3239,6 +3277,7 @@ const extraPassHint = computed(() => {
|
||||
return 'Each extra pass is another Edit on the last output. You cannot switch graphs between passes.'
|
||||
})
|
||||
const extraPassPlaceholder = computed(() => {
|
||||
if (v2Mode.value === 'iterate') return 'Next iteration prompt…'
|
||||
if (imagePassMode.value === 'batch') return 'Another prompt for the same start still…'
|
||||
return studioMode.value === 'editv2' && v2Mode.value === 'compose'
|
||||
? 'Next compose prompt, applied to the previous pass output…'
|
||||
@@ -3247,14 +3286,25 @@ const extraPassPlaceholder = computed(() => {
|
||||
const editV2SubmitLabel = computed(() => {
|
||||
const occupied = videoBusy.value || editBusy.value || studioJobs.value.some(job => job.status === 'running')
|
||||
const n = v2PassChaining.value ? editPassQueue.value.length : 0
|
||||
const label = v2Mode.value === 'generate' ? 'Generate image' : v2Mode.value === 'refine' ? 'Refine image' : v2Mode.value === 'compose' ? 'Compose image' : 'Edit image'
|
||||
const label = v2Mode.value === 'generate'
|
||||
? 'Generate image'
|
||||
: v2Mode.value === 'iterate'
|
||||
? 'Iterate'
|
||||
: v2Mode.value === 'refine'
|
||||
? 'Refine image'
|
||||
: v2Mode.value === 'compose'
|
||||
? 'Compose image'
|
||||
: 'Edit image'
|
||||
if (!occupied) {
|
||||
if (v2Mode.value === 'iterate') return n ? `Iterate × ${n + 1}` : 'Iterate'
|
||||
if (!n) return label
|
||||
if (imagePassMode.value === 'batch') return n === 1 ? `${label} × 2` : `${label} × ${n + 1}`
|
||||
return n === 1 ? `${label} + 1 pass` : `${label} + ${n} passes`
|
||||
}
|
||||
if (n) {
|
||||
return imagePassMode.value === 'batch' ? `Queue ${n + 1} from start still` : `Queue ${n + 1} passes`
|
||||
return v2Mode.value === 'iterate'
|
||||
? `Queue ${n + 1} iterations`
|
||||
: imagePassMode.value === 'batch' ? `Queue ${n + 1} from start still` : `Queue ${n + 1} passes`
|
||||
}
|
||||
return `Queue ${label.toLowerCase()}`
|
||||
})
|
||||
@@ -3646,7 +3696,8 @@ function stillFamilyScript(parts: LibraryStill[]) {
|
||||
function stillMetaLine(still: LibraryStill) {
|
||||
const res = still.width && still.height ? `${still.width}×${still.height}` : 'image'
|
||||
const mode = stillModeLabel(still)
|
||||
const pass = typeof still.chainIndex === 'number' ? `pass ${still.chainIndex + 1}` : ''
|
||||
const unit = still.settings?.mode === 'iterate' ? 'iteration' : 'pass'
|
||||
const pass = typeof still.chainIndex === 'number' ? `${unit} ${still.chainIndex + 1}` : ''
|
||||
return [res, mode, pass].filter(Boolean).join(' · ')
|
||||
}
|
||||
|
||||
@@ -4618,7 +4669,15 @@ function applyGenerationPreset(preset: GenerationPreset) {
|
||||
if (preset.kind === 'imagev2') {
|
||||
const settings = preset.settings as ImageV2PresetSettings
|
||||
persistImageV2LoraStack(imageV2LoraStack.value, v2Engine.value)
|
||||
v2Mode.value = settings.mode === 'compose' ? 'compose' : settings.mode === 'refine' ? 'refine' : settings.mode === 'generate' ? 'generate' : 'edit'
|
||||
v2Mode.value = settings.mode === 'compose'
|
||||
? 'compose'
|
||||
: settings.mode === 'refine'
|
||||
? 'refine'
|
||||
: settings.mode === 'generate'
|
||||
? 'generate'
|
||||
: settings.mode === 'iterate'
|
||||
? 'iterate'
|
||||
: 'edit'
|
||||
if (v2Mode.value !== 'edit' && v2Mode.value !== 'compose') clearEditPasses()
|
||||
v2Engine.value = parseImageV2Engine(settings.engine, 'flux')
|
||||
v2Task.value = v2Mode.value === 'compose' ? (settings.task || 'scene') : v2Mode.value === 'refine' ? 'refine' : v2Mode.value === 'generate' ? 't2i' : 'scene'
|
||||
@@ -5419,7 +5478,7 @@ async function restoreStudioEditJob(payload: {
|
||||
loraStack?: LoraStackItem[]
|
||||
negative?: string
|
||||
imagePipeline?: 'v1' | 'v2'
|
||||
v2Mode?: 'edit' | 'compose' | 'refine' | 'generate'
|
||||
v2Mode?: 'edit' | 'compose' | 'refine' | 'generate' | 'iterate'
|
||||
v2Task?: 'scene' | 'identity' | 'outfit' | 'face_lock' | 'refine' | 't2i'
|
||||
engine?: 'flux' | 'krea'
|
||||
snofsModel?: number
|
||||
@@ -5445,7 +5504,7 @@ async function restoreStudioEditJob(payload: {
|
||||
if (v2) {
|
||||
studioMode.value = 'editv2'
|
||||
outputFocus.value = 'edit'
|
||||
const mode = payload.v2Mode === 'compose' || payload.v2Mode === 'refine' || payload.v2Mode === 'generate'
|
||||
const mode = payload.v2Mode === 'compose' || payload.v2Mode === 'refine' || payload.v2Mode === 'generate' || payload.v2Mode === 'iterate'
|
||||
? payload.v2Mode
|
||||
: 'edit'
|
||||
setV2Mode(mode)
|
||||
@@ -5552,7 +5611,7 @@ async function restoreStudioPayload(kind: string, payload: {
|
||||
shotLoraStacks?: LoraStackItem[][]
|
||||
negative?: string
|
||||
imagePipeline?: 'v1' | 'v2'
|
||||
v2Mode?: 'edit' | 'compose' | 'refine' | 'generate'
|
||||
v2Mode?: 'edit' | 'compose' | 'refine' | 'generate' | 'iterate'
|
||||
v2Task?: 'scene' | 'identity' | 'outfit' | 'face_lock' | 'refine' | 't2i'
|
||||
engine?: 'flux' | 'krea'
|
||||
snofsModel?: number
|
||||
@@ -6332,7 +6391,7 @@ function applyStillSettings(still: LibraryStill) {
|
||||
if (dest === 'imagev2') {
|
||||
studioMode.value = 'editv2'
|
||||
outputFocus.value = 'edit'
|
||||
const mode = settings?.mode === 'compose' || settings?.mode === 'refine' || settings?.mode === 'generate'
|
||||
const mode = settings?.mode === 'compose' || settings?.mode === 'refine' || settings?.mode === 'generate' || settings?.mode === 'iterate'
|
||||
? settings.mode
|
||||
: 'edit'
|
||||
setV2Mode(mode)
|
||||
@@ -6392,6 +6451,7 @@ function stillUseAsInputMessage(still: LibraryStill) {
|
||||
const dest = inferStillPipeline(still)
|
||||
const mode = still.settings?.mode
|
||||
if (dest === 'imagev2' && mode === 'generate') return 'Generate settings and still loaded. Switch to Edit anytime — the image is already in Still A.'
|
||||
if (dest === 'imagev2' && mode === 'iterate') return 'Iterate settings and still loaded.'
|
||||
if (dest === 'imagev2' && mode === 'compose') {
|
||||
return still.settings?.referenceStillId
|
||||
? 'Compose settings loaded with stills A and B.'
|
||||
@@ -6976,6 +7036,7 @@ function absorbPastedImageBatch() {
|
||||
}
|
||||
|
||||
function imagePassUnit() {
|
||||
if (v2Mode.value === 'iterate') return 'Iteration'
|
||||
return imagePassMode.value === 'batch' ? 'Batch' : 'Pass'
|
||||
}
|
||||
|
||||
@@ -7102,8 +7163,12 @@ function setV2Mode(mode: ImageV2Mode) {
|
||||
if (mode === 'generate') {
|
||||
v2Task.value = 't2i'
|
||||
}
|
||||
if (mode === 'iterate') {
|
||||
v2Task.value = 'scene'
|
||||
imagePassMode.value = 'batch'
|
||||
}
|
||||
if (v2Engine.value === 'krea' && mode === 'edit') v2Denoise.value = IMAGE_V2_KREA_EDIT_DENOISE
|
||||
if (v2Engine.value === 'krea' && mode === 'compose') v2Denoise.value = IMAGE_V2_KREA_COMPOSE_DENOISE
|
||||
if (v2Engine.value === 'krea' && (mode === 'compose' || mode === 'iterate')) v2Denoise.value = IMAGE_V2_KREA_COMPOSE_DENOISE
|
||||
}
|
||||
|
||||
function setV2Engine(engine: ImageV2Engine) {
|
||||
@@ -7228,10 +7293,17 @@ async function editImageV2() {
|
||||
await ensureGenerationNotifyPermission()
|
||||
const body = new FormData()
|
||||
body.append('mode', v2Mode.value)
|
||||
body.append('task', v2Mode.value === 'generate' ? 't2i' : v2Mode.value === 'refine' ? 'refine' : v2Mode.value === 'compose' ? v2Task.value : 'scene')
|
||||
const iterateGenerate = v2Mode.value === 'iterate' && !file.value
|
||||
body.append('task', v2Mode.value === 'generate' || iterateGenerate
|
||||
? 't2i'
|
||||
: v2Mode.value === 'refine'
|
||||
? 'refine'
|
||||
: (v2Mode.value === 'compose' || (v2Mode.value === 'iterate' && editRefFile.value))
|
||||
? v2Task.value
|
||||
: 'scene')
|
||||
if (v2Mode.value !== 'generate' && file.value) body.append('image_a', file.value)
|
||||
if (v2Mode.value === 'compose' && editRefFile.value) body.append('image_b', editRefFile.value)
|
||||
if (v2Mode.value === 'refine' || (v2Engine.value === 'krea' && v2Mode.value !== 'generate')) {
|
||||
if ((v2Mode.value === 'compose' || v2Mode.value === 'iterate') && editRefFile.value) body.append('image_b', editRefFile.value)
|
||||
if (v2Mode.value === 'refine' || (v2Engine.value === 'krea' && v2Mode.value !== 'generate' && !iterateGenerate)) {
|
||||
if (v2Mode.value === 'refine') {
|
||||
const maskBlob = await refinePainter.value?.exportPng()
|
||||
if (!maskBlob) {
|
||||
@@ -7242,7 +7314,7 @@ async function editImageV2() {
|
||||
}
|
||||
body.append('strength', String(clampImageV2Denoise(v2Denoise.value)))
|
||||
}
|
||||
if (v2Mode.value === 'generate') {
|
||||
if (v2Mode.value === 'generate' || iterateGenerate) {
|
||||
const size = generateSizeForAspect(aspect.value)
|
||||
body.append('width', String(size.width))
|
||||
body.append('height', String(size.height))
|
||||
@@ -7260,7 +7332,7 @@ async function editImageV2() {
|
||||
body.append('consistency_clip', String(imageV2EngineLoras().find(item => isImageV2ConsistencyLora(item.name))?.strengthClip ?? 0))
|
||||
body.append('steps', String(clampImageSteps(v2Steps.value, v2Engine.value === 'krea' ? IMAGE_V2_KREA_STEPS : IMAGE_V2_STEPS_DEFAULT)))
|
||||
body.append('cfg', String(clampImageCfg(v2Cfg.value, v2Engine.value === 'krea' ? IMAGE_V2_KREA_CFG : IMAGE_V2_CFG_DEFAULT)))
|
||||
if (v2Mode.value !== 'generate') {
|
||||
if (v2Mode.value !== 'generate' && !iterateGenerate) {
|
||||
body.append('scaleToTotalPixels', String(v2ScaleOn.value))
|
||||
if (v2ScaleOn.value) body.append('megapixels', String(clampImageScaleMegapixels(v2Megapixels.value, 1)))
|
||||
}
|
||||
@@ -7270,9 +7342,9 @@ async function editImageV2() {
|
||||
body.append('hideInput', String(showPrivacyToggles.value && hideInputPreview.value))
|
||||
body.append('hideThumbnail', String(showPrivacyToggles.value && hideThumbnail.value))
|
||||
body.append('name', clipName.value.trim())
|
||||
if (inputStillId.value) body.append('stillId', inputStillId.value)
|
||||
if (inputStillId.value && file.value) body.append('stillId', inputStillId.value)
|
||||
if (extraPasses.length) body.append('passes', JSON.stringify(extraPasses))
|
||||
body.append('passMode', imagePassMode.value)
|
||||
body.append('passMode', iterateGenerate ? 'batch' : imagePassMode.value)
|
||||
const v2Stack = filterLoraStackForImageEngine(
|
||||
filterLoraStackForStudio(imageV2LoraStack.value, ltxEnabled.value),
|
||||
v2Engine.value
|
||||
@@ -7301,9 +7373,11 @@ async function editImageV2() {
|
||||
if (started.queued) {
|
||||
const n = 1 + extraPasses.length
|
||||
toast(n > 1
|
||||
? (imagePassMode.value === 'batch'
|
||||
? `Queued ${n} Image v2 stills from the start image behind the current job.`
|
||||
: `Queued ${n} Image v2 passes behind the current job.`)
|
||||
? (v2Mode.value === 'iterate'
|
||||
? `Queued ${n} iterations behind the current job.`
|
||||
: imagePassMode.value === 'batch'
|
||||
? `Queued ${n} Image v2 stills from the start image behind the current job.`
|
||||
: `Queued ${n} Image v2 passes behind the current job.`)
|
||||
: (v2Engine.value === 'krea' ? 'Queued Krea generate behind the current job.' : 'Queued Image v2 behind the current job.'))
|
||||
await refreshStudioQueue()
|
||||
return
|
||||
@@ -7324,7 +7398,15 @@ async function editImageV2() {
|
||||
editChainLabel.value = extraPasses.length ? `${imagePassUnit()} 1` : ''
|
||||
editOverallProgress.value = 0
|
||||
editCompletedChainStep.value = 0
|
||||
const passNoun = v2Mode.value === 'compose' ? 'Compose' : v2Mode.value === 'refine' ? 'Refine' : v2Mode.value === 'generate' ? 'Generate' : 'Edit'
|
||||
const passNoun = v2Mode.value === 'iterate'
|
||||
? 'Iteration'
|
||||
: v2Mode.value === 'compose'
|
||||
? 'Compose'
|
||||
: v2Mode.value === 'refine'
|
||||
? 'Refine'
|
||||
: v2Mode.value === 'generate'
|
||||
? 'Generate'
|
||||
: 'Edit'
|
||||
editActiveChainPlan.value = imagePassPlan(prompt.value.trim(), extraPasses, passNoun)
|
||||
startTimer('edit')
|
||||
editDownloadName.value = downloadName
|
||||
|
||||
Reference in New Issue
Block a user