快速开始

这个指南会创建一个文生图任务,然后轮询结果。

1. 设置 API Key

export BUBLE_API_KEY="sk_your_api_key"

API Key 只应该在服务端使用,不要暴露在浏览器代码中。

2. 查看可用媒体模型

curl https://img2vid.net/api/v1/media_models \
  -H "Authorization: Bearer $BUBLE_API_KEY"

从响应中选择媒体 model,并使用它的 operations[].mode

3. 创建文生图任务

curl https://img2vid.net/api/v1/generations \
  -H "Authorization: Bearer $BUBLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/nano-banana-pro",
    "mode": "text_to_image",
    "prompt": "A premium product photo of a matte black wireless speaker on a marble table, cinematic studio lighting",
    "aspect_ratio": "1:1",
    "resolution": "1K",
    "output_format": "png"
  }'

响应会返回生成任务 id

4. 轮询任务

curl https://img2vid.net/api/v1/generations/YOUR_GENERATION_ID \
  -H "Authorization: Bearer $BUBLE_API_KEY"

持续轮询,直到 data.status 变为 successfailed

5. 需要素材时先上传文件

图生图或图生视频工作流通常需要先上传源文件:

curl https://img2vid.net/api/v1/files \
  -H "Authorization: Bearer $BUBLE_API_KEY" \
  -F "file=@./reference.png" \
  -F "file_type=image" \
  -F "model=google/nano-banana-pro" \
  -F "mode=image_to_image"

然后把返回的 data.url 传给所选 mode 支持的 image_urlsstart_frame 等字段。

6. 使用官方 SDK

SDK 封装的是稳定的公开 API 契约:模型和 app 发现、文件上传、创建异步生成任务、轮询结果,以及 Chat 协议调用。SDK 不会把每个模型的私有细节硬编码进去;模型 key、mode、app 参数和模型专属参数仍应从 API 返回结果中读取。

已发布的 SDK 包名、客户端类名和 BUBLE_API_KEY 环境变量作为兼容标识继续保留;它们仍调用 https://img2vid.net 上的 Img2Vid API。

语言 安装方式
JavaScript / TypeScript npm install @buble/sdk
Python pip install buble-ai
Go go get github.com/bublehq/sdks/go
Rust cargo add buble
Swift .package(url: "https://github.com/bublehq/swift-sdk.git", from: "0.1.0")
Dart / Flutter dart pub add bubleflutter pub add buble
Elixir {:buble, "~> 0.1.0"}
Java ai.buble:buble-sdk:0.1.0
.NET dotnet add package Buble.SDK --version 0.1.2
PHP composer require buble/sdk
Ruby gem install buble

下面的 SDK 示例在没有显式传入 API key 时都会读取 BUBLE_API_KEY 环境变量。请只在服务端保存和使用这个 key。

JavaScript / TypeScript

import { Buble } from '@buble/sdk';

const buble = new Buble();

const task = await buble.generations.create({
  model: 'google/nano-banana',
  mode: 'text_to_image',
  prompt: 'A cinematic product photo of a matte black espresso cup',
  aspect_ratio: '1:1',
  output_format: 'png',
});

const result = await buble.generations.wait(task.data.id);
console.log(result.data.result?.images?.[0]?.url);

Python

from buble_ai import Buble

client = Buble()

task = client.generations.create(
    model="google/nano-banana",
    mode="text_to_image",
    prompt="A cinematic product photo of a matte black espresso cup",
    aspect_ratio="1:1",
    output_format="png",
)

result = client.generations.wait(task["data"]["id"])
print(result["data"]["result"]["images"][0]["url"])

Go

client := buble.NewClient()

task, err := client.Generations.Create(ctx, &buble.CreateGenerationRequest{
	Model:  "google/nano-banana",
	Mode:   "text_to_image",
	Prompt: "A cinematic product photo of a matte black espresso cup",
	Params: map[string]any{
		"aspect_ratio":  "1:1",
		"output_format": "png",
	},
})
if err != nil {
	return err
}

result, err := client.Generations.Wait(ctx, task.Data.ID)
if err != nil {
	return err
}
fmt.Println(result.Data.Result.Images[0].URL)

Rust

use buble::{Client, CreateGenerationRequest, WaitOptions};

let client = Client::from_env()?;

let task = client.generations().create(
    CreateGenerationRequest::new("google/nano-banana")
        .mode("text_to_image")
        .prompt("A cinematic product photo of a matte black espresso cup")
        .param("aspect_ratio", "1:1")?
        .param("output_format", "png")?,
).await?;

let result = client
    .generations()
    .wait(&task.data.id, WaitOptions::default())
    .await?;

Swift

import Buble

let client = try BubleClient.fromEnvironment()

let task = try await client.generations.create(
    try CreateGenerationRequest(model: "google/nano-banana")
        .mode("text_to_image")
        .prompt("A cinematic product photo of a matte black espresso cup")
        .param("aspect_ratio", "1:1")
        .param("output_format", "png")
)

let result = try await client.generations.wait(task.data.id)
print(result.data.result?.images?.first?.url.absoluteString ?? "")

Dart / Flutter

import 'package:buble/buble.dart';

final client = BubleClient.fromEnvironment();

final task = await client.generations.create(
  CreateGenerationRequest(
    model: 'google/nano-banana',
    mode: 'text_to_image',
    prompt: 'A cinematic product photo of a matte black espresso cup',
  ).withParam('aspect_ratio', '1:1').withParam('output_format', 'png'),
);

final result = await client.generations.wait(task.data.id);
print(result.data.result?.images.firstOrNull?.url);

Elixir

client = Buble.Client.new!()

{:ok, task} =
  Buble.Generations.create(client, %{
    model: "google/nano-banana",
    mode: "text_to_image",
    prompt: "A cinematic product photo of a matte black espresso cup",
    aspect_ratio: "1:1",
    output_format: "png"
  })

{:ok, result} = Buble.Generations.wait(client, task["data"]["id"])
IO.puts(result["data"]["result"]["images"] |> List.first() |> Map.fetch!("url"))

Java

BubleClient client = BubleClient.fromEnv();

Envelope<GenerationTask> task = client.generations().create(
        CreateGenerationRequest.builder()
                .model("google/nano-banana")
                .mode("text_to_image")
                .prompt("A cinematic product photo of a matte black espresso cup")
                .param("aspect_ratio", "1:1")
                .param("output_format", "png")
                .build());

Envelope<GenerationTask> result = client.generations().wait(task.getData().getId());

.NET

using var client = BubleClient.FromEnv();

var task = await client.Generations.CreateAsync(new CreateGenerationRequest
{
    Model = "google/nano-banana",
    Mode = "text_to_image",
    Prompt = "A cinematic product photo of a matte black espresso cup"
}.WithParam("aspect_ratio", "1:1").WithParam("output_format", "png"));

var result = await client.Generations.WaitAsync(task!.Data!.Id!);

PHP

use Buble\BubleClient;
use Buble\Generations\CreateGenerationRequest;

$client = BubleClient::fromEnv();

$task = $client->generations()->create(
    CreateGenerationRequest::make(
        model: 'google/nano-banana',
        mode: 'text_to_image',
        prompt: 'A cinematic product photo of a matte black espresso cup',
    )->withParam('aspect_ratio', '1:1')
     ->withParam('output_format', 'png')
);

$result = $client->generations()->wait($task['data']['id']);

Ruby

require "buble"

client = Buble::Client.new

task = client.generations.create(
  model: "google/nano-banana",
  mode: "text_to_image",
  prompt: "A cinematic product photo of a matte black espresso cup",
  aspect_ratio: "1:1",
  output_format: "png"
)

result = client.generations.wait(task.dig("data", "id"))
puts result.dig("data", "result", "images", 0, "url")