7 models 廊 gallery 订 pricing API docs
Guide

SillyTavern image generation with Nano Banana & GPT Image

Use Nano Banana Pro, Nano Banana 2 or GPT Image 2 / 2.5 for SillyTavern's Image Generation extension at about $0.037 per image, through a small local adapter.

How it works

SillyTavern has no built-in VELIN source, and you cannot plug VELIN in by pasting a key. VELIN is its own async REST API, not a Stable Diffusion server. The workaround is a tiny local adapter (about 80 lines of Node, no dependencies) that pretends to be a Stable Diffusion WebUI backend. SillyTavern talks to the adapter on 127.0.0.1:7861; the adapter calls VELIN, polls until the image is ready and returns it as base64.

Setup

  1. Get an API key: sign in at 72agi.com, open My account and copy the key. Top up on the billing page (USDT; card payments coming soon), or ask for a free test on Telegram.
  2. Install Node 18 or newer and download the adapter: velin-sd-adapter.mjs (or copy it from below).
  3. Run it: export VELIN_API_KEY=your_key then node velin-sd-adapter.mjs. It prints VELIN adapter on http://127.0.0.1:7861.
  4. In SillyTavern open Extensions → Image Generation. Set Source to Stable Diffusion Web UI (AUTOMATIC1111) and the URL to http://127.0.0.1:7861, then press Connect.
  5. Choose a model from the model dropdown (the adapter lists gpt-image-2.5-flare, gpt-image-2.5-sunburst, gpt-image-2, nano-banana-2 and nano-banana-pro). Generate an image from the chat as usual.

Adapter code

Save as velin-sd-adapter.mjs. It maps the width and height SillyTavern sends to the nearest VELIN aspect ratio, always requests 1K (the price is the same at any resolution, so change resolution if you want more), and ignores sampler, steps and other Stable Diffusion settings, which do not apply.

#!/usr/bin/env node
// Minimal "Stable Diffusion WebUI"-style adapter for SillyTavern -> VELIN.
// Node 18+, no dependencies.
//   export VELIN_API_KEY=your_key
//   node velin-sd-adapter.mjs            # listens on http://127.0.0.1:7861
import http from "node:http";

const BASE = process.env.VELIN_BASE_URL || "https://72agi.com";
const KEY = process.env.VELIN_API_KEY;
const PORT = Number(process.env.PORT || 7861);
if (!KEY) { console.error("Set VELIN_API_KEY first"); process.exit(1); }

const auth = { Authorization: `Bearer ${KEY}` };
const MODELS = ["gpt-image-2.5-flare", "gpt-image-2.5-sunburst", "gpt-image-2",
                "nano-banana-2", "nano-banana-pro"];
let model = MODELS[0];
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

// width x height -> nearest supported VELIN aspect ratio
const RATIOS = { "1:1": 1, "16:9": 16 / 9, "9:16": 9 / 16, "4:3": 4 / 3, "3:4": 3 / 4, "3:2": 1.5, "2:3": 2 / 3 };
function nearestRatio(w, h) {
  const r = w / h;
  return Object.entries(RATIOS).sort((a, b) => Math.abs(a[1] - r) - Math.abs(b[1] - r))[0][0];
}

async function generate(prompt, w, h) {
  const form = new FormData();
  form.set("prompt", prompt);
  form.set("model", model);
  form.set("size", nearestRatio(w, h));
  form.set("resolution", "1K");
  const res = await fetch(`${BASE}/api/generate`, { method: "POST", headers: auth, body: form });
  const body = await res.json().catch(() => ({}));
  if (!res.ok) throw new Error(`submit HTTP ${res.status}: ${body.error ?? ""}`);
  for (let i = 0; i < 180; i++) {            // poll every 5 s, up to 15 min
    await sleep(5000);
    const job = await (await fetch(`${BASE}/api/task/${body.id}`, { headers: auth })).json();
    if (job.status === "succeeded") {
      const img = await fetch(BASE + job.url, { headers: auth });
      return Buffer.from(await img.arrayBuffer()).toString("base64");
    }
    if (job.status === "failed") throw new Error(`failed (not charged): ${job.error}`);
  }
  throw new Error("timed out");
}

const json = (res, code, obj) => {
  res.writeHead(code, { "Content-Type": "application/json" });
  res.end(JSON.stringify(obj));
};

http.createServer(async (req, res) => {
  const path = new URL(req.url, "http://x").pathname;
  let raw = "";
  for await (const c of req) raw += c;
  const body = raw ? JSON.parse(raw) : {};
  try {
    if (path === "/sdapi/v1/options" && req.method === "POST") {
      if (MODELS.includes(body.sd_model_checkpoint)) model = body.sd_model_checkpoint;
      return json(res, 200, {});
    }
    if (path === "/sdapi/v1/options") return json(res, 200, { sd_model_checkpoint: model });
    if (path === "/sdapi/v1/sd-models") return json(res, 200, MODELS.map((m) => ({ title: m, model_name: m })));
    if (path === "/sdapi/v1/samplers") return json(res, 200, [{ name: "Euler" }]);
    if (path === "/sdapi/v1/schedulers") return json(res, 200, [{ name: "Automatic" }]);
    if (path === "/sdapi/v1/upscalers") return json(res, 200, [{ name: "None" }]);
    if (path === "/sdapi/v1/latent-upscale-modes") return json(res, 200, []);
    if (path === "/sdapi/v1/sd-vae" || path === "/sdapi/v1/sd-modules") return json(res, 200, []);
    if (path === "/sdapi/v1/progress") return json(res, 200, { progress: 0, state: { job_count: 0 } });
    if (path === "/sdapi/v1/interrupt") return json(res, 200, {});
    if (path === "/sdapi/v1/txt2img" && req.method === "POST") {
      const b64 = await generate(body.prompt, body.width || 1024, body.height || 1024);
      return json(res, 200, { images: [b64], parameters: {}, info: "{}" });
    }
    json(res, 404, { error: "not found" });
  } catch (e) {
    console.error(e.message);
    json(res, 500, { error: e.message });
  }
}).listen(PORT, "127.0.0.1", () => console.log(`VELIN adapter on http://127.0.0.1:${PORT}`));

Notes

FAQ

Does SillyTavern have a built-in VELIN option?

No. SillyTavern's Image Generation extension talks to a fixed list of providers, and VELIN is not one of them. The adapter on this page makes VELIN look like a Stable Diffusion WebUI server, which SillyTavern already supports.

Why is an adapter needed?

VELIN is asynchronous (submit a task, poll for the result), returns a URL path rather than base64, and sends no CORS headers. The adapter runs on your machine, does the polling and hands SillyTavern a base64 image.

Is my key safe?

The key stays in the adapter's environment variable on your own machine. Do not put it in a character card, preset or shared SillyTavern config. The key also signs in to your account, so treat it like a password.

How long does an image take?

Typically about 45 to 100 seconds depending on the model; 4K and many reference images take longer. The API is asynchronous: submit a task, then poll for the result.

Do I pay for failed generations?

No. Credits are reserved when you submit a task and refunded automatically if it fails.

How do I pay?

Top up with USDT on the billing page; the balance is credited automatically. Card payments are coming soon.

Can I get a free test?

Free tests are available on request: message @ayan8866e on Telegram. There are no automatic free credits.

Get started

  1. Sign in at 72agi.com and copy your API key from My account.
  2. Top up with USDT on the billing page (card payments are coming soon).
  3. Call the API. Full reference: API docs. Ready-made examples: GitHub kit.

Want a free test, higher rate limits or volume pricing? Message @ayan8866e on Telegram. Free tests are on request; there are no automatic free credits.

Ask for a free test on Telegram→ Read the API docs→

More guides

Nano Banana and Gemini are trademarks of Google. GPT Image is a trademark of OpenAI. VELIN is an independent service and is not affiliated with or endorsed by either company. Competitor prices are quoted from the linked public pages on the date shown and may change.