Apps API
Img2Vid app 是预先配置好的生成工作流。当你希望直接调用某个 app,而不是自己选择媒体模型、mode 和模型参数时,可以使用 Apps API。
App 公开 API 保持极简:查询接口只返回 app id 和扁平输入参数;创建生成任务时,直接把这些参数名放在请求体根层级。
接口
| Method | Endpoint | 用途 |
|---|---|---|
GET |
/api/v1/apps |
查询可调用 app 及输入参数。 |
GET |
/api/v1/apps/{app} |
查询单个 app 的输入参数。 |
POST |
/api/v1/apps/{app}/generations |
基于 app 创建异步生成任务。 |
GET |
/api/v1/apps/{app}/generations/{id} |
查询 app 生成任务状态和结果。 |
所有接口都需要 Authorization: Bearer $BUBLE_API_KEY。
查询 app 列表
GET /api/v1/apps
Query 参数
| Name | Type | Required | Description |
|---|---|---|---|
page |
number | 否 | 页码,默认 1。 |
limit |
number | 否 | 每页数量,默认 50,最大 100。 |
请求示例
curl "https://img2vid.net/api/v1/apps?limit=20" \
-H "Authorization: Bearer $BUBLE_API_KEY"
响应结构
{
"data": [
{
"id": "video-background-remover",
"input_parameters": [
{
"name": "source_video",
"type": "array"
},
{
"name": "output_format",
"type": "string",
"values": ["webm", "mp4"]
}
]
}
]
}
输入参数
每个 app 都会暴露一组扁平输入参数。
| Field | 说明 |
|---|---|
name |
创建生成任务时使用的参数名。 |
type |
JSON 值类型:string、number、boolean 或 array。 |
values |
可选值范围;只有配置了离散可选值的参数才会返回该字段。 |
媒体输入参数的 type 是 array;调用时传入源文件 URL 数组。
查询单个 app
GET /api/v1/apps/{app}
curl https://img2vid.net/api/v1/apps/video-background-remover \
-H "Authorization: Bearer $BUBLE_API_KEY"
响应中的 data 与 GET /api/v1/apps 返回列表中的单个 app 结构一致。
创建 app 生成任务
POST /api/v1/apps/{app}/generations
Content-Type: application/json
请求体是扁平结构。只能使用 /api/v1/apps 返回的参数名;未知字段会被拒绝。
请求示例
curl https://img2vid.net/api/v1/apps/video-background-remover/generations \
-H "Authorization: Bearer $BUBLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_video": ["https://example.com/source-video.mp4"]
}'
响应结构
{
"data": {
"id": "task_id",
"status": "pending"
}
}
如果 app 使用视频时长计费,Img2Vid 会在服务端根据提交的视频 URL 自动计算源视频时长。不要通过传递 duration 字段来控制计费。
查询 app 生成任务
GET /api/v1/apps/{app}/generations/{id}
curl https://img2vid.net/api/v1/apps/video-background-remover/generations/task_id \
-H "Authorization: Bearer $BUBLE_API_KEY"
状态值
| Status | 含义 |
|---|---|
pending |
任务已创建,等待执行。 |
processing |
供应商正在生成结果。 |
success |
生成成功。 |
failed |
生成失败,查看 error。 |
canceled |
任务已取消。 |
成功响应示例
{
"data": {
"id": "task_id",
"status": "success",
"result": {
"videos": [
{
"url": "https://..."
}
]
}
}
}
失败响应示例
{
"data": {
"id": "task_id",
"status": "failed",
"error": {
"message": "Generation failed."
}
}
}
App API 与媒体模型 API 的区别
当你希望使用预设工作流和简化输入时,使用 /api/v1/apps。当你希望直接选择具体媒体模型、mode 和模型参数时,使用 /api/v1/media_models 与 /api/v1/generations。
SDK 示例
SDK 的 app 生成方法对应 POST /api/v1/apps/{app}/generations。只发送 list 或 retrieve 返回的参数名;媒体参数必须接收 URL,不能直接传本地文件路径。
下面的片段假设你已经按快速开始初始化了 SDK client,并引入了对应语言需要的 SDK 类型。
JavaScript / TypeScript
const app = await buble.apps.retrieve('video-background-remover');
console.log(app.data.input_parameters);
const task = await buble.apps.generations.create('video-background-remover', {
source_video: ['https://example.com/source.mp4'],
refine_foreground_edges: true,
subject_is_person: true,
});
const result = await buble.apps.generations.wait(
'video-background-remover',
task.data.id
);
Python
app = client.apps.retrieve("video-background-remover")
print(app["data"]["input_parameters"])
task = client.apps.generations.create(
"video-background-remover",
source_video=["https://example.com/source.mp4"],
refine_foreground_edges=True,
subject_is_person=True,
)
result = client.apps.generations.wait("video-background-remover", task["data"]["id"])
Go
app, err := client.Apps.Retrieve(ctx, "video-background-remover")
if err != nil {
return err
}
fmt.Println(app.Data.InputParameters)
task, err := client.Apps.Generations.Create(ctx, "video-background-remover", map[string]any{
"source_video": []string{"https://example.com/source.mp4"},
"refine_foreground_edges": true,
"subject_is_person": true,
})
if err != nil {
return err
}
result, err := client.Apps.Generations.Wait(ctx, "video-background-remover", task.Data.ID)
Rust
let app = client.apps().retrieve("video-background-remover").await?;
println!("{:?}", app.data.input_parameters);
let mut body = serde_json::Map::new();
body.insert(
"source_video".to_string(),
serde_json::json!(["https://example.com/source.mp4"]),
);
body.insert("refine_foreground_edges".to_string(), serde_json::json!(true));
body.insert("subject_is_person".to_string(), serde_json::json!(true));
let task = client
.apps()
.generations()
.create("video-background-remover", body)
.await?;
let result = client
.apps()
.generations()
.wait("video-background-remover", &task.data.id, WaitOptions::default())
.await?;
Swift
let app = try await client.apps.retrieve("video-background-remover")
print(app.data.inputParameters)
let task = try await client.apps.generations.create(
"video-background-remover",
body: [
"source_video": ["https://example.com/source.mp4"],
"refine_foreground_edges": true,
"subject_is_person": true
]
)
let result = try await client.apps.generations.wait(
"video-background-remover",
task.data.id
)
Dart / Flutter
final app = await client.apps.retrieve('video-background-remover');
print(app.data.inputParameters);
final task = await client.apps.generations.create('video-background-remover', {
'source_video': ['https://example.com/source.mp4'],
'refine_foreground_edges': true,
'subject_is_person': true,
});
final result = await client.apps.generations.wait(
'video-background-remover',
task.data.id,
);
Elixir
{:ok, app} = Buble.Apps.retrieve(client, "video-background-remover")
IO.inspect(app["data"]["input_parameters"])
{:ok, task} =
Buble.Apps.Generations.create(client, "video-background-remover", %{
source_video: ["https://example.com/source.mp4"],
refine_foreground_edges: true,
subject_is_person: true
})
{:ok, result} =
Buble.Apps.Generations.wait(client, "video-background-remover", task["data"]["id"])
Java
Envelope<PublicApp> app = client.apps().retrieve("video-background-remover");
System.out.println(app.getData().getInputParameters());
Envelope<AppGenerationTask> task = client.apps().generations().create(
"video-background-remover",
Map.of(
"source_video", List.of("https://example.com/source.mp4"),
"refine_foreground_edges", true,
"subject_is_person", true));
Envelope<AppGenerationTask> result = client.apps().generations().wait(
"video-background-remover",
task.getData().getId());
.NET
var app = await client.Apps.RetrieveAsync("video-background-remover");
Console.WriteLine(app!.Data!.InputParameters);
var task = await client.Apps.Generations.CreateAsync(
"video-background-remover",
new Dictionary<string, object?>
{
["source_video"] = new[] { "https://example.com/source.mp4" },
["refine_foreground_edges"] = true,
["subject_is_person"] = true
});
var result = await client.Apps.Generations.WaitAsync(
"video-background-remover",
task!.Data!.Id!);
PHP
$app = $client->apps()->retrieve('video-background-remover');
var_dump($app['data']['input_parameters']);
$task = $client->apps()->generations()->create('video-background-remover', [
'source_video' => ['https://example.com/source.mp4'],
'refine_foreground_edges' => true,
'subject_is_person' => true,
]);
$result = $client->apps()->generations()->wait(
'video-background-remover',
$task['data']['id']
);
Ruby
app = client.apps.retrieve("video-background-remover")
puts app.dig("data", "input_parameters")
task = client.apps.generations.create("video-background-remover", {
"source_video" => ["https://example.com/source.mp4"],
"refine_foreground_edges" => true,
"subject_is_person" => true
})
result = client.apps.generations.wait("video-background-remover", task.dig("data", "id"))