Overhaul Studio controls and add image batch from one still.
Video and Image pickers, thumbwheels, aspect icons, and a Scale to MP paddle; extra prompts default to batch so each run starts from the original image. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,7 +3,7 @@ import { parsePostedLoraStack, listStudioLoras, persistLoraFields } from '~/serv
|
||||
import { assertImageScaleToTotalPixelsNode, comfyConfigured } from '~/server/utils/comfy'
|
||||
import { imageDimensions } from '~/server/utils/resolution'
|
||||
import { parseImageAspect } from '~/utils/imageAspect'
|
||||
import { clampImageCfg, clampImageScaleMegapixels, clampImageSteps, parseImageScaleToTotalPixels } from '~/utils/generationPresets'
|
||||
import { clampImageCfg, clampImageScaleMegapixels, clampImageSteps, parseImagePassMode, parseImageScaleToTotalPixels } from '~/utils/generationPresets'
|
||||
|
||||
function parsePasses(raw: string | undefined) {
|
||||
if (!raw) return [] as { prompt: string }[]
|
||||
@@ -35,6 +35,7 @@ export default defineEventHandler(async (event) => {
|
||||
|
||||
const prompt = (fields.prompt || '').trim()
|
||||
const extraPasses = parsePasses(fields.passes)
|
||||
const passMode = parseImagePassMode(fields.passMode)
|
||||
const aspect = parseImageAspect(fields.aspect)
|
||||
if (!image) {
|
||||
throw createError({ statusCode: 400, statusMessage: 'An input image is required' })
|
||||
@@ -152,6 +153,7 @@ export default defineEventHandler(async (event) => {
|
||||
queueAutoRun: false,
|
||||
negative: (fields.negative || '').trim(),
|
||||
passes,
|
||||
passMode,
|
||||
referenceStillId: savedRef?.id,
|
||||
referenceStillFilename: savedRef?.filename,
|
||||
scaleToTotalPixels,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { addStudioJob, kickStudioQueue, listStudioJobs, videoJobsBusy } from '~/
|
||||
import { comfyConfigured } from '~/server/utils/comfy'
|
||||
import { parseImageAspect, generateSizeForAspect } from '~/utils/imageAspect'
|
||||
import { imageDimensions } from '~/server/utils/resolution'
|
||||
import { clampImageCfg, clampImageScaleMegapixels, clampImageSteps } from '~/utils/generationPresets'
|
||||
import { clampImageCfg, clampImageScaleMegapixels, clampImageSteps, parseImagePassMode } from '~/utils/generationPresets'
|
||||
import {
|
||||
IMAGE_V2_CFG_DEFAULT,
|
||||
IMAGE_V2_CONSISTENCY_CLIP,
|
||||
@@ -137,6 +137,7 @@ export default defineEventHandler(async (event) => {
|
||||
)
|
||||
const prompt = String(fields.prompt || '').trim()
|
||||
const extraPasses = parsePasses(fields.passes)
|
||||
const passMode = parseImagePassMode(fields.passMode)
|
||||
const aspect = parseImageAspect(fields.aspect)
|
||||
if (!prompt && (mode === 'generate' || aspect === 'auto')) {
|
||||
throw createError({ statusCode: 400, statusMessage: 'A prompt is required' })
|
||||
@@ -213,7 +214,13 @@ export default defineEventHandler(async (event) => {
|
||||
const cfg = engine === 'krea'
|
||||
? clampImageCfg(fields.cfg, IMAGE_V2_KREA_CFG)
|
||||
: turbo ? IMAGE_V2_TURBO_CFG : clampImageCfg(fields.cfg, IMAGE_V2_CFG_DEFAULT)
|
||||
const megapixels = mode === 'generate' ? 0 : clampImageScaleMegapixels(fields.megapixels ?? fields.scaleMegapixels, 1)
|
||||
const megapixels = mode === 'generate'
|
||||
? 0
|
||||
: fields.scaleToTotalPixels == null
|
||||
? clampImageScaleMegapixels(fields.megapixels ?? fields.scaleMegapixels, 1)
|
||||
: parseBool(fields.scaleToTotalPixels)
|
||||
? clampImageScaleMegapixels(fields.megapixels ?? fields.scaleMegapixels, 1)
|
||||
: 0
|
||||
const seed = fields.seed && String(fields.seed) !== 'random'
|
||||
? Number(fields.seed)
|
||||
: Math.floor(Math.random() * 2_147_483_647)
|
||||
@@ -324,9 +331,10 @@ export default defineEventHandler(async (event) => {
|
||||
queueAutoRun: false,
|
||||
negative: String(fields.negative || '').trim(),
|
||||
passes: extraPasses,
|
||||
passMode,
|
||||
referenceStillId: savedRef?.id,
|
||||
referenceStillFilename: savedRef?.filename,
|
||||
scaleToTotalPixels: mode !== 'generate',
|
||||
scaleToTotalPixels: mode !== 'generate' && megapixels > 0,
|
||||
scaleMegapixels: megapixels,
|
||||
imagePipeline: 'v2',
|
||||
v2Mode,
|
||||
|
||||
@@ -140,7 +140,8 @@ function sanitizeImageV2Settings(raw: unknown): ImageV2PresetSettings {
|
||||
consistencyClip: clampImageV2Strength(rec.consistencyClip ?? rec.consistency_clip, mode === 'generate' ? 0 : IMAGE_V2_CONSISTENCY_CLIP),
|
||||
steps: engine === 'krea' ? clampImageSteps(rec.steps, IMAGE_V2_KREA_STEPS) : turbo ? 8 : clampImageSteps(rec.steps, IMAGE_V2_STEPS_DEFAULT),
|
||||
cfg: engine === 'krea' ? clampImageCfg(rec.cfg, IMAGE_V2_KREA_CFG) : turbo ? 1 : clampImageCfg(rec.cfg, IMAGE_V2_CFG_DEFAULT),
|
||||
megapixels: mode === 'generate' ? undefined : clampImageScaleMegapixels(rec.megapixels ?? rec.scaleMegapixels, 1),
|
||||
megapixels: mode === 'generate' || rec.scaleToTotalPixels === false ? undefined : clampImageScaleMegapixels(rec.megapixels ?? rec.scaleMegapixels, 1),
|
||||
scaleToTotalPixels: mode === 'generate' ? undefined : rec.scaleToTotalPixels === false ? false : true,
|
||||
turbo,
|
||||
strength: mode === 'generate' || (mode !== 'refine' && engine !== 'krea')
|
||||
? undefined
|
||||
|
||||
+17
-10
@@ -25,6 +25,7 @@ export type EditRunParams = {
|
||||
loraStack?: import('~/utils/loras').LoraStackItem[]
|
||||
scaleToTotalPixels?: boolean
|
||||
scaleMegapixels?: number
|
||||
passMode?: 'batch' | 'chain'
|
||||
}
|
||||
|
||||
export async function runEdit(job: Job, params: EditRunParams) {
|
||||
@@ -32,6 +33,8 @@ export async function runEdit(job: Job, params: EditRunParams) {
|
||||
if (!library) throw new Error('Edit job is missing library metadata')
|
||||
const prompts = [params.prompt, ...params.passes.map(item => item.prompt)]
|
||||
const chainTotal = prompts.length
|
||||
const batch = params.passMode !== 'chain'
|
||||
const unit = batch ? 'Batch' : 'Pass'
|
||||
library.chainTotal = chainTotal
|
||||
library.familyId = chainTotal > 1 ? (library.familyId || crypto.randomUUID()) : library.familyId
|
||||
|
||||
@@ -63,7 +66,7 @@ export async function runEdit(job: Job, params: EditRunParams) {
|
||||
for (let index = 0; index < prompts.length; index++) {
|
||||
if (job.status === 'cancelled') throw new Error('Job interrupted.')
|
||||
if (index > 0 && library.stopAfterCurrent === true) break
|
||||
const prompt = index === 0 ? composeFillPrompt(prompts[index], filled.padded) : prompts[index]
|
||||
const prompt = (batch || index === 0) ? composeFillPrompt(prompts[index], filled.padded) : prompts[index]
|
||||
const last = index === prompts.length - 1
|
||||
if (index > 0) {
|
||||
await ensureComfyReady((status) => {
|
||||
@@ -80,7 +83,7 @@ export async function runEdit(job: Job, params: EditRunParams) {
|
||||
library.seed = seed
|
||||
library.chainIndex = index
|
||||
library.chainStep = index + 1
|
||||
library.chainLabel = chainTotal > 1 ? `Pass ${index + 1}` : undefined
|
||||
library.chainLabel = chainTotal > 1 ? `${unit} ${index + 1}` : undefined
|
||||
const reference = index === 0 ? params.reference : null
|
||||
const dual = Boolean(reference)
|
||||
const passName = stillChainName(library.name || '', index)
|
||||
@@ -163,7 +166,7 @@ export async function runEdit(job: Job, params: EditRunParams) {
|
||||
name: passName || undefined,
|
||||
prompt,
|
||||
familyId: library.familyId,
|
||||
parentStillId,
|
||||
parentStillId: batch ? library.stillId : parentStillId,
|
||||
chainIndex: index,
|
||||
settings: {
|
||||
kind: 'image',
|
||||
@@ -180,7 +183,7 @@ export async function runEdit(job: Job, params: EditRunParams) {
|
||||
}
|
||||
})
|
||||
job.stillId = still?.id
|
||||
parentStillId = still?.id
|
||||
if (!batch) parentStillId = still?.id
|
||||
await purgeComfyArtifacts({
|
||||
video: { filename: output.filename, subfolder: output.subfolder, type: output.type },
|
||||
imageName: uploaded.name,
|
||||
@@ -192,16 +195,18 @@ export async function runEdit(job: Job, params: EditRunParams) {
|
||||
if (!last) {
|
||||
emitChainJob(job, {
|
||||
type: 'checkpoint',
|
||||
message: `Pass ${index + 1} saved`,
|
||||
message: `${unit} ${index + 1} of ${chainTotal} saved`,
|
||||
progress: 100,
|
||||
stillId: still?.id,
|
||||
hideThumbnail: job.hideThumbnail,
|
||||
folderLocked: library.folderLocked
|
||||
})
|
||||
current = {
|
||||
filename: still?.filename || `pass_${index + 1}.png`,
|
||||
data: buffer,
|
||||
type: 'image/png'
|
||||
if (!batch) {
|
||||
current = {
|
||||
filename: still?.filename || `pass_${index + 1}.png`,
|
||||
data: buffer,
|
||||
type: 'image/png'
|
||||
}
|
||||
}
|
||||
if (library.stopAfterCurrent === true) break
|
||||
continue
|
||||
@@ -210,7 +215,9 @@ export async function runEdit(job: Job, params: EditRunParams) {
|
||||
job.status = 'complete'
|
||||
emitChainJob(job, {
|
||||
type: 'complete',
|
||||
message: chainTotal > 1 ? 'Edit chain finished on Beast' : 'Edit finished on Beast',
|
||||
message: chainTotal > 1
|
||||
? (batch ? 'Edit batch finished on Beast' : 'Edit chain finished on Beast')
|
||||
: 'Edit finished on Beast',
|
||||
progress: 100,
|
||||
stillId: still?.id,
|
||||
filename: output.filename,
|
||||
|
||||
@@ -37,6 +37,7 @@ export type EditV2RunParams = {
|
||||
referenceStillId?: string
|
||||
loraStack?: import('~/utils/loras').LoraStackItem[]
|
||||
passes?: { prompt: string }[]
|
||||
passMode?: 'batch' | 'chain'
|
||||
}
|
||||
|
||||
export async function runEditV2(job: Job, params: EditV2RunParams) {
|
||||
@@ -61,6 +62,8 @@ export async function runEditV2(job: Job, params: EditV2RunParams) {
|
||||
: []
|
||||
const prompts = [params.prompt, ...extraPasses.map(item => item.prompt)]
|
||||
const chainTotal = prompts.length
|
||||
const batch = params.passMode !== 'chain'
|
||||
const unit = batch ? 'Batch' : 'Pass'
|
||||
library.chainTotal = chainTotal
|
||||
library.familyId = chainTotal > 1 ? (library.familyId || crypto.randomUUID()) : library.familyId
|
||||
|
||||
@@ -83,13 +86,14 @@ export async function runEditV2(job: Job, params: EditV2RunParams) {
|
||||
const { applyImageFill } = await import('~/server/utils/imagePad')
|
||||
const { composeFillPrompt } = await import('~/utils/imageAspect')
|
||||
let current = params.image || null
|
||||
let startPadded = false
|
||||
let mask = params.mask
|
||||
let parentStillId: string | undefined
|
||||
let uploadedRef: { name: string } | null = null
|
||||
let uploadedMask: { name: string } | null = null
|
||||
|
||||
await ensureComfyLoraNames('image')
|
||||
if (!generate) await assertImageScaleToTotalPixelsNode()
|
||||
if (!generate && params.megapixels > 0) await assertImageScaleToTotalPixelsNode()
|
||||
const krea = engine === 'krea' ? await resolveKreaGenerateAssets() : null
|
||||
|
||||
if (!generate && params.mode === 'compose' && params.reference) {
|
||||
@@ -108,7 +112,7 @@ export async function runEditV2(job: Job, params: EditV2RunParams) {
|
||||
library.seed = seed
|
||||
library.chainIndex = index
|
||||
library.chainStep = index + 1
|
||||
library.chainLabel = chainTotal > 1 ? `Pass ${index + 1}` : undefined
|
||||
library.chainLabel = chainTotal > 1 ? `${unit} ${index + 1}` : undefined
|
||||
const passName = stillChainName(library.name || '', index)
|
||||
let prompt = prompts[index]
|
||||
let image = current
|
||||
@@ -151,6 +155,7 @@ export async function runEditV2(job: Job, params: EditV2RunParams) {
|
||||
}, job.id)
|
||||
}
|
||||
padded = filled.padded
|
||||
startPadded = filled.padded
|
||||
prompt = composeFillPrompt(prompt, padded)
|
||||
if (padded) {
|
||||
emitChainJob(job, {
|
||||
@@ -159,6 +164,8 @@ export async function runEditV2(job: Job, params: EditV2RunParams) {
|
||||
progress: 7
|
||||
})
|
||||
}
|
||||
} else if (batch && startPadded) {
|
||||
prompt = composeFillPrompt(prompt, true)
|
||||
}
|
||||
|
||||
if (index === 0 && params.mode === 'refine' && mask && !uploadedMask) {
|
||||
@@ -258,7 +265,7 @@ export async function runEditV2(job: Job, params: EditV2RunParams) {
|
||||
name: passName || undefined,
|
||||
prompt,
|
||||
familyId: library.familyId,
|
||||
parentStillId,
|
||||
parentStillId: batch ? (params.sourceStillId || library.stillId) : parentStillId,
|
||||
chainIndex: index,
|
||||
settings: {
|
||||
kind: 'imagev2',
|
||||
@@ -272,7 +279,8 @@ export async function runEditV2(job: Job, params: EditV2RunParams) {
|
||||
consistencyClip: params.consistencyClip,
|
||||
steps: params.steps,
|
||||
cfg: params.cfg,
|
||||
megapixels: params.mode === 'generate' ? undefined : params.megapixels,
|
||||
megapixels: params.mode === 'generate' || !(params.megapixels > 0) ? undefined : params.megapixels,
|
||||
scaleToTotalPixels: params.mode === 'generate' ? undefined : params.megapixels > 0,
|
||||
turbo: params.turbo === true,
|
||||
strength: params.mode === 'generate' ? undefined : params.strength,
|
||||
width: params.mode === 'generate' ? params.width : undefined,
|
||||
@@ -285,7 +293,7 @@ export async function runEditV2(job: Job, params: EditV2RunParams) {
|
||||
}
|
||||
})
|
||||
job.stillId = still?.id
|
||||
parentStillId = still?.id
|
||||
if (!batch) parentStillId = still?.id
|
||||
await purgeComfyArtifacts({
|
||||
video: { filename: output.filename, subfolder: output.subfolder, type: output.type },
|
||||
imageName: uploaded?.name,
|
||||
@@ -299,16 +307,18 @@ export async function runEditV2(job: Job, params: EditV2RunParams) {
|
||||
if (!last) {
|
||||
emitChainJob(job, {
|
||||
type: 'checkpoint',
|
||||
message: `Pass ${index + 1} saved`,
|
||||
message: `${unit} ${index + 1} of ${chainTotal} saved`,
|
||||
progress: 100,
|
||||
stillId: still?.id,
|
||||
hideThumbnail: job.hideThumbnail,
|
||||
folderLocked: library.folderLocked
|
||||
})
|
||||
current = {
|
||||
filename: still?.filename || `pass_${index + 1}.png`,
|
||||
data: buffer,
|
||||
type: 'image/png'
|
||||
if (!batch) {
|
||||
current = {
|
||||
filename: still?.filename || `pass_${index + 1}.png`,
|
||||
data: buffer,
|
||||
type: 'image/png'
|
||||
}
|
||||
}
|
||||
if (library.stopAfterCurrent === true) break
|
||||
continue
|
||||
@@ -318,7 +328,7 @@ export async function runEditV2(job: Job, params: EditV2RunParams) {
|
||||
emitChainJob(job, {
|
||||
type: 'complete',
|
||||
message: chainTotal > 1
|
||||
? `${engineLabel} v2 chain finished on Beast`
|
||||
? `${engineLabel} v2 ${batch ? 'batch' : 'chain'} finished on Beast`
|
||||
: `${engineLabel} v2 finished on Beast`,
|
||||
progress: 100,
|
||||
stillId: still?.id,
|
||||
|
||||
@@ -110,6 +110,34 @@ function patchScaleMegapixels(graph: WorkflowGraph, megapixels: number) {
|
||||
}
|
||||
}
|
||||
|
||||
function linkSource(value: unknown): string | null {
|
||||
return Array.isArray(value) && typeof value[0] === 'string' ? value[0] : null
|
||||
}
|
||||
|
||||
function stripScaleNodes(graph: WorkflowGraph) {
|
||||
for (const [id, node] of Object.entries(graph)) {
|
||||
if (node.class_type !== IMAGE_SCALE_TO_TOTAL_PIXELS) continue
|
||||
const src = Array.isArray(node.inputs.image) ? node.inputs.image : null
|
||||
for (const [otherId, other] of Object.entries(graph)) {
|
||||
if (otherId === id) continue
|
||||
for (const [key, value] of Object.entries(other.inputs)) {
|
||||
if (linkSource(value) !== id || !Array.isArray(value)) continue
|
||||
other.inputs[key] = src ? [src[0], value[1] === 0 ? src[1] : value[1]] : value
|
||||
}
|
||||
}
|
||||
delete graph[id]
|
||||
}
|
||||
}
|
||||
|
||||
function applyScaleMegapixels(graph: WorkflowGraph, megapixels?: number) {
|
||||
const mp = Number(megapixels)
|
||||
if (Number.isFinite(mp) && mp > 0) {
|
||||
patchScaleMegapixels(graph, mp)
|
||||
return
|
||||
}
|
||||
stripScaleNodes(graph)
|
||||
}
|
||||
|
||||
function graphHasMaskInput(graph: WorkflowGraph) {
|
||||
return Object.values(graph).some((node) => {
|
||||
const mask = node.inputs?.mask
|
||||
@@ -401,7 +429,7 @@ function buildKreaItiWorkflow(params: ImageV2BuildParams) {
|
||||
setInput(graph, '15', 'scheduler', 'simple')
|
||||
setInput(graph, '15', 'denoise', denoise)
|
||||
setInput(graph, SAVE, 'filename_prefix', params.filenamePrefix || `v2-krea-${params.mode}`)
|
||||
patchScaleMegapixels(graph, params.megapixels ?? 1)
|
||||
applyScaleMegapixels(graph, params.megapixels)
|
||||
const userLoras = applyImageV2UserLoras(graph, imageV2UserStack(params, 'krea'), 'krea')
|
||||
|
||||
assertImageV2Graph(graph, params.mode, compose ? params.imageBName : undefined, 'krea')
|
||||
@@ -420,7 +448,7 @@ function buildKreaItiWorkflow(params: ImageV2BuildParams) {
|
||||
steps,
|
||||
cfg,
|
||||
seed: params.seed,
|
||||
megapixels: clampImageScaleMegapixels(params.megapixels ?? 1)
|
||||
megapixels: Number(params.megapixels) > 0 ? clampImageScaleMegapixels(params.megapixels) : 0
|
||||
}))
|
||||
return { graph, workflowFile, loaders, prompt, strength: denoise }
|
||||
}
|
||||
@@ -513,7 +541,7 @@ export function buildImageV2Workflow(params: ImageV2BuildParams) {
|
||||
setInput(graph, SCHEDULER, 'steps', steps)
|
||||
setInput(graph, CFG, 'cfg', cfg)
|
||||
setInput(graph, SAVE, 'filename_prefix', params.filenamePrefix || (generate ? 'v2-generate' : 'v2'))
|
||||
if (!generate) patchScaleMegapixels(graph, params.megapixels ?? 1)
|
||||
if (!generate) applyScaleMegapixels(graph, params.megapixels)
|
||||
|
||||
const userLoras = applyImageV2UserLoras(graph, imageV2UserStack(params, 'flux'), 'flux')
|
||||
const guider = Object.values(graph).find(node => node.class_type === 'CFGGuider' || node.class_type === 'BasicGuider')
|
||||
@@ -538,7 +566,7 @@ export function buildImageV2Workflow(params: ImageV2BuildParams) {
|
||||
steps,
|
||||
cfg,
|
||||
seed: params.seed,
|
||||
megapixels: generate ? undefined : clampImageScaleMegapixels(params.megapixels ?? 1)
|
||||
megapixels: generate ? undefined : (Number(params.megapixels) > 0 ? clampImageScaleMegapixels(params.megapixels) : 0)
|
||||
}))
|
||||
|
||||
return { graph, workflowFile, loaders, prompt, strength }
|
||||
|
||||
@@ -47,6 +47,7 @@ export interface StudioJobPayload {
|
||||
shotLoraStacks?: import('~/utils/loras').LoraStackItem[][]
|
||||
negative?: string
|
||||
passes?: { prompt: string }[]
|
||||
passMode?: 'batch' | 'chain'
|
||||
referenceStillId?: string
|
||||
referenceStillFilename?: string
|
||||
scaleToTotalPixels?: boolean
|
||||
@@ -781,7 +782,9 @@ async function startStudioEditJob(item: StudioJob) {
|
||||
chainIndex: 0,
|
||||
chainStep: 1,
|
||||
chainTotal: 1 + ((mode === 'edit' || mode === 'compose') ? (payload.passes?.length || 0) : 0),
|
||||
chainLabel: (mode === 'edit' || mode === 'compose') && payload.passes?.length ? 'Pass 1' : undefined,
|
||||
chainLabel: (mode === 'edit' || mode === 'compose') && payload.passes?.length
|
||||
? (payload.passMode === 'chain' ? 'Pass 1' : 'Batch 1')
|
||||
: undefined,
|
||||
passes: payload.passes,
|
||||
...persistLoraFields(payload.loraStack || payload.loraName)
|
||||
}
|
||||
@@ -796,6 +799,7 @@ async function startStudioEditJob(item: StudioJob) {
|
||||
mask,
|
||||
prompt: payload.prompt,
|
||||
passes: payload.passes || [],
|
||||
passMode: payload.passMode === 'chain' ? 'chain' : 'batch',
|
||||
negative: payload.negative || '',
|
||||
steps: payload.steps,
|
||||
seed: live.library?.seed || payload.seed,
|
||||
@@ -804,7 +808,7 @@ async function startStudioEditJob(item: StudioJob) {
|
||||
snofsClip: payload.snofsClip ?? 0,
|
||||
consistencyModel: payload.consistencyModel ?? (mode === 'generate' || payload.engine === 'krea' ? 0 : 0.7),
|
||||
consistencyClip: payload.consistencyClip ?? (mode === 'generate' || payload.engine === 'krea' ? 0 : 0.7),
|
||||
megapixels: payload.scaleMegapixels ?? 1,
|
||||
megapixels: payload.scaleToTotalPixels === false ? 0 : (payload.scaleMegapixels ?? 1),
|
||||
strength: payload.refineStrength,
|
||||
aspect: payload.aspect || 'auto',
|
||||
width: payload.width,
|
||||
@@ -848,7 +852,7 @@ async function startStudioEditJob(item: StudioJob) {
|
||||
chainIndex: 0,
|
||||
chainStep: 1,
|
||||
chainTotal: 1 + passes.length,
|
||||
chainLabel: passes.length ? 'Pass 1' : undefined,
|
||||
chainLabel: passes.length ? (payload.passMode === 'chain' ? 'Pass 1' : 'Batch 1') : undefined,
|
||||
passes,
|
||||
...persistLoraFields(payload.loraStack || payload.loraName)
|
||||
}
|
||||
@@ -860,6 +864,7 @@ async function startStudioEditJob(item: StudioJob) {
|
||||
reference,
|
||||
prompt: payload.prompt,
|
||||
passes,
|
||||
passMode: payload.passMode === 'chain' ? 'chain' : 'batch',
|
||||
negative: payload.negative || '',
|
||||
steps: payload.steps,
|
||||
seed: live.library?.seed || payload.seed,
|
||||
|
||||
Reference in New Issue
Block a user