callBackUrl 参数设置回调 URL。任务完成时,系统将自动将结果推送到您指定的地址。
回调机制概述
回调机制消除了轮询 API 获取任务状态的需要。系统将主动将任务完成结果推送到您的服务器。
回调时机
系统将在以下情况下发送回调通知:- 视频修改任务成功完成
- 视频修改任务失败
- 任务处理过程中出现错误
回调方式
- HTTP 方法:POST
- 内容类型:application/json
- 超时设置:15 秒
回调请求格式
任务完成时,系统将向您的callBackUrl 发送 POST 请求,格式如下:
复制
{
"code": 200,
"msg": "修改记录生成成功。",
"data": {
"taskId": "774d9a7dd608a0e49293903095e45a4c",
"promptJson": "{\"callBackUrl\":\"https://b7af305f36d6.ngrok-free.app/api/v1/modify/test\",\"prompt\":\"一个夜晚的未来主义城市景观,高耸的玻璃尖塔伸向繁星满天的天空。蓝色和紫色的霓虹灯照亮着建筑物,飞行器在建筑物之间静静滑行。全息广告在建筑物外墙上闪烁变化。\",\"videoUrl\":\"https://tempfile.aiquickdraw.com/kieai/file/veo3-video/1755074605154fqb0m8ge.mp4\",\"waterMark\":\"\"}",
"resultUrls": [
"https://tempfile.aiquickdraw.com/l/f782018c-6be4-4990-96ba-7231cd5a39e7.mp4"
]
}
}
状态码说明
回调状态码,指示任务处理结果:
| 状态码 | 描述 |
|---|---|
| 200 | 成功 - 视频修改成功完成 |
| 500 | 失败 - 视频修改任务失败 |
状态消息,提供详细的状态描述
任务 ID,与您提交任务时返回的 taskId 一致
JSON 格式的原始请求参数,包括提示、视频 URL、回调 URL 和水印设置
生成的视频 URL。仅在成功完成时出现(code 200)。
回调接收示例
以下是用流行编程语言接收回调的示例代码:- Node.js
- Python
- PHP
复制
const express = require('express');
const fs = require('fs');
const https = require('https');
const app = express();
app.use(express.json());
app.post('/luma-modify-callback', (req, res) => {
const { code, msg, data } = req.body;
console.log('收到 Luma 视频修改回调:', {
taskId: data.taskId,
status: code,
message: msg
});
if (code === 200) {
// 任务成功完成
console.log('Luma 视频修改成功完成');
const { taskId, promptJson, resultUrls } = data;
console.log(`任务 ID: ${taskId}`);
console.log(`原始参数: ${promptJson}`);
console.log(`生成的视频 URL: ${resultUrls.join(', ')}`);
// 下载生成的视频
resultUrls.forEach((url, index) => {
const filename = `luma_result_${taskId}_${index + 1}.mp4`;
downloadFile(url, filename)
.then(() => console.log(`视频 ${index + 1} 下载成功`))
.catch(err => console.error(`视频 ${index + 1} 下载失败:`, err));
});
} else {
// 任务失败
console.log('Luma 视频修改失败:', msg);
// 记录原始参数用于调试
const { promptJson } = data;
console.log('原始参数:', promptJson);
// 处理特定错误情况
console.log('请检查您的输入视频和提示,然后重试');
}
// 返回 200 状态码确认收到回调
res.status(200).json({ status: 'received' });
});
// 下载文件的辅助函数
function downloadFile(url, filename) {
return new Promise((resolve, reject) => {
const file = fs.createWriteStream(filename);
https.get(url, (response) => {
if (response.statusCode === 200) {
response.pipe(file);
file.on('finish', () => {
file.close();
resolve();
});
} else {
reject(new Error(`HTTP ${response.statusCode}`));
}
}).on('error', reject);
});
}
app.listen(3000, () => {
console.log('Luma 回调服务器运行在端口 3000');
});
复制
from flask import Flask, request, jsonify
import requests
import os
import json
app = Flask(__name__)
@app.route('/luma-modify-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('taskId')
prompt_json = callback_data.get('promptJson')
result_urls = callback_data.get('resultUrls', [])
print(f"收到 Luma 视频修改回调:")
print(f"任务 ID: {task_id}")
print(f"状态: {code}, 消息: {msg}")
if code == 200:
# 任务成功完成
print("Luma 视频修改成功完成")
print(f"任务 ID: {task_id}")
print(f"原始参数: {prompt_json}")
print(f"生成的视频 URL: {', '.join(result_urls)}")
# 解析原始参数
try:
original_params = json.loads(prompt_json)
print(f"原始提示: {original_params.get('prompt', 'N/A')}")
print(f"原始视频 URL: {original_params.get('videoUrl', 'N/A')}")
except json.JSONDecodeError:
print("无法解析原始参数")
# 下载生成的视频
for index, url in enumerate(result_urls):
try:
filename = f"luma_result_{task_id}_{index + 1}.mp4"
download_file(url, filename)
print(f"视频 {index + 1} 下载为 {filename}")
except Exception as e:
print(f"视频 {index + 1} 下载失败: {e}")
else:
# 任务失败
print(f"Luma 视频修改失败: {msg}")
# 记录原始参数用于调试
print(f"原始参数: {prompt_json}")
# 处理特定错误情况
print("请检查您的输入视频和提示,然后重试")
# 返回 200 状态码确认收到回调
return jsonify({'status': 'received'}), 200
def download_file(url, filename):
"""从 URL 下载文件并保存到本地"""
response = requests.get(url, stream=True)
response.raise_for_status()
os.makedirs('downloads', exist_ok=True)
filepath = os.path.join('downloads', filename)
with open(filepath, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
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['taskId'] ?? '';
$promptJson = $callbackData['promptJson'] ?? '';
$resultUrls = $callbackData['resultUrls'] ?? [];
error_log("收到 Luma 视频修改回调:");
error_log("任务 ID: $taskId");
error_log("状态: $code, 消息: $msg");
if ($code === 200) {
// 任务成功完成
error_log("Luma 视频修改成功完成");
error_log("任务 ID: $taskId");
error_log("原始参数: $promptJson");
error_log("生成的视频 URL: " . implode(', ', $resultUrls));
// 解析原始参数
$originalParams = json_decode($promptJson, true);
if ($originalParams) {
error_log("原始提示: " . ($originalParams['prompt'] ?? 'N/A'));
error_log("原始视频 URL: " . ($originalParams['videoUrl'] ?? 'N/A'));
}
// 下载生成的视频
foreach ($resultUrls as $index => $url) {
try {
$filename = "luma_result_{$taskId}_" . ($index + 1) . ".mp4";
downloadFile($url, $filename);
error_log("视频 " . ($index + 1) . " 下载为 $filename");
} catch (Exception $e) {
error_log("视频 " . ($index + 1) . " 下载失败: " . $e->getMessage());
}
}
} else {
// 任务失败
error_log("Luma 视频修改失败: $msg");
// 记录原始参数用于调试
error_log("原始参数: $promptJson");
// 处理特定错误情况
error_log("请检查您的输入视频和提示,然后重试");
}
// 返回 200 状态码确认收到回调
http_response_code(200);
echo json_encode(['status' => 'received']);
function downloadFile($url, $filename) {
$downloadDir = 'downloads';
if (!is_dir($downloadDir)) {
mkdir($downloadDir, 0755, true);
}
$filepath = $downloadDir . '/' . $filename;
$fileContent = file_get_contents($url);
if ($fileContent === false) {
throw new Exception("从 URL 下载文件失败");
}
$result = file_put_contents($filepath, $fileContent);
if ($result === false) {
throw new Exception("本地保存文件失败");
}
}
?>
最佳实践
回调 URL 配置建议
- 使用 HTTPS:确保您的回调 URL 使用 HTTPS 协议进行安全数据传输
- 验证来源:在回调处理中验证请求来源的合法性
- 幂等处理:同一个 taskId 可能收到多次回调,确保处理逻辑是幂等的
- 快速响应:回调处理应尽快返回 200 状态码以避免超时
- 异步处理:复杂业务逻辑应异步处理,避免阻塞回调响应
- 及时下载:生成的视频可能在一段时间后过期,收到成功回调后立即下载保存
重要提醒
- 回调 URL 必须是公网可访问的地址
- 服务器必须在 15 秒内响应,否则将被视为超时
- 如果连续 3 次重试失败,系统将停止发送回调
- 生成的视频 URL 可能会过期 - 收到回调后立即下载
- 请确保回调处理逻辑的稳定性,避免因异常导致回调失败
- 需要处理成功和失败两种状态码以实现完整的错误处理
- 大视频文件可能需要时间下载 - 实施适当的超时设置
问题排查
如果您没有收到回调通知,请检查以下内容:网络连接问题
网络连接问题
- 确认回调 URL 可从公网访问
- 检查防火墙设置,确保入站请求未被阻止
- 验证域名解析是否正确
服务器响应问题
服务器响应问题
- 确保服务器在 15 秒内返回 HTTP 200 状态码
- 检查服务器日志中的错误消息
- 验证接口路径和 HTTP 方法是否正确
内容格式问题
内容格式问题
- 确认收到的 POST 请求体是 JSON 格式
- 检查 Content-Type 是否为 application/json
- 验证 JSON 解析是否正确
视频处理问题
视频处理问题
- 确认视频 URL 可访问
- 检查视频下载权限和网络连接
- 验证视频保存路径和权限
- 处理视频下载超时和重试逻辑
- 为大视频文件实施校验和验证
任务失败问题
任务失败问题
- 检查视频修改参数是否合理
- 验证输入视频格式和质量
- 确认提示长度和格式
- 考虑调整修改参数并重试
- 查看 promptJson 中的错误消息进行调试
替代方案
如果您无法使用回调机制,也可以使用轮询:轮询查询结果
使用获取 Luma 修改详情端点定期查询任务状态。对于视频生成任务,我们建议每 30 秒查询一次。
