Add LoRA stacks with per-item strengths and named video/image generation presets so setups survive reload without mixing Klein onto MiniMax. Keep LTX Pink Cherry and xAIGen LoRAs on xAIGen, and run Recommend on Beast.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
import { getJob, listJobs, type Job } from '~/server/utils/jobs'
|
||||
import { parsePostedLoraStack, persistLoraFields } from '~/server/utils/loras'
|
||||
import type { LoraStackItem } from '~/utils/loras'
|
||||
|
||||
export type ShotQueueStatus = 'idle' | 'running' | 'paused' | 'complete' | 'error'
|
||||
export type ShotSegmentStatus = 'pending' | 'running' | 'complete' | 'error'
|
||||
@@ -13,6 +15,8 @@ export interface ShotQueueSegment {
|
||||
clipId?: string
|
||||
error?: string
|
||||
permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[]
|
||||
loraName?: string
|
||||
loraStack?: LoraStackItem[]
|
||||
}
|
||||
|
||||
export interface ShotQueue {
|
||||
@@ -46,6 +50,8 @@ export interface ShotQueue {
|
||||
referenceStillIds?: Array<string | null>
|
||||
globalLocks?: string
|
||||
permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[]
|
||||
loraName?: string
|
||||
loraStack?: LoraStackItem[]
|
||||
segments: ShotQueueSegment[]
|
||||
lastError?: string
|
||||
}
|
||||
@@ -163,8 +169,10 @@ export async function createShotQueue(params: {
|
||||
referenceStillIds?: Array<string | null>
|
||||
globalLocks?: string
|
||||
permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[]
|
||||
initial: { prompt: string; duration: number; permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[] }
|
||||
extensions: { prompt: string; duration: number; permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[] }[]
|
||||
loraName?: string
|
||||
loraStack?: LoraStackItem[]
|
||||
initial: { prompt: string; duration: number; permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[]; loraName?: string; loraStack?: LoraStackItem[] }
|
||||
extensions: { prompt: string; duration: number; permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[]; loraName?: string; loraStack?: LoraStackItem[] }[]
|
||||
jobId?: string
|
||||
}): Promise<ShotQueue> {
|
||||
const now = Date.now()
|
||||
@@ -198,14 +206,17 @@ export async function createShotQueue(params: {
|
||||
referenceStillIds: params.referenceStillIds,
|
||||
globalLocks: params.globalLocks,
|
||||
permanenceRefs: params.permanenceRefs,
|
||||
loraName: params.loraName,
|
||||
loraStack: params.loraStack,
|
||||
segments: [
|
||||
{ index: 0, prompt: params.initial.prompt, duration: params.initial.duration, status: 'running', permanenceRefs: params.initial.permanenceRefs },
|
||||
{ index: 0, prompt: params.initial.prompt, duration: params.initial.duration, status: 'running', permanenceRefs: params.initial.permanenceRefs, ...persistLoraFields(params.initial.loraStack || params.initial.loraName) },
|
||||
...params.extensions.map((item, index) => ({
|
||||
index: index + 1,
|
||||
prompt: item.prompt,
|
||||
duration: item.duration,
|
||||
status: 'pending' as const,
|
||||
permanenceRefs: item.permanenceRefs
|
||||
permanenceRefs: item.permanenceRefs,
|
||||
...persistLoraFields(item.loraStack || item.loraName)
|
||||
}))
|
||||
]
|
||||
}
|
||||
@@ -230,7 +241,7 @@ export async function updateShotQueue(owner: string, id: string, patch: (queue:
|
||||
export async function patchShotQueueSegments(
|
||||
owner: string,
|
||||
id: string,
|
||||
segments: Array<{ index: number; prompt?: string; duration?: number }>
|
||||
segments: Array<{ index: number; prompt?: string; duration?: number; loraName?: string; loraStack?: unknown }>
|
||||
) {
|
||||
return updateShotQueue(owner, id, (queue) => {
|
||||
if (queue.status === 'complete') {
|
||||
@@ -248,6 +259,17 @@ export async function patchShotQueueSegments(
|
||||
if (typeof next.duration === 'number' && Number.isFinite(next.duration)) {
|
||||
segment.duration = Math.min(120, Math.max(0.5, Math.round(next.duration * 10) / 10))
|
||||
}
|
||||
if ('loraStack' in next || 'loraName' in next) {
|
||||
const stack = parsePostedLoraStack(next.loraStack ?? next.loraName, 'video')
|
||||
const fields = persistLoraFields(stack)
|
||||
if (fields.loraStack) {
|
||||
segment.loraStack = fields.loraStack
|
||||
segment.loraName = fields.loraName
|
||||
} else {
|
||||
delete segment.loraStack
|
||||
delete segment.loraName
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -426,10 +448,10 @@ export function listOwnersWithQueues() {
|
||||
.filter(owner => existsSync(queuesPath(owner)))
|
||||
}
|
||||
|
||||
export function remainingFromQueue(queue: ShotQueue): { prompt: string; duration: number; permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[] }[] {
|
||||
export function remainingFromQueue(queue: ShotQueue): { prompt: string; duration: number; permanenceRefs?: import('~/utils/globalLocks').PermanenceRef[]; loraName?: string; loraStack?: LoraStackItem[] }[] {
|
||||
return queue.segments
|
||||
.filter(segment => segment.index > 0)
|
||||
.map(segment => ({ prompt: segment.prompt, duration: segment.duration, permanenceRefs: segment.permanenceRefs }))
|
||||
.map(segment => ({ prompt: segment.prompt, duration: segment.duration, permanenceRefs: segment.permanenceRefs, ...persistLoraFields(segment.loraStack || segment.loraName) }))
|
||||
}
|
||||
|
||||
export function lastCompletedIndex(queue: ShotQueue) {
|
||||
@@ -443,6 +465,7 @@ export function liveSegmentPrompt(queue: ShotQueue, extensionIndex: number) {
|
||||
return {
|
||||
prompt: segment?.prompt || '',
|
||||
duration: segment?.duration || 5,
|
||||
permanenceRefs: segment?.permanenceRefs
|
||||
permanenceRefs: segment?.permanenceRefs,
|
||||
...persistLoraFields(segment?.loraStack || segment?.loraName)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user