Skip to content

Commit 55f1d06

Browse files
EE
authored andcommitted
docs: add API.md documenting UI and backend API surface
Made-with: Cursor
1 parent 76f72a8 commit 55f1d06

1 file changed

Lines changed: 242 additions & 0 deletions

File tree

API.md

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
# ACE-Step CPP UI — API Reference
2+
3+
This document maps and describes the API surface used by the **acestep-cpp-ui** Electron app: how the UI talks to the backend, and how the backend talks to the acestep.cpp engine. It is intended to support migrations and future development.
4+
5+
**Scope:** API and IPC only. Build, packaging, and tooling are out of scope.
6+
7+
---
8+
9+
## 1. Architecture Overview
10+
11+
- **UI (React)** runs in the Electron renderer and loads `http://127.0.0.1:PORT` (or Vite proxy in dev).
12+
- **Backend (Express)** runs on `PORT` (default `3001`). All UI calls use **same-origin relative URLs** (`API_BASE = ''` in `services/api.ts`).
13+
- **acestep.cpp** is used in one of two ways:
14+
- **Spawn mode:** Backend runs `ace-lm`, `ace-synth`, and optionally `ace-understand` as child processes (no Node addons).
15+
- **HTTP mode:** Backend calls an external acestep-cpp server at `ACESTEP_API_URL` (e.g. `http://localhost:7860`).
16+
17+
There are **no WebSockets** for app logic; only one **SSE** stream (model download progress).
18+
19+
---
20+
21+
## 2. Electron IPC
22+
23+
Used only by the **loading/setup window** (`electron/loading.html`), not by the main React app.
24+
25+
| Channel | Direction | Description |
26+
|---------------|-----------------|-------------|
27+
| `setup:status` | Main → Renderer | Progress during startup and first-run model downloads. |
28+
29+
**Preload API** (`electron/preload.js`):
30+
31+
- **`setupAPI.onStatus(callback)`** — Registers a listener for `setup:status`. Payload: `{ msg, pct, label }`.
32+
- **`electronAPI.platform`**`process.platform` (e.g. `'darwin'`, `'linux'`, `'win32'`).
33+
- **`electronAPI.versions`**`{ electron, node }` (version strings).
34+
35+
The main React app does **not** use `invoke` or `send`; it talks to the backend only over HTTP.
36+
37+
---
38+
39+
## 3. HTTP API (UI → Express)
40+
41+
Base URL is the same origin (relative). All JSON request/response unless noted. Auth: `Authorization: Bearer <token>` where required.
42+
43+
### 3.1 Health (no auth)
44+
45+
| Method | Path | Description |
46+
|--------|----------------|-------------|
47+
| GET | `/health` | App health. Response: `{ status, service }`. |
48+
| GET | `/api/generate/health` | Backend + acestep health. Response: `{ healthy, mode, lmBin?, ditVaeBin?, aceStepUrl }`. |
49+
50+
### 3.2 Auth (`/api/auth`)
51+
52+
| Method | Path | Auth | Request | Response |
53+
|--------|----------------|------|---------|----------|
54+
| GET | `/api/auth/auto` | No || `AuthResponse`: `{ user: User, token }`. |
55+
| POST | `/api/auth/setup` | No | `{ username }` | `AuthResponse`. |
56+
| GET | `/api/auth/me` | Yes || `{ user: User }`. |
57+
| POST | `/api/auth/logout` | No || `{ success: boolean }`. |
58+
| POST | `/api/auth/refresh` | Yes || `AuthResponse`. |
59+
| PATCH | `/api/auth/username` | Yes | `{ username }` | `AuthResponse`. |
60+
61+
**Types:** `User`: `{ id, username, isAdmin?, bio?, avatar_url?, banner_url?, createdAt? }`. `AuthResponse`: `{ user: User, token: string }`.
62+
63+
### 3.3 Songs (`/api/songs`)
64+
65+
| Method | Path | Auth | Request | Response |
66+
|--------|------|------|---------|----------|
67+
| GET | `/api/songs` | Yes || `{ songs: Song[] }`. |
68+
| GET | `/api/songs/public` | No | Query: `limit`, `offset` | `{ songs: Song[] }`. |
69+
| GET | `/api/songs/public/featured` | No || `{ songs: Song[] }`. |
70+
| GET | `/api/songs/:id` | Optional || `{ song: Song }`. |
71+
| GET | `/api/songs/:id/full` | Optional || `{ song: Song, comments: Comment[] }`. |
72+
| POST | `/api/songs` | Yes | `Partial<Song>` | `{ song: Song }`. |
73+
| PATCH | `/api/songs/:id` | Yes | `Partial<Song>` | `{ song: Song }`. |
74+
| DELETE | `/api/songs/:id` | Yes || `{ success: boolean }`. |
75+
| POST | `/api/songs/:id/like` | Yes || `{ liked: boolean }`. |
76+
| GET | `/api/songs/liked/list` | Yes || `{ songs: Song[] }`. |
77+
| PATCH | `/api/songs/:id/privacy` | Yes || `{ isPublic: boolean }`. |
78+
| POST | `/api/songs/:id/play` | Optional || `{ viewCount: number }`. |
79+
| GET | `/api/songs/:id/comments` | Optional || `{ comments: Comment[] }`. |
80+
| POST | `/api/songs/:id/comments` | Yes | `{ content }` | `{ comment: Comment }`. |
81+
| DELETE | `/api/songs/comments/:commentId` | Yes || `{ success: boolean }`. |
82+
83+
**Song** (main fields): `id`, `title`, `lyrics`, `style`, `caption?`, `cover_url?`, `audio_url?` / `audioUrl?`, `duration?`, `bpm?`, `key_scale?`, `time_signature?`, `tags`, `is_public`, `like_count?`, `view_count?`, `user_id?`, `created_at`, `creator?`, `ditModel?`, `generation_params?`.
84+
85+
### 3.4 Generation (`/api/generate`)
86+
87+
| Method | Path | Auth | Request | Response |
88+
|--------|------|------|---------|----------|
89+
| POST | `/api/generate` | Yes | `GenerationParams` (see below) | `GenerationJob` (jobId, status, queuePosition). |
90+
| GET | `/api/generate/status/:jobId` | Yes || `GenerationJob` (full status, result when done). |
91+
| GET | `/api/generate/history` | Yes || `{ jobs: GenerationJob[] }`. |
92+
| POST | `/api/generate/upload-audio` | Yes | `FormData` field `audio` (file) | `{ url, key }`. |
93+
| POST | `/api/generate/format` | Yes | Format body (see below) | Format response (see below). |
94+
| GET | `/api/generate/random-description` | Yes || `{ description, instrumental, vocalLanguage }`. |
95+
| GET | `/api/generate/models` | No || `{ models: Array<{ name, is_active?, is_preloaded? }> }`. |
96+
| GET | `/api/generate/limits` | No || Limits object (e.g. `tier`, `gpu_memory_gb`, `max_duration_*`, `max_batch_size_*`). |
97+
| GET | `/api/generate/health` | No || See §3.1. |
98+
| GET | `/api/generate/endpoints` | Yes || `{ endpoints: { provider, mode, lmBin?, ditVaeBin?, apiUrl? } }`. |
99+
| GET | `/api/generate/audio` | No | Query: `path` | Binary audio stream (proxy to acestep or local file). |
100+
| GET | `/api/generate/logs` | Yes || `{ jobs: Array<{ jobId, status, startTime, stage?, logCount }> }`. |
101+
| GET | `/api/generate/logs/:jobId` | Yes | Query: `after` (index) | `{ lines: string[], total, status }`. |
102+
| GET | `/api/generate/debug/:taskId` | Yes || `{ rawResponse }`. |
103+
104+
**GenerationParams** (key fields): `customMode?`, `songDescription?`, `lyrics`, `style`, `title`, `instrumental`, `vocalLanguage?`, `duration?`, `bpm?`, `keyScale?`, `timeSignature?`, `inferenceSteps?`, `guidanceScale?`, `batchSize?`, `randomSeed?`, `seed?`, `thinking?`, `audioFormat?` ('wav' \| 'mp3'), `inferMethod?`, `shift?`, LM params (`lmTemperature?`, `lmCfgScale?`, `lmTopK?`, `lmTopP?`, `lmNegativePrompt?`, `lmBackend?`, `lmModel?`), `referenceAudioUrl?`, `sourceAudioUrl?`, `referenceAudioTitle?`, `sourceAudioTitle?`, `audioCodes?`, `repaintingStart?`, `repaintingEnd?`, `instruction?`, `audioCoverStrength?`, `taskType?` (e.g. `text2music`, `cover`, `audio2audio`, `repaint`, `lego`, `passthrough`), `useAdg?`, `cfgIntervalStart?`, `cfgIntervalEnd?`, `customTimesteps?`, `useCotMetas?`, `useCotCaption?`, `useCotLanguage?`, `autogen?`, `trackName?`, `completeTrackClasses?`, `isFormatCaption?`, `ditModel?`, and other expert options.
105+
106+
**GenerationJob:** `jobId`, `id?`, `status`: 'pending' \| 'queued' \| 'running' \| 'succeeded' \| 'failed', `queuePosition?`, `etaSeconds?`, `progress?`, `stage?`, `params?`, `created_at?`, `result?`: `{ audioUrls, bpm?, duration?, keyScale?, timeSignature? }`, `error?`.
107+
108+
**Format request:** `caption`, `lyrics?`, `bpm?`, `duration?`, `keyScale?`, `timeSignature?`, `temperature?`, `topK?`, `topP?`, `lmModel?`, `lmBackend?`. **Format response:** `caption?`, `lyrics?`, `bpm?`, `duration?`, `key_scale?`, `vocal_language?`, `time_signature?`, `status_message?`, `error?`.
109+
110+
### 3.5 LoRA (`/api/lora`)
111+
112+
| Method | Path | Auth | Request | Response |
113+
|--------|------|------|---------|----------|
114+
| POST | `/api/lora/load` | Yes | `{ lora_path }` | `{ message, lora_path?, loaded? }`. |
115+
| POST | `/api/lora/unload` | Yes || `{ message }`. |
116+
| POST | `/api/lora/scale` | Yes | `{ scale }` (0–1) | `{ message, scale? }`. |
117+
| POST | `/api/lora/toggle` | Yes | `{ enabled }` | `{ message, active }`. |
118+
| GET | `/api/lora/status` | Yes || `{ loaded, active, scale, path }`. |
119+
120+
### 3.6 Reference tracks (`/api/reference-tracks`)
121+
122+
| Method | Path | Auth | Request | Response |
123+
|--------|------|------|---------|----------|
124+
| GET | `/api/reference-tracks` | Yes || List of reference tracks. |
125+
| POST | `/api/reference-tracks` | Yes | `FormData` field `audio` (file) | Created track. |
126+
| PATCH | `/api/reference-tracks/:id` | Yes | Partial track (e.g. title) | Updated track. |
127+
| POST | `/api/reference-tracks/:id/transcribe` | Yes || Transcription result. |
128+
| POST | `/api/reference-tracks/:id/understand` | Yes || Understand result (metadata/lyrics from ace-understand). |
129+
| POST | `/api/reference-tracks/understand-url` | Yes | `{ audioUrl }` | Same shape as understand. |
130+
| DELETE | `/api/reference-tracks/:id` | Yes || Success. |
131+
132+
### 3.7 Models — GGUF catalog & downloads (`/api/models`)
133+
134+
| Method | Path | Auth | Request | Response |
135+
|--------|------|------|---------|----------|
136+
| GET | `/api/models/catalog` | No || `{ catalog: CatalogEntry[], repo }`. |
137+
| GET | `/api/models/status` | No || `ModelStatus`: `{ modelsDir, activeModel, onDisk, catalog, queue }`. |
138+
| POST | `/api/models/download` | Yes | `{ files: string[] }` (filenames) | `{ enqueued, queueLength }`. |
139+
| GET | `/api/models/download/stream` | No || **SSE** stream: events e.g. `progress` with job data. |
140+
| POST | `/api/models/active` | Yes | `{ filename }` | `{ message, filename, path }`. |
141+
142+
**CatalogEntry:** `filename`, `label`, `group` ('vae' \| 'encoder' \| 'lm' \| 'dit'), `quant`, `variant?`, `essential`, `approxSizeMB`, plus from status: `downloaded?`, `queued?`, `active?`. **DownloadJob:** `id`, `filename`, `status`, `downloadedBytes`, `totalBytes`, `error?`.
143+
144+
### 3.8 Users (`/api/users`)
145+
146+
| Method | Path | Auth | Request | Response |
147+
|--------|------|------|---------|----------|
148+
| GET | `/api/users/public/featured` | No || `{ creators: (UserProfile & { follower_count? })[] }`. |
149+
| GET | `/api/users/:username` | Optional || `{ user: UserProfile }`. |
150+
| GET | `/api/users/:username/songs` | No || `{ songs: Song[] }`. |
151+
| GET | `/api/users/:username/playlists` | No || `{ playlists }`. |
152+
| PATCH | `/api/users/me` | Yes | `Partial<User>` | `{ user: User }`. |
153+
| POST | `/api/users/me/avatar` | Yes | `FormData` field `avatar` | `{ user, url }`. |
154+
| POST | `/api/users/me/banner` | Yes | `FormData` field `banner` | `{ user, url }`. |
155+
| POST | `/api/users/:username/follow` | Yes || `{ following, followerCount }`. |
156+
| GET | `/api/users/:username/followers` | No || `{ followers: User[] }`. |
157+
| GET | `/api/users/:username/following` | No || `{ following: User[] }`. |
158+
| GET | `/api/users/:username/stats` | Optional || `{ followerCount, followingCount, isFollowing }`. |
159+
160+
### 3.9 Playlists (`/api/playlists`)
161+
162+
| Method | Path | Auth | Request | Response |
163+
|--------|------|------|---------|----------|
164+
| POST | `/api/playlists` | Yes | `{ name, description, isPublic }` | `{ playlist: Playlist }`. |
165+
| GET | `/api/playlists` | Yes || `{ playlists: Playlist[] }`. |
166+
| GET | `/api/playlists/public/featured` | No || `{ playlists }`. |
167+
| GET | `/api/playlists/:id` | Optional || `{ playlist, songs }`. |
168+
| POST | `/api/playlists/:id/songs` | Yes | `{ songId }` | `{ success }`. |
169+
| DELETE | `/api/playlists/:id/songs/:songId` | Yes || `{ success }`. |
170+
| PATCH | `/api/playlists/:id` | Yes | `Partial<Playlist>` | `{ playlist }`. |
171+
| DELETE | `/api/playlists/:id` | Yes || Success. |
172+
173+
### 3.10 Search, contact, proxies
174+
175+
| Method | Path | Auth | Request | Response |
176+
|--------|------|------|---------|----------|
177+
| GET | `/api/search` | No | Query: `q`, optional `type` ('songs' \| 'creators' \| 'playlists' \| 'all') | `{ songs, creators, playlists }`. |
178+
| POST | `/api/contact` | No | `ContactFormData`: `name`, `email`, `subject`, `message`, `category` | `{ success, message?, id? }`. |
179+
| GET | `/api/oembed` | No | Query: `url` (song page URL) | oEmbed JSON. |
180+
| GET | `/api/proxy/image` | No | Query: `url` | Proxied image binary. |
181+
| GET | `/api/pexels/photos` | No | Query: `query`. Optional header `x-pexels-api-key` | Pexels API response. |
182+
| GET | `/api/pexels/videos` | No | Same | Pexels API response. |
183+
184+
---
185+
186+
## 4. Backend → acestep.cpp (HTTP fallback only)
187+
188+
When **spawn mode** is not used (no `ace-lm` / `ace-synth` binaries), the server uses `config.acestep.apiUrl` (e.g. `http://localhost:7860`).
189+
190+
| Method | URL / path | Request | Response / notes |
191+
|--------|------------|---------|-------------------|
192+
| GET | `{apiUrl}/health` || Health check. |
193+
| POST | `{apiUrl}/v1/generate` | JSON body from `buildHttpRequest(params)` (see `server/src/services/acestep.ts`) | `{ audio_paths?, bpm?, key_scale?, time_signature?, duration?, error? }`. |
194+
| GET | `{apiUrl}/v1/audio?path=...` || Binary audio. |
195+
| GET | `{apiUrl}/v1/models` || `{ models: [...] }` (or legacy `data.models`). |
196+
| GET | `{apiUrl}/v1/limits` || Limits object. |
197+
| POST | `{apiUrl}/format_input` | `{ prompt, lyrics, temperature, param_obj }` | Format/enhance response. |
198+
| POST | `{apiUrl}/v1/lora/load` | `{ lora_path }` ||
199+
| POST | `{apiUrl}/v1/lora/unload` |||
200+
| POST | `{apiUrl}/v1/lora/scale` | `{ scale }` ||
201+
| POST | `{apiUrl}/v1/lora/toggle` | `{ enabled }` ||
202+
203+
Spawn mode does not use these HTTP calls; it runs `ace-lm` and `ace-synth` with a JSON request file and reads output files from a temp directory.
204+
205+
---
206+
207+
## 5. Configuration and environment
208+
209+
Values that affect the API or backend behaviour (from `server/src/config/index.ts` and root/server `.env`):
210+
211+
| Variable | Default / note |
212+
|----------|-----------------|
213+
| `PORT` | `3001` — Express and UI server. |
214+
| `ACESTEP_API_URL` | `http://localhost:7860` — Used only in HTTP fallback mode. |
215+
| `MODELS_DIR` | `<APP_ROOT>/models` — GGUF models. |
216+
| `AUDIO_DIR` | `<server_root>/public/audio` — Served at `/audio`. |
217+
| `DATABASE_PATH` | `<APP_ROOT>/data/acestep.db`. |
218+
| `JWT_SECRET` | Local default; set in production. |
219+
| `ACE_LM_BIN`, `ACE_SYNTH_BIN`, `ACE_UNDERSTAND_BIN` | Optional; otherwise resolved from `bin/`. |
220+
| `ACESTEP_MODEL`, `ACESTEP_BASE_MODEL`, `LM_MODEL`, `TEXT_ENCODER_MODEL`, `VAE_MODEL` | Optional overrides for model paths. |
221+
| `PEXELS_API_KEY` | Optional; can be overridden per-request via `x-pexels-api-key`. |
222+
| `FRONTEND_URL` | `http://localhost:PORT`. |
223+
224+
Electron sets `process.env.PORT`, `MODELS_DIR`, `AUDIO_DIR`, `DATABASE_PATH`, `JWT_SECRET`, and binary paths when starting the server; the UI still uses same-origin relative URLs.
225+
226+
---
227+
228+
## 6. Types and clients
229+
230+
- **UI API client:** `services/api.ts` — defines `authApi`, `songsApi`, `generateApi`, `usersApi`, `playlistsApi`, `searchApi`, `contactApi`, `modelsApi`, and the types referenced in this document (`User`, `AuthResponse`, `Song`, `GenerationParams`, `GenerationJob`, `CatalogEntry`, `DownloadJob`, `ModelStatus`, `UserProfile`, `Playlist`, `SearchResult`, `ContactFormData`).
231+
- **Server route types:** `GenerateBody` in `server/src/routes/generate.ts` aligns with `GenerationParams`; `server/src/services/acestep.ts` defines `GenerationParams`, `GenerationResult`, `JobStatus`, `LoraState`, `UnderstandResult`, and the HTTP response type for `v1/generate`.
232+
233+
---
234+
235+
## 7. Static and special routes
236+
237+
- **Audio files:** `GET /audio/*` — Express static from `config.storage.audioDir`.
238+
- **Editors:** `/editor` (AudioMass), `/demucs-web` (Demucs) — static with relaxed CSP where needed.
239+
- **Song share / SEO:** `GET /song/:id` — Serves HTML meta for bots; redirects others to the app with `?song=:id`.
240+
- **Contact admin** (not used by main UI): `GET/PATCH/DELETE /api/contact/admin/*`, `GET /api/contact/admin/unread-count` — admin-only.
241+
242+
This file is the single source of truth for the UI-facing and backend→acestep API surface as of the last update.

0 commit comments

Comments
 (0)