Restore pre/post text when using clips as input or extending.
Extend no longer blanks wrappers when a part omitted them, Use as input inherits family pre/post, and non-image stills stay on Video instead of being forced into Image mode. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+64
-18
@@ -2261,7 +2261,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { composePromptParts, formatPromptParts, restorePromptParts } from '~/utils/promptParts'
|
||||
import { composePromptParts, formatPromptParts, resolvePromptWrappers, restorePromptParts } from '~/utils/promptParts'
|
||||
import { parseEditPasses, looksLikeShotScript } from '~/utils/parseRecommend'
|
||||
import { parseImageBatchScript, parseShotScript } from '~/utils/parseShots'
|
||||
import type { DirectorScript } from '~/utils/directorScripts'
|
||||
@@ -4325,16 +4325,39 @@ function insertKeepPrompt(item: KeepPrompt) {
|
||||
}
|
||||
|
||||
function applyPromptRestore(saved: string, stored?: { prompt?: string; promptPre?: string; promptPost?: string } | null) {
|
||||
const parts = restorePromptParts(saved, {
|
||||
pre: stored?.promptPre,
|
||||
prompt: saved,
|
||||
post: stored?.promptPost
|
||||
const wrappers = resolvePromptWrappers(stored || undefined)
|
||||
const mid = String(saved || stored?.prompt || '').trim()
|
||||
const parts = restorePromptParts(mid, {
|
||||
pre: wrappers.promptPre || stored?.promptPre,
|
||||
prompt: mid,
|
||||
post: wrappers.promptPost || stored?.promptPost
|
||||
})
|
||||
promptPre.value = parts.pre
|
||||
prompt.value = parts.prompt
|
||||
promptPost.value = parts.post
|
||||
}
|
||||
|
||||
function promptPartsForClip(
|
||||
clip: LibraryClip | null | undefined,
|
||||
midFallback = ''
|
||||
) {
|
||||
const family = clip ? familyPartsFor(clip) : []
|
||||
const wrappers = resolvePromptWrappers(
|
||||
clip || undefined,
|
||||
family[0],
|
||||
{
|
||||
promptPre: promptPre.value,
|
||||
promptPost: promptPost.value
|
||||
}
|
||||
)
|
||||
const mid = String(clip?.prompt || midFallback || '').trim()
|
||||
return restorePromptParts(mid, {
|
||||
pre: wrappers.promptPre,
|
||||
prompt: mid,
|
||||
post: wrappers.promptPost
|
||||
})
|
||||
}
|
||||
|
||||
function queuedExtensionFrom(
|
||||
item: { prompt?: string; promptPre?: string; promptPost?: string; duration?: number; loraName?: string; loraStack?: LoraStackItem[] },
|
||||
duration: number,
|
||||
@@ -5533,6 +5556,7 @@ async function restoreStudioPayload(kind: string, payload: {
|
||||
refinementDenoise?: number
|
||||
promptPre?: string
|
||||
promptPost?: string
|
||||
promptMid?: string
|
||||
globalLocks?: string
|
||||
permanenceRefs?: PermanenceRef[]
|
||||
shotPermanenceRefs?: PermanenceRef[][]
|
||||
@@ -5568,9 +5592,15 @@ async function restoreStudioPayload(kind: string, payload: {
|
||||
|| Object.prototype.hasOwnProperty.call(item, 'promptPost')
|
||||
)
|
||||
applyVideoWorkflow(payload.workflow)
|
||||
const mid = String(payload.promptMid || '').trim() || String(payload.prompt || '').trim()
|
||||
applyPromptRestore(queuedAsCards || !extensions.length
|
||||
? (payload.prompt || '')
|
||||
: [payload.prompt.trim(), ...extensions.map((item, index) => `shot ${index + 2}\n${item.prompt.trim()}`)].join('\n\n'), payload)
|
||||
? mid
|
||||
: [mid, ...extensions.map((item, index) => `shot ${index + 2}\n${String(item.prompt || '').trim()}`)].join('\n\n'), {
|
||||
...payload,
|
||||
prompt: mid,
|
||||
promptPre: payload.promptPre,
|
||||
promptPost: payload.promptPost
|
||||
})
|
||||
clipName.value = payload.name || ''
|
||||
seedInput.value = String(payload.seed || '')
|
||||
restoreAdvanced({
|
||||
@@ -5944,7 +5974,13 @@ async function rerun(item: LibraryClip, collection = false) {
|
||||
const parts = familyPartsFor(item)
|
||||
const target = collection ? parts[0] || item : item
|
||||
const restoreAll = collection && parts.length > 1
|
||||
applyPromptRestore(restoreAll ? familyScript(parts) : target.prompt, target)
|
||||
const ordered = chronologicalParts(parts)
|
||||
const wrappers = resolvePromptWrappers(target, ordered[0])
|
||||
applyPromptRestore(restoreAll ? familyScript(parts) : target.prompt, {
|
||||
prompt: restoreAll ? familyScript(parts) : target.prompt,
|
||||
promptPre: wrappers.promptPre || target.promptPre,
|
||||
promptPost: wrappers.promptPost || target.promptPost
|
||||
})
|
||||
clipName.value = restoreAll
|
||||
? (familyBaseName(collectionTitle({ head: target, parts })) || target.name || '')
|
||||
: (target.name || '')
|
||||
@@ -5959,7 +5995,6 @@ async function rerun(item: LibraryClip, collection = false) {
|
||||
if (typeof target.sound === 'boolean') withSound.value = target.sound
|
||||
shotScriptMode.value = restoreAll
|
||||
identityRefs.value.forEach((_, index) => clearIdentityRef(index))
|
||||
const ordered = chronologicalParts(parts)
|
||||
globalLocks.value = ordered.find(part => part.globalLocks)?.globalLocks || target.globalLocks || ''
|
||||
familyPermanenceRefs.value = ordered[0]?.permanenceRefs || target.permanenceRefs || []
|
||||
const familyIds = new Set(familyPermanenceRefs.value.map(ref => ref.stillId))
|
||||
@@ -5974,11 +6009,18 @@ async function rerun(item: LibraryClip, collection = false) {
|
||||
restoreAll ? ordered : undefined
|
||||
)
|
||||
extensionQueue.value = restoreAll
|
||||
? parts.slice(1).map(part => queuedExtensionFrom(
|
||||
part,
|
||||
? parts.slice(1).map(part => {
|
||||
const shotWrappers = resolvePromptWrappers(part, ordered[0], target)
|
||||
return queuedExtensionFrom(
|
||||
{
|
||||
...part,
|
||||
promptPre: shotWrappers.promptPre || part.promptPre,
|
||||
promptPost: shotWrappers.promptPost || part.promptPost
|
||||
},
|
||||
clipGenerateDuration(part),
|
||||
loraStacksEqual(readLoraStack(part), readLoraStack(ordered[0] || target)) ? [] : readLoraStack(part)
|
||||
))
|
||||
)
|
||||
})
|
||||
: []
|
||||
try {
|
||||
const initialTextToVideo = textToVideo.value && !target.parentClipId && !(target.chainIndex)
|
||||
@@ -6144,13 +6186,11 @@ async function openExtend(item?: LibraryClip) {
|
||||
}
|
||||
currentClipId.value = id
|
||||
extendClipId.value = id
|
||||
const clip = clips.value.find(entry => entry.id === id)
|
||||
const clip = clips.value.find(entry => entry.id === id) || item || null
|
||||
if (clip) ensureFamilyExpanded(clip)
|
||||
const parts = restorePromptParts(clip?.prompt || prompt.value, {
|
||||
pre: clip ? (clip.promptPre || '') : promptPre.value,
|
||||
prompt: clip?.prompt || prompt.value,
|
||||
post: clip ? (clip.promptPost || '') : promptPost.value
|
||||
})
|
||||
// Prefer clip wrappers, then family head, then the main form — never blank pre/post
|
||||
// just because this part did not re-store them.
|
||||
const parts = promptPartsForClip(clip, prompt.value)
|
||||
extendPromptPre.value = parts.pre
|
||||
extendPrompt.value = parts.prompt
|
||||
extendPromptPost.value = parts.post
|
||||
@@ -6297,6 +6337,12 @@ function applyStillSettings(still: LibraryStill) {
|
||||
browseFolderId.value = still.folderId
|
||||
rememberInputSeed(settings?.seed)
|
||||
applyPromptRestore(still.prompt || '', still)
|
||||
// Non-image stills are video start frames — keep Video mode and only restore prompt parts.
|
||||
if (!dest) {
|
||||
studioMode.value = 'video'
|
||||
outputFocus.value = 'video'
|
||||
return
|
||||
}
|
||||
if (dest === 'imagev2') {
|
||||
studioMode.value = 'editv2'
|
||||
outputFocus.value = 'edit'
|
||||
|
||||
Reference in New Issue
Block a user