Name outputs from the input, engine, and LoRA keys instead of aigen_0001. Image-edit presets now store prompts, and aspect fill pads stills without stretching.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-08-30 16:24:49 -05:00
co-authored by Cursor
parent 4d411f83d4
commit 0e1222d035
23 changed files with 668 additions and 93 deletions
+9 -5
View File
@@ -3,7 +3,7 @@ import { addStudioJob, kickStudioQueue, listStudioJobs, videoJobsBusy } from '~/
import { listStudioLoras, parsePostedLoraStack, parseShotLoraStacks, persistLoraFields } from '~/server/utils/loras'
import type { LoraStackItem } from '~/utils/loras'
import { clampVideoCfg } from '~/utils/generationPresets'
import { defaultVideoSteps, isLtxWorkflow, isTextToVideo, LTX_DISABLED_MESSAGE, ltxWorkflowEnabled, parseVideoWorkflow } from '~/utils/videoModels'
import { defaultVideoSteps, isLtxWorkflow, isTextToVideo, LTX_DISABLED_MESSAGE, ltxWorkflowEnabled, parseVideoWorkflow, videoEngineOf } from '~/utils/videoModels'
import { allowIdentityRefs, normalizePermanenceRefs, resolveGlobalLocks, type PermanenceRef } from '~/utils/globalLocks'
function parseDuration(raw: unknown) {
@@ -115,16 +115,16 @@ export default defineEventHandler(async (event) => {
const textToVideo = isTextToVideo(workflow)
const ownerKey = libraryOwnerKey(event)
const postedStillId = (fields.stillId || '').trim()
let libraryStill: { id: string; filename: string } | null = null
let libraryStill: { id: string; filename: string; name?: string } | null = null
if (postedStillId) {
const path = stillPath(ownerKey, postedStillId)
if (existsSync(path)) {
try {
const existing = getStill(ownerKey, postedStillId)
libraryStill = { id: existing.id, filename: existing.filename }
libraryStill = { id: existing.id, filename: existing.filename, name: existing.name }
if (!image) {
image = {
filename: existing.filename || 'still.png',
filename: existing.name ? `${existing.name}.png` : (existing.filename || 'still.png'),
data: readFileSync(path),
type: 'image/png'
}
@@ -179,7 +179,6 @@ export default defineEventHandler(async (event) => {
const hideThumbnail = fields.hideThumbnail === 'true'
const hideInput = fields.hideInput === 'true'
const sound = !isLtxWorkflow(workflow) && fields.sound !== 'false'
const clipName = (fields.name || '').trim().slice(0, 80)
const library = publicLibrary(event)
const folderId = library.folders.some(folder => folder.id === fields.folderId)
? fields.folderId
@@ -204,6 +203,11 @@ export default defineEventHandler(async (event) => {
if (!textToVideo && !still?.id) {
throw createError({ statusCode: 400, statusMessage: 'An initial image is required' })
}
const clipName = allocateOutputName(ownerKey, folderId, (fields.name || '').trim(), {
inputFilename: libraryStill?.name || image?.filename || still?.filename || '',
engine: videoEngineOf(workflow),
loraStack: defaultStack
})
console.info('[aigen generate]', {
hasImage: Boolean(image?.data?.length),
imageBytes: image?.data?.length || 0,