Accept only YuE2 in the music generate API.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-09-15 18:16:45 -05:00
co-authored by Cursor
parent 17cc07e3bc
commit c50bde723f
+19 -62
View File
@@ -1,16 +1,7 @@
import { yueGpConfigured } from '~/server/utils/yueGp'
import { yue2Configured } from '~/server/utils/yue2' import { yue2Configured } from '~/server/utils/yue2'
import { addStudioJob, kickStudioQueue, listStudioJobs, videoJobsBusy } from '~/server/utils/studioQueue' import { addStudioJob, kickStudioQueue, listStudioJobs, videoJobsBusy } from '~/server/utils/studioQueue'
import { comfyConfigured } from '~/server/utils/comfy'
import { import {
clampLyricsStrength,
clampMusicCfg,
clampMusicDuration, clampMusicDuration,
clampMusicSteps,
MUSIC_CFG_DEFAULT,
MUSIC_CFG_DEFAULT_15,
MUSIC_STEPS_DEFAULT,
MUSIC_STEPS_DEFAULT_15,
parseMusicEngine, parseMusicEngine,
parseMusicSeed, parseMusicSeed,
sanitizeMusicLyrics, sanitizeMusicLyrics,
@@ -23,37 +14,28 @@ export default defineEventHandler(async (event) => {
tags?: unknown tags?: unknown
lyrics?: unknown lyrics?: unknown
duration?: unknown duration?: unknown
steps?: unknown
seed?: unknown seed?: unknown
cfg?: unknown
lyricsStrength?: unknown
instrumental?: unknown
folderId?: unknown folderId?: unknown
name?: unknown name?: unknown
yueProfile?: unknown
engine?: unknown engine?: unknown
sampler_name?: unknown
scheduler?: unknown
}>(event).catch(() => ({} as Record<string, unknown>)) }>(event).catch(() => ({} as Record<string, unknown>))
const engine = parseMusicEngine(body.engine) const engine = parseMusicEngine(body.engine)
if (engine === 'yue' && !yueGpConfigured()) throw createError({ statusCode: 503, statusMessage: 'YuEGP host is not configured. Set COMFY_CONTROL_URL.' }) if (engine !== 'yue2') {
if (engine === 'yue2' && !yue2Configured()) throw createError({ statusCode: 503, statusMessage: 'YuE2 host is not configured. Set COMFY_CONTROL_URL.' }) throw createError({ statusCode: 400, statusMessage: 'Only YuE2 is supported for music generation.' })
if (engine !== 'yue' && engine !== 'yue2' && !comfyConfigured()) { }
throw createError({ if (!yue2Configured()) {
statusCode: 503, throw createError({ statusCode: 503, statusMessage: 'YuE2 host is not configured. Set COMFY_CONTROL_URL.' })
statusMessage: 'Beast ComfyUI is not configured. Set COMFY_HOST.'
})
} }
const instrumental = body.instrumental === true || body.instrumental === 'true'
const tags = sanitizeMusicTags(body.tags) const tags = sanitizeMusicTags(body.tags)
const lyrics = sanitizeMusicLyrics(body.lyrics, instrumental) const lyrics = sanitizeMusicLyrics(body.lyrics, false)
if (!tags) { if (!tags) {
throw createError({ statusCode: 400, statusMessage: 'Genre and style tags are required' }) throw createError({ statusCode: 400, statusMessage: 'Genre and style tags are required' })
} }
if (!instrumental && !lyrics) { const lyricsProblem = yueLyricsProblem(lyrics)
throw createError({ statusCode: 400, statusMessage: 'Lyrics are required unless Instrumental is on' }) if (lyricsProblem) {
throw createError({ statusCode: 400, statusMessage: lyricsProblem })
} }
const ownerKey = libraryOwnerKey(event) const ownerKey = libraryOwnerKey(event)
@@ -68,34 +50,12 @@ export default defineEventHandler(async (event) => {
const destFolder = library.folders.find(folder => folder.id === folderId) const destFolder = library.folders.find(folder => folder.id === folderId)
const folderLocked = Boolean(destFolder?.protected && !destFolder.unlocked) const folderLocked = Boolean(destFolder?.protected && !destFolder.unlocked)
if ((engine === 'yue' || engine === 'yue2') && instrumental) throw createError({ statusCode: 400, statusMessage: 'YuE currently requires lyrics. Use ACE for instrumental music.' })
const yueProfile = body.yueProfile ?? 1
if (engine === 'yue' && yueProfile !== 1 && yueProfile !== 3) throw createError({ statusCode: 400, statusMessage: 'Choose YuEGP profile 1 or manual fallback 3.' })
if (engine === 'yue' && !instrumental) {
const problem = yueLyricsProblem(lyrics)
if (problem) throw createError({ statusCode: 400, statusMessage: problem })
}
if (engine === 'yue2' && !instrumental && !lyrics) {
throw createError({ statusCode: 400, statusMessage: 'YuE2 needs lyrics.' })
}
const duration = clampMusicDuration(body.duration) const duration = clampMusicDuration(body.duration)
if ((engine === 'yue' || engine === 'yue2') && duration > 150) throw createError({ statusCode: 400, statusMessage: 'YuE supports up to 150 seconds per section.' })
const steps = clampMusicSteps(
body.steps,
engine === 'ace-step-1.5' ? MUSIC_STEPS_DEFAULT_15 : MUSIC_STEPS_DEFAULT
)
const cfg = clampMusicCfg(
body.cfg,
engine === 'ace-step-1.5' ? MUSIC_CFG_DEFAULT_15 : MUSIC_CFG_DEFAULT
)
const lyricsStrength = clampLyricsStrength(body.lyricsStrength)
const seed = parseMusicSeed(body.seed) const seed = parseMusicSeed(body.seed)
const clipName = allocateOutputName(ownerKey, folderId, String(body.name || '').trim(), { const clipName = allocateOutputName(ownerKey, folderId, String(body.name || '').trim(), {
engine: engine === 'ace-step-1.5' ? 'ace15' : engine === 'yue' ? 'yue' : engine === 'yue2' ? 'yue2' : 'ace' engine: 'yue2'
}) })
const samplerName = String(body.sampler_name || 'euler')
const scheduler = String(body.scheduler || 'simple')
const familyId = crypto.randomUUID() const familyId = crypto.randomUUID()
const studio = await addStudioJob({ const studio = await addStudioJob({
ownerKey, ownerKey,
@@ -108,15 +68,15 @@ export default defineEventHandler(async (event) => {
aspect: 'audio', aspect: 'audio',
width: 0, width: 0,
height: 0, height: 0,
steps, steps: 0,
turbo: false, turbo: false,
seed, seed,
cfg, cfg: 0,
fps: 0, fps: 0,
samplerName, samplerName: 'euler',
scheduler, scheduler: 'simple',
duration, duration,
sound: !instrumental, sound: true,
workflow: 'v1', workflow: 'v1',
useIdentityRefs: false, useIdentityRefs: false,
hideThumbnail: false, hideThumbnail: false,
@@ -125,10 +85,9 @@ export default defineEventHandler(async (event) => {
extensions: [], extensions: [],
queueAutoRun: false, queueAutoRun: false,
lyrics, lyrics,
instrumental, instrumental: false,
lyricsStrength, lyricsStrength: 0,
musicEngine: engine, musicEngine: 'yue2'
...(engine === 'yue' ? { yueProfile: yueProfile as 1 | 3 } : {})
} }
}) })
await kickStudioQueue() await kickStudioQueue()
@@ -145,11 +104,9 @@ export default defineEventHandler(async (event) => {
queued: !liveJobId, queued: !liveJobId,
seed, seed,
duration, duration,
steps,
cfg,
folderId, folderId,
folderLocked, folderLocked,
engine, engine: 'yue2' as const,
name: clipName name: clipName
} }
}) })