Add clickable keep-prompt snippets for video and image.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+54
-6
@@ -190,7 +190,15 @@
|
||||
|
||||
<div>
|
||||
<div class="mb-2 flex flex-wrap items-center justify-between gap-2">
|
||||
<label class="text-sm font-medium text-zinc-300">{{ studioMode === 'editv2' && v2Mode === 'generate' ? 'Generate prompt' : studioMode === 'editv2' && v2Mode === 'refine' ? 'Refine prompt' : studioMode === 'edit' || studioMode === 'editv2' ? 'Edit prompt' : 'Motion & scene prompt' }}</label>
|
||||
<div class="flex items-center gap-2">
|
||||
<label class="text-sm font-medium text-zinc-300">{{ studioMode === 'editv2' && v2Mode === 'generate' ? 'Generate prompt' : studioMode === 'editv2' && v2Mode === 'refine' ? 'Refine prompt' : studioMode === 'edit' || studioMode === 'editv2' ? 'Edit prompt' : 'Motion & scene prompt' }}</label>
|
||||
<KeepPromptMenu
|
||||
:items="activeKeepPrompts"
|
||||
:heading="keepPromptHeading"
|
||||
align="left"
|
||||
@insert="insertKeepPrompt"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<button
|
||||
v-if="identityPrompting"
|
||||
@@ -486,7 +494,16 @@
|
||||
class="rounded-2xl border border-white/10 bg-zinc-950/50 p-4"
|
||||
>
|
||||
<div class="mb-3 flex items-center justify-between gap-2">
|
||||
<p class="text-sm font-medium text-zinc-200">Extension #{{ index + 1 }}</p>
|
||||
<div class="flex items-center gap-2">
|
||||
<p class="text-sm font-medium text-zinc-200">Extension #{{ index + 1 }}</p>
|
||||
<KeepPromptMenu
|
||||
:items="keepPrompts.video"
|
||||
heading="Video prompts"
|
||||
align="left"
|
||||
:disabled="videoBusy"
|
||||
@insert="insertKeepIntoExtension(item.id, $event)"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="text-xs text-red-300 hover:text-red-200"
|
||||
@@ -1360,7 +1377,16 @@
|
||||
</p>
|
||||
</div>
|
||||
<label class="block text-sm">
|
||||
<span class="mb-1 block text-zinc-400">Extension prompt</span>
|
||||
<span class="mb-1 flex items-center gap-2 text-zinc-400">
|
||||
Extension prompt
|
||||
<KeepPromptMenu
|
||||
:items="keepPrompts.video"
|
||||
heading="Video prompts"
|
||||
align="left"
|
||||
:disabled="lastFrameLoading || videoBusy"
|
||||
@insert="insertKeepExtend"
|
||||
/>
|
||||
</span>
|
||||
<textarea
|
||||
v-model="extendPrompt"
|
||||
rows="4"
|
||||
@@ -1965,6 +1991,8 @@
|
||||
v-model:text="prompt"
|
||||
:title="studioMode === 'edit' || studioMode === 'editv2' ? 'Edit prompt' : (shotScriptMode ? 'Shot script' : 'Prompt')"
|
||||
:placeholder="promptPlaceholder"
|
||||
:keep-items="activeKeepPrompts"
|
||||
:keep-heading="keepPromptHeading"
|
||||
@update:open="promptDrawerOpen = $event"
|
||||
/>
|
||||
<ImageBatchModal
|
||||
@@ -2122,6 +2150,7 @@ import {
|
||||
} from '~/utils/libraryGeneration'
|
||||
import { parseImageAspect, generateSizeForAspect } from '~/utils/imageAspect'
|
||||
import { buildOutputBaseName, nextUniqueName } from '~/utils/outputNames'
|
||||
import { emptyKeepPrompts, insertKeepSnippet, normalizeKeepPrompts, type KeepPrompt, type KeepPromptLists } from '~/utils/keepPrompts'
|
||||
import {
|
||||
IMAGE_V2_CFG_DEFAULT,
|
||||
IMAGE_V2_CONSISTENCY_LORA,
|
||||
@@ -2567,6 +2596,9 @@ const stills = ref<LibraryStill[]>([])
|
||||
const drafts = ref<RetryDraft[]>([])
|
||||
const loraAliases = ref<Record<string, string>>({})
|
||||
const loraTriggers = ref<Record<string, string>>({})
|
||||
const keepPrompts = ref<KeepPromptLists>(emptyKeepPrompts())
|
||||
const activeKeepPrompts = computed(() => studioMode.value === 'video' ? keepPrompts.value.video : keepPrompts.value.image)
|
||||
const keepPromptHeading = computed(() => studioMode.value === 'video' ? 'Video prompts' : 'Image prompts')
|
||||
const folderId = ref('')
|
||||
const browseFolderId = ref('')
|
||||
const renamingId = ref('')
|
||||
@@ -3503,8 +3535,8 @@ function applyInstancePrivacy() {
|
||||
hideThumbnail.value = readPrivacyToggle('aigen-hide-output-preview', true)
|
||||
}
|
||||
|
||||
function applyLibrary(data: { folders?: LibraryFolder[]; clips?: LibraryClip[]; stills?: LibraryStill[]; drafts?: RetryDraft[]; loraAliases?: Record<string, string>; loraTriggers?: Record<string, string> } | unknown) {
|
||||
const payload = (data || {}) as { folders?: LibraryFolder[]; clips?: LibraryClip[]; stills?: LibraryStill[]; drafts?: RetryDraft[]; loraAliases?: Record<string, string>; loraTriggers?: Record<string, string> }
|
||||
function applyLibrary(data: { folders?: LibraryFolder[]; clips?: LibraryClip[]; stills?: LibraryStill[]; drafts?: RetryDraft[]; loraAliases?: Record<string, string>; loraTriggers?: Record<string, string>; keepPrompts?: KeepPromptLists } | unknown) {
|
||||
const payload = (data || {}) as { folders?: LibraryFolder[]; clips?: LibraryClip[]; stills?: LibraryStill[]; drafts?: RetryDraft[]; loraAliases?: Record<string, string>; loraTriggers?: Record<string, string>; keepPrompts?: KeepPromptLists }
|
||||
folders.value = payload.folders || []
|
||||
clips.value = payload.clips || []
|
||||
stills.value = payload.stills || []
|
||||
@@ -3515,6 +3547,9 @@ function applyLibrary(data: { folders?: LibraryFolder[]; clips?: LibraryClip[];
|
||||
if (payload.loraTriggers && typeof payload.loraTriggers === 'object') {
|
||||
loraTriggers.value = payload.loraTriggers
|
||||
}
|
||||
if (payload.keepPrompts) {
|
||||
keepPrompts.value = normalizeKeepPrompts(payload.keepPrompts)
|
||||
}
|
||||
if (!folderId.value || !folders.value.some(folder => folder.id === folderId.value)) {
|
||||
folderId.value = folders.value[0]?.id || ''
|
||||
}
|
||||
@@ -3524,7 +3559,7 @@ function applyLibrary(data: { folders?: LibraryFolder[]; clips?: LibraryClip[];
|
||||
}
|
||||
|
||||
async function loadLibrary(light = false) {
|
||||
const data = await $fetch<{ folders?: LibraryFolder[]; clips?: LibraryClip[]; stills?: LibraryStill[]; drafts?: RetryDraft[]; loraAliases?: Record<string, string>; loraTriggers?: Record<string, string> }>(light ? '/api/library?light=1' : '/api/library')
|
||||
const data = await $fetch<{ folders?: LibraryFolder[]; clips?: LibraryClip[]; stills?: LibraryStill[]; drafts?: RetryDraft[]; loraAliases?: Record<string, string>; loraTriggers?: Record<string, string>; keepPrompts?: KeepPromptLists }>(light ? '/api/library?light=1' : '/api/library')
|
||||
applyLibrary(data)
|
||||
if (light) return
|
||||
const queued = await $fetch<{ pendingCount?: number }>('/api/queues').catch(() => ({ pendingCount: 0 }))
|
||||
@@ -3996,6 +4031,19 @@ async function saveLoraTrigger(name: string, trigger: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function insertKeepPrompt(item: KeepPrompt) {
|
||||
prompt.value = insertKeepSnippet(prompt.value, item.text)
|
||||
}
|
||||
|
||||
function insertKeepExtend(item: KeepPrompt) {
|
||||
extendPrompt.value = insertKeepSnippet(extendPrompt.value, item.text)
|
||||
}
|
||||
|
||||
function insertKeepIntoExtension(id: string, item: KeepPrompt) {
|
||||
const row = extensionQueue.value.find(entry => entry.id === id)
|
||||
if (row) row.prompt = insertKeepSnippet(row.prompt, item.text)
|
||||
}
|
||||
|
||||
function insertLoraTrigger(phrase: string, target: 'main' | 'extend' | { shot: number } | { extensionId: string } = 'main') {
|
||||
const token = String(phrase || '').trim()
|
||||
if (!token) return
|
||||
|
||||
Reference in New Issue
Block a user