import { startMusicJob } from '~/server/utils/musicChain' import { comfyConfigured } from '~/server/utils/comfy' import { clampLyricsStrength, clampMusicCfg, clampMusicDuration, clampMusicSteps, parseMusicEngine, parseMusicSeed, sanitizeMusicLyrics, sanitizeMusicTags } from '~/utils/music' export default defineEventHandler(async (event) => { const body = await readBody<{ tags?: unknown lyrics?: unknown duration?: unknown steps?: unknown seed?: unknown cfg?: unknown lyricsStrength?: unknown instrumental?: unknown folderId?: unknown name?: unknown engine?: unknown sampler_name?: unknown scheduler?: unknown }>(event).catch(() => ({} as Record)) if (!comfyConfigured()) { throw createError({ statusCode: 503, statusMessage: 'Beast ComfyUI is not configured. Set COMFY_HOST.' }) } const instrumental = body.instrumental === true || body.instrumental === 'true' const tags = sanitizeMusicTags(body.tags) const lyrics = sanitizeMusicLyrics(body.lyrics, instrumental) if (!tags) { throw createError({ statusCode: 400, statusMessage: 'Genre and style tags are required' }) } if (!instrumental && !lyrics) { throw createError({ statusCode: 400, statusMessage: 'Lyrics are required unless Instrumental is on' }) } const ownerKey = libraryOwnerKey(event) const library = publicLibrary(event) const folderId = library.folders.some(folder => folder.id === String(body.folderId || '')) ? String(body.folderId) : library.folders[0]?.id if (!folderId) { throw createError({ statusCode: 400, statusMessage: 'Create a library folder before generating' }) } assertFolderExists(event, folderId) const destFolder = library.folders.find(folder => folder.id === folderId) const folderLocked = Boolean(destFolder?.protected && !destFolder.unlocked) const duration = clampMusicDuration(body.duration) const steps = clampMusicSteps(body.steps) const cfg = clampMusicCfg(body.cfg) const lyricsStrength = clampLyricsStrength(body.lyricsStrength) const seed = parseMusicSeed(body.seed) const engine = parseMusicEngine(body.engine) const clipName = allocateOutputName(ownerKey, folderId, String(body.name || '').trim(), { engine: engine === 'ace-step-1.5' ? 'ace15' : 'ace' }) const job = await startMusicJob({ ownerKey, folderId, name: clipName, tags, lyrics, duration, steps, seed, cfg, lyricsStrength, instrumental, folderLocked, engine, samplerName: String(body.sampler_name || 'euler'), scheduler: String(body.scheduler || 'simple') }) return { jobId: job.id, queued: job.status === 'queued', seed, duration, steps, cfg, folderId, folderLocked, engine, name: clipName } })