diff --git a/pages/music.vue b/pages/music.vue index eb943a6..2c8b6ae 100644 --- a/pages/music.vue +++ b/pages/music.vue @@ -411,14 +411,35 @@ async function refreshStudioQueue() { if (queued.value && !jobId.value) { queued.value = false } + if (jobId.value && /waiting in the job queue/i.test(status.value)) { + status.value = selectedEngine.value === 'yue' + ? 'YuE running on Comfy — Stage A can take 10–20+ minutes' + : 'Generating…' + } return } if (row.status === 'waiting' || (row.status === 'held' && !row.liveJobId)) { queued.value = true busy.value = true - status.value = row.status === 'held' ? 'Paused in the job queue' : 'Waiting in the job queue…' + status.value = row.status === 'held' + ? 'Paused in the job queue' + : (selectedEngine.value === 'yue' + ? 'Waiting for GPU… YuE is heavy; do not spam Generate' + : 'Waiting in the job queue…') return } + if (row.status === 'running' && row.liveJobId) { + queued.value = false + if (!jobId.value || jobId.value !== row.liveJobId) { + jobId.value = row.liveJobId + listen(row.liveJobId) + } + if (/waiting/i.test(status.value)) { + status.value = selectedEngine.value === 'yue' + ? 'YuE running on Comfy — Stage A can take 10–20+ minutes' + : 'Generating…' + } + } if (row.status === 'error') { queued.value = false busy.value = false diff --git a/server/assets/workflow_yue.json b/server/assets/workflow_yue.json index ef59b86..b17278d 100644 --- a/server/assets/workflow_yue.json +++ b/server/assets/workflow_yue.json @@ -5,9 +5,9 @@ "xcodec_ckpt": "ckpt_00360000.pth", "quantization_model": "fp16", "use_mmgp": true, - "stage1_cache_size": 16384, + "stage1_cache_size": 8192, "exllamav2_cache_mode": "FP16", - "mmgp_profile": 2 + "mmgp_profile": 4 }, "class_type": "YUE_Stage_A_Loader", "_meta": { @@ -23,7 +23,7 @@ "repetition_penalty": 1.1, "prompt_start_time": 0, "prompt_end_time": 30, - "max_new_tokens": 3000, + "max_new_tokens": 2000, "use_dual_tracks_prompt": false, "use_audio_prompt": false, "offload_model": true, @@ -38,8 +38,8 @@ "16": { "inputs": { "stage_B_repo": "m-a-p/YuE-s2-1B-general", - "stage2_cache_size": 8192, - "stage2_batch_size": 2, + "stage2_cache_size": 4096, + "stage2_batch_size": 1, "exllamav2_cache_mode": "FP16", "use_mmgp": true, "info": ["8", 1] diff --git a/server/utils/musicChain.ts b/server/utils/musicChain.ts index 552f061..46f015d 100644 --- a/server/utils/musicChain.ts +++ b/server/utils/musicChain.ts @@ -32,8 +32,8 @@ function sleep(ms: number) { function classifyError(message: string) { const lower = message.toLowerCase() - if (lower.includes('out of memory') || (lower.includes('cuda') && lower.includes('alloc')) || lower.includes('vram')) { - return 'ComfyUI VRAM allocation failed. Try fewer steps or a shorter duration.' + if (lower.includes('out of memory') || lower.includes('exceed allowed memory') || (lower.includes('cuda') && lower.includes('alloc')) || lower.includes('vram')) { + return 'ComfyUI ran out of VRAM. For YuE use shorter lyrics (fewer sections) or ACE-Step instead.' } if (lower.includes('econnrefused') || lower.includes('unreachable') || lower.includes('fetch failed')) { return 'ComfyUI host connection dropped. Confirm the desktop instance is running.' @@ -245,11 +245,18 @@ function watchMusicJob(job: Job): Promise { return } const entry = (job.promptId ? history?.[job.promptId] : undefined) as { - status?: { status_str?: string; completed?: boolean } + status?: { + status_str?: string + completed?: boolean + messages?: Array<[string, Record]> + } } | undefined const status = entry?.status?.status_str - if (status === 'error') await fail('ComfyUI reported an execution error') - else if (status === 'interrupted') await fail('Job interrupted.') + if (status === 'error') { + const err = entry?.status?.messages?.find(([type]) => type === 'execution_error')?.[1] + const detail = String(err?.exception_message || err?.message || '').trim() + await fail(detail || 'ComfyUI reported an execution error') + } else if (status === 'interrupted') await fail('Job interrupted.') } catch { // history can miss while the graph is still running } @@ -382,14 +389,19 @@ export async function startMusicJob(params: MusicJobParams) { try { const queued = await queuePrompt(graph, job.clientId, { timeoutMs: 25_000 }) if (queued?.prompt_id) job.promptId = queued.prompt_id - emitJob(job, { type: 'status', message: 'Job queued on ComfyUI', progress: 8 }) + const runningMessage = params.engine === 'yue' + ? 'YuE Stage A on Comfy — 16GB job, often 10–20+ minutes. Leave it alone.' + : 'Job queued on ComfyUI' + emitJob(job, { type: 'status', message: runningMessage, progress: 8 }) } catch (queueError: unknown) { const statusCode = Number((queueError as { statusCode?: number; status?: number })?.statusCode || (queueError as { status?: number })?.status || 0) if (statusCode >= 400) throw queueError emitJob(job, { type: 'status', - message: 'Waiting for ComfyUI to pick up the job...', + message: params.engine === 'yue' + ? 'YuE submitted — waiting for Comfy to start Stage A…' + : 'Waiting for ComfyUI to pick up the job...', progress: 8 }) } diff --git a/server/utils/musicWorkflow.ts b/server/utils/musicWorkflow.ts index 041b1e4..6a0dc19 100644 --- a/server/utils/musicWorkflow.ts +++ b/server/utils/musicWorkflow.ts @@ -116,7 +116,9 @@ function buildYueWorkflow(params: MusicWorkflowParams): WorkflowGraph { const prefix = params.filenamePrefix || musicFilenamePrefix() const tags = params.tags const lyrics = params.lyrics || '[instrumental]\n' - const segments = Math.max(1, Math.min(10, lyrics.split(/\[[^\]]+\]/g).filter(part => part.trim()).length || 2)) + // 5080 16GB OOMs past ~3 long Stage-A segments on fp16+mmgp. Cap hard. + const sections = lyrics.split(/\[[^\]]+\]/g).filter(part => part.trim()).length || 2 + const segments = Math.max(1, Math.min(2, sections)) for (const node of Object.values(graph)) { if (node.class_type === 'YUE_Stage_A_Loader') { node.inputs.stage_A_repo = yueStageARepo() @@ -128,8 +130,9 @@ function buildYueWorkflow(params: MusicWorkflowParams): WorkflowGraph { node.inputs.genres_prompt = tags.replace(/,/g, ' ').replace(/\s+/g, ' ').trim() node.inputs.lyrics_prompt = lyrics node.inputs.seed = params.seed - node.inputs.prompt_end_time = params.duration + node.inputs.prompt_end_time = Math.min(params.duration, 45) node.inputs.run_n_segment = segments + node.inputs.max_new_tokens = 2000 } } applyPrefix(graph, prefix)