Keep family pre/post text on shot queues and wrap the mid prompt at Comfy time.
Later shots were starting a new job without those wrappers, so only the first clip got them. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -53,16 +53,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<label v-if="draft.promptPre" class="block text-sm">
|
<label class="block text-sm">
|
||||||
<span class="mb-1 block font-medium text-zinc-300">Prompt pre</span>
|
<span class="mb-1 block font-medium text-zinc-300">Pre-text</span>
|
||||||
<textarea v-model="draft.promptPre" rows="2" class="max-h-28 w-full overflow-y-auto rounded-xl border border-white/10 bg-zinc-950 px-3 py-2 text-sm outline-none ring-amber-300/40 [overflow-wrap:anywhere] focus:ring-2 disabled:opacity-70" :disabled="!editable" />
|
<textarea v-model="draft.promptPre" rows="2" class="max-h-28 w-full overflow-y-auto rounded-xl border border-white/10 bg-zinc-950 px-3 py-2 text-sm outline-none ring-amber-300/40 [overflow-wrap:anywhere] focus:ring-2 disabled:opacity-70" :disabled="!editable" />
|
||||||
</label>
|
</label>
|
||||||
<label class="block text-sm">
|
<label class="block text-sm">
|
||||||
<span class="mb-1 block font-medium text-zinc-300">{{ shots.length > 1 ? (job.kind === 'edit' ? 'Pass 1' : 'Shot 1') : 'Prompt' }}</span>
|
<span class="mb-1 block font-medium text-zinc-300">{{ shots.length > 1 ? (job.kind === 'edit' ? 'Pass 1' : 'Shot 1') : 'Prompt' }}</span>
|
||||||
<textarea v-model="draft.prompt" rows="5" class="max-h-48 w-full overflow-y-auto rounded-xl border border-white/10 bg-zinc-950 px-3 py-2 text-sm outline-none ring-amber-300/40 [overflow-wrap:anywhere] focus:ring-2 disabled:opacity-70" :disabled="!editable" />
|
<textarea v-model="draft.prompt" rows="5" class="max-h-48 w-full overflow-y-auto rounded-xl border border-white/10 bg-zinc-950 px-3 py-2 text-sm outline-none ring-amber-300/40 [overflow-wrap:anywhere] focus:ring-2 disabled:opacity-70" :disabled="!editable" />
|
||||||
</label>
|
</label>
|
||||||
<label v-if="draft.promptPost" class="block text-sm">
|
<label class="block text-sm">
|
||||||
<span class="mb-1 block font-medium text-zinc-300">Prompt post</span>
|
<span class="mb-1 block font-medium text-zinc-300">Post-text</span>
|
||||||
<textarea v-model="draft.promptPost" rows="2" class="max-h-28 w-full overflow-y-auto rounded-xl border border-white/10 bg-zinc-950 px-3 py-2 text-sm outline-none ring-amber-300/40 [overflow-wrap:anywhere] focus:ring-2 disabled:opacity-70" :disabled="!editable" />
|
<textarea v-model="draft.promptPost" rows="2" class="max-h-28 w-full overflow-y-auto rounded-xl border border-white/10 bg-zinc-950 px-3 py-2 text-sm outline-none ring-amber-300/40 [overflow-wrap:anywhere] focus:ring-2 disabled:opacity-70" :disabled="!editable" />
|
||||||
</label>
|
</label>
|
||||||
<label v-if="job.kind === 'edit'" class="block text-sm">
|
<label v-if="job.kind === 'edit'" class="block text-sm">
|
||||||
@@ -164,6 +164,7 @@ import {
|
|||||||
type QueuedInspectPayload,
|
type QueuedInspectPayload,
|
||||||
type QueuedShotDraft
|
type QueuedShotDraft
|
||||||
} from '~/utils/queuedJob'
|
} from '~/utils/queuedJob'
|
||||||
|
import { restorePromptParts } from '~/utils/promptParts'
|
||||||
import { loraMatchesUse, loraStackLabel, persistLoraFields, readLoraStack, type LoraStackItem } from '~/utils/loras'
|
import { loraMatchesUse, loraStackLabel, persistLoraFields, readLoraStack, type LoraStackItem } from '~/utils/loras'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -243,6 +244,7 @@ function currentPayload(): QueuedInspectPayload {
|
|||||||
const base = { ...(job.value?.payload || {}) }
|
const base = { ...(job.value?.payload || {}) }
|
||||||
base.name = draft.name
|
base.name = draft.name
|
||||||
base.prompt = draft.prompt
|
base.prompt = draft.prompt
|
||||||
|
base.promptMid = draft.prompt
|
||||||
base.promptPre = draft.promptPre
|
base.promptPre = draft.promptPre
|
||||||
base.promptPost = draft.promptPost
|
base.promptPost = draft.promptPost
|
||||||
base.negative = draft.negative
|
base.negative = draft.negative
|
||||||
@@ -271,9 +273,14 @@ function hydrate(next: QueuedInspectJob) {
|
|||||||
job.value = next
|
job.value = next
|
||||||
const payload = next.payload || {}
|
const payload = next.payload || {}
|
||||||
draft.name = payload.name || next.name || ''
|
draft.name = payload.name || next.name || ''
|
||||||
draft.prompt = payload.prompt || next.prompt || ''
|
const parts = restorePromptParts(payload.promptMid || payload.prompt || next.prompt || '', {
|
||||||
draft.promptPre = payload.promptPre || ''
|
pre: payload.promptPre,
|
||||||
draft.promptPost = payload.promptPost || ''
|
prompt: payload.promptMid || payload.prompt || next.prompt || '',
|
||||||
|
post: payload.promptPost
|
||||||
|
})
|
||||||
|
draft.prompt = parts.prompt
|
||||||
|
draft.promptPre = parts.pre
|
||||||
|
draft.promptPost = parts.post
|
||||||
draft.negative = payload.negative || ''
|
draft.negative = payload.negative || ''
|
||||||
draft.tags = payload.tags || (next.kind === 'music' ? (payload.prompt || next.prompt) : '') || ''
|
draft.tags = payload.tags || (next.kind === 'music' ? (payload.prompt || next.prompt) : '') || ''
|
||||||
draft.lyrics = payload.lyrics || ''
|
draft.lyrics = payload.lyrics || ''
|
||||||
@@ -363,6 +370,7 @@ async function saveChanges() {
|
|||||||
body: {
|
body: {
|
||||||
name: payload.name,
|
name: payload.name,
|
||||||
prompt: job.value.kind === 'music' ? payload.tags : payload.prompt,
|
prompt: job.value.kind === 'music' ? payload.tags : payload.prompt,
|
||||||
|
promptMid: job.value.kind === 'music' ? undefined : payload.prompt,
|
||||||
tags: payload.tags,
|
tags: payload.tags,
|
||||||
lyrics: payload.lyrics,
|
lyrics: payload.lyrics,
|
||||||
instrumental: payload.instrumental,
|
instrumental: payload.instrumental,
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { assertImageScaleToTotalPixelsNode, comfyConfigured } from '~/server/uti
|
|||||||
import { imageDimensions } from '~/server/utils/resolution'
|
import { imageDimensions } from '~/server/utils/resolution'
|
||||||
import { parseImageAspect } from '~/utils/imageAspect'
|
import { parseImageAspect } from '~/utils/imageAspect'
|
||||||
import { clampImageCfg, clampImageScaleMegapixels, clampImageSteps, parseImagePassMode, parseImageScaleToTotalPixels } from '~/utils/generationPresets'
|
import { clampImageCfg, clampImageScaleMegapixels, clampImageSteps, parseImagePassMode, parseImageScaleToTotalPixels } from '~/utils/generationPresets'
|
||||||
import { joinPromptParts } from '~/utils/promptParts'
|
|
||||||
|
|
||||||
function parsePasses(raw: string | undefined) {
|
function parsePasses(raw: string | undefined) {
|
||||||
if (!raw) return [] as { prompt: string }[]
|
if (!raw) return [] as { prompt: string }[]
|
||||||
@@ -37,7 +36,7 @@ export default defineEventHandler(async (event) => {
|
|||||||
const promptMid = (fields.prompt || '').trim()
|
const promptMid = (fields.prompt || '').trim()
|
||||||
const promptPre = (fields.promptPre || '').trim()
|
const promptPre = (fields.promptPre || '').trim()
|
||||||
const promptPost = (fields.promptPost || '').trim()
|
const promptPost = (fields.promptPost || '').trim()
|
||||||
const prompt = joinPromptParts(promptPre, promptMid, promptPost)
|
const prompt = promptMid
|
||||||
const extraPasses = parsePasses(fields.passes)
|
const extraPasses = parsePasses(fields.passes)
|
||||||
const passMode = parseImagePassMode(fields.passMode)
|
const passMode = parseImagePassMode(fields.passMode)
|
||||||
const aspect = parseImageAspect(fields.aspect)
|
const aspect = parseImageAspect(fields.aspect)
|
||||||
@@ -131,6 +130,7 @@ export default defineEventHandler(async (event) => {
|
|||||||
kind: 'edit',
|
kind: 'edit',
|
||||||
payload: {
|
payload: {
|
||||||
prompt,
|
prompt,
|
||||||
|
promptMid: promptMid || undefined,
|
||||||
promptPre: promptPre || undefined,
|
promptPre: promptPre || undefined,
|
||||||
promptPost: promptPost || undefined,
|
promptPost: promptPost || undefined,
|
||||||
name: clipName,
|
name: clipName,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { listStudioLoras, parsePostedLoraStack, parseShotLoraStacks, persistLora
|
|||||||
import { clampVideoCfg } from '~/utils/generationPresets'
|
import { clampVideoCfg } from '~/utils/generationPresets'
|
||||||
import { defaultVideoSteps, isLtxWorkflow, isTextToVideo, LTX_DISABLED_MESSAGE, ltxWorkflowEnabled, parseVideoWorkflow, videoEngineOf } 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'
|
import { allowIdentityRefs, normalizePermanenceRefs, resolveGlobalLocks, type PermanenceRef } from '~/utils/globalLocks'
|
||||||
import { composePromptParts, joinPromptParts, persistPromptWrappers } from '~/utils/promptParts'
|
import { composePromptParts, persistPromptWrappers } from '~/utils/promptParts'
|
||||||
import type { QueuedExtension } from '~/server/utils/library'
|
import type { QueuedExtension } from '~/server/utils/library'
|
||||||
|
|
||||||
function parseDuration(raw: unknown) {
|
function parseDuration(raw: unknown) {
|
||||||
@@ -150,7 +150,7 @@ export default defineEventHandler(async (event) => {
|
|||||||
throw createError({ statusCode: 400, statusMessage: 'A motion prompt is required' })
|
throw createError({ statusCode: 400, statusMessage: 'A motion prompt is required' })
|
||||||
}
|
}
|
||||||
const resolvedLocks = resolveGlobalLocks(fields.globalLocks || '', promptMid)
|
const resolvedLocks = resolveGlobalLocks(fields.globalLocks || '', promptMid)
|
||||||
const prompt = joinPromptParts(promptPre, resolvedLocks.prompt, promptPost)
|
const prompt = resolvedLocks.prompt
|
||||||
const globalLocks = resolvedLocks.locks
|
const globalLocks = resolvedLocks.locks
|
||||||
const extensions = parseExtensions(fields.extensions)
|
const extensions = parseExtensions(fields.extensions)
|
||||||
const permanenceRefs = parseFamilyPermanenceRefs(fields.permanenceRefs)
|
const permanenceRefs = parseFamilyPermanenceRefs(fields.permanenceRefs)
|
||||||
@@ -251,7 +251,7 @@ export default defineEventHandler(async (event) => {
|
|||||||
familyId,
|
familyId,
|
||||||
payload: {
|
payload: {
|
||||||
prompt,
|
prompt,
|
||||||
promptMid: promptMid || undefined,
|
promptMid: prompt || undefined,
|
||||||
promptPre: promptPre || undefined,
|
promptPre: promptPre || undefined,
|
||||||
promptPost: promptPost || undefined,
|
promptPost: promptPost || undefined,
|
||||||
name: clipName,
|
name: clipName,
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import {
|
|||||||
type ImageV2Task
|
type ImageV2Task
|
||||||
} from '~/utils/imageV2'
|
} from '~/utils/imageV2'
|
||||||
import { isXaigenStudio } from '~/utils/videoModels'
|
import { isXaigenStudio } from '~/utils/videoModels'
|
||||||
import { joinPromptParts } from '~/utils/promptParts'
|
|
||||||
import { listStudioLoras, parsePostedLoraStack, persistLoraFields, assertImageV2LoraStack } from '~/server/utils/loras'
|
import { listStudioLoras, parsePostedLoraStack, persistLoraFields, assertImageV2LoraStack } from '~/server/utils/loras'
|
||||||
import { getStill, rememberInputStill, stillPath } from '~/server/utils/library'
|
import { getStill, rememberInputStill, stillPath } from '~/server/utils/library'
|
||||||
import { existsSync, readFileSync } from 'node:fs'
|
import { existsSync, readFileSync } from 'node:fs'
|
||||||
@@ -140,7 +139,7 @@ export default defineEventHandler(async (event) => {
|
|||||||
const promptMid = String(fields.prompt || '').trim()
|
const promptMid = String(fields.prompt || '').trim()
|
||||||
const promptPre = String(fields.promptPre || '').trim()
|
const promptPre = String(fields.promptPre || '').trim()
|
||||||
const promptPost = String(fields.promptPost || '').trim()
|
const promptPost = String(fields.promptPost || '').trim()
|
||||||
const prompt = joinPromptParts(promptPre, promptMid, promptPost)
|
const prompt = promptMid
|
||||||
const extraPasses = parsePasses(fields.passes)
|
const extraPasses = parsePasses(fields.passes)
|
||||||
const passMode = parseImagePassMode(fields.passMode)
|
const passMode = parseImagePassMode(fields.passMode)
|
||||||
const aspect = parseImageAspect(fields.aspect)
|
const aspect = parseImageAspect(fields.aspect)
|
||||||
@@ -319,6 +318,7 @@ export default defineEventHandler(async (event) => {
|
|||||||
kind: 'edit',
|
kind: 'edit',
|
||||||
payload: {
|
payload: {
|
||||||
prompt,
|
prompt,
|
||||||
|
promptMid: promptMid || undefined,
|
||||||
promptPre: promptPre || undefined,
|
promptPre: promptPre || undefined,
|
||||||
promptPost: promptPost || undefined,
|
promptPost: promptPost || undefined,
|
||||||
name: clipName,
|
name: clipName,
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ export interface ShotQueue {
|
|||||||
permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[]
|
permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[]
|
||||||
loraName?: string
|
loraName?: string
|
||||||
loraStack?: LoraStackItem[]
|
loraStack?: LoraStackItem[]
|
||||||
|
promptPre?: string
|
||||||
|
promptPost?: string
|
||||||
segments: ShotQueueSegment[]
|
segments: ShotQueueSegment[]
|
||||||
lastError?: string
|
lastError?: string
|
||||||
}
|
}
|
||||||
@@ -190,7 +192,9 @@ export async function createShotQueue(params: {
|
|||||||
permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[]
|
permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[]
|
||||||
loraName?: string
|
loraName?: string
|
||||||
loraStack?: LoraStackItem[]
|
loraStack?: LoraStackItem[]
|
||||||
initial: { prompt: string; duration: number; permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[]; loraName?: string; loraStack?: LoraStackItem[] }
|
promptPre?: string
|
||||||
|
promptPost?: string
|
||||||
|
initial: { prompt: string; promptPre?: string; promptPost?: string; duration: number; permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[]; loraName?: string; loraStack?: LoraStackItem[] }
|
||||||
extensions: QueuedExtension[]
|
extensions: QueuedExtension[]
|
||||||
jobId?: string
|
jobId?: string
|
||||||
}): Promise<ShotQueue> {
|
}): Promise<ShotQueue> {
|
||||||
@@ -227,8 +231,18 @@ export async function createShotQueue(params: {
|
|||||||
permanenceRefs: params.permanenceRefs,
|
permanenceRefs: params.permanenceRefs,
|
||||||
loraName: params.loraName,
|
loraName: params.loraName,
|
||||||
loraStack: params.loraStack,
|
loraStack: params.loraStack,
|
||||||
|
...persistPromptWrappers(params),
|
||||||
segments: [
|
segments: [
|
||||||
{ index: 0, prompt: params.initial.prompt, duration: params.initial.duration, status: 'running', permanenceRefs: params.initial.permanenceRefs, ...persistLoraFields(params.initial.loraStack || params.initial.loraName) },
|
{
|
||||||
|
index: 0,
|
||||||
|
prompt: params.initial.prompt,
|
||||||
|
duration: params.initial.duration,
|
||||||
|
status: 'running',
|
||||||
|
permanenceRefs: params.initial.permanenceRefs,
|
||||||
|
...persistLoraFields(params.initial.loraStack || params.initial.loraName),
|
||||||
|
...persistPromptWrappers(params),
|
||||||
|
...persistPromptWrappers(params.initial)
|
||||||
|
},
|
||||||
...params.extensions.map((item, index) => ({
|
...params.extensions.map((item, index) => ({
|
||||||
index: index + 1,
|
index: index + 1,
|
||||||
prompt: item.prompt,
|
prompt: item.prompt,
|
||||||
@@ -236,6 +250,7 @@ export async function createShotQueue(params: {
|
|||||||
status: 'pending' as const,
|
status: 'pending' as const,
|
||||||
permanenceRefs: item.permanenceRefs,
|
permanenceRefs: item.permanenceRefs,
|
||||||
...persistLoraFields(item.loraStack || item.loraName),
|
...persistLoraFields(item.loraStack || item.loraName),
|
||||||
|
...persistPromptWrappers(params),
|
||||||
...persistPromptWrappers(item)
|
...persistPromptWrappers(item)
|
||||||
}))
|
}))
|
||||||
]
|
]
|
||||||
@@ -479,6 +494,7 @@ export function listOwnersWithQueues() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function remainingFromQueue(queue: ShotQueue): QueuedExtension[] {
|
export function remainingFromQueue(queue: ShotQueue): QueuedExtension[] {
|
||||||
|
const family = persistPromptWrappers(queue)
|
||||||
return queue.segments
|
return queue.segments
|
||||||
.filter(segment => segment.index > 0)
|
.filter(segment => segment.index > 0)
|
||||||
.map(segment => ({
|
.map(segment => ({
|
||||||
@@ -486,6 +502,7 @@ export function remainingFromQueue(queue: ShotQueue): QueuedExtension[] {
|
|||||||
duration: segment.duration,
|
duration: segment.duration,
|
||||||
permanenceRefs: segment.permanenceRefs,
|
permanenceRefs: segment.permanenceRefs,
|
||||||
...persistLoraFields(segment.loraStack || segment.loraName),
|
...persistLoraFields(segment.loraStack || segment.loraName),
|
||||||
|
...family,
|
||||||
...persistPromptWrappers(segment)
|
...persistPromptWrappers(segment)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@@ -503,6 +520,7 @@ export function liveSegmentPrompt(queue: ShotQueue, extensionIndex: number) {
|
|||||||
duration: segment?.duration || 5,
|
duration: segment?.duration || 5,
|
||||||
permanenceRefs: segment?.permanenceRefs,
|
permanenceRefs: segment?.permanenceRefs,
|
||||||
...persistLoraFields(segment?.loraStack || segment?.loraName),
|
...persistLoraFields(segment?.loraStack || segment?.loraName),
|
||||||
|
...persistPromptWrappers(queue),
|
||||||
...persistPromptWrappers(segment)
|
...persistPromptWrappers(segment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { fetchLiveQueue } from '~/server/utils/comfy'
|
|||||||
import { isLtxWorkflow, isTextToVideo, isXaigenStudio, LTX_DISABLED_MESSAGE, ltxWorkflowEnabled, parseVideoWorkflow, type VideoWorkflowId } from '~/utils/videoModels'
|
import { isLtxWorkflow, isTextToVideo, isXaigenStudio, LTX_DISABLED_MESSAGE, ltxWorkflowEnabled, parseVideoWorkflow, type VideoWorkflowId } from '~/utils/videoModels'
|
||||||
import { persistLoraFields } from '~/server/utils/loras'
|
import { persistLoraFields } from '~/server/utils/loras'
|
||||||
import { resolveLoraStack } from '~/utils/loras'
|
import { resolveLoraStack } from '~/utils/loras'
|
||||||
|
import { persistPromptWrappers } from '~/utils/promptParts'
|
||||||
import { imageV2StackSpecials } from '~/utils/imageV2'
|
import { imageV2StackSpecials } from '~/utils/imageV2'
|
||||||
import { allowIdentityRefs, type PermanenceRef } from '~/utils/globalLocks'
|
import { allowIdentityRefs, type PermanenceRef } from '~/utils/globalLocks'
|
||||||
|
|
||||||
@@ -823,6 +824,7 @@ async function startStudioEditJob(item: StudioJob) {
|
|||||||
folderLocked: payload.folderLocked,
|
folderLocked: payload.folderLocked,
|
||||||
name: payload.name,
|
name: payload.name,
|
||||||
prompt: payload.prompt,
|
prompt: payload.prompt,
|
||||||
|
promptMid: payload.promptMid || payload.prompt,
|
||||||
promptPre: payload.promptPre,
|
promptPre: payload.promptPre,
|
||||||
promptPost: payload.promptPost,
|
promptPost: payload.promptPost,
|
||||||
aspect: payload.aspect || 'auto',
|
aspect: payload.aspect || 'auto',
|
||||||
@@ -897,6 +899,7 @@ async function startStudioEditJob(item: StudioJob) {
|
|||||||
folderLocked: payload.folderLocked,
|
folderLocked: payload.folderLocked,
|
||||||
name: payload.name,
|
name: payload.name,
|
||||||
prompt: payload.prompt,
|
prompt: payload.prompt,
|
||||||
|
promptMid: payload.promptMid || payload.prompt,
|
||||||
promptPre: payload.promptPre,
|
promptPre: payload.promptPre,
|
||||||
promptPost: payload.promptPost,
|
promptPost: payload.promptPost,
|
||||||
aspect: payload.aspect || 'auto',
|
aspect: payload.aspect || 'auto',
|
||||||
@@ -1076,8 +1079,8 @@ export async function startStudioJob(item: StudioJob) {
|
|||||||
hideInput: payload.hideInput,
|
hideInput: payload.hideInput,
|
||||||
folderLocked: payload.folderLocked,
|
folderLocked: payload.folderLocked,
|
||||||
name: payload.name,
|
name: payload.name,
|
||||||
prompt: payload.prompt,
|
prompt: payload.promptMid || payload.prompt,
|
||||||
promptMid: payload.promptMid,
|
promptMid: payload.promptMid || payload.prompt,
|
||||||
promptPre: payload.promptPre,
|
promptPre: payload.promptPre,
|
||||||
promptPost: payload.promptPost,
|
promptPost: payload.promptPost,
|
||||||
aspect: payload.aspect,
|
aspect: payload.aspect,
|
||||||
@@ -1140,7 +1143,14 @@ export async function startStudioJob(item: StudioJob) {
|
|||||||
globalLocks: payload.globalLocks,
|
globalLocks: payload.globalLocks,
|
||||||
permanenceRefs: payload.permanenceRefs,
|
permanenceRefs: payload.permanenceRefs,
|
||||||
...persistLoraFields(payload.loraStack || payload.loraName),
|
...persistLoraFields(payload.loraStack || payload.loraName),
|
||||||
initial: { prompt: payload.prompt, duration: payload.duration, permanenceRefs: payload.shotPermanenceRefs?.[0], ...persistLoraFields(resolveLoraStack(payload.loraStack || payload.loraName, payload.shotLoraStacks?.[0] || payload.shotLoras?.[0])) },
|
...persistPromptWrappers(payload),
|
||||||
|
initial: {
|
||||||
|
prompt: payload.promptMid || payload.prompt,
|
||||||
|
duration: payload.duration,
|
||||||
|
permanenceRefs: payload.shotPermanenceRefs?.[0],
|
||||||
|
...persistLoraFields(resolveLoraStack(payload.loraStack || payload.loraName, payload.shotLoraStacks?.[0] || payload.shotLoras?.[0])),
|
||||||
|
...persistPromptWrappers(payload)
|
||||||
|
},
|
||||||
extensions: extensions.map((item, index) => ({
|
extensions: extensions.map((item, index) => ({
|
||||||
...item,
|
...item,
|
||||||
...persistLoraFields(item.loraStack || item.loraName || payload.shotLoraStacks?.[index + 1] || payload.shotLoras?.[index + 1])
|
...persistLoraFields(item.loraStack || item.loraName || payload.shotLoraStacks?.[index + 1] || payload.shotLoras?.[index + 1])
|
||||||
@@ -1169,7 +1179,7 @@ export async function startStudioJob(item: StudioJob) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void runGeneration(job, {
|
void runGeneration(job, {
|
||||||
prompt: payload.prompt,
|
prompt: payload.promptMid || payload.prompt,
|
||||||
image: stillFile,
|
image: stillFile,
|
||||||
width: payload.width,
|
width: payload.width,
|
||||||
height: payload.height,
|
height: payload.height,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import {
|
|||||||
updateShotQueue
|
updateShotQueue
|
||||||
} from '~/server/utils/shotQueue'
|
} from '~/server/utils/shotQueue'
|
||||||
import { composeShotPrompt, allowIdentityRefs, type PermanenceRef } from '~/utils/globalLocks'
|
import { composeShotPrompt, allowIdentityRefs, type PermanenceRef } from '~/utils/globalLocks'
|
||||||
import { composePromptParts, joinPromptParts, resolvePromptWrappers } from '~/utils/promptParts'
|
import { composePromptParts, joinPromptParts, resolvePromptWrappers, wrappedPromptForComfy } from '~/utils/promptParts'
|
||||||
import type { QueuedExtension } from '~/server/utils/library'
|
import type { QueuedExtension } from '~/server/utils/library'
|
||||||
import { persistLoraFields, ensureComfyLoraNames } from '~/server/utils/loras'
|
import { persistLoraFields, ensureComfyLoraNames } from '~/server/utils/loras'
|
||||||
import { readLoraStack, resolveLoraStack } from '~/utils/loras'
|
import { readLoraStack, resolveLoraStack } from '~/utils/loras'
|
||||||
@@ -191,7 +191,7 @@ export async function queueMiniMax(
|
|||||||
const shotIndex = job.library?.chainIndex || 0
|
const shotIndex = job.library?.chainIndex || 0
|
||||||
const composedPrompt = composeShotPrompt({
|
const composedPrompt = composeShotPrompt({
|
||||||
globalLocks: job.library?.globalLocks || params.globalLocks,
|
globalLocks: job.library?.globalLocks || params.globalLocks,
|
||||||
prompt: joinPromptParts(job.library?.promptPre, params.prompt, job.library?.promptPost),
|
prompt: wrappedPromptForComfy(job.library, job.library?.promptMid, params.prompt),
|
||||||
shotIndex,
|
shotIndex,
|
||||||
familyRefs: job.library?.permanenceRefs || params.permanenceRefs,
|
familyRefs: job.library?.permanenceRefs || params.permanenceRefs,
|
||||||
shotRefs: job.library?.shotPermanenceRefs?.[shotIndex] || params.shotPermanenceRefs?.[shotIndex]
|
shotRefs: job.library?.shotPermanenceRefs?.[shotIndex] || params.shotPermanenceRefs?.[shotIndex]
|
||||||
@@ -566,6 +566,7 @@ export async function startQueueBurst(owner: string, queueId: string, count: num
|
|||||||
}
|
}
|
||||||
const source = getClip(owner, clipId)
|
const source = getClip(owner, clipId)
|
||||||
const destFolderLocked = false
|
const destFolderLocked = false
|
||||||
|
const nextSegment = queue.segments.find(segment => segment.index === lastIndex + 1)
|
||||||
const job = createJob()
|
const job = createJob()
|
||||||
job.kind = 'video'
|
job.kind = 'video'
|
||||||
job.maxStep = queue.steps
|
job.maxStep = queue.steps
|
||||||
@@ -578,7 +579,10 @@ export async function startQueueBurst(owner: string, queueId: string, count: num
|
|||||||
hideInput: queue.hideInput,
|
hideInput: queue.hideInput,
|
||||||
folderLocked: destFolderLocked,
|
folderLocked: destFolderLocked,
|
||||||
name: nextFamilyPartName(owner, source),
|
name: nextFamilyPartName(owner, source),
|
||||||
prompt: queue.segments[lastIndex]?.prompt || source.prompt,
|
prompt: nextSegment?.prompt || queue.segments[lastIndex]?.prompt || source.prompt,
|
||||||
|
promptMid: nextSegment?.prompt || queue.segments[lastIndex]?.prompt || source.prompt,
|
||||||
|
promptPre: queue.promptPre || source.promptPre,
|
||||||
|
promptPost: queue.promptPost || source.promptPost,
|
||||||
aspect: queue.aspect,
|
aspect: queue.aspect,
|
||||||
width: queue.width,
|
width: queue.width,
|
||||||
height: queue.height,
|
height: queue.height,
|
||||||
|
|||||||
+15
-5
@@ -15,6 +15,11 @@ export function composePromptParts(pre: string, prompt: string, post: string) {
|
|||||||
.join('\n\n')
|
.join('\n\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PromptWrapperFields = {
|
||||||
|
promptPre?: string
|
||||||
|
promptPost?: string
|
||||||
|
}
|
||||||
|
|
||||||
/** Combine wrappers for Comfy. If mid already includes pre/post, do not wrap twice. */
|
/** Combine wrappers for Comfy. If mid already includes pre/post, do not wrap twice. */
|
||||||
export function joinPromptParts(pre?: string, mid?: string, post?: string) {
|
export function joinPromptParts(pre?: string, mid?: string, post?: string) {
|
||||||
const parts = restorePromptParts(mid || '', {
|
const parts = restorePromptParts(mid || '', {
|
||||||
@@ -25,6 +30,16 @@ export function joinPromptParts(pre?: string, mid?: string, post?: string) {
|
|||||||
return composePromptParts(parts.pre, parts.prompt, parts.post)
|
return composePromptParts(parts.pre, parts.prompt, parts.post)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Prefer stored mid so an already-joined prompt is not the source of truth. */
|
||||||
|
export function wrappedPromptForComfy(
|
||||||
|
wrappers?: PromptWrapperFields | null,
|
||||||
|
mid?: string,
|
||||||
|
fallback?: string
|
||||||
|
) {
|
||||||
|
const body = sanitizePromptPart(mid || '').trim() || sanitizePromptPart(fallback || '').trim()
|
||||||
|
return joinPromptParts(wrappers?.promptPre, body, wrappers?.promptPost)
|
||||||
|
}
|
||||||
|
|
||||||
export function applyPromptParts(parts: PromptParts, middle: string) {
|
export function applyPromptParts(parts: PromptParts, middle: string) {
|
||||||
return composePromptParts(parts.pre, middle, parts.post)
|
return composePromptParts(parts.pre, middle, parts.post)
|
||||||
}
|
}
|
||||||
@@ -46,11 +61,6 @@ export function restorePromptParts(saved: string, stored?: Partial<PromptParts>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PromptWrapperFields = {
|
|
||||||
promptPre?: string
|
|
||||||
promptPost?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
function hasWrapperKey(item: object | null | undefined, key: 'promptPre' | 'promptPost') {
|
function hasWrapperKey(item: object | null | undefined, key: 'promptPre' | 'promptPost') {
|
||||||
return Boolean(item && Object.prototype.hasOwnProperty.call(item, key))
|
return Boolean(item && Object.prototype.hasOwnProperty.call(item, key))
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-4
@@ -63,6 +63,7 @@ export type QueuedInspectPayload = {
|
|||||||
lyrics?: string
|
lyrics?: string
|
||||||
instrumental?: boolean
|
instrumental?: boolean
|
||||||
lyricsStrength?: number
|
lyricsStrength?: number
|
||||||
|
musicEngine?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type QueuedInspectJob = {
|
export type QueuedInspectJob = {
|
||||||
@@ -128,9 +129,11 @@ export function applyQueuedShots(kind: string, shots: QueuedShotDraft[], payload
|
|||||||
}
|
}
|
||||||
next.prompt = shots[0]?.prompt || ''
|
next.prompt = shots[0]?.prompt || ''
|
||||||
next.duration = Number(shots[0]?.duration) || next.duration || 5
|
next.duration = Number(shots[0]?.duration) || next.duration || 5
|
||||||
next.extensions = shots.slice(1).map((item) => {
|
next.extensions = shots.slice(1).map((item, index) => {
|
||||||
const fields = persistLoraFields(item.loraStack || item.loraName)
|
const prev = payload.extensions?.[index]
|
||||||
|
const fields = persistLoraFields(item.loraStack || item.loraName || prev?.loraStack || prev?.loraName)
|
||||||
return {
|
return {
|
||||||
|
...prev,
|
||||||
prompt: item.prompt || '',
|
prompt: item.prompt || '',
|
||||||
duration: Number(item.duration) || 5,
|
duration: Number(item.duration) || 5,
|
||||||
loraName: fields.loraName,
|
loraName: fields.loraName,
|
||||||
@@ -182,7 +185,7 @@ export function queuedJobCopyText(job: QueuedInspectJob) {
|
|||||||
else lines.push(line('Lyrics', payload.lyrics))
|
else lines.push(line('Lyrics', payload.lyrics))
|
||||||
} else {
|
} else {
|
||||||
if (payload.promptPre) lines.push(line('Prompt pre', payload.promptPre))
|
if (payload.promptPre) lines.push(line('Prompt pre', payload.promptPre))
|
||||||
lines.push(line('Prompt', payload.prompt || job.prompt))
|
lines.push(line('Prompt', payload.promptMid || payload.prompt || job.prompt))
|
||||||
if (payload.promptPost) lines.push(line('Prompt post', payload.promptPost))
|
if (payload.promptPost) lines.push(line('Prompt post', payload.promptPost))
|
||||||
const shots = queuedJobShots(payload, job.kind)
|
const shots = queuedJobShots(payload, job.kind)
|
||||||
if (shots.length > 1) {
|
if (shots.length > 1) {
|
||||||
@@ -220,7 +223,8 @@ export function queuedJobPresetBody(job: QueuedInspectJob, name: string) {
|
|||||||
duration: clampMusicDuration(payload.duration),
|
duration: clampMusicDuration(payload.duration),
|
||||||
steps: clampMusicSteps(payload.steps),
|
steps: clampMusicSteps(payload.steps),
|
||||||
seed: payload.seed,
|
seed: payload.seed,
|
||||||
cfg: payload.cfg
|
cfg: payload.cfg,
|
||||||
|
engine: payload.musicEngine || payload.engine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user