Skip to content

异步请求模式

mode 设为 "async" 时,服务器立即返回生成任务 ID,并在后台处理。客户端通过轮询查询结果。适合批量调用或对响应时间敏感的场景。

工作流程

客户端                            服务器
  │                                 │
  │─── POST /generate (async) ────►│
  │                                 │  立即返回 generationId
  │◄── 200 { generationId } ───────│
  │                                 │  后台生成中...
  │─── GET /generate?id=xxx ──────►│
  │◄── { status: "processing" } ───│
  │                                 │
  │─── GET /generate?id=xxx ──────►│
  │◄── { status: "processing" } ───│
  │                                 │  生成完成
  │─── GET /generate?id=xxx ──────►│
  │◄── { status: "completed" } ────│
  │    { outputImageUrls: [...] }   │

请求示例

1. 提交生成任务

sh
curl -X POST https://www.nananobanana.com/api/v1/generate \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer nb_your_api_key_here" \
  -d '{
    "prompt": "水墨画风格的山水风景",
    "selectedModel": "nano-banana",
    "mode": "async"
  }'

2. 轮询查询结果

sh
curl https://www.nananobanana.com/api/v1/generate?id=YOUR_GENERATION_ID \
  -H "Authorization: Bearer nb_your_api_key_here"

响应格式

提交成功 (200 OK)

json
{
  "success": true,
  "async": true,
  "generationId": "clxx...",
  "message": "Generation started. Use GET /api/v1/generate?id={generationId} to poll for results.",
  "creditsUsed": 1,
  "remainingCredits": 99
}
字段类型说明
successboolean是否提交成功
asyncboolean固定为 true,标识异步模式
generationIdstring生成任务 ID,用于轮询查询
messagestring提示信息
creditsUsednumber本次消耗的积分
remainingCreditsnumber账户剩余积分

轮询响应

轮询 GET /api/v1/generate?id={generationId} 时,根据 processingStatus 判断状态:

生成中:

json
{
  "data": {
    "id": "clxx...",
    "prompt": "水墨画风格的山水风景",
    "outputImageUrls": null,
    "modelUsed": "nano-banana",
    "processingStatus": "processing",
    "creditsUsed": 1,
    "createdAt": "2025-01-01T00:00:00.000Z"
  }
}

生成完成:

json
{
  "data": {
    "id": "clxx...",
    "prompt": "水墨画风格的山水风景",
    "outputImageUrls": ["https://..."],
    "modelUsed": "nano-banana",
    "processingStatus": "completed",
    "creditsUsed": 1,
    "createdAt": "2025-01-01T00:00:00.000Z"
  }
}

生成失败:

json
{
  "data": {
    "id": "clxx...",
    "prompt": "水墨画风格的山水风景",
    "outputImageUrls": null,
    "modelUsed": "nano-banana",
    "processingStatus": "failed",
    "errorMessage": "Generation failed due to server error",
    "creditsUsed": 1,
    "createdAt": "2025-01-01T00:00:00.000Z"
  }
}

服务器繁忙 (503 Service Unavailable)

当并发任务数达到上限时:

json
{
  "error": "Server is busy, too many concurrent tasks. Please retry later.",
  "type": "server_busy",
  "activeTasks": 10
}

WARNING

服务器繁忙时,已扣除的积分将自动退还,无需手动处理。

代码示例

python
import requests
import time

API_KEY = "nb_your_api_key_here"
BASE_URL = "https://www.nananobanana.com/api/v1"
HEADERS = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {API_KEY}"
}

# 异步模式 — 提交任务后轮询结果
response = requests.post(
    f"{BASE_URL}/generate",
    headers=HEADERS,
    json={
        "prompt": "水墨画风格的山水风景",
        "selectedModel": "nano-banana",
        "mode": "async"
    }
)

result = response.json()

# 处理服务器繁忙
if response.status_code == 503:
    print("Server busy, please retry later.")
    exit()

if not result.get("success"):
    print("Submit failed:", result.get("error"))
    exit()

generation_id = result["generationId"]
print(f"Task submitted! ID: {generation_id}")
print(f"Credits used: {result['creditsUsed']}")

# 轮询查询结果
max_retries = 60  # 最多轮询 60 次(3 分钟)
for i in range(max_retries):
    status_response = requests.get(
        f"{BASE_URL}/generate?id={generation_id}",
        headers=HEADERS
    )
    data = status_response.json()["data"]
    
    print(f"[{i+1}/{max_retries}] Status: {data['processingStatus']}")
    
    if data["processingStatus"] == "completed":
        print("✅ Generation complete!")
        print("Image URLs:", data["outputImageUrls"])
        break
    elif data["processingStatus"] == "failed":
        print("❌ Generation failed:", data.get("errorMessage"))
        break
    
    time.sleep(3)  # 每 3 秒轮询一次
else:
    print("⏰ Timeout: generation did not complete in time.")
javascript
const API_KEY = "nb_your_api_key_here";
const BASE_URL = "https://www.nananobanana.com/api/v1";
const HEADERS = {
  "Content-Type": "application/json",
  "Authorization": `Bearer ${API_KEY}`
};

// 异步模式 — 提交任务后轮询结果
async function generateAsync() {
  const response = await fetch(`${BASE_URL}/generate`, {
    method: "POST",
    headers: HEADERS,
    body: JSON.stringify({
      prompt: "水墨画风格的山水风景",
      selectedModel: "nano-banana",
      mode: "async"
    })
  });

  // 处理服务器繁忙
  if (response.status === 503) {
    console.error("Server busy, please retry later.");
    return;
  }

  const result = await response.json();
  if (!result.success) {
    console.error("Submit failed:", result.error);
    return;
  }

  const generationId = result.generationId;
  console.log(`Task submitted! ID: ${generationId}`);
  console.log(`Credits used: ${result.creditsUsed}`);

  // 轮询查询结果
  const maxRetries = 60;
  for (let i = 0; i < maxRetries; i++) {
    const statusRes = await fetch(
      `${BASE_URL}/generate?id=${generationId}`,
      { headers: HEADERS }
    );
    const { data } = await statusRes.json();

    console.log(`[${i + 1}/${maxRetries}] Status: ${data.processingStatus}`);

    if (data.processingStatus === "completed") {
      console.log("✅ Generation complete!");
      console.log("Image URLs:", data.outputImageUrls);
      return;
    } else if (data.processingStatus === "failed") {
      console.error("❌ Generation failed:", data.errorMessage);
      return;
    }

    await new Promise(r => setTimeout(r, 3000)); // 每 3 秒轮询
  }

  console.error("⏰ Timeout: generation did not complete in time.");
}

generateAsync();
python
import requests
import time
from concurrent.futures import ThreadPoolExecutor

API_KEY = "nb_your_api_key_here"
BASE_URL = "https://www.nananobanana.com/api/v1"
HEADERS = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {API_KEY}"
}

prompts = [
    "日出时的富士山",
    "夜晚的巴黎铁塔",
    "秋天的京都街道",
]

# 批量提交任务
task_ids = []
for prompt in prompts:
    response = requests.post(
        f"{BASE_URL}/generate",
        headers=HEADERS,
        json={
            "prompt": prompt,
            "selectedModel": "nano-banana",
            "mode": "async"
        }
    )
    result = response.json()
    if result.get("success"):
        task_ids.append(result["generationId"])
        print(f"✅ Submitted: {prompt[:20]}... -> {result['generationId']}")
    else:
        print(f"❌ Failed: {prompt[:20]}... -> {result.get('error')}")

print(f"\nSubmitted {len(task_ids)} tasks. Polling for results...\n")

# 轮询所有任务
pending = set(task_ids)
results = {}

while pending:
    for task_id in list(pending):
        resp = requests.get(
            f"{BASE_URL}/generate?id={task_id}",
            headers=HEADERS
        )
        data = resp.json()["data"]
        
        if data["processingStatus"] == "completed":
            results[task_id] = data["outputImageUrls"]
            pending.discard(task_id)
            print(f"✅ Completed: {task_id}")
        elif data["processingStatus"] == "failed":
            pending.discard(task_id)
            print(f"❌ Failed: {task_id} - {data.get('errorMessage')}")
    
    if pending:
        print(f"⏳ {len(pending)} tasks still processing...")
        time.sleep(3)

print(f"\nAll done! {len(results)} images generated.")
for task_id, urls in results.items():
    print(f"  {task_id}: {urls}")

适用场景

  • ✅ 批量生成多张图片
  • ✅ 后台任务处理(无需用户等待)
  • ✅ 对 HTTP 响应时间敏感的场景
  • ✅ 需要解耦"提交"和"获取结果"的架构设计

轮询建议

参数建议值说明
轮询间隔3 秒避免过于频繁的请求
最大轮询次数60 次约 3 分钟超时
首次轮询延迟5 秒给服务器足够的启动时间

注意事项

WARNING

  • 积分在提交任务时即扣除,而非生成完成后。
  • 如果服务器繁忙(503),积分会自动退还。
  • 生成失败时积分不会自动退还。
  • 建议设置合理的轮询超时,避免无限等待。

Released under the MIT License.