# 创建自定义模型
> 用 6 到 24 条参考音频训练一个可复用的模型，异步任务
> 训练可能持续数分钟，最长约 20 分钟
> 训练与每次生成分别计费
`POST /v1/music/generations/createModel`
## 认证
- `Authorization` (string / 必填) — 所有接口均使用 Bearer Token 进行认证。 获取 API Key：[访问控制台](https://api.oairoute.com/keys) 创建。 请求时在请求头中添加： ```http Authorization: Bearer YOUR_OAIRoute_KEY ```
## 请求参数
- `model` (string / 可选) — 默认 `suno`，该值固定，只有这一项取值。
- `name` (string / 必填) — 模型名称。**去除首尾空白后不能为空**。
- `audio_urls` (array / 必填) — 6 到 24 条公网可访问的 HTTP(S) 音频直链。 推荐用 MP3、WAV、M4A。每条链接都须直接返回音频文件，不能是需要登录的网页。
## 参考音频怎么挑
训练质量取决于参考集的「一致性与多样性」：
| 要点 | 建议 |
|---|---|
| 数量 | 8 到 12 条通常够了，6 条是下限，24 条是上限 |
| 风格 | 目标风格占绝对多数，不要混入差异过大的曲目 |
| 时长 | 每条 30 秒以上，太短的片段信息量不足 |
| 音质 | 无底噪、无削波 |
| 人声 | 想训练特定音色，参考集里保持同一位演唱者 |
> **Note:** 
> 6 条是硬性下限，少一条就直接报错。但别为了凑数塞入风格冲突的曲目——那样训出来的模型会「四不像」，反而不如用公共版本。
## 提交响应
- `code` (integer) — 响应状态码。
- `data[0].status` (string) — 提交状态，提交成功时为 `submitted`。
- `data[0].task_id` (string) — 训练任务 ID，用于轮询。
## 完成响应
- `data.id` (string) — 任务 ID。
- `data.status` (string) — 任务状态，例如 `completed`。
- `data.progress` (integer) — 进度百分比。
- `data.result.model_id` (string) — 自定义模型 ID，**需要保存**。
- `data.result.name` (string) — 模型名称。
## 训练耗时
创建可能持续数分钟，最长约 20 分钟。轮询间隔建议放宽到 10 到 30 秒，不必像生成任务那样 3 到 5 秒一次。
## 拿到 model_id 之后
在支持自定义模型的接口里传 `custom_model_id`，**同时设 `custom: true`**，并不再传 `version` 和 `persona_id`：
```json
{
  "model": "suno",
  "custom": true,
  "custom_model_id": "8f3a1c2e-....",
  "prompt": "[Verse]\n新的歌词",
  "tags": "my style"
}
```
> **Note:** 
> `custom_model_id` 与 `version` 互斥。两者同时出现会报错。这与「填了自定义模型就别填版本号」是同一条规则。
## 计费
训练和每次生成分别计费。训练是一次性成本，之后每次用这个模型生成按正常生成价收费。
## 错误码
错误响应的格式、状态码与重试建议见[错误码与限流](../../../support/errors.html)，常见报错的排查步骤见[常见问题](../../../support/faq.html)。
## 使用示例
提交一个任务并拿到 `task_id`：
> **Note:** 
> 提交成功只表示任务已受理。真正的产物要拿返回的 `task_id` 去任务查询接口轮询，`status` 变成 `completed` 之后才有结果。
**创建自定义模型{Create custom model}::cURL**
```
curl -X POST https://api.oairoute.com/v1/music/generations/createModel \
  -H 'Authorization: Bearer YOUR_OAIRoute_KEY' \
  -H 'Content-Type: application/json' \
  --data '{
    "model": "suno",
    "name": "我的城市流行",
    "audio_urls": [
      "https://example.com/ref-01.mp3",
      "https://example.com/ref-02.mp3",
      "https://example.com/ref-03.mp3",
      "https://example.com/ref-04.mp3",
      "https://example.com/ref-05.mp3",
      "https://example.com/ref-06.mp3"
    ]
  }'
```
**创建自定义模型{Create custom model}::Python**
```
import requests, time
HEAD = {"Authorization": "Bearer YOUR_OAIRoute_KEY",
        "Content-Type": "application/json"}
r = requests.post(
    "https://api.oairoute.com/v1/music/generations/createModel",
    headers=HEAD,
    json={
        "model": "suno",
        "name": "我的城市流行",
        "audio_urls": [f"https://example.com/ref-{i:02d}.mp3" for i in range(1, 7)],
    },
)
task_id = r.json()["data"][0]["task_id"]
# 训练较慢，间隔放宽到 15 秒
while True:
    d = requests.get(f"https://api.oairoute.com/v1/music/tasks/{task_id}",
                     headers=HEAD).json()["data"]
    if d["status"] == "completed":
        print("模型 ID", d["result"]["model_id"])
        break
    if d["status"] == "failed":
        raise RuntimeError(d.get("error"))
    time.sleep(15)
```
**创建自定义模型{Create custom model}::JavaScript**
```
const url = "https://api.oairoute.com/v1/music/generations/createModel";
const options = {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_OAIRoute_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "model": "suno",
    "name": "我的城市流行",
    "audio_urls": [
      "https://example.com/ref-01.mp3",
      "https://example.com/ref-02.mp3",
      "https://example.com/ref-03.mp3",
      "https://example.com/ref-04.mp3",
      "https://example.com/ref-05.mp3",
      "https://example.com/ref-06.mp3"
    ]
  }),
};
fetch(url, options)
  .then((res) => res.json())
  .then((json) => console.log(json))
  .catch((err) => console.error(err));
```
**200 创建自定义模型{Create custom model}**
```
{
  "code": 200,
  "data": [
    { "status": "submitted", "task_id": "task_01K8E44M0HP1GJWBJYZMKX1XS1" }
  ]
}
```
