# ACE-Step OpenRouter API 문서 > AI 음악 생성을 위한 OpenAI Chat Completions 호환 API **Base URL:** `http://{host}:{port}` (기본값 `http://127.0.0.1:8002`) --- ## 목차 - [인증](#인증) - [엔드포인트](#엔드포인트) - [POST /v1/chat/completions - 음악 생성](#1-음악-생성) - [GET /v1/models - 모델 목록](#2-모델-목록) - [GET /health - 헬스 체크](#3-헬스-체크) - [입력 모드](#입력-모드) - [오디오 입력](#오디오-입력) - [스트리밍 응답](#스트리밍-응답) - [예제](#예제) - [에러 코드](#에러-코드) --- ## 인증 서버에 API 키가 설정된 경우(환경 변수 `OPENROUTER_API_KEY` 또는 `--api-key` 플래그 사용), 모든 요청은 다음 헤더를 포함해야 합니다: ``` Authorization: Bearer ``` API 키가 설정되지 않은 경우 인증이 필요하지 않습니다. --- ## 엔드포인트 ### 1. 음악 생성 **POST** `/v1/chat/completions` 채팅 메시지로부터 음악을 생성하고 오디오 데이터와 LM이 생성한 메타데이터를 반환합니다. #### 요청 파라미터 | 필드 | 타입 | 필수 | 기본값 | 설명 | |---|---|---|---|---| | `model` | string | 아니요 | 자동 | 모델 ID (`/v1/models`에서 확인) | | `messages` | array | **예** | - | 채팅 메시지 리스트. [입력 모드](#입력-모드) 참조 | | `stream` | boolean | 아니요 | `false` | 스트리밍 응답 활성화. [스트리밍 응답](#스트리밍-응답) 참조 | | `audio_config` | object | 아니요 | `null` | 오디오 생성 설정. 아래 참조 | | `temperature` | float | 아니요 | `0.85` | LM 샘플링 온도 | | `top_p` | float | 아니요 | `0.9` | LM nucleus sampling 파라미터 | | `seed` | int \| string | 아니요 | `null` | 랜덤 시드. `batch_size > 1`일 때 쉼표로 구분하여 여러 개 지정 가능 (예: `"42,123,456"`) | | `lyrics` | string | 아니요 | `""` | 직접 전달되는 가사 (메시지에서 파싱된 가사보다 우선). 설정 시 messages 텍스트는 prompt로 사용 | | `sample_mode` | boolean | 아니요 | `false` | LLM sample 모드 활성화. messages 텍스트가 sample_query로 LLM에 전달되어 prompt/lyrics 자동 생성 | | `thinking` | boolean | 아니요 | `false` | 더 깊은 추론을 위한 LLM thinking 모드 활성화 | | `use_format` | boolean | 아니요 | `false` | 사용자가 prompt/lyrics를 제공할 때 LLM 포맷팅으로 개선 | | `use_cot_caption` | boolean | 아니요 | `true` | CoT를 통해 음악 설명을 재작성/개선 | | `use_cot_language` | boolean | 아니요 | `true` | CoT를 통해 보컬 언어를 자동 감지 | | `guidance_scale` | float | 아니요 | `7.0` | Classifier-free guidance scale | | `batch_size` | int | 아니요 | `1` | 생성할 오디오 수 | | `task_type` | string | 아니요 | `"text2music"` | 작업 유형. [오디오 입력](#오디오-입력) 참조 | | `repainting_start` | float | 아니요 | `0.0` | repaint 영역 시작 위치(초) | | `repainting_end` | float | 아니요 | `null` | repaint 영역 종료 위치(초) | | `audio_cover_strength` | float | 아니요 | `1.0` | 커버 강도 (0.0~1.0) | #### audio_config 객체 | 필드 | 타입 | 기본값 | 설명 | |---|---|---|---| | `duration` | float | `null` | 오디오 길이(초). 생략 시 LM이 자동 결정 | | `bpm` | integer | `null` | 분당 비트수(BPM). 생략 시 LM이 자동 결정 | | `vocal_language` | string | `"en"` | 보컬 언어 코드 (예: `"ko"`, `"en"`, `"ja"`) | | `instrumental` | boolean | `null` | 보컬 없는 연주곡 여부. 생략 시 가사에 따라 자동 판단 | | `format` | string | `"mp3"` | 출력 오디오 포맷 | | `key_scale` | string | `null` | 조성 (예: `"C major"`) | | `time_signature` | string | `null` | 박자 (예: `"4/4"`) | > **messages 텍스트의 의미는 모드에 따라 다릅니다:** > - `lyrics` 설정 시 → messages 텍스트 = prompt (음악 설명) > - `sample_mode: true` 설정 시 → messages 텍스트 = sample_query (LLM에게 모든 것을 생성하도록 함) > - 둘 다 미설정 → 자동 감지: 태그가 있으면 태그 모드, 가사처럼 보이면 가사 모드, 그 외 sample 모드 #### messages 형식 일반 텍스트와 멀티모달(텍스트 + 오디오) 두 가지 형식을 지원합니다: **일반 텍스트:** ```json { "messages": [ {"role": "user", "content": "입력 내용"} ] } ``` **멀티모달 (오디오 입력 포함):** ```json { "messages": [ { "role": "user", "content": [ {"type": "text", "text": "이 노래를 커버해줘"}, { "type": "input_audio", "input_audio": { "data": "", "format": "mp3" } } ] } ] } ``` --- #### 비스트리밍 응답 (`stream: false`) ```json { "id": "chatcmpl-a1b2c3d4e5f6g7h8", "object": "chat.completion", "created": 1706688000, "model": "acemusic/acestep-v15-turbo", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "## Metadata\n**Caption:** Upbeat pop song...\n**BPM:** 120\n**Duration:** 30s\n**Key:** C major\n\n## Lyrics\n[Verse 1]\nHello world...", "audio": [ { "type": "audio_url", "audio_url": { "url": "data:audio/mpeg;base64,SUQzBAAAAAAAI1RTU0UAAAA..." } } ] }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 10, "completion_tokens": 100, "total_tokens": 110 } } ``` **응답 필드 설명:** | 필드 | 설명 | |---|---| | `choices[0].message.content` | LM이 생성한 텍스트 정보. Metadata(Caption/BPM/Duration/Key/Time Signature/Language)와 Lyrics를 포함. LM이 관여하지 않은 경우 `"Music generated successfully."` 반환 | | `choices[0].message.audio` | 오디오 데이터 배열. 각 항목에 `type` (`"audio_url"`)과 `audio_url.url` (Base64 Data URL, 형식: `data:audio/mpeg;base64,...`)을 포함 | | `choices[0].finish_reason` | `"stop"`은 정상 완료를 나타냄 | **오디오 디코딩 형식:** `audio_url.url` 값은 Data URL 형식: `data:audio/mpeg;base64,` 쉼표 이후의 base64 데이터 부분을 추출하여 디코딩하면 MP3 파일을 얻을 수 있습니다: ```python import base64 url = response["choices"][0]["message"]["audio"][0]["audio_url"]["url"] # "data:audio/mpeg;base64," 접두사 제거 b64_data = url.split(",", 1)[1] audio_bytes = base64.b64decode(b64_data) with open("output.mp3", "wb") as f: f.write(audio_bytes) ``` ```javascript const url = response.choices[0].message.audio[0].audio_url.url; const b64Data = url.split(",")[1]; const audioBytes = atob(b64Data); // Data URL을