Skip to content

thinking-lm: Quality presets, wire Thinking/LM params, LM planner fro…#45

Merged
lmangani merged 4 commits intomainfrom
thinking-lm
Feb 7, 2026
Merged

thinking-lm: Quality presets, wire Thinking/LM params, LM planner fro…#45
lmangani merged 4 commits intomainfrom
thinking-lm

Conversation

@lmangani
Copy link
Contributor

@lmangani lmangani commented Feb 6, 2026

Extend Settings

  • CreatePanel: Quality preset (Fast/Good/Best/Custom) sets steps, guidance, Thinking, CoT
  • API/generate_ace: pass thinking, useCot*, lm* and lm_checkpoint_path to pipeline
  • generate_ace: resolve LM path from Settings (ace_step_lm); no external LLM
  • Pipeline: accept thinking/CoT/LM kwargs and lm_checkpoint_path; optional _refine_prompt_with_lm when ACE-Step 1.5 LM API available
  • Settings: LM planner copy says bundled 5Hz LM, no external LLM
  • ace_step_models API + acestep15_downloader for model list/downloads

E and others added 3 commits February 6, 2026 22:45
…m Settings

- CreatePanel: Quality preset (Fast/Good/Best/Custom) sets steps, guidance, Thinking, CoT
- API/generate_ace: pass thinking, useCot*, lm* and lm_checkpoint_path to pipeline
- generate_ace: resolve LM path from Settings (ace_step_lm); no external LLM
- Pipeline: accept thinking/CoT/LM kwargs and lm_checkpoint_path; optional _refine_prompt_with_lm when ACE-Step 1.5 LM API available
- Settings: LM planner copy says bundled 5Hz LM, no external LLM
- ace_step_models API + acestep15_downloader for model list/downloads

Co-authored-by: Cursor <cursoragent@cursor.com>
…anced

- Quality presets: Basic/Great/Best (both Simple and Advanced), tuned from ACE-Step docs
- Simple: Quality buttons + Generation influence sliders (Weirdness, Style, Audio when ref)
- Exclude styles (negative prompt) Suno-style above sliders in Simple, and in Advanced
- API: pass negativePrompt to generate_track_ace
- Remove unused Track Name and Complete Track Classes from Advanced and types

Co-authored-by: Cursor <cursoragent@cursor.com>
- Add Title field in Simple mode (same as Custom)
- Save title, lyrics, style to track metadata on generation success; songs API uses meta title
- Advanced Settings and Music Parameters only in Custom mode; Simple has no advanced section
- Add Reference & cover (optional) to Simple so ref/cover not hidden; infer taskType cover when source set
- Remove trackName/completeTrackClasses from App genParams

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR expands the ACE-Step integration across the UI + Flask API by adding quality presets, negative prompting, per-job progress/ETA reporting, and a new ACE-Step model management API (list/download/status) including a bundled downloader for packaged builds.

Changes:

  • UI: add quality presets, “Exclude styles” (negative prompt), and improved job progress display (percent/steps/ETA).
  • API/pipeline: wire Thinking/CoT/LM params through to generation, add per-job progress callback plumbing, and persist track metadata (title/lyrics/style).
  • Add /api/ace-step/* endpoints plus vendored acestep15_downloader and update preferences/docs to support DiT/LM selection.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 19 comments.

Show a summary per file
File Description
ui/types.ts Adds generation progress fields to Song and adds negativePrompt to generation params.
ui/services/api.ts Adds ACE-Step models API typings + endpoints; adds job progress fields to GenerationJob; adds preferences keys.
ui/components/SongList.tsx Displays generation progress percent/steps/ETA while generating.
ui/components/SettingsModal.tsx Adds ACE-Step Models settings UI + downloader progress/cancel UI.
ui/components/Player.tsx Hardens seek/progress calculations against zero/invalid duration.
ui/components/CreatePanel.tsx Adds quality presets, negative prompt, and Simple-mode influence sliders; removes unused fields.
ui/App.tsx Improves audio duration/seek behavior; updates temp-song progress fields from job status polling.
music_forge_ui.py Adds per-thread job id log prefixing and registers the new ACE-Step models blueprint.
generate_ace.py Adds job-progress callback support, LM checkpoint resolution from preferences, and accepts new task types.
cdmf_state.py Adds thread-local current job id helpers for progress/log tagging.
cdmf_pipeline_ace_step.py Adds optional LM prompt refinement hook and forces vocal language tokenization when specified.
api/generate.py Wires Thinking/CoT/LM params, negative prompt, job progress reporting, and saves track metadata on success.
api/ace_step_models.py New API for listing/downloading/cancelling ACE-Step DiT/LM models + discovered checkpoints.
api/songs.py Uses saved metadata title if present (fallback to stem).
docs/ACEFORGE_API.md Documents new preferences keys and /api/ace-step/* routes.
acestep15_downloader/* Vendored downloader with progress callback + cancel support.
CDMF.spec Ensures downloader modules are bundled in the frozen app.
Comments suppressed due to low confidence (1)

generate_ace.py:588

  • lego/extract/complete are now accepted task types here, but the current pipeline (cdmf_pipeline_ace_step.ACEStepPipeline.__call__) will force any run with audio2audio_enable + ref_audio_input to task = 'audio2audio', so these tasks won’t execute their intended behavior (they effectively run as audio2audio/retake). Consider rejecting these tasks with a clear error until the full ACE-Step 1.5 task implementation is available, or add explicit handling so the requested task is preserved.
    task_norm = (task or "text2music").strip().lower()
    if task_norm not in ("text2music", "retake", "repaint", "extend", "cover", "audio2audio", "lego", "extract", "complete"):
        task_norm = "text2music"
    # Map UI task names to pipeline task: cover and audio2audio both run as retake
    # (pipeline will set task to "audio2audio" when ref_audio_input is passed).
    if task_norm in ("cover", "audio2audio"):
        task_norm = "retake"

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 626 to 676
const genParams = {
customMode: params.customMode,
songDescription: params.songDescription,
lyrics: params.lyrics,
style: params.style,
title: params.title,
instrumental: params.instrumental,
vocalLanguage: params.vocalLanguage,
duration: params.duration,
bpm: params.bpm,
keyScale: params.keyScale,
timeSignature: params.timeSignature,
inferenceSteps: params.inferenceSteps,
guidanceScale: params.guidanceScale,
batchSize: params.batchSize,
randomSeed: params.randomSeed,
seed: params.seed,
thinking: params.thinking,
audioFormat: params.audioFormat,
inferMethod: params.inferMethod,
shift: params.shift,
lmTemperature: params.lmTemperature,
lmCfgScale: params.lmCfgScale,
lmTopK: params.lmTopK,
lmTopP: params.lmTopP,
lmNegativePrompt: params.lmNegativePrompt,
referenceAudioUrl: params.referenceAudioUrl,
sourceAudioUrl: params.sourceAudioUrl,
audioCodes: params.audioCodes,
repaintingStart: params.repaintingStart,
repaintingEnd: params.repaintingEnd,
instruction: params.instruction,
audioCoverStrength: params.audioCoverStrength,
taskType: params.taskType,
useAdg: params.useAdg,
cfgIntervalStart: params.cfgIntervalStart,
cfgIntervalEnd: params.cfgIntervalEnd,
customTimesteps: params.customTimesteps,
useCotMetas: params.useCotMetas,
useCotCaption: params.useCotCaption,
useCotLanguage: params.useCotLanguage,
autogen: params.autogen,
constrainedDecodingDebug: params.constrainedDecodingDebug,
allowLmBatch: params.allowLmBatch,
getScores: params.getScores,
getLrc: params.getLrc,
scoreScale: params.scoreScale,
lmBatchChunkSize: params.lmBatchChunkSize,
trackName: params.trackName,
completeTrackClasses: params.completeTrackClasses,
isFormatCaption: params.isFormatCaption,
...(prefs.output_dir ? { outputDir: prefs.output_dir } : {}),
};
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

negativePrompt is included in ui/types.ts and is populated in CreatePanel, but it is not forwarded into the genParams object sent to POST /api/generate here. As a result, the backend never receives the negative prompt and api/generate.py will always see it as empty. Add negativePrompt: params.negativePrompt (or equivalent mapping) when building genParams.

Copilot uses AI. Check for mistakes.
Comment on lines +61 to +64
const ditVal = prefs.ace_step_dit_model ?? 'turbo';
setAceStepDitModel(ACE_STEP_DIT_OPTIONS.some((o) => o.value === ditVal) ? ditVal : 'turbo');
const lmVal = prefs.ace_step_lm ?? '1.7B';
setAceStepLm(ACE_STEP_LM_OPTIONS.some((o) => o.value === lmVal) ? lmVal : '1.7B');
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This validation only allows ace_step_dit_model values that match ACE_STEP_DIT_OPTIONS, so any previously selected discovered/custom DiT model id from the checkpoints folder will be overwritten to turbo when opening Settings. To support discovered models, keep the raw preference value here and validate/sanitize only after aceStepList is loaded (or validate against both preset + discovered ids).

Copilot uses AI. Check for mistakes.
Comment on lines +321 to +328
use_cot_metas=True,
use_cot_caption=True,
use_cot_language=True,
lm_temperature=0.85,
lm_cfg_scale=2.0,
lm_top_k=0,
lm_top_p=0.9,
lm_negative_prompt="NO USER INPUT",
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use_cot_metas, use_cot_caption, use_cot_language, lm_cfg_scale, and lm_negative_prompt are accepted here but currently unused, which is misleading and makes it hard to reason about which LM settings actually take effect. Either wire these parameters into the ACE-Step LM call (if supported) or remove them from the helper signature until they are implemented.

Suggested change
use_cot_metas=True,
use_cot_caption=True,
use_cot_language=True,
lm_temperature=0.85,
lm_cfg_scale=2.0,
lm_top_k=0,
lm_top_p=0.9,
lm_negative_prompt="NO USER INPUT",
lm_temperature=0.85,
lm_top_k=0,
lm_top_p=0.9,

Copilot uses AI. Check for mistakes.

from pathlib import Path
import subprocess
import sys
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sys is imported but never used in this module. Removing unused imports helps keep the API module clean and avoids lint warnings.

Suggested change
import sys

Copilot uses AI. Check for mistakes.
Comment on lines +263 to +289
@bp.route("/models", methods=["GET"])
@bp.route("/models/", methods=["GET"])
def list_models():
"""
GET /api/ace-step/models
Returns known DiT/LM models with installed status plus all discovered model dirs on disk (custom/trained).
"""
use_15 = _acestep_download_available()
# Known DiT: always include; installed = on disk (1.5 layout or v1 legacy)
dit = []
for m in DIT_MODELS:
installed = _model_installed_15(m["id"], "dit") if use_15 else (m["id"] == "turbo" and _default_dit_installed())
dit.append({**m, "installed": installed})
# Known LM
lm = []
for m in LM_MODELS:
installed = _model_installed_15(m["id"], "lm") if use_15 else (m["id"] == "none")
lm.append({**m, "installed": installed})
# All model dirs found under checkpoints (custom trained, v1, 1.5, etc.)
discovered = _discover_model_dirs()
return jsonify({
"dit_models": dit,
"lm_models": lm,
"discovered_models": discovered,
"acestep_download_available": use_15,
"checkpoints_path": str(_checkpoint_root()),
})
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New /api/ace-step/* routes are introduced here, but tests/test_new_ui_api.py currently has no coverage for listing models, starting a download, and checking status/cancel behavior. Adding at least contract-level tests (status codes + response shape) would help prevent regressions.

Copilot uses AI. Check for mistakes.
Comment on lines +260 to +266
except Exception:
pass
if _JOB_PROGRESS_CALLBACK is not None:
try:
_JOB_PROGRESS_CALLBACK(frac, stage, steps_current, steps_total, eta_seconds)
except Exception:
pass
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Suggested change
except Exception:
pass
if _JOB_PROGRESS_CALLBACK is not None:
try:
_JOB_PROGRESS_CALLBACK(frac, stage, steps_current, steps_total, eta_seconds)
except Exception:
pass
except Exception as exc:
print(
f"[generate_ace] ERROR: progress callback raised an exception: {exc}",
file=sys.stderr,
flush=True,
)
if _JOB_PROGRESS_CALLBACK is not None:
try:
_JOB_PROGRESS_CALLBACK(frac, stage, steps_current, steps_total, eta_seconds)
except Exception as exc:
print(
f"[generate_ace] ERROR: job progress callback raised an exception: {exc}",
file=sys.stderr,
flush=True,
)

Copilot uses AI. Check for mistakes.
if _JOB_PROGRESS_CALLBACK is not None:
try:
_JOB_PROGRESS_CALLBACK(frac, stage, steps_current, steps_total, eta_seconds)
except Exception:
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Copilot uses AI. Check for mistakes.
eta_sec = fd.get("remaining")
if eta_sec is not None and not isinstance(eta_sec, (int, float)):
eta_sec = None
except Exception:
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Copilot uses AI. Check for mistakes.
Comment on lines +71 to +72
except Exception:
pass
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Suggested change
except Exception:
pass
except Exception as exc:
logger.exception("Error in progress callback during download: %s", exc)

Copilot uses AI. Check for mistakes.
@lmangani lmangani merged commit 357c51b into main Feb 7, 2026
4 checks passed
@lmangani lmangani deleted the thinking-lm branch February 7, 2026 10:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant