#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Nano Banana (Gemini) Image Generation - Python Version
Supports non-streaming output and auto-saves base64 images locally
"""
import requests
import json
import base64
import re
import os
import datetime
from typing import Optional, Tuple
class GeminiImageGenerator:
def __init__(self, api_key: str, api_url: str = "https://api.yelinai.com/v1/chat/completions"):
"""
Initialize Gemini image generator
Args:
api_key: API key (pay-per-use type)
api_url: API endpoint
"""
self.api_key = api_key
self.api_url = api_url
self.headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}"
}
def generate_image(self, prompt: str, model: str = "gemini-2.5-flash-image-preview",
output_dir: str = ".") -> Tuple[bool, str]:
"""
Generate image and save locally
Args:
prompt: Image description prompt
model: Model to use
output_dir: Output directory
Returns:
Tuple[success status, result message]
"""
print("🚀 Starting image generation...")
print(f"Prompt: {prompt}")
print(f"Model: {model}")
# Generate filename
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
output_file = os.path.join(output_dir, f"gemini_generated_{timestamp}.png")
try:
# Prepare request data
payload = {
"model": model,
"stream": False,
"messages": [
{
"role": "user",
"content": prompt
}
]
}
print("📡 Sending API request...")
# Send non-streaming request
response = requests.post(
self.api_url,
headers=self.headers,
json=payload,
timeout=300
)
if response.status_code != 200:
error_msg = f"API request failed, status code: {response.status_code}"
try:
error_detail = response.json()
error_msg += f", error details: {error_detail}"
except:
error_msg += f", response content: {response.text[:500]}"
return False, error_msg
print("✅ API request successful, parsing response...")
# Parse JSON response
try:
result = response.json()
print("✅ Successfully parsed JSON response")
except json.JSONDecodeError as e:
return False, f"JSON parse failed: {str(e)}"
# Extract message content
full_content = ""
if "choices" in result and len(result["choices"]) > 0:
choice = result["choices"][0]
if "message" in choice and "content" in choice["message"]:
full_content = choice["message"]["content"]
if not full_content:
return False, "Message content not found"
print(f"📝 Got message content, length: {len(full_content)} characters")
print("🔍 Parsing image data...")
# Extract and save images
success, message = self._extract_and_save_images(full_content, output_file)
if success:
return True, message
else:
return False, f"Image save failed: {message}"
except requests.exceptions.Timeout:
return False, "Request timeout (300 seconds)"
except requests.exceptions.ConnectionError as e:
return False, f"Connection error: {str(e)}"
except Exception as e:
return False, f"Unknown error: {str(e)}"
def _extract_and_save_images(self, content: str, base_output_file: str) -> Tuple[bool, str]:
"""
Efficiently extract and save base64 image data
Args:
content: Content containing image data
base_output_file: Base output file path
Returns:
Tuple[success status, result message]
"""
try:
print(f"📄 Content preview (first 200 chars): {content[:200]}")
# Use precise regex to extract base64 image data
base64_pattern = r'data:image/([^;]+);base64,([A-Za-z0-9+/=]+)'
match = re.search(base64_pattern, content)
if not match:
print('⚠️ base64 image data not found')
return False, "Response does not contain base64 image data"
image_format = match.group(1) # png, jpg, etc.
b64_data = match.group(2)
print(f'🎨 Image format: {image_format}')
print(f'📏 Base64 data length: {len(b64_data)} characters')
# Decode and save image
image_data = base64.b64decode(b64_data)
if len(image_data) < 100:
return False, "Decoded image data too small, possibly invalid"
# Set file extension based on detected format
output_file = base_output_file.replace('.png', f'.{image_format}')
os.makedirs(os.path.dirname(output_file) if os.path.dirname(output_file) else ".", exist_ok=True)
with open(output_file, 'wb') as f:
f.write(image_data)
print(f'🖼️ Image saved successfully: {output_file}')
print(f'📊 File size: {len(image_data)} bytes')
return True, f"Image saved successfully: {output_file}"
except Exception as e:
return False, f"Error processing image: {str(e)}"
def main():
"""
Main function example
"""
# Configuration parameters
API_KEY = "sk-YOUR_API_KEY" # Replace with your actual API key (pay-per-use type)
PROMPT = "A cute cat playing in a garden with bright sunshine and blooming flowers"
print("="*60)
print("Nano Banana (Gemini) Image Generator")
print("="*60)
print(f"Start time: {datetime.datetime.now()}")
# Create generator instance
generator = GeminiImageGenerator(API_KEY)
# Generate image
success, message = generator.generate_image(PROMPT)
print("\n" + "="*60)
if success:
print("🎉 Execution successful!")
print(f"✅ {message}")
else:
print("❌ Execution failed!")
print(f"💥 {message}")
print(f"End time: {datetime.datetime.now()}")
print("="*60)
if __name__ == "__main__":
main()