Various UI improvements

This commit is contained in:
riversedge
2026-02-04 23:15:00 -05:00
parent b75bea3860
commit 424bd3fd25
9 changed files with 262 additions and 67 deletions
+63 -16
View File
@@ -125,7 +125,6 @@ async function submitToApi(params: GenerationParams): Promise<{ taskId: string }
const body: Record<string, unknown> = {
prompt,
lyrics,
audio_duration: params.duration ?? 60,
batch_size: params.batchSize ?? 1,
inference_steps: params.inferenceSteps ?? 8,
guidance_scale: params.guidanceScale ?? 10.0,
@@ -139,6 +138,7 @@ async function submitToApi(params: GenerationParams): Promise<{ taskId: string }
use_cot_metas: false, // Explicitly disable CoT features that require LLM
};
if (params.duration && params.duration > 0) body.audio_duration = params.duration;
if (params.bpm && params.bpm > 0) body.bpm = params.bpm;
if (params.keyScale) body.key_scale = params.keyScale;
if (params.timeSignature) body.time_signature = params.timeSignature;
@@ -166,20 +166,42 @@ async function submitToApi(params: GenerationParams): Promise<{ taskId: string }
if (params.cfgIntervalStart !== undefined && params.cfgIntervalStart > 0) body.cfg_interval_start = params.cfgIntervalStart;
if (params.cfgIntervalEnd !== undefined && params.cfgIntervalEnd < 1.0) body.cfg_interval_end = params.cfgIntervalEnd;
const resolveAudioPath = (audioUrl: string): string => {
if (audioUrl.startsWith('/audio/')) {
return path.join(AUDIO_DIR, audioUrl.replace('/audio/', ''));
}
if (audioUrl.startsWith('http')) {
try {
const parsed = new URL(audioUrl);
if (parsed.pathname.startsWith('/audio/')) {
return path.join(AUDIO_DIR, parsed.pathname.replace('/audio/', ''));
}
} catch {
// fall through
}
}
return audioUrl;
};
// Guard: cover/audio2audio requires a source or audio codes
if ((params.taskType === 'cover' || params.taskType === 'audio2audio') && !params.sourceAudioUrl && !params.audioCodes) {
throw new Error(`task_type='${params.taskType}' requires a source audio or audio codes`);
}
// Handle reference audio - need to pass file path
if (params.referenceAudioUrl) {
let refAudioPath = params.referenceAudioUrl;
if (refAudioPath.startsWith('/audio/')) {
refAudioPath = path.join(AUDIO_DIR, refAudioPath.replace('/audio/', ''));
}
body.reference_audio_path = refAudioPath;
body.reference_audio_path = resolveAudioPath(params.referenceAudioUrl);
}
if (params.sourceAudioUrl) {
let srcAudioPath = params.sourceAudioUrl;
if (srcAudioPath.startsWith('/audio/')) {
srcAudioPath = path.join(AUDIO_DIR, srcAudioPath.replace('/audio/', ''));
}
body.src_audio_path = srcAudioPath;
body.src_audio_path = resolveAudioPath(params.sourceAudioUrl);
}
if (params.taskType === 'cover' || params.taskType === 'audio2audio') {
console.log(`[ACE-Step] cover/audio2audio inputs`, {
reference_audio_path: body.reference_audio_path,
src_audio_path: body.src_audio_path,
has_audio_codes: Boolean(params.audioCodes),
});
}
const response = await fetch(`${ACESTEP_API}/release_task`, {
@@ -263,6 +285,20 @@ async function pollApiResult(taskId: string, maxWaitMs = 600000): Promise<ApiTas
throw new Error(`Generation failed on API side: ${details}`);
}
// Log progress while processing (if provided)
if (taskData.result) {
try {
const resultData = typeof taskData.result === 'string' ? JSON.parse(taskData.result) : taskData.result;
const item = Array.isArray(resultData) ? resultData[0] : resultData;
if (item && typeof item === 'object' && typeof (item as any).progress === 'number') {
const pct = Math.round((item as any).progress * 100);
console.log(`[ACE-Step] API task ${taskId} progress: ${pct}%`);
}
} catch {
// ignore parse failures
}
}
// Still processing
await new Promise(resolve => setTimeout(resolve, pollInterval));
}
@@ -349,6 +385,8 @@ export interface GenerationParams {
// Expert Parameters
referenceAudioUrl?: string;
sourceAudioUrl?: string;
referenceAudioTitle?: string;
sourceAudioTitle?: string;
audioCodes?: string;
repaintingStart?: number;
repaintingEnd?: number;
@@ -403,6 +441,8 @@ interface ActiveJob {
processPromise?: Promise<void>;
rawResponse?: unknown;
queuePosition?: number;
progress?: number;
stage?: string;
}
const activeJobs = new Map<string, ActiveJob>();
@@ -466,6 +506,8 @@ async function processQueue(): Promise<void> {
// Submit generation job to queue
export async function generateMusicViaAPI(params: GenerationParams): Promise<{ jobId: string }> {
// Force a fresh API availability check when starting a job
resetApiCache();
const jobId = `job_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
const job: ActiveJob = {
@@ -573,9 +615,10 @@ async function processGeneration(
const jobOutputDir = path.join(ACESTEP_DIR, 'output', jobId);
await mkdir(jobOutputDir, { recursive: true });
const durationToSend = params.duration && params.duration > 0 ? params.duration : 60;
const args = [
'--prompt', prompt,
'--duration', String(params.duration ?? 60),
'--duration', String(durationToSend),
'--batch-size', String(params.batchSize ?? 1),
'--infer-steps', String(params.inferenceSteps ?? 8),
'--guidance-scale', String(params.guidanceScale ?? 10.0),
@@ -701,7 +744,6 @@ function runPythonGeneration(scriptArgs: string[]): Promise<PythonResult> {
cwd: ACESTEP_DIR,
env: {
...process.env,
CUDA_VISIBLE_DEVICES: '0',
ACESTEP_PATH: ACESTEP_DIR,
},
});
@@ -863,13 +905,16 @@ export async function getJobStatus(jobId: string): Promise<JobStatus> {
const item = Array.isArray(resultData) ? resultData[0] : resultData;
if (item && typeof item === 'object') {
const progress = typeof (item as any).progress === 'number' ? (item as any).progress : undefined;
const rawProgress = (item as any).progress;
const progress = Number.isFinite(Number(rawProgress)) ? Number(rawProgress) : undefined;
const stage = typeof (item as any).stage === 'string' ? (item as any).stage : undefined;
if (progress !== undefined) job.progress = progress;
if (stage) job.stage = stage;
return {
status: job.status,
etaSeconds: Math.max(0, 180 - elapsed),
progress,
stage,
progress: progress ?? job.progress,
stage: stage ?? job.stage,
};
}
}
@@ -882,6 +927,8 @@ export async function getJobStatus(jobId: string): Promise<JobStatus> {
return {
status: job.status,
etaSeconds: Math.max(0, 180 - elapsed), // 3 min estimate
progress: job.progress,
stage: job.stage,
};
}