callBackUrl 参数设置回调URL。当任务完成时,系统会自动将结果推送到您指定的地址。
回调机制概述
回调机制无需轮询API查询任务状态,系统会主动将任务完成结果推送到您的服务器。
回调时机
系统会在以下情况发送回调通知:- 人声分离任务成功完成
- 人声分离任务失败
- 任务处理过程中发生错误
回调方式
- HTTP方法: POST
- Content Type: application/json
- 超时设置: 15秒
回调请求格式
任务完成时,系统会根据您选择的分离类型发送不同格式的回调数据:{
"code": 200,
"data": {
"task_id": "3e63b4cc88d52611159371f6af5571e7",
"vocal_removal_info": {
"instrumental_url": "https://file.aiquickdraw.com/s/d92a13bf-c6f4-4ade-bb47-f69738435528_Instrumental.mp3",
"origin_url": "",
"vocal_url": "https://file.aiquickdraw.com/s/3d7021c9-fa8b-4eda-91d1-3b9297ddb172_Vocals.mp3"
}
},
"msg": "vocal Removal generated successfully."
}
{
"code": 200,
"data": {
"task_id": "e649edb7abfd759285bd41a47a634b10",
"vocal_removal_info": {
"origin_url": "",
"backing_vocals_url": "https://file.aiquickdraw.com/s/aadc51a3-4c88-4c8e-a4c8-e867c539673d_Backing_Vocals.mp3",
"bass_url": "https://file.aiquickdraw.com/s/a3c2da5a-b364-4422-adb5-2692b9c26d33_Bass.mp3",
"brass_url": "https://file.aiquickdraw.com/s/334b2d23-0c65-4a04-92c7-22f828afdd44_Brass.mp3",
"drums_url": "https://file.aiquickdraw.com/s/ac75c5ea-ac77-4ad2-b7d9-66e140b78e44_Drums.mp3",
"fx_url": "https://file.aiquickdraw.com/s/a8822c73-6629-4089-8f2a-d19f41f0007d_FX.mp3",
"guitar_url": "https://file.aiquickdraw.com/s/064dd08e-d5d2-4201-9058-c5c40fb695b4_Guitar.mp3",
"keyboard_url": "https://file.aiquickdraw.com/s/adc934e0-df7d-45da-8220-1dba160d74e0_Keyboard.mp3",
"percussion_url": "https://file.aiquickdraw.com/s/0f70884d-047c-41f1-a6d0-7044618b7dc6_Percussion.mp3",
"strings_url": "https://file.aiquickdraw.com/s/49829425-a5b0-424e-857a-75d4c63a426b_Strings.mp3",
"synth_url": "https://file.aiquickdraw.com/s/56b2d94a-eb92-4d21-bc43-3460de0c8348_Synth.mp3",
"vocal_url": "https://file.aiquickdraw.com/s/07420749-29a2-4054-9b62-e6a6f8b90ccb_Vocals.mp3",
"woodwinds_url": "https://file.aiquickdraw.com/s/d81545b1-6f94-4388-9785-1aaa6ecabb02_Woodwinds.mp3"
}
},
"msg": "vocal Removal generated successfully."
}
{
"code": 200,
"msg": "vocal Removal generated successfully.",
"data": {
"task_id": "7220be2955295dda60de46ec6e4ead4c",
"vocal_removal_info": {
"origin_data": [
{
"extract": {
"duration": 194.92,
"audio_url": "https://tempfile.aiquickdraw.com/r/eb7d0f18-8349-4735-a65e-1812705d5ddf_Lead Vocal.mp3",
"stem_type_group_name": "Lead Vocal",
"id": "eb7d0f18-8349-4735-a65e-1812705d5ddf"
},
"remove": {
"duration": 194.92,
"audio_url": "https://tempfile.aiquickdraw.com/r/706d32df-e988-412e-bce4-42c9302e5478_Lead Vocal.mp3",
"stem_type_group_name": "Lead Vocal",
"id": "706d32df-e988-412e-bce4-42c9302e5478"
}
},
{
"extract": {
"duration": 194.92,
"audio_url": "https://tempfile.aiquickdraw.com/r/a7c503f6-1265-4f7e-bf5d-c50fb3b07238_Lead Vocal.mp3",
"stem_type_group_name": "Lead Vocal",
"id": "a7c503f6-1265-4f7e-bf5d-c50fb3b07238"
},
"remove": {
"duration": 194.92,
"audio_url": "https://tempfile.aiquickdraw.com/r/a3a0c954-1980-410f-9b34-8539b8eb23f8_Lead Vocal.mp3",
"stem_type_group_name": "Lead Vocal",
"id": "a3a0c954-1980-410f-9b34-8539b8eb23f8"
}
}
]
}
}
}
{
"code": 400,
"msg": "人声分离失败",
"data": {
"task_id": "5e72d367bdfbe44785e28d72cb1697c7",
"vocal_removal_info": null
}
}
状态码说明
integer
必填
回调状态码,表示任务处理结果:
| 状态码 | 说明 |
|---|---|
| 200 | 成功 - 人声分离完成 |
| 400 | 请求错误 - 参数错误、音频文件格式不支持等 |
| 451 | 下载失败 - 无法下载源音频文件 |
| 500 | 服务器错误 - 请稍后重试 |
string
必填
状态消息,提供详细的状态描述
string
必填
任务ID,与您提交任务时返回的taskId一致
object
人声分离结果信息,成功时返回
separate_vocal类型字段说明
string
原始混音音频文件URL
string
纯伴奏音频文件URL(去除人声)
string
纯人声音频文件URL(去除伴奏)
split_stem类型字段说明
string
原始混音音频文件URL
string
纯人声音频文件URL
string
和声部分音频文件URL
string
鼓声部分音频文件URL
string
贝斯部分音频文件URL
string
吉他部分音频文件URL
string
键盘部分音频文件URL
string
打击乐部分音频文件URL
string
弦乐部分音频文件URL
string
合成器部分音频文件URL
string
音效部分音频文件URL
string
铜管乐部分音频文件URL
string
木管乐部分音频文件URL
split_stem_advanced 类型字段
array
原始音频的分离结果数组,包含多个音轨组的提取和移除信息。每个元素代表一个独立的音轨组(如 Lead Vocal)。
object
提取出的指定音轨信息(保留该音轨,移除其他)。
number
提取音频的时长,单位为秒。
string
提取出的指定音轨音频文件的下载地址。
string
音轨类型分组名称(如 Lead Vocal),表示该组提取的是哪种类型的音轨。
string
提取音频的唯一标识符。
object
移除指定音轨后的剩余音频信息(移除该音轨,保留其他)。
number
移除后音频的时长,单位为秒。
string
移除指定音轨后剩余音频文件的下载地址。
string
音轨类型分组名称(如 Lead Vocal),与对应的 extract 保持一致。
string
移除后音频的唯一标识符。
回调接收示例
以下是主流编程语言接收回调的示例代码:- Node.js
- Python
- PHP
const express = require('express');
const app = express();
app.use(express.json());
app.post('/vocal-separation-callback', (req, res) => {
const { code, msg, data } = req.body;
console.log('收到人声分离回调:', {
taskId: data.task_id,
status: code,
message: msg
});
if (code === 200) {
// 任务成功完成
console.log('人声分离完成');
const vocalInfo = data.vocal_removal_info;
if (vocalInfo) {
console.log('分离结果:');
console.log(` 原始音频: ${vocalInfo.origin_url}`);
// 根据不同的分离类型处理不同的文件
if (vocalInfo.instrumental_url) {
// separate_vocal 类型
console.log(` 纯伴奏: ${vocalInfo.instrumental_url}`);
console.log(` 纯人声: ${vocalInfo.vocal_url}`);
} else {
// split_stem 类型
console.log(` 人声: ${vocalInfo.vocal_url}`);
console.log(` 和声: ${vocalInfo.backing_vocals_url}`);
console.log(` 鼓声: ${vocalInfo.drums_url}`);
console.log(` 贝斯: ${vocalInfo.bass_url}`);
console.log(` 吉他: ${vocalInfo.guitar_url}`);
console.log(` 键盘: ${vocalInfo.keyboard_url}`);
console.log(` 打击乐: ${vocalInfo.percussion_url}`);
console.log(` 弦乐: ${vocalInfo.strings_url}`);
console.log(` 合成器: ${vocalInfo.synth_url}`);
console.log(` 音效: ${vocalInfo.fx_url}`);
console.log(` 铜管乐: ${vocalInfo.brass_url}`);
console.log(` 木管乐: ${vocalInfo.woodwinds_url}`);
}
// 下载分离后的音频文件
const https = require('https');
const fs = require('fs');
const downloadFile = (url, filename) => {
if (!url) return;
const file = fs.createWriteStream(filename);
https.get(url, (response) => {
response.pipe(file);
file.on('finish', () => {
file.close();
console.log(`已保存: ${filename}`);
});
}).on('error', (err) => {
console.error(`下载失败 ${filename}:`, err.message);
});
};
// 下载所有可用的音频文件
Object.keys(vocalInfo).forEach(key => {
if (vocalInfo[key] && key.endsWith('_url')) {
const filename = `${data.task_id}_${key.replace('_url', '')}.mp3`;
downloadFile(vocalInfo[key], filename);
}
});
}
} else {
// 任务失败
console.log('人声分离失败:', msg);
// 处理失败情况...
if (code === 400) {
console.log('参数错误或音频格式不支持');
} else if (code === 451) {
console.log('源音频文件下载失败');
} else if (code === 500) {
console.log('服务器内部错误');
}
}
// 返回200状态码确认收到回调
res.status(200).json({ status: 'received' });
});
app.listen(3000, () => {
console.log('回调服务器运行在端口 3000');
});
from flask import Flask, request, jsonify
import requests
app = Flask(__name__)
@app.route('/vocal-separation-callback', methods=['POST'])
def handle_callback():
data = request.json
code = data.get('code')
msg = data.get('msg')
callback_data = data.get('data', {})
task_id = callback_data.get('task_id')
vocal_info = callback_data.get('vocal_removal_info')
print(f"收到人声分离回调: {task_id}, 状态: {code}, 消息: {msg}")
if code == 200:
# 任务成功完成
print("人声分离完成")
if vocal_info:
print("分离结果:")
print(f" 原始音频: {vocal_info.get('origin_url')}")
# 根据不同的分离类型处理不同的文件
if vocal_info.get('instrumental_url'):
# separate_vocal 类型
print(f" 纯伴奏: {vocal_info.get('instrumental_url')}")
print(f" 纯人声: {vocal_info.get('vocal_url')}")
else:
# split_stem 类型
print(f" 人声: {vocal_info.get('vocal_url')}")
print(f" 和声: {vocal_info.get('backing_vocals_url')}")
print(f" 鼓声: {vocal_info.get('drums_url')}")
print(f" 贝斯: {vocal_info.get('bass_url')}")
print(f" 吉他: {vocal_info.get('guitar_url')}")
print(f" 键盘: {vocal_info.get('keyboard_url')}")
print(f" 打击乐: {vocal_info.get('percussion_url')}")
print(f" 弦乐: {vocal_info.get('strings_url')}")
print(f" 合成器: {vocal_info.get('synth_url')}")
print(f" 音效: {vocal_info.get('fx_url')}")
print(f" 铜管乐: {vocal_info.get('brass_url')}")
print(f" 木管乐: {vocal_info.get('woodwinds_url')}")
# 下载分离后的音频文件
def download_file(url, filename):
if not url:
return
try:
response = requests.get(url)
if response.status_code == 200:
with open(filename, "wb") as f:
f.write(response.content)
print(f"已保存: {filename}")
except Exception as e:
print(f"下载失败 {filename}: {e}")
# 下载所有可用的音频文件
for key, url in vocal_info.items():
if url and key.endswith('_url'):
filename = f"{task_id}_{key.replace('_url', '')}.mp3"
download_file(url, filename)
else:
# 任务失败
print(f"人声分离失败: {msg}")
# 处理失败情况...
if code == 400:
print("参数错误或音频格式不支持")
elif code == 451:
print("源音频文件下载失败")
elif code == 500:
print("服务器内部错误")
# 返回200状态码确认收到回调
return jsonify({'status': 'received'}), 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=3000)
<?php
header('Content-Type: application/json');
// 获取POST数据
$input = file_get_contents('php://input');
$data = json_decode($input, true);
$code = $data['code'] ?? null;
$msg = $data['msg'] ?? '';
$callbackData = $data['data'] ?? [];
$taskId = $callbackData['task_id'] ?? '';
$vocalInfo = $callbackData['vocal_removal_info'] ?? null;
error_log("收到人声分离回调: $taskId, 状态: $code, 消息: $msg");
if ($code === 200) {
// 任务成功完成
error_log("人声分离完成");
if ($vocalInfo) {
error_log("分离结果:");
error_log(" 原始音频: " . ($vocalInfo['origin_url'] ?? ''));
// 根据不同的分离类型处理不同的文件
if (isset($vocalInfo['instrumental_url'])) {
// separate_vocal 类型
error_log(" 纯伴奏: " . ($vocalInfo['instrumental_url'] ?? ''));
error_log(" 纯人声: " . ($vocalInfo['vocal_url'] ?? ''));
} else {
// split_stem 类型
error_log(" 人声: " . ($vocalInfo['vocal_url'] ?? ''));
error_log(" 和声: " . ($vocalInfo['backing_vocals_url'] ?? ''));
error_log(" 鼓声: " . ($vocalInfo['drums_url'] ?? ''));
error_log(" 贝斯: " . ($vocalInfo['bass_url'] ?? ''));
error_log(" 吉他: " . ($vocalInfo['guitar_url'] ?? ''));
error_log(" 键盘: " . ($vocalInfo['keyboard_url'] ?? ''));
error_log(" 打击乐: " . ($vocalInfo['percussion_url'] ?? ''));
error_log(" 弦乐: " . ($vocalInfo['strings_url'] ?? ''));
error_log(" 合成器: " . ($vocalInfo['synth_url'] ?? ''));
error_log(" 音效: " . ($vocalInfo['fx_url'] ?? ''));
error_log(" 铜管乐: " . ($vocalInfo['brass_url'] ?? ''));
error_log(" 木管乐: " . ($vocalInfo['woodwinds_url'] ?? ''));
}
// 下载分离后的音频文件
function downloadFile($url, $filename) {
if (!$url) return;
try {
$content = file_get_contents($url);
if ($content !== false) {
file_put_contents($filename, $content);
error_log("已保存: $filename");
}
} catch (Exception $e) {
error_log("下载失败 $filename: " . $e->getMessage());
}
}
// 下载所有可用的音频文件
foreach ($vocalInfo as $key => $url) {
if ($url && strpos($key, '_url') !== false) {
$filename = $taskId . '_' . str_replace('_url', '', $key) . '.mp3';
downloadFile($url, $filename);
}
}
}
} else {
// 任务失败
error_log("人声分离失败: $msg");
// 处理失败情况...
if ($code === 400) {
error_log("参数错误或音频格式不支持");
} elseif ($code === 451) {
error_log("源音频文件下载失败");
} elseif ($code === 500) {
error_log("服务器内部错误");
}
}
// 返回200状态码确认收到回调
http_response_code(200);
echo json_encode(['status' => 'received']);
?>
最佳实践
回调URL配置建议
- 使用HTTPS: 确保回调URL使用HTTPS协议,保障数据传输安全
- 验证来源: 在回调处理中验证请求来源的合法性
- 幂等处理: 同一个taskId可能收到多次回调,确保处理逻辑是幂等的
- 快速响应: 回调处理应尽快返回200状态码,避免超时
- 异步处理: 复杂的业务逻辑应异步处理,避免阻塞回调响应
- 文件管理: 分离后的音频文件下载和处理应在异步任务中进行
- 类型判断: 根据返回字段判断分离类型,采用相应的处理逻辑
重要提醒
- 回调URL必须是公网可访问的地址
- 服务器必须在15秒内响应,否则视为超时
- 连续3次重试失败后,系统将停止发送回调
- 请确保回调处理逻辑的稳定性,避免因异常导致回调失败
- 生成的音频文件URL可能有时效限制,建议及时下载保存
- split_stem 模式会产生更多文件,注意存储空间管理
- 确保源音频文件包含对应的音乐成分以获得最佳分离效果
- 不同分离类型的回调结构不同,需要相应的处理逻辑
故障排查
如果您没有收到回调通知,请检查以下内容:网络连接问题
网络连接问题
- 确认回调URL可以从公网访问
- 检查防火墙设置,确保不会阻拦入站请求
- 验证域名解析是否正确
服务器响应问题
服务器响应问题
- 确保服务器在15秒内返回HTTP 200状态码
- 检查服务器日志是否有错误信息
- 验证接口路径和HTTP方法是否正确
内容格式问题
内容格式问题
- 确认接收到的POST请求体为JSON格式
- 检查Content-Type是否为application/json
- 验证JSON解析是否正确
- 确保能正确处理不同分离类型的数据结构
音频处理问题
音频处理问题
- 确认分离后的音频文件URL是否可访问
- 检查音频下载权限和网络连接
- 验证音频保存路径和权限
- 注意源音频文件质量对分离效果的影响
- 确认源音频文件格式是否受支持
- split_stem 模式需要检查更多的音频文件
替代方案
如果您无法使用回调机制,也可以使用轮询方式:轮询查询结果
使用获取人声分离详情接口定时查询任务状态,建议每30秒查询一次。
