Upload and Generate

This end-to-end example uploads a source image, then uses it for image-to-image generation.

1. Upload the source image

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

Save the returned data.url.

2. Create a generation

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": "image_to_image",
    "prompt": "Redesign this room as a premium modern Japanese-inspired interior with warm oak, paper lantern lighting, low furniture, and calm editorial styling",
    "image_urls": ["https://example.com/uploaded-room.png"],
    "aspect_ratio": "16:9",
    "resolution": "1K",
    "output_format": "png"
  }'

3. Poll the result

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

Node.js version

import fs from 'node:fs';

const fileForm = new FormData();
fileForm.append(
  'file',
  new Blob([fs.readFileSync('./room.png')], { type: 'image/png' }),
  'room.png'
);
fileForm.append('file_type', 'image');
fileForm.append('model', 'google/nano-banana-pro');
fileForm.append('mode', 'image_to_image');

const upload = await fetch('https://img2vid.net/api/v1/files', {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.BUBLE_API_KEY}` },
  body: fileForm,
});
const { data: uploaded, error: uploadError } = await upload.json();
if (uploadError) throw new Error(uploadError.message);

const generation = await fetch('https://img2vid.net/api/v1/generations', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.BUBLE_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'google/nano-banana-pro',
    mode: 'image_to_image',
    prompt:
      'Redesign this room as a premium modern Japanese-inspired interior.',
    image_urls: [uploaded.url],
    aspect_ratio: '16:9',
    resolution: '1K',
    output_format: 'png',
  }),
});
const { data: task, error } = await generation.json();
if (error) throw new Error(error.message);
console.log(task.id);

SDK examples

These SDK examples upload ./room.png, use the returned data.url as image_urls[0], create the generation, and then wait for the task to finish.

TypeScript / JavaScript

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

const buble = new Buble();

const uploaded = await buble.files.upload('./room.png', {
  file_type: 'image',
  model: 'google/nano-banana-pro',
  mode: 'image_to_image',
});

const task = await buble.generations.create({
  model: 'google/nano-banana-pro',
  mode: 'image_to_image',
  prompt:
    'Redesign this room as a premium modern Japanese-inspired interior with warm oak, paper lantern lighting, low furniture, and calm editorial styling',
  image_urls: [uploaded.data.url],
  aspect_ratio: '16:9',
  resolution: '1K',
  output_format: 'png',
});

const result = await buble.generations.wait(task.data.id);
console.log(result.data);

Python

from buble_ai import Buble

client = Buble()

uploaded = client.files.upload(
    './room.png',
    file_type='image',
    model='google/nano-banana-pro',
    mode='image_to_image',
)

task = client.generations.create(
    model='google/nano-banana-pro',
    mode='image_to_image',
    prompt='Redesign this room as a premium modern Japanese-inspired interior with warm oak, paper lantern lighting, low furniture, and calm editorial styling',
    image_urls=[uploaded['data']['url']],
    aspect_ratio='16:9',
    resolution='1K',
    output_format='png',
)

result = client.generations.wait(task['data']['id'])
print(result['data'])

Go

package main

import (
    "context"
    "fmt"
    "log"

    buble "github.com/bublehq/sdks/go"
)

func main() {
    ctx := context.Background()
    client := buble.NewClient()

    uploaded, err := client.Files.Upload(
        ctx,
        buble.FileFromPath("./room.png"),
        buble.WithFileType("image"),
        buble.WithUploadModel("google/nano-banana-pro"),
        buble.WithUploadMode("image_to_image"),
    )
    if err != nil {
        log.Fatal(err)
    }

    task, err := client.Generations.Create(ctx, &buble.CreateGenerationRequest{
        Model:     "google/nano-banana-pro",
        Mode:      "image_to_image",
        Prompt:    "Redesign this room as a premium modern Japanese-inspired interior with warm oak, paper lantern lighting, low furniture, and calm editorial styling",
        ImageURLs: []string{uploaded.Data.URL},
        Params: map[string]any{
            "aspect_ratio":  "16:9",
            "resolution":    "1K",
            "output_format": "png",
        },
    })
    if err != nil {
        log.Fatal(err)
    }

    result, err := client.Generations.Wait(ctx, task.Data.ID)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("%+v\n", result.Data)
}

Rust

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

#[tokio::main]
async fn main() -> buble::Result<()> {
    let client = Client::from_env();

    let uploaded = client
        .files()
        .upload(
            FileUpload::from_path("./room.png"),
            UploadOptions::new()
                .file_type("image")
                .model("google/nano-banana-pro")
                .mode("image_to_image"),
        )
        .await?;

    let task = client
        .generations()
        .create(
            CreateGenerationRequest::new("google/nano-banana-pro")
                .mode("image_to_image")
                .prompt("Redesign this room as a premium modern Japanese-inspired interior with warm oak, paper lantern lighting, low furniture, and calm editorial styling")
                .image_urls([uploaded.data.url])
                .param("aspect_ratio", "16:9")?
                .param("resolution", "1K")?
                .param("output_format", "png")?,
        )
        .await?;

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

    println!("{:?}", result.data);
    Ok(())
}

Swift

import Buble

let client = try BubleClient.fromEnvironment()

let uploaded = try await client.files.upload(
    .fromFileURL(URL(fileURLWithPath: "./room.png"), contentType: "image/png"),
    options: UploadOptions(
        fileType: "image",
        model: "google/nano-banana-pro",
        mode: "image_to_image"
    )
)

let task = try await client.generations.create(
    try CreateGenerationRequest(model: "google/nano-banana-pro")
        .mode("image_to_image")
        .prompt("Redesign this room as a premium modern Japanese-inspired interior with warm oak, paper lantern lighting, low furniture, and calm editorial styling")
        .imageURLs([uploaded.data.url.absoluteString])
        .param("aspect_ratio", "16:9")
        .param("resolution", "1K")
        .param("output_format", "png")
)

let result = try await client.generations.wait(task.data.id)
print(result.data)

Dart / Flutter

import 'package:buble/buble.dart';

Future<void> main() async {
  final client = BubleClient.fromEnvironment();

  final uploaded = await client.files.upload(
    FileUpload.fromPath('./room.png', contentType: 'image/png'),
    options: const UploadOptions(
      fileType: 'image',
      model: 'google/nano-banana-pro',
      mode: 'image_to_image',
    ),
  );

  final task = await client.generations.create(
    CreateGenerationRequest(
      model: 'google/nano-banana-pro',
      mode: 'image_to_image',
      prompt:
          'Redesign this room as a premium modern Japanese-inspired interior with warm oak, paper lantern lighting, low furniture, and calm editorial styling',
      imageUrls: [uploaded.data.url.toString()],
    ).withParams({
      'aspect_ratio': '16:9',
      'resolution': '1K',
      'output_format': 'png',
    }),
  );

  final result = await client.generations.wait(task.data.id);
  print(result.data.raw);
}

Elixir

client = Buble.Client.new!()

{:ok, uploaded} =
  Buble.Files.upload(client, "./room.png", %{
    file_type: "image",
    model: "google/nano-banana-pro",
    mode: "image_to_image"
  })

{:ok, task} =
  Buble.Generations.create(client, %{
    model: "google/nano-banana-pro",
    mode: "image_to_image",
    prompt:
      "Redesign this room as a premium modern Japanese-inspired interior with warm oak, paper lantern lighting, low furniture, and calm editorial styling",
    image_urls: [get_in(uploaded, ["data", "url"])],
    aspect_ratio: "16:9",
    resolution: "1K",
    output_format: "png"
  })

{:ok, result} = Buble.Generations.wait(client, get_in(task, ["data", "id"]))
IO.inspect(result["data"])

Java

import ai.buble.sdk.BubleClient;
import ai.buble.sdk.Envelope;
import ai.buble.sdk.files.FileUpload;
import ai.buble.sdk.files.UploadOptions;
import ai.buble.sdk.files.UploadedFile;
import ai.buble.sdk.generations.CreateGenerationRequest;
import ai.buble.sdk.generations.GenerationTask;

import java.nio.file.Path;
import java.util.List;

public class Example {
    public static void main(String[] args) {
        BubleClient client = BubleClient.fromEnv();

        Envelope<UploadedFile> uploaded = client.files().upload(
            FileUpload.fromPath(Path.of("./room.png")),
            UploadOptions.builder()
                    .fileType("image")
                    .model("google/nano-banana-pro")
                    .mode("image_to_image")
                    .build()
        );

        Envelope<GenerationTask> task = client.generations().create(
            CreateGenerationRequest.builder()
                    .model("google/nano-banana-pro")
                    .mode("image_to_image")
                    .prompt("Redesign this room as a premium modern Japanese-inspired interior with warm oak, paper lantern lighting, low furniture, and calm editorial styling")
                    .imageUrls(List.of(uploaded.getData().getUrl()))
                    .param("aspect_ratio", "16:9")
                    .param("resolution", "1K")
                    .param("output_format", "png")
                    .build()
        );

        Envelope<GenerationTask> result = client.generations().wait(task.getData().getId());
        System.out.println(result.getData().getStatus());
    }
}

.NET

using Buble.Sdk;
using Buble.Sdk.Files;
using Buble.Sdk.Generations;

var client = BubleClient.FromEnv();

var uploaded = await client.Files.UploadAsync(
    FileUpload.FromPath("./room.png", contentType: "image/png"),
    new UploadOptions
    {
        FileType = "image",
        Model = "google/nano-banana-pro",
        Mode = "image_to_image",
    }
);

var request = new CreateGenerationRequest
{
    Model = "google/nano-banana-pro",
    Mode = "image_to_image",
    Prompt = "Redesign this room as a premium modern Japanese-inspired interior with warm oak, paper lantern lighting, low furniture, and calm editorial styling",
    ImageUrls = new[] { uploaded!.Data!.Url! },
}
.WithParam("aspect_ratio", "16:9")
.WithParam("resolution", "1K")
.WithParam("output_format", "png");

var task = await client.Generations.CreateAsync(request);
var result = await client.Generations.WaitAsync(task!.Data!.Id!);
Console.WriteLine(result.Data.Status);

PHP

<?php

use Buble\BubleClient;
use Buble\Files\FileUpload;
use Buble\Files\UploadOptions;
use Buble\Generations\CreateGenerationRequest;

$client = BubleClient::fromEnv();

$uploaded = $client->files()->upload(
    FileUpload::fromPath('./room.png', 'image/png'),
    new UploadOptions(
        fileType: 'image',
        model: 'google/nano-banana-pro',
        mode: 'image_to_image',
    ),
);

$request = new CreateGenerationRequest(
    model: 'google/nano-banana-pro',
    mode: 'image_to_image',
    prompt: 'Redesign this room as a premium modern Japanese-inspired interior with warm oak, paper lantern lighting, low furniture, and calm editorial styling',
    imageUrls: [$uploaded['data']['url']],
);

$task = $client->generations()->create(
    $request
        ->withParam('aspect_ratio', '16:9')
        ->withParam('resolution', '1K')
        ->withParam('output_format', 'png')
);

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

Ruby

require 'buble'

client = Buble::Client.new

uploaded = client.files.upload(
  './room.png',
  file_type: 'image',
  model: 'google/nano-banana-pro',
  mode: 'image_to_image'
)

task = client.generations.create(
  model: 'google/nano-banana-pro',
  mode: 'image_to_image',
  prompt: 'Redesign this room as a premium modern Japanese-inspired interior with warm oak, paper lantern lighting, low furniture, and calm editorial styling',
  image_urls: [uploaded['data']['url']],
  aspect_ratio: '16:9',
  resolution: '1K',
  output_format: 'png'
)

result = client.generations.wait(task['data']['id'])
puts result['data']