• 把续写产生的多个分段拼成一首完整歌曲,异步任务
  • 只接受续写(extend)的产物,普通生成整首会被拒
  • 拼接本身不收费,续写各段按各自价格单独计费
POST/v1/music/generations/concat

认证

string必填

所有接口均使用 Bearer Token 进行认证。

获取 API Key:访问控制台 创建。

请求时在请求头中添加:

Authorization: Bearer YOUR_OAIRoute_KEY

请求参数

string可选

音频模型,默认 suno,当前只支持 suno。

string必填

源任务的 task_id,必须是 extend 或 extendMusic 续写的产物。

缺失、不是续写结果、或源无法解析时,提交阶段直接返回 400。

integer可选

指定引用源任务结果 data.result.music[] 中的第几首,默认 1。一次生成一般返回两首。

string可选

输出音频格式,取值 mp3、m4a、wav。

前置条件

这条限制最容易踩:拼接只对续写的分段有效。

源任务类型能否拼接
extend 续写产物可以
extendMusic 续写产物可以
一次性生成的整首歌不行,返回 400

想做整首歌,正确流程是先生成一段,再续写若干段,最后拼接。

响应

integer

响应状态码,成功为 200。

array

提交成功后为单元素数组。

data[] 的元素字段 · 2 项
string

任务状态,当前提交成功只会返回 submitted。

string

新任务的唯一标识,用于后续轮询。

计费说明

拼接操作本身不收费。但生成续写片段时调用的 extend 接口,按各自的价格单独计费。

所以整首歌的总成本 = 首次生成 + 各次续写,拼接这一步是免费的。

轮询

用 GET /v1/music/tasks/{task_id},间隔 3 到 5 秒,典型耗时 30 到 120 秒。

status 取值 pending、processing、completed、failed,只有 completed 或 failed 是终态。progress 是 0 到 100 的整数,不保证按固定节点变化。

完成后从 data.result.music[].audio_url 取音频。失败时 data.error.message 给出原因,并自动退回预扣额度。

完整流程

import time, requests

BASE = "https://api.oairoute.com"
HEAD = {"Authorization": "Bearer YOUR_OAIRoute_KEY",
        "Content-Type": "application/json"}

def wait(task_id):
    while True:
        d = requests.get(f"{BASE}/v1/music/tasks/{task_id}",
                         headers=HEAD).json()["data"]
        if d["status"] == "completed":
            return d
        if d["status"] == "failed":
            raise RuntimeError(d.get("error"))
        time.sleep(5)

# 1. 生成第一段
r = requests.post(f"{BASE}/v1/music/generations", headers=HEAD, json={
    "model": "suno", "custom": True, "version": "v6",
    "prompt": "[Verse]\n第一段歌词", "tags": "folk",
})
first = r.json()["data"][0]["task_id"]
base = wait(first)

# 2. 续写第二段
r = requests.post(f"{BASE}/v1/music/generations/extend", headers=HEAD, json={
    "model": "suno", "task_id": first, "audio_index": 1,
    "continue_at": base["result"]["music"][0]["duration"] - 2,
    "custom": True, "prompt": "[Verse]\n第二段歌词", "tags": "folk",
})
second = r.json()["data"][0]["task_id"]
wait(second)

# 3. 拼接
r = requests.post(f"{BASE}/v1/music/generations/concat", headers=HEAD, json={
    "model": "suno", "task_id": second, "audio_index": 1,
    "audio_format": "wav",
})
print("拼接任务", r.json()["data"][0]["task_id"])

续写时的 continue_at 建议设在源音频结束前 1 到 2 秒,让两段有重叠,拼接处更自然。设成正好等于结尾,接缝容易听出来。

错误码

错误响应的格式、状态码与重试建议见错误码与限流,常见报错的排查步骤见常见问题。

使用示例

提交一个任务并拿到 task_id:

提交成功只表示任务已受理。真正的产物要拿返回的 task_id 去任务查询接口轮询,status 变成 completed 之后才有结果。