Skip to content

Commit a47cd58

Browse files
author
qxip
committed
feat: AceStep 1.5 API proxy (Bun + acestep.cpp), CI/release workflows
- Bun.serve proxy mapping release_task, query_result, v1/audio, models, stats, health - ace-lm + ace-synth pipeline, bundled v0.0.3 fetch script, MODELS_DIR env - GitHub Actions: CI on PR/push (linux, macos-arm64, windows), release artifacts - Unit tests for normalize/paths Made-with: Cursor
0 parents  commit a47cd58

22 files changed

Lines changed: 1671 additions & 0 deletions

.github/workflows/ci.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Tests and compile smoke check on every PR and push to main.
2+
name: CI
3+
4+
on:
5+
pull_request:
6+
push:
7+
branches: [main, master]
8+
9+
concurrency:
10+
group: ci-${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
test-and-build:
15+
name: ${{ matrix.os }}
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
include:
20+
- os: ubuntu-latest
21+
outfile: dist/acestep-api
22+
binary: dist/acestep-api
23+
- os: macos-latest
24+
outfile: dist/acestep-api
25+
binary: dist/acestep-api
26+
- os: windows-latest
27+
outfile: dist/acestep-api.exe
28+
binary: dist/acestep-api.exe
29+
30+
runs-on: ${{ matrix.os }}
31+
32+
steps:
33+
- name: Checkout
34+
uses: actions/checkout@v4
35+
36+
- name: Setup Bun
37+
uses: oven-sh/setup-bun@v2
38+
with:
39+
bun-version: latest
40+
41+
- name: Install dependencies
42+
run: bun install --frozen-lockfile
43+
44+
- name: Unit tests
45+
run: bun test
46+
47+
- name: Bundle acestep.cpp runtime (v0.0.3)
48+
run: bun run bundle:acestep
49+
50+
- name: Create dist directory
51+
shell: bash
52+
run: mkdir -p dist
53+
54+
- name: Compile standalone binary
55+
run: bun build ./src/index.ts --compile --minify --sourcemap=external --outfile ${{ matrix.outfile }}
56+
57+
- name: Sync acestep-runtime next to binary
58+
run: bun run sync:runtime
59+
60+
- name: Verify binary exists
61+
shell: bash
62+
run: test -f "${{ matrix.binary }}"

.github/workflows/release.yml

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# Build distributables for Linux, macOS (arm64), and Windows; attach to GitHub Releases.
2+
name: Release
3+
4+
on:
5+
release:
6+
types: [published]
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: write
11+
12+
jobs:
13+
build:
14+
name: ${{ matrix.label }}
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
include:
19+
- os: ubuntu-latest
20+
label: linux-x64
21+
outfile: dist/acestep-api
22+
binary: dist/acestep-api
23+
archive: tar
24+
- os: macos-latest
25+
label: macos-arm64
26+
outfile: dist/acestep-api
27+
binary: dist/acestep-api
28+
archive: tar
29+
- os: windows-latest
30+
label: windows-x64
31+
outfile: dist/acestep-api.exe
32+
binary: dist/acestep-api.exe
33+
archive: zip
34+
35+
runs-on: ${{ matrix.os }}
36+
37+
steps:
38+
- name: Checkout
39+
uses: actions/checkout@v4
40+
41+
- name: Setup Bun
42+
uses: oven-sh/setup-bun@v2
43+
with:
44+
bun-version: latest
45+
46+
- name: Install dependencies
47+
run: bun install --frozen-lockfile
48+
49+
- name: Bundle acestep.cpp runtime (v0.0.3)
50+
run: bun run bundle:acestep
51+
52+
- name: Create dist directory
53+
shell: bash
54+
run: mkdir -p dist
55+
56+
- name: Compile standalone binary
57+
run: bun build ./src/index.ts --compile --minify --sourcemap=external --outfile ${{ matrix.outfile }}
58+
59+
- name: Sync acestep-runtime next to binary
60+
run: bun run sync:runtime
61+
62+
- name: Verify binary exists
63+
shell: bash
64+
run: test -f "${{ matrix.binary }}"
65+
66+
- name: Package (tar.gz)
67+
id: pack-tar
68+
if: matrix.archive == 'tar'
69+
shell: bash
70+
env:
71+
VERSION: ${{ github.event.release.tag_name || github.ref_name }}
72+
run: |
73+
NAME="acestep-api-${VERSION}-${{ matrix.label }}"
74+
mkdir -p "pack/${NAME}"
75+
if [ -d dist/acestep-runtime ]; then cp -R dist/acestep-runtime "pack/${NAME}/"; fi
76+
cp "${{ matrix.binary }}" "pack/${NAME}/"
77+
(cd pack && tar -czvf "../${NAME}.tar.gz" "${NAME}")
78+
echo "asset=${NAME}.tar.gz" >> "$GITHUB_OUTPUT"
79+
ls -la "${NAME}.tar.gz"
80+
81+
- name: Package (zip)
82+
id: pack-zip
83+
if: matrix.archive == 'zip'
84+
shell: pwsh
85+
env:
86+
VERSION: ${{ github.event.release.tag_name || github.ref_name }}
87+
run: |
88+
$label = '${{ matrix.label }}'
89+
$name = "acestep-api-$env:VERSION-$label"
90+
New-Item -ItemType Directory -Force -Path "pack/$name" | Out-Null
91+
if (Test-Path dist/acestep-runtime) { Copy-Item -Recurse dist/acestep-runtime "pack/$name/" }
92+
Copy-Item "${{ matrix.binary }}" "pack/$name/"
93+
Compress-Archive -Path "pack/$name" -DestinationPath "$name.zip" -Force
94+
Add-Content -Path $env:GITHUB_OUTPUT -Value "asset=$name.zip"
95+
Get-Item "$name.zip"
96+
97+
- name: Upload artifact (tar)
98+
if: matrix.archive == 'tar'
99+
uses: actions/upload-artifact@v4
100+
with:
101+
name: package-${{ matrix.label }}
102+
path: ${{ steps.pack-tar.outputs.asset }}
103+
if-no-files-found: error
104+
105+
- name: Upload artifact (zip)
106+
if: matrix.archive == 'zip'
107+
uses: actions/upload-artifact@v4
108+
with:
109+
name: package-${{ matrix.label }}
110+
path: ${{ steps.pack-zip.outputs.asset }}
111+
if-no-files-found: error
112+
113+
attach-to-release:
114+
name: Upload release assets
115+
needs: build
116+
if: github.event_name == 'release'
117+
runs-on: ubuntu-latest
118+
steps:
119+
- name: Download all packages
120+
uses: actions/download-artifact@v4
121+
with:
122+
pattern: package-*
123+
path: downloaded
124+
merge-multiple: true
125+
126+
- name: Flatten assets for upload
127+
shell: bash
128+
run: |
129+
mkdir -p flat
130+
find downloaded -type f \( -name '*.tar.gz' -o -name '*.zip' \) -exec cp -v {} flat/ \;
131+
ls -la flat/
132+
133+
- name: Upload to GitHub Release
134+
uses: softprops/action-gh-release@v2
135+
with:
136+
files: flat/*
137+
env:
138+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
node_modules/
2+
dist/
3+
storage/
4+
acestep-bin/
5+
acestep-runtime/
6+
bundled/
7+
*.log
8+
.DS_Store

README.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# acestep-cpp-api
2+
3+
[ACE-Step 1.5 HTTP API](https://github.com/ace-step/ACE-Step-1.5/blob/main/docs/en/API.md) proxy backed by [acestep.cpp](https://github.com/audiohacking/acestep.cpp) (`ace-lm` + `ace-synth`). Built with **[Bun](https://bun.sh)**.
4+
5+
CLI usage matches the upstream [acestep.cpp README](https://github.com/audiohacking/acestep.cpp/blob/master/README.md): **MP3 by default** (128 kbps, overridable), **`--wav`** for stereo 48 kHz WAV, plus optional **`--lora`**, **`--lora-scale`**, **`--vae-chunk`**, **`--vae-overlap`**, **`--mp3-bitrate`**.
6+
7+
## Bundled acestep.cpp binaries (v0.0.3)
8+
9+
`bun run build` downloads the correct asset from **[acestep.cpp releases v0.0.3](https://github.com/audiohacking/acestep.cpp/releases/tag/v0.0.3)** for the **current** OS/arch, installs them under `acestep-runtime/bin/`, compiles `dist/acestep-api`, then copies `acestep-runtime` next to the executable:
10+
11+
```text
12+
dist/
13+
acestep-api # or acestep-api.exe
14+
acestep-runtime/
15+
bin/
16+
ace-lm
17+
ace-synth
18+
```
19+
20+
Run the API **from `dist/`** (or anywhere) — the binary resolves siblings via `dirname(execPath)`:
21+
22+
```bash
23+
cd dist && ./acestep-api
24+
```
25+
26+
Override layout with **`ACESTEP_APP_ROOT`** (directory that should contain `acestep-runtime/`) or **`ACESTEP_BIN_DIR`** (direct path to the folder containing `ace-lm` / `ace-synth`).
27+
28+
- Skip download: `SKIP_ACESTEP_BUNDLE=1 bun run build:binary-only`
29+
- Unsupported host (e.g. **darwin x64** has no v0.0.3 zip): set **`ACESTEP_BIN_DIR`** to your own build or use another machine.
30+
31+
## Models directory (always via env)
32+
33+
GGUF paths can be **absolute**, **relative to the app root** (`./models/...`), or **bare filenames** resolved under a models directory:
34+
35+
| Variable | Purpose |
36+
|----------|---------|
37+
| **`ACESTEP_MODELS_DIR`** | Base directory for default LM / embedding / DiT / VAE **filenames** |
38+
| **`ACESTEP_MODEL_PATH`** | Alias (same as above) |
39+
| **`MODELS_DIR`** | Extra alias |
40+
41+
Example (paths from [Hugging Face ACE-Step-1.5-GGUF](https://huggingface.co/Serveurperso/ACE-Step-1.5-GGUF)):
42+
43+
```bash
44+
export ACESTEP_MODELS_DIR="$HOME/models/acestep"
45+
export ACESTEP_LM_MODEL=acestep-5Hz-lm-4B-Q8_0.gguf
46+
export ACESTEP_EMBEDDING_MODEL=Qwen3-Embedding-0.6B-Q8_0.gguf
47+
export ACESTEP_DIT_MODEL=acestep-v15-turbo-Q8_0.gguf
48+
export ACESTEP_VAE_MODEL=vae-BF16.gguf
49+
```
50+
51+
Per-request `lm_model_path` and **`ACESTEP_MODEL_MAP`** values use the same resolution rules.
52+
53+
## Run (source)
54+
55+
```bash
56+
bun install
57+
bun run bundle:acestep # once: fetch v0.0.3 binaries for this machine
58+
export ACESTEP_MODELS_DIR=...
59+
export ACESTEP_LM_MODEL=...
60+
export ACESTEP_EMBEDDING_MODEL=...
61+
export ACESTEP_DIT_MODEL=...
62+
export ACESTEP_VAE_MODEL=...
63+
bun run start
64+
```
65+
66+
## Build
67+
68+
```bash
69+
bun run build # bundle + compile + copy runtime → dist/
70+
bun run build:windows # on Windows x64
71+
bun run build:binary-only # compile only (reuse existing acestep-runtime/)
72+
```
73+
74+
## ace-synth flags (env)
75+
76+
| Variable | Maps to |
77+
|----------|---------|
78+
| `ACESTEP_MP3_BITRATE` | `--mp3-bitrate` (default **128**) when output is MP3 |
79+
| `ACESTEP_LORA` / `ACESTEP_LORA_SCALE` | `--lora` / `--lora-scale` |
80+
| `ACESTEP_VAE_CHUNK` / `ACESTEP_VAE_OVERLAP` | `--vae-chunk` / `--vae-overlap` |
81+
82+
API `audio_format: "wav"` adds **`--wav`** (no `--mp3-bitrate`).
83+
84+
## Reference / source audio (cover, repaint, lego)
85+
86+
Modes that need a reference or source track (**cover**, **repaint**, **lego**) require one of:
87+
88+
- **Upload** (multipart `POST /release_task`):
89+
- **`reference_audio`** or **`ref_audio`** — file part (MP3, WAV, etc.)
90+
- **`src_audio`** or **`ctx_audio`** — file part
91+
- Uploaded files are written under the task job dir and passed to `ace-synth --src-audio`.
92+
- **Path** (JSON or form fields):
93+
- **`reference_audio_path`** / **`referenceAudioPath`** — server path (absolute or relative to app root)
94+
- **`src_audio_path`** / **`srcAudioPath`** — server path
95+
96+
If **`task_type`** is `cover`, `repaint`, or `lego` and neither a path nor an uploaded file is provided, the API returns **400** with a message that reference/source audio is required.
97+
98+
Worker uses **`src_audio_path`** when set, otherwise **`reference_audio_path`**; a single `--src-audio` is passed to ace-synth. Request JSON already supports **`audio_cover_strength`**, **`repainting_start`** / **`repainting_end`**, and **`lego`** (track name) per [acestep.cpp README](https://github.com/audiohacking/acestep.cpp/blob/master/README.md).
99+
100+
## API emulation notes
101+
102+
See earlier revisions for full AceStep 1.5 route mapping. **`/format_input`** and **`/create_random_sample`** remain shape-compatible stubs (no separate LM HTTP service).
103+
104+
## GitHub Actions
105+
106+
| Workflow | Trigger | What it does |
107+
|----------|---------|----------------|
108+
| **[CI](.github/workflows/ci.yml)** | Pull requests & pushes to `main` / `master` | `bun test`, bundle acestep v0.0.3 runtime, compile binary on **Ubuntu**, **macOS (arm64)**, **Windows** |
109+
| **[Release](.github/workflows/release.yml)** | **Published releases** & manual `workflow_dispatch` | Same builds, produces `acestep-api-<tag>-linux-x64.tar.gz`, `…-macos-arm64.tar.gz`, `…-windows-x64.zip` (binary + `acestep-runtime/` when present). On **release published**, uploads those archives to the GitHub Release. |
110+
111+
Manual runs (`workflow_dispatch`) build artifacts attached to the workflow run only (not to a draft release).
112+
113+
## License
114+
115+
Your choice for this repo; upstream APIs/models have their own licenses.

bun.lock

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bunfig.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# https://bun.sh/docs/runtime/bunfig
2+
# Optional: tune install / test here

package.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "acestep-cpp-api",
3+
"version": "0.1.0",
4+
"description": "AceStep 1.5 API proxy using acestep.cpp (ace-lm + ace-synth), built with Bun",
5+
"type": "module",
6+
"scripts": {
7+
"start": "bun run src/index.ts",
8+
"dev": "bun run --watch src/index.ts",
9+
"bundle:acestep": "bun run scripts/bundle-acestep.ts",
10+
"sync:runtime": "bun run scripts/sync-runtime-to-dist.ts",
11+
"build": "bun run bundle:acestep && bun build ./src/index.ts --compile --minify --sourcemap=external --outfile ./dist/acestep-api && bun run sync:runtime",
12+
"build:windows": "bun run bundle:acestep && bun build ./src/index.ts --compile --minify --sourcemap=external --outfile ./dist/acestep-api.exe && bun run sync:runtime",
13+
"build:binary-only": "bun build ./src/index.ts --compile --minify --sourcemap=external --outfile ./dist/acestep-api && bun run sync:runtime",
14+
"build:all": "bun run build && bun run build:windows",
15+
"test": "bun test"
16+
},
17+
"devDependencies": {
18+
"@types/bun": "latest"
19+
},
20+
"engines": {
21+
"bun": ">=1.1.0"
22+
}
23+
}

0 commit comments

Comments
 (0)