Spaces:
Running
A newer version of the Gradio SDK is available: 6.20.0
ACE-Step OpenRouter API ๋ฌธ์
AI ์์ ์์ฑ์ ์ํ OpenAI Chat Completions ํธํ API
Base URL: http://{host}:{port} (๊ธฐ๋ณธ๊ฐ http://127.0.0.1:8002)
๋ชฉ์ฐจ
์ธ์ฆ
์๋ฒ์ API ํค๊ฐ ์ค์ ๋ ๊ฒฝ์ฐ(ํ๊ฒฝ ๋ณ์ OPENROUTER_API_KEY ๋๋ --api-key ํ๋๊ทธ ์ฌ์ฉ), ๋ชจ๋ ์์ฒญ์ ๋ค์ ํค๋๋ฅผ ํฌํจํด์ผ ํฉ๋๋ค:
Authorization: Bearer <your-api-key>
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 ํ ์คํธ = captionsample_mode: true์ค์ ์ โ messages ํ ์คํธ = sample_query (LLM์๊ฒ ๋ชจ๋ ๊ฒ์ ์์ฑํ๋๋ก ํจ)- ๋ ๋ค ๋ฏธ์ค์ โ ์๋ ๊ฐ์ง: ํ๊ทธ๊ฐ ์์ผ๋ฉด ํ๊ทธ ๋ชจ๋, ๊ฐ์ฌ์ฒ๋ผ ๋ณด์ด๋ฉด ๊ฐ์ฌ ๋ชจ๋, ๊ทธ ์ธ caption ๋ก ์ง์ ์์ฑ์ ์ฌ์ฉ
messages ํ์
์ผ๋ฐ ํ ์คํธ์ ๋ฉํฐ๋ชจ๋ฌ(ํ ์คํธ + ์ค๋์ค) ๋ ๊ฐ์ง ํ์์ ์ง์ํฉ๋๋ค:
์ผ๋ฐ ํ ์คํธ:
{
"messages": [
{"role": "user", "content": "์
๋ ฅ ๋ด์ฉ"}
]
}
๋ฉํฐ๋ชจ๋ฌ (์ค๋์ค ์ ๋ ฅ ํฌํจ):
{
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "์ด ๋
ธ๋๋ฅผ ์ปค๋ฒํด์ค"},
{
"type": "input_audio",
"input_audio": {
"data": "<base64 ์ค๋์ค ๋ฐ์ดํฐ>",
"format": "mp3"
}
}
]
}
]
}
๋น์คํธ๋ฆฌ๋ฐ ์๋ต (stream: false)
{
"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_data>
์ผํ ์ดํ์ base64 ๋ฐ์ดํฐ ๋ถ๋ถ์ ์ถ์ถํ์ฌ ๋์ฝ๋ฉํ๋ฉด MP3 ํ์ผ์ ์ป์ ์ ์์ต๋๋ค:
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)
const url = response.choices[0].message.audio[0].audio_url.url;
const b64Data = url.split(",")[1];
const audioBytes = atob(b64Data);
// Data URL์ <audio> ํ๊ทธ์ ์ง์ ์ฌ์ฉ ๊ฐ๋ฅ
const audio = new Audio(url);
audio.play();
2. ๋ชจ๋ธ ๋ชฉ๋ก
GET /v1/models
์ฌ์ฉ ๊ฐ๋ฅํ ๋ชจ๋ธ ์ ๋ณด๋ฅผ ๋ฐํํฉ๋๋ค.
์๋ต
{
"data": [
{
"id": "acemusic/acestep-v15-turbo",
"name": "ACE-Step",
"created": 1706688000,
"description": "High-performance text-to-music generation model. Supports multiple styles, lyrics input, and various audio durations.",
"input_modalities": ["text", "audio"],
"output_modalities": ["audio", "text"],
"context_length": 4096,
"pricing": {"prompt": "0", "completion": "0", "request": "0"},
"supported_sampling_parameters": ["temperature", "top_p"]
}
]
}
3. ํฌ์ค ์ฒดํฌ
GET /health
์๋ต
{
"status": "ok",
"service": "ACE-Step OpenRouter API",
"version": "1.0"
}
์ ๋ ฅ ๋ชจ๋
์์คํ
์ ๋ง์ง๋ง user ๋ฉ์์ง์ ๋ด์ฉ์ ๋ฐ๋ผ ์
๋ ฅ ๋ชจ๋๋ฅผ ์๋์ผ๋ก ์ ํํฉ๋๋ค. lyrics ๋๋ sample_mode ํ๋๋ก ๋ช
์์ ์ผ๋ก ์ง์ ํ ์๋ ์์ต๋๋ค.
๋ชจ๋ 1: ํ๊ทธ ๋ชจ๋ (๊ถ์ฅ)
<prompt>์ <lyrics> ํ๊ทธ๋ฅผ ์ฌ์ฉํ์ฌ ์์
์ค๋ช
๊ณผ ๊ฐ์ฌ๋ฅผ ๋ช
์์ ์ผ๋ก ์ง์ ํฉ๋๋ค:
{
"messages": [
{
"role": "user",
"content": "<prompt>A gentle acoustic ballad in C major, female vocal</prompt>\n<lyrics>[Verse 1]\nSunlight through the window\nA brand new day begins\n\n[Chorus]\nWe are the dreamers\nWe are the light</lyrics>"
}
],
"audio_config": {
"duration": 30,
"vocal_language": "en"
}
}
<prompt>...</prompt>โ ์์ ์คํ์ผ/์ฅ๋ฉด ์ค๋ช (caption)<lyrics>...</lyrics>โ ๊ฐ์ฌ ๋ด์ฉ- ํ๋์ ํ๊ทธ๋ง ์ฌ์ฉํ ์๋ ์์
use_format: true์ผ ๋ LLM์ด prompt์ lyrics๋ฅผ ์๋์ผ๋ก ๊ฐ์
๋ชจ๋ 2: ์์ฐ์ด ๋ชจ๋ (์ํ ๋ชจ๋)
์ํ๋ ์์ ์ ์์ฐ์ด๋ก ์ค๋ช ํฉ๋๋ค. ์์คํ ์ด LLM์ ์ฌ์ฉํ์ฌ prompt์ lyrics๋ฅผ ์๋์ผ๋ก ์์ฑํฉ๋๋ค:
{
"messages": [
{"role": "user", "content": "์ฌ๋ฆ๊ณผ ์ฌํ์ ๊ดํ ์ ๋๋ ํ์ก์ ๋ง๋ค์ด์ค"}
],
"sample_mode": true,
"audio_config": {
"vocal_language": "ko"
}
}
ํธ๋ฆฌ๊ฑฐ ์กฐ๊ฑด: sample_mode: true, ๋๋ ๋ฉ์์ง์ ํ๊ทธ๊ฐ ์๊ณ ๊ฐ์ฌ์ฒ๋ผ ๋ณด์ด์ง ์์ ๋ ์๋ ํธ๋ฆฌ๊ฑฐ.
๋ชจ๋ 3: ๊ฐ์ฌ ์ ์ฉ ๋ชจ๋
๊ตฌ์กฐ ๋ง์ปค๊ฐ ์๋ ๊ฐ์ฌ๋ฅผ ์ง์ ์ ๋ฌํ๋ฉด ์์คํ ์ด ์๋์ผ๋ก ์ธ์ํฉ๋๋ค:
{
"messages": [
{
"role": "user",
"content": "[Verse 1]\nWalking down the street\nFeeling the beat\n\n[Chorus]\nDance with me tonight\nUnder the moonlight"
}
],
"audio_config": {"duration": 30}
}
ํธ๋ฆฌ๊ฑฐ ์กฐ๊ฑด: ๋ฉ์์ง์ [Verse], [Chorus] ๋ฑ์ ๋ง์ปค๊ฐ ํฌํจ๋๊ฑฐ๋ ์ฌ๋ฌ ์ค์ ์งง์ ํ
์คํธ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง ๊ฒฝ์ฐ.
๋ชจ๋ 4: ๊ฐ์ฌ + Prompt ๋ถ๋ฆฌ
lyrics ํ๋๋ก ๊ฐ์ฌ๋ฅผ ์ง์ ์ ๋ฌํ๊ณ , messages ํ
์คํธ๋ ์๋์ผ๋ก prompt๋ก ์ฌ์ฉ๋ฉ๋๋ค:
{
"messages": [
{"role": "user", "content": "Energetic EDM with heavy bass drops"}
],
"lyrics": "[Verse 1]\nFeel the rhythm in your soul\nLet the music take control\n\n[Drop]\n(instrumental break)",
"audio_config": {
"bpm": 128,
"duration": 60
}
}
์ฐ์ฃผ๊ณก ๋ชจ๋
audio_config.instrumental: true ์ค์ :
{
"messages": [
{"role": "user", "content": "<prompt>Epic orchestral cinematic score, dramatic and powerful</prompt>"}
],
"audio_config": {
"instrumental": true,
"duration": 30
}
}
์ค๋์ค ์ ๋ ฅ
๋ฉํฐ๋ชจ๋ฌ messages๋ฅผ ํตํด ์ค๋์ค ํ์ผ(base64 ์ธ์ฝ๋ฉ)์ ์ ๋ฌํ์ฌ cover, repaint ๋ฑ์ ์์ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
task_type ์ ํ
| task_type | ์ค๋ช | ์ค๋์ค ์ ๋ ฅ ํ์ |
|---|---|---|
text2music |
ํ ์คํธ์์ ์์ ์์ฑ (๊ธฐ๋ณธ๊ฐ) | ์ ํ (reference๋ก) |
cover |
์ปค๋ฒ/์คํ์ผ ์ ํ | src_audio ํ์ |
repaint |
๋ถ๋ถ ๋ฆฌํ์ธํ | src_audio ํ์ |
lego |
์ค๋์ค ์ ํฉ | src_audio ํ์ |
extract |
์ค๋์ค ์ถ์ถ | src_audio ํ์ |
complete |
์ค๋์ค ์ด์ด์ฐ๊ธฐ | src_audio ํ์ |
์ค๋์ค ๋ผ์ฐํ ๊ท์น
์ฌ๋ฌ input_audio ๋ธ๋ก์ ์์๋๋ก ๋ค๋ฅธ ํ๋ผ๋ฏธํฐ์ ๋ผ์ฐํ
๋ฉ๋๋ค (๋ค์ค ์ด๋ฏธ์ง ์
๋ก๋์ ์ ์ฌ):
| task_type | audio[0] | audio[1] |
|---|---|---|
text2music |
reference_audio (์คํ์ผ ์ฐธ์กฐ) | - |
cover/repaint/lego/extract/complete |
src_audio (ํธ์ง ๋์ ์ค๋์ค) | reference_audio (์ ํ์ ์คํ์ผ ์ฐธ์กฐ) |
์ค๋์ค ์ ๋ ฅ ์์
Cover ์์ (์ปค๋ฒ):
{
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "<prompt>Jazz style cover with saxophone</prompt>"},
{
"type": "input_audio",
"input_audio": {"data": "<base64 ์๋ณธ ์ค๋์ค>", "format": "mp3"}
}
]
}
],
"task_type": "cover",
"audio_cover_strength": 0.8,
"audio_config": {"duration": 30}
}
Repaint ์์ (๋ถ๋ถ ๋ฆฌํ์ธํ ):
{
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "<prompt>Replace with guitar solo</prompt>"},
{
"type": "input_audio",
"input_audio": {"data": "<base64 ์๋ณธ ์ค๋์ค>", "format": "mp3"}
}
]
}
],
"task_type": "repaint",
"repainting_start": 10.0,
"repainting_end": 20.0,
"audio_config": {"duration": 30}
}
์คํธ๋ฆฌ๋ฐ ์๋ต
"stream": true๋ก ์ค์ ํ๋ฉด SSE(Server-Sent Events) ์คํธ๋ฆฌ๋ฐ์ด ํ์ฑํ๋ฉ๋๋ค.
์ด๋ฒคํธ ํ์
๊ฐ ์ด๋ฒคํธ๋ data: ๋ก ์์ํ๊ณ JSON์ด ๋ค๋ฐ๋ฅด๋ฉฐ ์ด์ค ์ค๋ฐ๊ฟ \n\n์ผ๋ก ๋๋ฉ๋๋ค:
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","created":1706688000,"model":"acemusic/acestep-v15-turbo","choices":[{"index":0,"delta":{...},"finish_reason":null}]}
์คํธ๋ฆฌ๋ฐ ์ด๋ฒคํธ ์์
| ๋จ๊ณ | delta ๋ด์ฉ | ์ค๋ช |
|---|---|---|
| 1. ์ด๊ธฐํ | {"role":"assistant","content":""} |
์ฐ๊ฒฐ ์๋ฆฝ |
| 2. LM ์ฝํ ์ธ | {"content":"\n\n## Metadata\n..."} |
LM ์ฌ์ฉ ์ metadata์ lyrics ์ ์ก |
| 3. ํํธ๋นํธ | {"content":"."} |
์ค๋์ค ์์ฑ ์ค 2์ด๋ง๋ค ์ ์ก, ์ฐ๊ฒฐ ์ ์ง |
| 4. ์ค๋์ค ๋ฐ์ดํฐ | {"audio":[{"type":"audio_url","audio_url":{"url":"data:..."}}]} |
์ค๋์ค base64 ๋ฐ์ดํฐ |
| 5. ์๋ฃ | finish_reason: "stop" |
์์ฑ ์๋ฃ |
| 6. ์ข ๋ฃ | data: [DONE] |
์คํธ๋ฆผ ์ข ๋ฃ ๋ง์ปค |
์คํธ๋ฆฌ๋ฐ ์๋ต ์์
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1706688000,"model":"acemusic/acestep-v15-turbo","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1706688000,"model":"acemusic/acestep-v15-turbo","choices":[{"index":0,"delta":{"content":"\n\n## Metadata\n**Caption:** Upbeat pop\n**BPM:** 120"},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1706688000,"model":"acemusic/acestep-v15-turbo","choices":[{"index":0,"delta":{"content":"."},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1706688000,"model":"acemusic/acestep-v15-turbo","choices":[{"index":0,"delta":{"audio":[{"type":"audio_url","audio_url":{"url":"data:audio/mpeg;base64,..."}}]},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1706688000,"model":"acemusic/acestep-v15-turbo","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: [DONE]
ํด๋ผ์ด์ธํธ ์ธก ์คํธ๋ฆฌ๋ฐ ์ฒ๋ฆฌ
import json
import httpx
with httpx.stream("POST", "http://127.0.0.1:8002/v1/chat/completions", json={
"messages": [{"role": "user", "content": "๊ฒฝ์พํ ๊ธฐํ ๊ณก์ ์์ฑํด์ค"}],
"sample_mode": True,
"stream": True,
"audio_config": {"instrumental": True}
}) as response:
content_parts = []
audio_url = None
for line in response.iter_lines():
if not line or not line.startswith("data: "):
continue
if line == "data: [DONE]":
break
chunk = json.loads(line[6:])
delta = chunk["choices"][0]["delta"]
if "content" in delta and delta["content"]:
content_parts.append(delta["content"])
if "audio" in delta and delta["audio"]:
audio_url = delta["audio"][0]["audio_url"]["url"]
if chunk["choices"][0].get("finish_reason") == "stop":
print("์์ฑ ์๋ฃ!")
print("Content:", "".join(content_parts))
if audio_url:
import base64
b64_data = audio_url.split(",", 1)[1]
with open("output.mp3", "wb") as f:
f.write(base64.b64decode(b64_data))
const response = await fetch("http://127.0.0.1:8002/v1/chat/completions", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
messages: [{ role: "user", content: "๊ฒฝ์พํ ๊ธฐํ ๊ณก์ ์์ฑํด์ค" }],
sample_mode: true,
stream: true,
audio_config: { instrumental: true }
})
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let audioUrl = null;
let content = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
const text = decoder.decode(value);
for (const line of text.split("\n")) {
if (!line.startsWith("data: ") || line === "data: [DONE]") continue;
const chunk = JSON.parse(line.slice(6));
const delta = chunk.choices[0].delta;
if (delta.content) content += delta.content;
if (delta.audio) audioUrl = delta.audio[0].audio_url.url;
}
}
// audioUrl์ <audio src="...">์ ์ง์ ์ฌ์ฉ ๊ฐ๋ฅ
์์
์์ 1: ์์ฐ์ด ์์ฑ (๊ฐ์ฅ ๊ฐ๋จํ ์ฌ์ฉ๋ฒ)
curl -X POST http://127.0.0.1:8002/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "๊ณ ํฅ๊ณผ ์ถ์ต์ ๊ดํ ๋ถ๋๋ฌ์ด ํฌํฌ ์ก"}
],
"sample_mode": true,
"audio_config": {"vocal_language": "ko"}
}'
์์ 2: ํ๊ทธ ๋ชจ๋ + ํ๋ผ๋ฏธํฐ ์ง์
curl -X POST http://127.0.0.1:8002/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"role": "user",
"content": "<prompt>Energetic EDM track with heavy bass drops and synth leads</prompt><lyrics>[Verse 1]\nFeel the rhythm in your soul\nLet the music take control\n\n[Drop]\n(instrumental break)</lyrics>"
}
],
"audio_config": {
"bpm": 128,
"duration": 60,
"vocal_language": "en"
}
}'
์์ 3: ์ฐ์ฃผ๊ณก + LM ๊ฐ์ ๋นํ์ฑํ
curl -X POST http://127.0.0.1:8002/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"role": "user",
"content": "<prompt>Peaceful piano solo, slow tempo, jazz harmony</prompt>"
}
],
"use_cot_caption": false,
"audio_config": {
"instrumental": true,
"duration": 45
}
}'
์์ 4: ์คํธ๋ฆฌ๋ฐ ์์ฒญ
curl -X POST http://127.0.0.1:8002/v1/chat/completions \
-H "Content-Type: application/json" \
-N \
-d '{
"messages": [
{"role": "user", "content": "์์ผ ์ถํ ๋
ธ๋๋ฅผ ๋ง๋ค์ด์ค"}
],
"sample_mode": true,
"stream": true
}'
์์ 5: ๋ฉํฐ ์๋ ๋ฐฐ์น ์์ฑ
curl -X POST http://127.0.0.1:8002/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "<prompt>Lo-fi hip hop beat</prompt>"}
],
"batch_size": 3,
"seed": "42,123,456",
"audio_config": {
"instrumental": true,
"duration": 30
}
}'
์๋ฌ ์ฝ๋
| HTTP ์ํ ์ฝ๋ | ์ค๋ช |
|---|---|
| 400 | ์๋ชป๋ ์์ฒญ ํ์ ๋๋ ์ ํจํ ์ ๋ ฅ ๋๋ฝ |
| 401 | API ํค ๋๋ฝ ๋๋ ์ ํจํ์ง ์์ |
| 429 | ์๋น์ค ๊ณผ๋ถํ, ํ ๊ฐ๋ ์ฐธ |
| 500 | ์์ ์์ฑ ์ค ๋ด๋ถ ์ค๋ฅ ๋ฐ์ |
| 503 | ๋ชจ๋ธ์ด ์์ง ์ด๊ธฐํ๋์ง ์์ |
| 504 | ์์ฑ ํ์์์ |
์๋ฌ ์๋ต ํ์:
{
"detail": "์๋ฌ ์ค๋ช
๋ฉ์์ง"
}
์๋ฒ ์ค์ (ํ๊ฒฝ ๋ณ์)
๋ค์ ํ๊ฒฝ ๋ณ์๋ก ์๋ฒ๋ฅผ ์ค์ ํ ์ ์์ต๋๋ค (์ด์ ์ฐธ๊ณ ์ฉ):
| ๋ณ์๋ช | ๊ธฐ๋ณธ๊ฐ | ์ค๋ช |
|---|---|---|
OPENROUTER_API_KEY |
์์ | API ์ธ์ฆ ํค |
OPENROUTER_HOST |
127.0.0.1 |
๋ฆฌ์จ ์ฃผ์ |
OPENROUTER_PORT |
8002 |
๋ฆฌ์จ ํฌํธ |
ACESTEP_CONFIG_PATH |
acestep-v15-turbo |
DiT ๋ชจ๋ธ ์ค์ ๊ฒฝ๋ก |
ACESTEP_DEVICE |
auto |
์ถ๋ก ๋๋ฐ์ด์ค |
ACESTEP_LM_MODEL_PATH |
acestep-5Hz-lm-0.6B |
LLM ๋ชจ๋ธ ๊ฒฝ๋ก |
ACESTEP_LM_BACKEND |
vllm |
LLM ์ถ๋ก ๋ฐฑ์๋ |
ACESTEP_QUEUE_MAXSIZE |
200 |
์์ ํ ์ต๋ ์ฉ๋ |
ACESTEP_GENERATION_TIMEOUT |
600 |
๋น์คํธ๋ฆฌ๋ฐ ์์ฒญ ํ์์์(์ด) |