nano-banana / app.py
Tonic's picture
Solves 500 error for some users
acde31d verified
raw
history blame
5.21 kB
import gradio as gr
import requests
import os
import base64
import json
from io import BytesIO
from PIL import Image
# --- Configuration ---
# Your Hugging Face Space URL. Set this in your Space secrets for best practice.
YOUR_SITE_URL = os.environ.get("YOUR_SITE_URL", "https://huggingface.co/spaces/broadfield-dev/nano-banana")
YOUR_SITE_NAME = "Gemini 2.5 Image Editor Demo"
# Fallback API key from Hugging Face secrets
FALLBACK_API_KEY = os.environ.get("OPENROUTER_API_KEY")
def edit_image(image, prompt, api_key):
"""
Sends an image and a prompt to the OpenRouter API and returns the edited image.
"""
final_api_key = api_key if api_key else FALLBACK_API_KEY
if not final_api_key:
raise gr.Error("API Key is required. Please enter your OpenRouter API key or set it in the Space secrets.")
if image is None:
raise gr.Error("An input image is required. Please upload an image.")
# Convert the input PIL image to a base64 string
buffered = BytesIO()
image.save(buffered, format="PNG")
img_base64 = base64.b64encode(buffered.getvalue()).decode("utf-8")
headers = {
"Authorization": f"Bearer {final_api_key}",
"Content-Type": "application/json",
"HTTP-Referer": YOUR_SITE_URL,
"X-Title": YOUR_SITE_NAME,
}
payload = {
# *** CORRECTED MODEL NAME ***
"model": "google/gemini-2.5-flash-image-preview:free",
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": prompt},
{
"type": "image_url",
"image_url": {"url": f"data:image/png;base64,{img_base64}"},
},
],
}
],
"max_tokens": 2048,
}
try:
response = requests.post(
"https://openrouter.ai/api/v1/chat/completions",
headers=headers,
data=json.dumps(payload)
)
response.raise_for_status()
result_data = response.json()
# --- *** CORRECTED RESPONSE PARSING LOGIC *** ---
# The image is in the 'images' list within the message, not 'content'.
message = result_data.get('choices', [{}])[0].get('message', {})
if message and 'images' in message and message['images']:
# Get the first image from the 'images' list
image_data = message['images'][0]
base64_string = image_data.get('image_url', {}).get('url', '')
if base64_string and ',' in base64_string:
# Remove the "data:image/png;base64," prefix
base64_content = base64_string.split(',')[1]
# Decode the base64 string and create a PIL image
img_bytes = base64.b64decode(base64_content)
edited_image = Image.open(BytesIO(img_bytes))
return edited_image
else:
raise gr.Error(f"API returned an invalid image format. Response: {json.dumps(result_data, indent=2)}")
else:
raise gr.Error(f"API did not return an image. Full Response: {json.dumps(result_data, indent=2)}")
except requests.exceptions.HTTPError as err:
error_body = err.response.text
if err.response.status_code == 401:
raise gr.Error("Authentication failed. Check your OpenRouter API key.")
elif err.response.status_code == 429:
raise gr.Error("Rate limit exceeded or insufficient credits. Check your OpenRouter account.")
else:
raise gr.Error(f"An API error occurred: {error_body}")
except Exception as e:
# Catch any other unexpected errors, like JSON parsing failures
raise gr.Error(f"An unexpected error occurred: {str(e)}")
# --- Gradio Interface ---
with gr.Blocks(theme=gr.themes.Soft()) as iface:
gr.Markdown(
"""
# Image Editing with Google Gemini 2.5 Flash via OpenRouter
OpenRouter API key included, but may run out of free inference, so you can use your own key.
Try the chatbot version here (BYOK)
[https://huggingface.co/spaces/broadfield-dev/nano-banana-chat](https://huggingface.co/spaces/broadfield-dev/nano-banana-chat)
Upload an image, describe the edit you want.
"""
)
with gr.Row():
with gr.Column(scale=1):
image_input = gr.Image(type="pil", label="Upload Image")
prompt_input = gr.Textbox(label="Prompt", placeholder="e.g., 'make the background black and white' or 'add sunglasses to the person'")
api_key_input = gr.Textbox(
label="OpenRouter API Key (optional)",
placeholder="Enter your key here (uses Space secret as fallback)",
type="password"
)
submit_button = gr.Button("Generate Image", variant="primary")
with gr.Column(scale=1):
image_output = gr.Image(label="Edited Image")
submit_button.click(
fn=edit_image,
inputs=[image_input, prompt_input, api_key_input],
outputs=image_output
)
iface.launch(ssr_mode=False)