Put ACE-Step music jobs on the same studio queue as video and image.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -44,6 +44,15 @@ function classifyError(message: string) {
|
||||
return message
|
||||
}
|
||||
|
||||
async function settleMusicStudio(job: Job) {
|
||||
try {
|
||||
const { onLiveVideoSettled } = await import('~/server/utils/studioQueue')
|
||||
await onLiveVideoSettled(job)
|
||||
} catch {
|
||||
/* queue kick is best-effort */
|
||||
}
|
||||
}
|
||||
|
||||
function nodeLabel(node: string) {
|
||||
if (!node) return ''
|
||||
return NODE_LABELS[node] || ''
|
||||
@@ -118,6 +127,7 @@ function watchMusicJob(job: Job): Promise<void> {
|
||||
job.status = job.status === 'cancelled' ? 'cancelled' : 'error'
|
||||
job.error = classifyError(error)
|
||||
emitJob(job, { type: 'error', error: job.error, message: job.error })
|
||||
await settleMusicStudio(job)
|
||||
resolve()
|
||||
}
|
||||
|
||||
@@ -183,6 +193,7 @@ function watchMusicJob(job: Job): Promise<void> {
|
||||
job.error = `Audio generated but library save failed: ${message}`
|
||||
emitJob(job, { type: 'error', error: job.error, message: job.error })
|
||||
}
|
||||
await settleMusicStudio(job)
|
||||
job.saving = false
|
||||
resolve()
|
||||
return true
|
||||
@@ -344,6 +355,7 @@ export async function startMusicJob(params: MusicJobParams) {
|
||||
job.status = 'error'
|
||||
job.error = classifyError(message)
|
||||
emitJob(job, { type: 'error', error: job.error, message: job.error })
|
||||
await settleMusicStudio(job)
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
||||
@@ -11,7 +11,7 @@ import { imageV2StackSpecials } from '~/utils/imageV2'
|
||||
import { allowIdentityRefs, type PermanenceRef } from '~/utils/globalLocks'
|
||||
|
||||
export type StudioJobStatus = 'waiting' | 'running' | 'held' | 'complete' | 'error' | 'cancelled'
|
||||
export type StudioJobKind = 'video' | 'edit'
|
||||
export type StudioJobKind = 'video' | 'edit' | 'music'
|
||||
|
||||
export interface StudioJobPayload {
|
||||
prompt: string
|
||||
@@ -68,6 +68,10 @@ export interface StudioJobPayload {
|
||||
maskStillFilename?: string
|
||||
refineStrength?: number
|
||||
extendFromClipId?: string
|
||||
lyrics?: string
|
||||
instrumental?: boolean
|
||||
lyricsStrength?: number
|
||||
musicEngine?: import('~/utils/music').MusicEngine
|
||||
}
|
||||
|
||||
export interface StudioJob {
|
||||
@@ -209,7 +213,9 @@ export function listStudioJobs(owner: string) {
|
||||
}
|
||||
|
||||
export function studioJobKind(job: Pick<StudioJob, 'kind'> | { kind?: string }) {
|
||||
return job.kind === 'edit' ? 'edit' : 'video'
|
||||
if (job.kind === 'edit') return 'edit'
|
||||
if (job.kind === 'music') return 'music'
|
||||
return 'video'
|
||||
}
|
||||
|
||||
export function summarizeStudioJob(job: StudioJob) {
|
||||
@@ -317,10 +323,12 @@ export async function addStudioJob(params: {
|
||||
kind?: StudioJobKind
|
||||
}) {
|
||||
const now = Date.now()
|
||||
const kind = params.kind === 'edit' ? 'edit' : 'video'
|
||||
const shotCount = kind === 'edit'
|
||||
? 1 + (params.payload.passes?.length || 0)
|
||||
: 1 + (params.payload.extensions?.length || 0)
|
||||
const kind = params.kind === 'edit' ? 'edit' : params.kind === 'music' ? 'music' : 'video'
|
||||
const shotCount = kind === 'music'
|
||||
? 1
|
||||
: kind === 'edit'
|
||||
? 1 + (params.payload.passes?.length || 0)
|
||||
: 1 + (params.payload.extensions?.length || 0)
|
||||
const job: StudioJob = {
|
||||
id: crypto.randomUUID(),
|
||||
ownerKey: params.ownerKey,
|
||||
@@ -976,7 +984,48 @@ async function startStudioExtendJob(item: StudioJob) {
|
||||
}
|
||||
}
|
||||
|
||||
async function startStudioMusicJob(item: StudioJob) {
|
||||
let live: import('~/server/utils/jobs').Job | undefined
|
||||
try {
|
||||
const { startMusicJob } = await import('~/server/utils/musicChain')
|
||||
const payload = item.payload
|
||||
live = await startMusicJob({
|
||||
ownerKey: item.ownerKey,
|
||||
folderId: payload.folderId,
|
||||
name: payload.name,
|
||||
tags: payload.prompt,
|
||||
lyrics: payload.instrumental ? '' : (payload.lyrics || ''),
|
||||
duration: payload.duration,
|
||||
steps: payload.steps,
|
||||
seed: payload.seed || Math.floor(Math.random() * 2_147_483_647),
|
||||
cfg: payload.cfg,
|
||||
lyricsStrength: payload.instrumental ? 0 : (payload.lyricsStrength ?? 0.9),
|
||||
instrumental: payload.instrumental === true,
|
||||
folderLocked: payload.folderLocked,
|
||||
engine: payload.musicEngine || 'ace-step',
|
||||
samplerName: payload.samplerName || 'euler',
|
||||
scheduler: payload.scheduler || 'simple'
|
||||
})
|
||||
await markStudioLive(item.ownerKey, item.id, live.id)
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
if (live && (live.status === 'queued' || live.status === 'uploading' || live.status === 'running')) {
|
||||
live.status = 'error'
|
||||
live.error = message
|
||||
}
|
||||
await patchStudioJob(item.ownerKey, item.id, (job) => {
|
||||
job.status = 'error'
|
||||
job.lastError = message
|
||||
}).catch(() => null)
|
||||
kickStudioQueue()
|
||||
}
|
||||
}
|
||||
|
||||
export async function startStudioJob(item: StudioJob) {
|
||||
if (studioJobKind(item) === 'music') {
|
||||
await startStudioMusicJob(item)
|
||||
return
|
||||
}
|
||||
if (studioJobKind(item) === 'edit') {
|
||||
await startStudioEditJob(item)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user