Show generator settings in the library and restore them as input.

Collapse tiles so prompts stay behind the info button. Use as input opens the matching Video or Image v2 mode with the saved sliders.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-08-28 23:38:23 -05:00
co-authored by Cursor
parent b35f9af10d
commit be5211f488
7 changed files with 458 additions and 22 deletions
+13 -1
View File
@@ -152,7 +152,19 @@ export async function runEdit(job: Job, params: EditRunParams) {
prompt,
familyId: library.familyId,
parentStillId,
chainIndex: index
chainIndex: index,
settings: {
kind: 'image',
steps: params.steps,
cfg: params.cfg,
negative: params.negative,
seed,
scaleToTotalPixels: params.scaleToTotalPixels === true,
scaleMegapixels: params.scaleMegapixels,
loraName: params.loraName,
loraStack: params.loraStack,
sourceStillId: library.stillId
}
})
job.stillId = still?.id
parentStillId = still?.id
+23 -1
View File
@@ -30,6 +30,8 @@ export type EditV2RunParams = {
width?: number
height?: number
turbo?: boolean
sourceStillId?: string
referenceStillId?: string
}
export async function runEditV2(job: Job, params: EditV2RunParams) {
@@ -163,7 +165,27 @@ export async function runEditV2(job: Job, params: EditV2RunParams) {
hideInput: job.hideThumbnail === true,
role: 'output',
name: library.name || undefined,
prompt: built.prompt
prompt: params.prompt,
settings: {
kind: 'imagev2',
mode: params.mode,
task: params.task,
negative: params.negative,
snofsModel: params.snofsModel,
snofsClip: params.snofsClip,
consistencyModel: params.consistencyModel,
consistencyClip: params.consistencyClip,
steps: params.steps,
cfg: params.cfg,
megapixels: params.mode === 'generate' ? undefined : params.megapixels,
turbo: params.turbo === true,
strength: params.mode === 'refine' ? params.strength : undefined,
width: params.mode === 'generate' ? params.width : undefined,
height: params.mode === 'generate' ? params.height : undefined,
seed: params.seed,
sourceStillId: params.sourceStillId || library.stillId,
referenceStillId: params.referenceStillId
}
})
job.stillId = still?.id
await purgeComfyArtifacts({
+11 -3
View File
@@ -7,6 +7,7 @@ import { promisify } from 'node:util'
import type { H3Event } from 'h3'
import { extractFirstFrame, extractFrameAt, extractLastFrame, probeDuration, remuxFaststart } from '~/server/utils/ffmpeg'
import { normalizePermanenceRefs, type PermanenceRef } from '~/utils/globalLocks'
import { normalizeStillSettings, type StillGenerationSettings } from '~/utils/libraryGeneration'
const scryptAsync = promisify(scrypt)
@@ -67,6 +68,7 @@ export interface LibraryStill {
familyId?: string
parentStillId?: string
chainIndex?: number
settings?: StillGenerationSettings
}
export interface PublicFolder {
@@ -205,7 +207,8 @@ function normalizeStill(still: LibraryStill): LibraryStill {
prompt: still.prompt,
familyId: still.familyId,
parentStillId: still.parentStillId,
chainIndex: still.chainIndex
chainIndex: still.chainIndex,
settings: normalizeStillSettings(still.settings)
}
}
@@ -1108,6 +1111,7 @@ export async function saveStill(params: {
familyId?: string
parentStillId?: string
chainIndex?: number
settings?: StillGenerationSettings
}): Promise<LibraryStill | null> {
if (lastFrameStillName(params.filename)) return null
const role = params.role === 'output' ? 'output' : 'input'
@@ -1123,7 +1127,8 @@ export async function saveStill(params: {
const hideInput = typeof params.hideInput === 'boolean' ? params.hideInput === true : existing.hideInput
const name = typeof params.name === 'string' ? params.name.trim().slice(0, 80) : existing.name
const prompt = typeof params.prompt === 'string' ? params.prompt : existing.prompt
if (existing.hideInput !== hideInput || existing.name !== name || existing.prompt !== prompt) {
const nextSettings = params.settings ? normalizeStillSettings(params.settings) : undefined
if (existing.hideInput !== hideInput || existing.name !== name || existing.prompt !== prompt || nextSettings) {
await mutate(params.ownerKey, (next) => {
const item = next.stills.find(still => still.id === existing.id)
if (!item) return
@@ -1134,11 +1139,13 @@ export async function saveStill(params: {
if (params.familyId) item.familyId = params.familyId
if (params.parentStillId) item.parentStillId = params.parentStillId
if (typeof params.chainIndex === 'number') item.chainIndex = params.chainIndex
if (nextSettings) item.settings = nextSettings
})
existing.hideInput = hideInput
existing.role = role
if (name) existing.name = name
if (prompt) existing.prompt = prompt
if (nextSettings) existing.settings = nextSettings
}
return existing
}
@@ -1159,7 +1166,8 @@ export async function saveStill(params: {
prompt: params.prompt || undefined,
familyId: params.familyId,
parentStillId: params.parentStillId,
chainIndex: params.chainIndex
chainIndex: params.chainIndex,
settings: normalizeStillSettings(params.settings)
}
mkdirSync(join(ownerRoot(params.ownerKey), 'stills'), { recursive: true })
writeFileSync(stillPath(params.ownerKey, still.id), params.data)
+3 -1
View File
@@ -770,7 +770,9 @@ async function startStudioEditJob(item: StudioJob) {
strength: payload.refineStrength,
width: payload.width,
height: payload.height,
turbo: payload.turbo === true
turbo: payload.turbo === true,
sourceStillId: payload.stillId,
referenceStillId: payload.referenceStillId
}).catch((error) => {
const message = error instanceof Error ? error.message : String(error)
if (live && live.status !== 'error' && live.status !== 'cancelled' && live.status !== 'deferred') {