Nano Banana Series
Model Introduction
Google's Nano Banana series is the internal codename for its image generation technology, currently offering three generations of models:
gemini-2.5-flash-image(Nano Banana)gemini-3-pro-image-preview(Nano Banana Pro)gemini-3.1-flash-image-preview(Nano Banana 2)
🆕 Nano Banana 2 (Newest)
- Model Name:
gemini-3.1-flash-image-preview - Version: Preview
- Technical Base: Based on Gemini 3 architecture, featuring stronger reasoning capabilities
- Features: Latest technology, superior image quality and detail representation
- Resolution Support: Supports 512, 1K, 2K, 4K
- Scenarios: Users pursuing best effects, requiring high resolution, and willing to try new features
Endpoint Migration Notice
Note
Preview image generation endpoints will be removed on July 17. The platform will redirect requests that still use preview endpoints to the model endpoints to keep your service uninterrupted. We still recommend updating to the model endpoints before July 17, 2026 to avoid future service impact.
| Preview Endpoint | Model Endpoint |
|---|---|
gemini-3.1-flash-image-preview | gemini-3.1-flash-image |
gemini-3-pro-image-preview | gemini-3-pro-image |
Calling Method: Google Native Format
💡 Model Switching Instructions
In Google Native Format, the model name is specified in the URL path:
Nano Banana 2 (New): /v1beta/models/gemini-3.1-flash-image-preview:generateContent
Nano Banana Pro: /v1beta/models/gemini-3-pro-image-preview:generateContent
Nano Banana: /v1beta/models/gemini-2.5-flash-image:generateContent
Supported Aspect Ratios
| Type | Aspect Ratio Options |
|---|---|
| Landscape | 21:9 (Ultra Wide), 16:9 (Wide), 4:3, 3:2 |
| Square | 1:1 |
| Portrait | 9:16 (Vertical), 3:4, 2:3 |
| Other | 5:4, 4:5 |
Supported Resolutions
ℹ️ Resolution Support Guide
- Nano Banana 2 (
gemini-3.1-flash-image-preview): Supports 512, 1K, 2K, 4K. - Nano Banana Pro (
gemini-3-pro-image-preview): Supports 1K, 2K, 4K. - Nano Banana (
gemini-2.5-flash-image): Fixed at 1K (1024px), does not supportimageSizeparameter.
Nano Banana 2 Resolution Options
| Aspect Ratio | 512 Resolution | 1K Resolution | 2K Resolution | 4K Resolution |
|---|---|---|---|---|
| 1:1 | 512×512 | 1024×1024 | 2048×2048 | 4096×4096 |
| 16:9 | 688×384 | 1376×768 | 2752×1536 | 5504×3072 |
| 9:16 | 384×688 | 768×1376 | 1536×2752 | 3072×5504 |
| 4:3 | 600×448 | 1200×896 | 2400×1792 | 4800×3584 |
| 3:4 | 448×600 | 896×1200 | 1792×2400 | 3584×4800 |
| 21:9 | 792×336 | 1584×672 | 3168×1344 | 6336×2688 |
| 3:2 | 624×416 | 1248×832 | 2496×1664 | 4992×3328 |
| 2:3 | 416×624 | 832×1248 | 1664×2496 | 3328×4992 |
| 5:4 | 576×448 | 1152×896 | 2304×1792 | 4608×3584 |
| 4:5 | 448×576 | 896×1152 | 1792×2304 | 3584×4608 |
💡 Resolution Selection Advice
- 1K: Suitable for web display, social media, quick preview.
- 2K: Suitable for high-quality printing, professional display.
- 4K: Suitable for large format printing, professional design, extreme detail.
Code Examples
Full Curl Example (Nano Banana 2 - 4K)
#!/bin/bash
# 1. Set API Key
export API_KEY="sk-xxxx"
# 2. Send request
curl -s -X POST "https://api.exchangetoken.ai/v1beta/models/gemini-3.1-flash-image-preview:generateContent" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{
"text": "A futuristic city skyline at sunset, high detailed, 4k"
}
]
}
],
"generationConfig": {
"responseModalities": ["IMAGE"]
}
}' \
| jq -r '.candidates[0].content.parts[0].inlineData.data' \
| base64 --decode > output_4k.png
echo "✅ Image saved: output_4k.png"Quick Start Curl Example (Nano Banana 1K)
For reference, here is the calling method for Nano Banana.
# Use Nano Banana (1K)
curl -s -X POST "https://api.exchangetoken.ai/v1beta/models/gemini-2.5-flash-image:generateContent" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [{
"role": "user",
"parts": [{"text": "a beautiful sunset over mountains"}]
}],
"generationConfig": {
"responseModalities": ["IMAGE"],
"imageConfig": {"aspectRatio": "16:9"}
}
}' | jq -r '.candidates[0].content.parts[0].inlineData.data' | base64 --decode > output.pngMore Code Scenarios
The following are advanced examples covering single image editing, multi-image synthesis, smart editing, and Base64 data processing.
1. Single Image Edit Example (Python)
Perform an edit operation on a single image.
import requests
import json
import base64
from Base64ImageHandler import Base64ImageHandler
def get_image_base64(url):
"""
[Critical Step]
The native Gemini interface does not support passing URLs directly;
the image must be downloaded and converted to Base64 encoding.
"""
print(f"[LOG] Downloading image to adapt to native interface: {url}")
try:
headers = {'User-Agent': 'Mozilla/5.0'}
response = requests.get(url, headers=headers, timeout=30)
if response.status_code == 200:
# Get content-type, default is image/png
mime_type = response.headers.get('Content-Type', 'image/png')
# Convert to base64 string
b64_data = base64.b64encode(response.content).decode('utf-8')
print(f"[LOG] Image download successful, format: {mime_type}, data length: {len(b64_data)}")
return mime_type, b64_data
else:
print(f"[ERROR] Image download failed, status code: {response.status_code}")
return None, None
except Exception as e:
print(f"[ERROR] Image download exception: {e}")
return None, None
def creative_merge(image_urls, merge_instruction):
print("=" * 50)
print("Starting image merge request processing (Gemini native protocol)")
print("=" * 50)
# 1. Prepare request content parts
parts = []
# Add text instruction
parts.append({
"text": merge_instruction + "\n\nPlease generate the image directly and return it in Base64 format."
})
# 2. Process images: Download and convert to inline_data format
if image_urls:
print(f"[LOG] Number of image URLs: {len(image_urls)}")
for i, url in enumerate(image_urls, 1):
mime_type, image_b64 = get_image_base64(url)
if image_b64:
parts.append({
"inline_data": {
"mime_type": mime_type,
"data": image_b64
}
})
# 3. Construct Gemini native Payload (contents structure)
# Structure: contents -> parts -> [text, inline_data]
data = {
"contents": [
{
"role": "user",
"parts": parts
}
],
"generationConfig": {
"temperature": 0.5,
"maxOutputTokens": 4096
}
}
# 4. Set native interface URL
# Note: Using the :generateContent interface here
api_endpoint = "https://api.exchangetoken.ai/v1beta/models/gemini-3.1-flash-image-preview:generateContent"
headers = {
"Authorization": f"Bearer sk-xxxxx",
"Content-Type": "application/json"
}
print(f"\n[LOG] Request URL: {api_endpoint}")
print(f"[LOG] Sending request...")
try:
response = requests.post(api_endpoint, headers=headers, json=data)
print(f"[LOG] HTTP Status Code: {response.status_code}")
# print(f"[LOG] Response Headers: {dict(response.headers)}")
if response.status_code != 200:
print(f"[ERROR] API request failed")
print(f"[ERROR] Response content: {response.text}")
return None, None
response_json = response.json()
print(f"\n[LOG] API call successful, starting to parse native response...")
# 5. Parse Gemini native response structure
# Successful response is usually in candidates[0].content.parts[0].text
response_str = json.dumps(response_json, ensure_ascii=False)
# Attempt to print response text
try:
candidates = response_json.get('candidates', [])
if candidates:
content = candidates[0].get('content', {})
res_parts = content.get('parts', [])
if res_parts and 'text' in res_parts[0]:
print(f"[LOG] Model response text snippet: {res_parts[0]['text'][:200]}...")
except Exception as e:
print(f"[WARNING] Simple text parsing failed: {e}")
# Use utility class to search for Base64 in the entire response string
result = Base64ImageHandler.extract_from_response(response_str)
if result and result[0]:
print(f"[LOG] Successfully extracted image data, length: {len(result[0])}")
else:
print(f"[WARNING] Failed to extract base64 data, please check model response content.")
return result
except requests.exceptions.RequestException as e:
print(f"[ERROR] Request exception: {e}")
return None, None
except Exception as e:
print(f"[ERROR] Unknown error: {e}")
import traceback
traceback.print_exc()
return None, None
if __name__ == "__main__":
images = [
"https://your_image.png",
]
# Prompt: Image-to-Text-to-Image technique for multimodal models
prompt = (
"You are an image editing assistant. Please modify the person in the image to wear a stylish hat.\n"
"[Key]: Please output the modified image data directly, do not just output a description.\n"
"If you can generate the image directly, please return the image.\n"
"If you can only return text, please encode the resulting image as a Base64 string and return it in JSON format,"
"for example: {\"image_base64\": \"...\"}."
)
result = creative_merge(images, prompt)
print("\n" + "=" * 50)
print("Save Image Result")
print("=" * 50)
if result and result[0]:
base64_data, image_format = result
print(f"[LOG] Preparing to save image, format: {image_format}")
saved_filename = Base64ImageHandler.save_to_file(base64_data)
print(f"[SUCCESS] Image saved as: {saved_filename}")
else:
print("[ERROR] Process ended, image not saved.")2. Multi-Image Synthesis - Creative Merge (Python)
Take multiple images as input and perform creative fusion through Prompt instructions.
import requests
import json
import base64
from Base64ImageHandler import Base64ImageHandler
def get_image_base64(url):
"""
[Critical Step]
The native Gemini interface does not support passing URLs directly;
the image must be downloaded and converted to Base64 encoding.
"""
print(f"[LOG] Downloading image to adapt to native interface: {url}")
try:
headers = {'User-Agent': 'Mozilla/5.0'}
response = requests.get(url, headers=headers, timeout=30)
if response.status_code == 200:
# Get content-type, default is image/png
mime_type = response.headers.get('Content-Type', 'image/png')
# Convert to base64 string
b64_data = base64.b64encode(response.content).decode('utf-8')
print(f"[LOG] Image download successful, format: {mime_type}, data length: {len(b64_data)}")
return mime_type, b64_data
else:
print(f"[ERROR] Image download failed, status code: {response.status_code}")
return None, None
except Exception as e:
print(f"[ERROR] Image download exception: {e}")
return None, None
def creative_merge(image_urls, merge_instruction):
print("=" * 50)
print("Starting image merge request processing (Gemini native protocol)")
print("=" * 50)
# 1. Prepare request content parts
parts = []
# Add text instruction
parts.append({
"text": merge_instruction + "\n\nPlease generate the image directly and return it in Base64 format."
})
# 2. Process images: Download and convert to inline_data format
if image_urls:
print(f"[LOG] Number of image URLs: {len(image_urls)}")
for i, url in enumerate(image_urls, 1):
mime_type, image_b64 = get_image_base64(url)
if image_b64:
parts.append({
"inline_data": {
"mime_type": mime_type,
"data": image_b64
}
})
# 3. Construct Gemini native Payload (contents structure)
# Structure: contents -> parts -> [text, inline_data]
data = {
"contents": [
{
"role": "user",
"parts": parts
}
],
"generationConfig": {
"temperature": 0.5,
"maxOutputTokens": 4096
}
}
# 4. Set native interface URL
# Note: Using the :generateContent interface here
api_endpoint = "https://api.exchangetoken.ai/v1beta/models/gemini-3.1-flash-image-preview:generateContent"
headers = {
"Authorization": f"Bearer sk-xxxxx",
"Content-Type": "application/json"
}
print(f"\n[LOG] Request URL: {api_endpoint}")
print(f"[LOG] Sending request...")
try:
response = requests.post(api_endpoint, headers=headers, json=data)
print(f"[LOG] HTTP Status Code: {response.status_code}")
# print(f"[LOG] Response Headers: {dict(response.headers)}")
if response.status_code != 200:
print(f"[ERROR] API request failed")
print(f"[ERROR] Response content: {response.text}")
return None, None
response_json = response.json()
print(f"\n[LOG] API call successful, starting to parse native response...")
# 5. Parse Gemini native response structure
# Successful response is usually in candidates[0].content.parts[0].text
response_str = json.dumps(response_json, ensure_ascii=False)
# Attempt to print response text
try:
candidates = response_json.get('candidates', [])
if candidates:
content = candidates[0].get('content', {})
res_parts = content.get('parts', [])
if res_parts and 'text' in res_parts[0]:
print(f"[LOG] Model response text snippet: {res_parts[0]['text'][:200]}...")
except Exception as e:
print(f"[WARNING] Simple text parsing failed: {e}")
# Use utility class to search for Base64 in the entire response string
result = Base64ImageHandler.extract_from_response(response_str)
if result and result[0]:
print(f"[LOG] Successfully extracted image data, length: {len(result[0])}")
else:
print(f"[WARNING] Failed to extract base64 data, please check model response content.")
return result
except requests.exceptions.RequestException as e:
print(f"[ERROR] Request exception: {e}")
return None, None
except Exception as e:
print(f"[ERROR] Unknown error: {e}")
import traceback
traceback.print_exc()
return None, None
if __name__ == "__main__":
images = [
"https://image_one.png",
"https://image_two.png"
]
# Example Prompt: Image-to-Text-to-Image technique for multimodal models
prompt = (
"You are an image editing assistant. Please add a stylish hat to the person in the first image. "
"Also, place the gold necklace from the second image onto the person in the first image.\n"
"[Key]: Please output the modified image data directly, do not just output a description.\n"
"If you can generate the image directly, please return the image.\n"
"If you can only return text, please encode the resulting image as a Base64 string and return it in JSON format,"
"for example: {\"image_base64\": \"...\"}."
)
result = creative_merge(images, prompt)
print("\n" + "=" * 50)
print("Save Image Result")
print("=" * 50)
if result and result[0]:
base64_data, image_format = result
print(f"[LOG] Preparing to save image, format: {image_format}")
saved_filename = Base64ImageHandler.save_to_file(base64_data)
print(f"[SUCCESS] Image saved as: {saved_filename}")
else:
print("[ERROR] Process ended, image not saved.")3. Smart Multi-Image Processing Strategy (Python)
Automatically adjust Prompt strategy based on the number of input images to implement single-image editing or multi-image synthesis.
def smart_multi_image_edit(images, instruction):
"""Smart multi-image editing, automatically handles different numbers of images"""
if len(images) == 1:
# Single image editing
prompt = f"Edit this image: {instruction}"
elif len(images) == 2:
# Two-image synthesis
prompt = f"Combine these two images creatively: {instruction}"
else:
# Multi-image processing
prompt = f"Process these {len(images)} images together: {instruction}"
# Build content
content = [{"type": "text", "text": prompt}]
for img in images:
content.append({
"type": "image_url",
"image_url": {"url": img}
})
# Send request...
return send_edit_request(content)4. Base64 Data Processing Utilities (Python)
Utilities for processing Base64 image data returned by the API, supporting extraction, saving, and PIL format conversion.
import base64
import io
import re
from datetime import datetime
from PIL import Image
class Base64ImageHandler:
"""Base64 Image Handler Class"""
@staticmethod
def extract_from_response(response_content):
"""Extract base64 data from API response"""
patterns = [
r'data:image/([^;]+);base64,([A-Za-z0-9+/=]+)',
r'([A-Za-z0-9+/=]{100,})'
]
for pattern in patterns:
match = re.search(pattern, response_content)
if match:
if len(match.groups()) == 2:
return match.group(2), match.group(1) # data, format
else:
return match.group(1), 'png' # default to png
return None, None
@staticmethod
def save_to_file(base64_data, filename=None):
"""Save base64 data as file"""
if not filename:
filename = f"image_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
image_data = base64.b64decode(base64_data)
with open(filename, 'wb') as f:
f.write(image_data)
return filename
@staticmethod
def to_pil_image(base64_data):
"""Convert to PIL Image object"""
image_data = base64.b64decode(base64_data)
return Image.open(io.BytesIO(image_data))
@staticmethod
def from_pil_image(pil_image, format='PNG'):
"""Convert from PIL Image to base64"""
buffer = io.BytesIO()
pil_image.save(buffer, format=format)
img_str = base64.b64encode(buffer.getvalue()).decode()
return f"data:image/{format.lower()};base64,{img_str}"