ChatGPT
fix: make upload and fallback robust
5a90820
|
Raw
History Blame Contribute Delete
18.9 kB

API documentation

Last updated: 2026-05-12

The active app is app.py, a FastAPI application.

Start server

uvicorn app:app --host 0.0.0.0 --port 7860

GET /api/health

Returns backend health.

{"status":"ok"}

GET /api/config

Returns supported models, stems, default pipeline params, stage definitions, and clustering mode labels.

curl http://127.0.0.1:7860/api/config

Important response keys:

Key Meaning
separation_backends Supported separation engines: spleeter, demucs, and none.
spleeter_models Supported Spleeter model profiles.
spleeter_stems Valid stems per Spleeter model, plus all.
demucs_models Supported Demucs model names.
demucs_stems Valid stems per Demucs model, plus all.
defaults Default PipelineParams.
stages Pipeline stage definitions.
clustering_modes Human-readable labels for batch and online clustering modes.

GET /api/jobs

Lists active in-memory jobs and completed run manifests found under .runs/.

curl http://127.0.0.1:7860/api/jobs?limit=50

Response:

{
  "active": [],
  "history": [
    {
      "id": "58ca0db4ac74",
      "status": "complete",
      "filename": "song.wav",
      "created_at": 1778540000.0,
      "duration_sec": 2.4,
      "audio_duration_sec": 8.0,
      "realtime_factor": 0.3,
      "bpm": 120.0,
      "hit_count": 32,
      "cluster_count": 8,
      "clustering_mode": "online_preview",
      "stem": "all",
      "error": null
    }
  ]
}

created_at is the manifest file modification time as a Unix timestamp.

POST /api/jobs

Creates an extraction job.

The endpoint accepts browser-form-style JSON values for numeric and boolean params. For example, { "subdivision": "16" } is coerced to integer 16 before validation. Invalid values return 400 with an actionable detail message suitable for direct UI display.

Content type: multipart/form-data

Fields:

Field Type Required Description
file file yes Audio source.
params JSON string no Partial or full pipeline params.

Example:

curl -F 'file=@song.wav' \
  -F 'params={"separation_backend":"spleeter","spleeter_model":"spleeter:4stems","stem":"drums","clustering_mode":"online_preview","target_min":4,"target_max":12,"synthesize":true}' \
  http://127.0.0.1:7860/api/jobs

Response status: 202 Accepted

Invalid params response example:

{"detail":"Invalid extraction parameter: subdivision must be one of 4, 8, 16, 32, 64"}
{
  "id": "58ca0db4ac74",
  "status": "pending",
  "filename": "song.wav",
  "params": {"stem": "all", "clustering_mode": "online_preview"},
  "stages": [],
  "logs": [],
  "result": null,
  "error": null
}

GET /api/jobs/{job_id}

Poll job status and retrieve results. This works for active in-memory jobs and completed historical jobs whose manifest is still present in .runs/.

Statuses:

Status Meaning
pending Job is queued.
running Job is executing.
complete Result and artifacts are ready.
error Pipeline failed; error and traceback are populated.

Completed jobs contain:

Key Meaning
duration_sec Total wall time.
audio_duration_sec Duration of processed stem/source.
realtime_factor duration_sec / audio_duration_sec.
bpm Detected tempo.
hit_count Number of accepted onsets/hits.
cluster_count Number of sample clusters.
stages Per-stage timing/status/detail list.
samples Representative sample rows with score, duration, first onset, and playback/download URL.
hits Per-detected-hit review rows with onset, duration, label, cluster, representative flag, and playback/download URL.
overview Decimated envelope and clickable onset markers for waveform display.
files Relative artifact paths. Includes source, stem, context_bed, target_reconstruction, reconstruction, midi, and archive when available.
file_urls Direct API URLs for top-level artifacts.

GET /api/jobs/{job_id}/events

Streams job snapshots as server-sent events. This is the preferred progress channel for the frontend; polling remains supported via GET /api/jobs/{job_id}.

curl -N http://127.0.0.1:7860/api/jobs/58ca0db4ac74/events

Event shape:

event: job
data: {"id":"58ca0db4ac74","status":"running","stages":[...]}

The stream closes after complete or error. Completed historical jobs emit one final job event and close.

Top-level artifact meanings

Key Path Meaning
source source.wav Normalized source mix used for source preview.
stem stem.wav Target stem being sampled.
context_bed context_bed.wav Non-target stems/context bed; silent for stem=all.
target_reconstruction target_reconstruction.wav Sample-triggered reconstruction of only the target stem.
reconstruction reconstruction.wav Full-context reproduced mix: context bed plus target reconstruction.
midi reconstruction.mid MIDI trigger reconstruction.
archive sample-pack.zip Complete sample pack and reproduction artifacts.

GET /api/jobs/{job_id}/files/{relative_path}

Downloads an artifact from a completed job.

Examples:

curl -O http://127.0.0.1:7860/api/jobs/58ca0db4ac74/files/sample-pack.zip
curl -O http://127.0.0.1:7860/api/jobs/58ca0db4ac74/files/reconstruction.mid
curl -O http://127.0.0.1:7860/api/jobs/58ca0db4ac74/files/reconstruction.wav
curl -O http://127.0.0.1:7860/api/jobs/58ca0db4ac74/files/target_reconstruction.wav
curl -O http://127.0.0.1:7860/api/jobs/58ca0db4ac74/files/samples/hihat_open_0.wav
curl -O http://127.0.0.1:7860/api/jobs/58ca0db4ac74/files/review/hits/hit_00000_kick.wav

The endpoint prevents path traversal by resolving downloads under .runs/<job-id>/output/ and requiring the final path to remain relative to that output root.

POST /api/cache/clear

Clears the in-memory DSP cache and disk stem/source cache.

curl -X POST http://127.0.0.1:7860/api/cache/clear

Response:

{"status":"cleared","scope":"memory+disk"}

Pipeline parameters

Defined in pipeline_runner.PipelineParams.

Parameter Default Meaning
stem drums Source/stem to extract, or all to bypass source separation. Valid values depend on the selected backend/model.
separation_backend spleeter Source-separation engine: spleeter, demucs, or none.
spleeter_model spleeter:4stems Spleeter model profile used by the default backend.
demucs_model htdemucs_ft Demucs model used when separation_backend=demucs or fallback is needed.
demucs_shifts 1 Test-time shifts for Demucs quality/speed tradeoff.
demucs_overlap 0.25 Demucs chunk overlap.
onset_mode auto auto, percussive, harmonic, or broadband.
onset_delta 0.12 Peak-pick threshold.
energy_threshold_db -35 RMS gate for accepting hits.
pre_pad 0.003 Seconds of audio before onset.
min_dur 0.02 Minimum hit duration.
max_dur 1.5 Maximum hit duration.
min_gap 0.03 Minimum time between onsets.
ncc_threshold 0.80 Similarity threshold. Also used by online clustering assignment.
attack_ms 25 Transient window used for NCC/prototypes.
mel_threshold 0.75 Candidate prefilter threshold. For online mode, lower values such as 0.62 are useful.
linkage average Agglomerative linkage for batch_quality.
clustering_mode batch_quality batch_quality or online_preview.
target_min 5 Lower cluster target; 0 disables target mode in batch mode.
target_max 20 Upper cluster target; 0 disables target/cap mode.
synthesize true Write synthesized alternates for clusters with multiple hits.
quantize_midi true Snap MIDI notes to grid.
subdivision 16 MIDI grid subdivision.
device cpu Torch device for Demucs.
use_disk_cache true Cache decoded full mix/stems by source digest and extraction settings.
allow_backend_fallback true If Spleeter is selected but unavailable/fails, fall back to Demucs instead of failing the job.

Sample-card action API

These endpoints back the simplified card workflow in the reference-style UI. They mutate supervision_state.json and preserve the original batch manifest.

POST /api/jobs/{job_id}/export-selected

Exports only the currently selected representative sample labels into selected/ artifacts.

Body:

{"labels":["kick_0","snare_0"],"synthesize":true}

Response shape:

{
  "export": {
    "kind": "selected-sample-export",
    "files": {"archive": "selected/sample-pack.zip", "midi": "selected/reconstruction.mid"},
    "file_urls": {}
  },
  "state": {}
}

Rules:

  • labels must contain at least one visible sample label.
  • Only selected semantic clusters are rendered.
  • Suppressed hits remain excluded.
  • Pinned/drawn representatives are honored.
  • The export is written under .runs/<job-id>/output/selected/ and does not mutate the original pack.

POST /api/jobs/{job_id}/samples/{sample_label}/draw

Cycles a card to the next active representative hit in that semantic cluster. The chosen hit is persisted as a representative override, so later selected/all edited exports use the same choice.

Response:

{"sample": {"label": "kick_0", "url": "..."}, "state": {}}

POST /api/jobs/{job_id}/samples/{sample_label}/edit

Applies a timing edit to the current representative and rewrites its preview WAV immediately.

Body:

{"start_offset_ms":-8,"tail_offset_ms":24}

The backend slices from stem.wav, writes overrides/hits/*_edited.wav, updates the representative hit in semantic state, and returns a refreshed card row.

Interactive supervision API

The interactive supervision API is backed by supervised_state.py and persists state as:

.runs/<job_id>/output/supervision_state.json

The batch manifest.json remains immutable. Supervised edits update semantic state and can be rendered into a separate edited export under supervised/ without mutating original artifacts.

GET /api/jobs/{job_id}/state

Returns the supervised state for a completed job. If the state file does not exist yet, it is created from the batch manifest.

Response keys:

Key Meaning
summary Counts for hits, clusters, constraints, events, suggestions, suppressed/forced hits, locked clusters, latest export, undo availability.
hits Semantic hit rows with confidence, suppression/favorite/review flags, file URLs, and current cluster assignment.
clusters Semantic clusters with hit IDs, representative hit, confidence, locked state, and suppressed count.
review_queue Low-confidence/high-priority hits sorted for review.
constraints Recent replayable constraints.
events Recent state mutation events.
suggestions Open move/split/suppress suggestions, including exact diff previews.
curl http://127.0.0.1:7860/api/jobs/<job-id>/state

POST /api/jobs/{job_id}/hits/force-onset

Creates a user-forced hit slice from stem.wav and adds it to semantic state.

Body:

{
  "onset_sec": 0.123,
  "duration_ms": 160,
  "target_cluster_id": "cluster:0",
  "label": "snare"
}

Required fields:

Field Required Meaning
onset_sec yes Onset location in seconds.
duration_ms no Slice length. If omitted, the system slices until the next active onset or a bounded default.
target_cluster_id no Existing cluster to place the hit into. If omitted, a new user cluster is created.
label no Override label. If omitted, the rule-based classifier labels the forced slice.

Effects:

  • writes review/hits/hit_NNNNN_<label>_forced.wav,
  • creates a semantic hit with source=forced,
  • creates force-onset and force-cluster constraints,
  • appends hit.force_onset,
  • recomputes confidence and review queue.

POST /api/jobs/{job_id}/hits/{hit_id}/restore

Restores a suppressed hit.

Effects:

  • sets suppressed=false,
  • clears review_status=suppressed back to unreviewed,
  • creates a restore-hit constraint,
  • appends hit.restored,
  • recomputes confidence and review queue.

POST /api/jobs/{job_id}/export

Renders the current semantic state into edited artifacts under supervised/. This does not modify the original manifest.json, original samples, or original ZIP.

Body:

{
  "synthesize": true,
  "quantize": true,
  "subdivision": 16
}

Response shape:

{
  "export": {
    "kind": "supervised-export",
    "hit_count": 17,
    "cluster_count": 10,
    "files": {
      "archive": "supervised/sample-pack.zip",
      "midi": "supervised/reconstruction.mid",
      "target_reconstruction": "supervised/target_reconstruction.wav",
      "reconstruction": "supervised/reconstruction.wav"
    },
    "file_urls": {}
  },
  "state": {}
}

Export rules:

  • suppressed hits are excluded,
  • forced hits are included,
  • moved/pulled hits use current semantic cluster membership,
  • favorite/pinned representatives are honored before quality scoring,
  • cluster labels are sanitized for filenames,
  • supervision_state.json receives latest_export and a supervised.exported event.

POST /api/jobs/{job_id}/hits/{hit_id}/move

Moves a hit into an existing target cluster.

Body:

{"target_cluster_id":"cluster:0"}

Effects:

  • updates hit membership in supervision_state.json,
  • creates force-cluster,
  • creates must-link to the target representative when possible,
  • appends events,
  • recomputes confidence/review queue,
  • may create similar-hit move suggestions,
  • pushes an undo snapshot.

Example:

curl -X POST http://127.0.0.1:7860/api/jobs/<job-id>/hits/hit%3A00003/move \
  -H 'Content-Type: application/json' \
  -d '{"target_cluster_id":"cluster:0"}'

POST /api/jobs/{job_id}/hits/{hit_id}/pull-out

Pulls a hit into a new user cluster.

Optional body:

{"label":"snare_user_1"}

Effects:

  • creates a new cluster:user:* cluster,
  • creates cannot-link from the source representative when possible,
  • creates force-cluster,
  • may create split suggestions,
  • pushes an undo snapshot.

POST /api/jobs/{job_id}/hits/{hit_id}/suppress

Marks a hit as bleed/noise/non-sample material.

Body:

{"reason":"bleed"}

Effects:

  • marks the hit suppressed,
  • creates suppress-pattern,
  • may create similar suppression suggestions,
  • recomputes confidence and review priority.

POST /api/jobs/{job_id}/hits/{hit_id}/review

Stores a review decision for a hit.

Body:

{"status":"accepted"}

Supported statuses:

Status Meaning
unreviewed Clear explicit review status.
accepted Mark the hit as reviewed/accepted.
favorite Mark as favorite and pin as semantic representative for its cluster.

POST /api/jobs/{job_id}/clusters/{cluster_id}/lock

Locks or unlocks a cluster.

Body:

{"locked":true}

Lock state is persisted and shown in the cluster board. It does not yet alter future full pipeline reruns.

GET /api/jobs/{job_id}/suggestions

Returns open suggestions and the state summary.

curl http://127.0.0.1:7860/api/jobs/<job-id>/suggestions

POST /api/jobs/{job_id}/suggestions/{suggestion_id}/accept

Applies a suggestion and records accepted constraints/examples.

Supported suggestion types:

  • move-hits,
  • split-hits,
  • suppress-hits.

POST /api/jobs/{job_id}/suggestions/{suggestion_id}/reject

Marks a suggestion rejected and records an event.

GET /api/jobs/{job_id}/explain/cluster/{cluster_id}

Returns explanation data for one cluster:

  • label,
  • locked state,
  • confidence and reasons,
  • representative hit,
  • hit counts,
  • label distribution,
  • lowest-confidence outliers,
  • relevant constraints,
  • summary string.

POST /api/jobs/{job_id}/undo

Restores the previous semantic state snapshot if available.

curl -X POST http://127.0.0.1:7860/api/jobs/<job-id>/undo

Job progress contract

Every serialized job now includes a top-level progress object. The same object is sent through GET /api/jobs/{job_id}, GET /api/jobs, and GET /api/jobs/{job_id}/events job events.

Example:

{
  "fraction": 0.1875,
  "completed_steps": 1,
  "total_steps": 8,
  "completed_units": 12.0,
  "total_units": 64.0,
  "stage_key": "stem",
  "stage_label": "Stem separation / source load",
  "stage_fraction": 0.5,
  "stage_work_done": 4,
  "stage_work_total": 8,
  "basis": "exact completed work units: Demucs chunks when available; Spleeter and non-instrumented stages advance only at real stage boundaries; no time-based estimates"
}

Semantics:

  • fraction is the completed work-unit fraction used by the UI waveform progress tint.
  • stage_fraction is the current stage-local progress when known.
  • stage_work_done and stage_work_total are exact work-unit counters when a stage exposes work units.
  • Demucs separated-stem extraction exposes exact completed split chunks.
  • Spleeter reports coarse start/complete boundaries because the backend does not expose reliable chunk callbacks here.
  • Non-instrumented stages update at exact stage boundaries only.
  • The API does not provide guessed ETA or interpolated time progress.

Progressive partial_samples

Active/running jobs may include partial_samples before result is available. These rows are emitted only after the corresponding sample WAV has been written, and they include the same url decoration used by final samples.

Final results remain authoritative under result.samples.

PipelineParams.auto_tune

auto_tune defaults to true. When enabled, the pipeline tunes onset sensitivity and group bounds from the loaded target stem before final onset detection. The effective tuned values are returned in the job params/result manifest.

Upload/runtime fallback update (2026-05-12)

  • Added a visible top-bar Choose audio affordance in addition to whole-app drag/drop.
  • Fixed the default hidden state of the error banner so placeholder errors are not shown on page load.
  • API errors now surface request path/status/detail in the visible banner and pipeline logs.
  • /api/config now includes runtime diagnostics for optional separation backends.
  • If Spleeter is unavailable, the simple UI keeps the app usable by switching to full-mix mode; backend fallback also uses full-mix rather than silently launching Demucs.