# 添加人声
> 给纯伴奏加上人声演唱，异步任务
> 源音轨**必须来自上传接口**，普通生成任务不能用
> 生成参数与「风格翻唱」同源
`POST /v1/music/generations/addVocals`
## 认证
- `Authorization` (string / 必填) — 所有接口均使用 Bearer Token 进行认证。 获取 API Key：[访问控制台](https://api.oairoute.com/keys) 创建。 请求时在请求头中添加： ```http Authorization: Bearer YOUR_OAIRoute_KEY ```
## 引用源音轨
- `task_id` (string / 必填) — **必须是 uploadTask 上传接口返回的 ID**。普通生成任务的 ID 不可用。 缺失或无法解析源音轨时，提交阶段即失败。
- `audio_index` (integer / 可选) — 引用源任务的第几首音轨，默认 `1`，从 1 开始。一次生成一般为 2 首。
> **Note:** 
> 这条限制与「添加伴奏」一致：源音轨必须先经过上传接口。直接拿生成任务的 task_id 过来会报错，因为人声叠加需要一条干净的伴奏作为基底。
## 生成参数
- `model` (string / 可选) — 音频模型，当前固定 `suno`。
- `version` (string / 可选) — 公共版本，默认 `v6`，可选 `v6-wild`、`v6-mini`。与 `custom_model_id` 不能同时使用。
- `custom_model_id` (string / 可选) — 自定义模型的完整 UUID，与 `version` 互斥。
- `custom` (boolean / 可选) — `true` 为自定义模式，`false` 为灵感模式。不传时按已提交字段推断。
- `prompt` (string / 可选) — 歌词，仅自定义模式生效，灵感模式下忽略。
- `gpt_description` (string / 条件必填) — 灵感提示词。`custom` 为 `false` 时必填，缺失在提交阶段返回 400 且不扣费。
- `title` (string / 可选) — 标题，仅自定义模式生效。
- `tags` (string / 可选) — 风格标签，仅自定义模式生效。
- `negative_tags` (string / 可选) — 要排除的风格标签，仅自定义模式生效。
- `style_weight` (number / 可选) — 风格权重，取值 0.00 到 1.00。越界返回 400，仅自定义模式生效。
- `weirdness` (number / 可选) — 创意度权重，取值 0.00 到 1.00。旧名 `weirdness_constraint` 仍兼容。
- `audio_weight` (number / 可选) — 音频权重，取值 0.00 到 1.00，仅自定义模式生效。
- `vocal_gender` (string / 可选) — 人声性别，取值 `Male` 或 `Female`，两种模式均生效。
- `variety` (string / 可选) — 风格变化程度，取值 `off`、`normal`、`high`、`extra`、`max`。
- `max_mode` (boolean / 可选) — 启用 Max 模式，默认 `false`。要求自定义模式，按普通售价 2 倍计费。
- `audio_format` (string / 可选) — 输出格式，取值 `mp3`、`m4a`、`wav`。
## 不支持的字段
`auto_lyrics`、`persona_id`、`instrumental`、目标时长都不支持。
> **Note:** 
> `instrumental` 在这里没有意义——本接口的目的就是加人声，传纯音乐标记会自相矛盾。
## 响应
- `code` (integer) — 响应状态码。
- `data[].status` (string) — 提交成功为 `submitted`。
- `data[].task_id` (string) — 任务唯一标识，用于轮询任务详情。
轮询时 `status` 可能为 `pending`、`processing`、`completed` 或 `failed`。`progress` 是 0 到 100 的整数，变化节点不固定。完成后从 `data.result.music[].audio_url` 取音频。失败原因见 `data.error.message`，失败会自动退回预扣额度。
## 完整流程
1. 把伴奏放到公网可访问的地址
2. 调「上传音频」拿 `task_id`
3. 等上传任务完成
4. 用那个 `task_id` 调本接口
## 错误码
错误响应的格式、状态码与重试建议见[错误码与限流](../../../support/errors.html)，常见报错的排查步骤见[常见问题](../../../support/faq.html)。
## 使用示例
提交一个任务并拿到 `task_id`：
> **Note:** 
> 提交成功只表示任务已受理。真正的产物要拿返回的 `task_id` 去任务查询接口轮询，`status` 变成 `completed` 之后才有结果。
**添加人声{Add vocals}::cURL**
```
curl -X POST https://api.oairoute.com/v1/music/generations/addVocals \
  -H 'Authorization: Bearer YOUR_OAIRoute_KEY' \
  -H 'Content-Type: application/json' \
  --data '{
    "model": "suno",
    "task_id": "task_01K8SGYNNNVBQTXNR4MM964S7K",
    "audio_index": 1,
    "custom": true,
    "prompt": "[Verse]\n夜色里慢慢唱",
    "tags": "pop, warm",
    "vocal_gender": "Female"
  }'
```
**添加人声{Add vocals}::Python**
```
import requests
res = requests.post(
    "https://api.oairoute.com/v1/music/generations/addVocals",
    headers={
        "Authorization": "Bearer YOUR_OAIRoute_KEY",
        "Content-Type": "application/json",
    },
    json={
        "model": "suno",
        "task_id": "task_01K8SGYNNNVBQTXNR4MM964S7K",
        "audio_index": 1,
        "custom": True,
        "prompt": "[Verse]\n夜色里慢慢唱",
        "tags": "pop, warm",
        "vocal_gender": "Female",
    },
)
print(res.json()["data"][0]["task_id"])
```
**添加人声{Add vocals}::JavaScript**
```
const url = "https://api.oairoute.com/v1/music/generations/addVocals";
const options = {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_OAIRoute_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "model": "suno",
    "task_id": "task_01K8SGYNNNVBQTXNR4MM964S7K",
    "audio_index": 1,
    "custom": true,
    "prompt": "[Verse]\n夜色里慢慢唱",
    "tags": "pop, warm",
    "vocal_gender": "Female"
  }),
};
fetch(url, options)
  .then((res) => res.json())
  .then((json) => console.log(json))
  .catch((err) => console.error(err));
```
**200 添加人声{Add vocals}**
```
{
  "code": 200,
  "data": [
    { "status": "submitted", "task_id": "task_01K8D99M0HP1GJWBJYZMKX1XS1" }
  ]
}
```
**灵感模式{Inspiration mode}::cURL**
```
curl --request POST \
  --url 'https://api.oairoute.com/v1/music/generations/addVocals' \
  --header 'Authorization: Bearer YOUR_OAIRoute_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "suno",
  "task_id": "task_01K8SGYNNNVBQTXNR4MM964S7K",
  "custom": false,
  "gpt_description": "温柔的女声，气声偏多，慢板"
}'
```
**灵感模式{Inspiration mode}::Python**
```
import requests
url = "https://api.oairoute.com/v1/music/generations/addVocals"
headers = {
    "Authorization": "Bearer YOUR_OAIRoute_KEY",
    "Content-Type": "application/json",
}
payload = {
      "model": "suno",
      "task_id": "task_01K8SGYNNNVBQTXNR4MM964S7K",
      "custom": false,
      "gpt_description": "温柔的女声，气声偏多，慢板"
    }
res = requests.post(url, headers=headers, json=payload)
print(res.json())
```
**灵感模式{Inspiration mode}::JavaScript**
```
const res = await fetch("https://api.oairoute.com/v1/music/generations/addVocals", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_OAIRoute_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "model": "suno",
    "task_id": "task_01K8SGYNNNVBQTXNR4MM964S7K",
    "custom": false,
    "gpt_description": "温柔的女声，气声偏多，慢板"
  }),
});
console.log(await res.json());
```
**200 灵感模式{Inspiration mode}**
```
{
  "code": 200,
  "data": [
    { "status": "submitted", "task_id": "task_01K8D99M0HP1GJWBJYZMKX1XS1" }
  ]
}
```
