Spaces:
Running
Running
add nano banana
Browse files
app.py
CHANGED
@@ -2175,46 +2175,41 @@ def generate_image_with_qwen(prompt: str, image_index: int = 0, token: gr.OAuthT
|
|
2175 |
return f"Error generating image: {str(e)}"
|
2176 |
|
2177 |
def generate_image_to_image(input_image_data, prompt: str, token: gr.OAuthToken | None = None) -> str:
|
2178 |
-
"""Generate an image using image-to-image
|
2179 |
|
2180 |
-
|
|
|
|
|
2181 |
"""
|
2182 |
try:
|
2183 |
-
# Check
|
2184 |
-
|
2185 |
-
|
2186 |
-
|
2187 |
-
# Prepare client
|
2188 |
-
client = InferenceClient(
|
2189 |
-
provider="auto",
|
2190 |
-
api_key=os.getenv('HF_TOKEN'),
|
2191 |
-
bill_to="huggingface",
|
2192 |
-
)
|
2193 |
|
2194 |
# Normalize input image to bytes
|
2195 |
import io
|
2196 |
from PIL import Image
|
|
|
|
|
|
|
2197 |
try:
|
2198 |
import numpy as np
|
2199 |
except Exception:
|
2200 |
np = None
|
2201 |
|
2202 |
if hasattr(input_image_data, 'read'):
|
2203 |
-
# File-like object
|
2204 |
raw = input_image_data.read()
|
2205 |
pil_image = Image.open(io.BytesIO(raw))
|
2206 |
elif hasattr(input_image_data, 'mode') and hasattr(input_image_data, 'size'):
|
2207 |
-
# PIL Image
|
2208 |
pil_image = input_image_data
|
2209 |
elif np is not None and isinstance(input_image_data, np.ndarray):
|
2210 |
pil_image = Image.fromarray(input_image_data)
|
2211 |
elif isinstance(input_image_data, (bytes, bytearray)):
|
2212 |
pil_image = Image.open(io.BytesIO(input_image_data))
|
2213 |
else:
|
2214 |
-
# Fallback: try to convert via bytes
|
2215 |
pil_image = Image.open(io.BytesIO(bytes(input_image_data)))
|
2216 |
|
2217 |
-
# Ensure RGB
|
2218 |
if pil_image.mode != 'RGB':
|
2219 |
pil_image = pil_image.convert('RGB')
|
2220 |
|
@@ -2223,34 +2218,84 @@ def generate_image_to_image(input_image_data, prompt: str, token: gr.OAuthToken
|
|
2223 |
if pil_image.width > max_input_size or pil_image.height > max_input_size:
|
2224 |
pil_image.thumbnail((max_input_size, max_input_size), Image.Resampling.LANCZOS)
|
2225 |
|
2226 |
-
|
2227 |
-
|
2228 |
-
|
2229 |
-
|
2230 |
-
|
2231 |
-
image = client.image_to_image(
|
2232 |
-
input_bytes,
|
2233 |
-
prompt=prompt,
|
2234 |
-
model="Qwen/Qwen-Image-Edit",
|
2235 |
-
)
|
2236 |
-
|
2237 |
-
# Resize/optimize (larger since not using data URIs)
|
2238 |
-
max_size = 1024
|
2239 |
-
if image.width > max_size or image.height > max_size:
|
2240 |
-
image.thumbnail((max_size, max_size), Image.Resampling.LANCZOS)
|
2241 |
|
2242 |
-
|
2243 |
-
|
2244 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2245 |
|
2246 |
-
#
|
2247 |
filename = "image_to_image_result.jpg"
|
2248 |
temp_url = upload_media_to_hf(image_bytes, filename, "image", token, use_temp=True)
|
2249 |
-
|
2250 |
-
# Check if creation was successful
|
2251 |
if temp_url.startswith("Error"):
|
2252 |
return temp_url
|
2253 |
-
|
2254 |
return f"<img src=\"{temp_url}\" alt=\"{prompt}\" style=\"max-width: 100%; height: auto; border-radius: 8px; margin: 10px 0;\" loading=\"lazy\" />"
|
2255 |
except Exception as e:
|
2256 |
print(f"Image-to-image generation error: {str(e)}")
|
|
|
2175 |
return f"Error generating image: {str(e)}"
|
2176 |
|
2177 |
def generate_image_to_image(input_image_data, prompt: str, token: gr.OAuthToken | None = None) -> str:
|
2178 |
+
"""Generate an image using image-to-image via OpenRouter.
|
2179 |
|
2180 |
+
Uses Google Gemini 2.5 Flash Image Preview via OpenRouter chat completions API.
|
2181 |
+
|
2182 |
+
Returns an HTML <img> tag whose src is an uploaded temporary URL.
|
2183 |
"""
|
2184 |
try:
|
2185 |
+
# Check for OpenRouter API key
|
2186 |
+
openrouter_key = os.getenv('OPENROUTER_API_KEY')
|
2187 |
+
if not openrouter_key:
|
2188 |
+
return "Error: OPENROUTER_API_KEY environment variable is not set. Please set it to your OpenRouter API key."
|
|
|
|
|
|
|
|
|
|
|
|
|
2189 |
|
2190 |
# Normalize input image to bytes
|
2191 |
import io
|
2192 |
from PIL import Image
|
2193 |
+
import base64
|
2194 |
+
import requests
|
2195 |
+
import json as _json
|
2196 |
try:
|
2197 |
import numpy as np
|
2198 |
except Exception:
|
2199 |
np = None
|
2200 |
|
2201 |
if hasattr(input_image_data, 'read'):
|
|
|
2202 |
raw = input_image_data.read()
|
2203 |
pil_image = Image.open(io.BytesIO(raw))
|
2204 |
elif hasattr(input_image_data, 'mode') and hasattr(input_image_data, 'size'):
|
|
|
2205 |
pil_image = input_image_data
|
2206 |
elif np is not None and isinstance(input_image_data, np.ndarray):
|
2207 |
pil_image = Image.fromarray(input_image_data)
|
2208 |
elif isinstance(input_image_data, (bytes, bytearray)):
|
2209 |
pil_image = Image.open(io.BytesIO(input_image_data))
|
2210 |
else:
|
|
|
2211 |
pil_image = Image.open(io.BytesIO(bytes(input_image_data)))
|
2212 |
|
|
|
2213 |
if pil_image.mode != 'RGB':
|
2214 |
pil_image = pil_image.convert('RGB')
|
2215 |
|
|
|
2218 |
if pil_image.width > max_input_size or pil_image.height > max_input_size:
|
2219 |
pil_image.thumbnail((max_input_size, max_input_size), Image.Resampling.LANCZOS)
|
2220 |
|
2221 |
+
# Convert to base64
|
2222 |
+
import io as _io
|
2223 |
+
buffered = _io.BytesIO()
|
2224 |
+
pil_image.save(buffered, format='PNG')
|
2225 |
+
img_b64 = base64.b64encode(buffered.getvalue()).decode('utf-8')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2226 |
|
2227 |
+
# Call OpenRouter API
|
2228 |
+
headers = {
|
2229 |
+
"Authorization": f"Bearer {openrouter_key}",
|
2230 |
+
"Content-Type": "application/json",
|
2231 |
+
"HTTP-Referer": os.getenv("YOUR_SITE_URL", "https://example.com"),
|
2232 |
+
"X-Title": os.getenv("YOUR_SITE_NAME", "AnyCoder Image I2I"),
|
2233 |
+
}
|
2234 |
+
payload = {
|
2235 |
+
"model": "google/gemini-2.5-flash-image-preview:free",
|
2236 |
+
"messages": [
|
2237 |
+
{
|
2238 |
+
"role": "user",
|
2239 |
+
"content": [
|
2240 |
+
{"type": "text", "text": prompt},
|
2241 |
+
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{img_b64}"}},
|
2242 |
+
],
|
2243 |
+
}
|
2244 |
+
],
|
2245 |
+
"max_tokens": 2048,
|
2246 |
+
}
|
2247 |
+
|
2248 |
+
try:
|
2249 |
+
resp = requests.post(
|
2250 |
+
"https://openrouter.ai/api/v1/chat/completions",
|
2251 |
+
headers=headers,
|
2252 |
+
data=_json.dumps(payload),
|
2253 |
+
timeout=60,
|
2254 |
+
)
|
2255 |
+
resp.raise_for_status()
|
2256 |
+
result_data = resp.json()
|
2257 |
+
|
2258 |
+
# Corrected response parsing logic
|
2259 |
+
message = result_data.get('choices', [{}])[0].get('message', {})
|
2260 |
+
|
2261 |
+
if message and 'images' in message and message['images']:
|
2262 |
+
# Get the first image from the 'images' list
|
2263 |
+
image_data = message['images'][0]
|
2264 |
+
base64_string = image_data.get('image_url', {}).get('url', '')
|
2265 |
+
|
2266 |
+
if base64_string and ',' in base64_string:
|
2267 |
+
# Remove the "data:image/png;base64," prefix
|
2268 |
+
base64_content = base64_string.split(',')[1]
|
2269 |
+
|
2270 |
+
# Decode the base64 string and create a PIL image
|
2271 |
+
img_bytes = base64.b64decode(base64_content)
|
2272 |
+
edited_image = Image.open(_io.BytesIO(img_bytes))
|
2273 |
+
|
2274 |
+
# Convert PIL image to JPEG bytes for upload
|
2275 |
+
out_buf = _io.BytesIO()
|
2276 |
+
edited_image.convert('RGB').save(out_buf, format='JPEG', quality=90, optimize=True)
|
2277 |
+
image_bytes = out_buf.getvalue()
|
2278 |
+
else:
|
2279 |
+
raise RuntimeError(f"API returned an invalid image format. Response: {_json.dumps(result_data, indent=2)}")
|
2280 |
+
else:
|
2281 |
+
raise RuntimeError(f"API did not return an image. Full Response: {_json.dumps(result_data, indent=2)}")
|
2282 |
+
|
2283 |
+
except requests.exceptions.HTTPError as err:
|
2284 |
+
error_body = err.response.text
|
2285 |
+
if err.response.status_code == 401:
|
2286 |
+
return "Error: Authentication failed. Check your OpenRouter API key."
|
2287 |
+
elif err.response.status_code == 429:
|
2288 |
+
return "Error: Rate limit exceeded or insufficient credits. Check your OpenRouter account."
|
2289 |
+
else:
|
2290 |
+
return f"Error: An API error occurred: {error_body}"
|
2291 |
+
except Exception as e:
|
2292 |
+
return f"Error: An unexpected error occurred: {str(e)}"
|
2293 |
|
2294 |
+
# Upload and return HTML tag
|
2295 |
filename = "image_to_image_result.jpg"
|
2296 |
temp_url = upload_media_to_hf(image_bytes, filename, "image", token, use_temp=True)
|
|
|
|
|
2297 |
if temp_url.startswith("Error"):
|
2298 |
return temp_url
|
|
|
2299 |
return f"<img src=\"{temp_url}\" alt=\"{prompt}\" style=\"max-width: 100%; height: auto; border-radius: 8px; margin: 10px 0;\" loading=\"lazy\" />"
|
2300 |
except Exception as e:
|
2301 |
print(f"Image-to-image generation error: {str(e)}")
|