Spaces:
Running
Running
| import base64 | |
| import json | |
| import os | |
| from io import BytesIO | |
| from typing import Optional, Dict, Any | |
| # --- New Dependency --- | |
| # The google-generativeai library is now required. | |
| # Please install it using: pip install google-generativeai | |
| try: | |
| from google import genai | |
| from google.genai.types import RawReferenceImage | |
| from google.genai import types | |
| except ImportError: | |
| print("google-generativeai library not found. Please install it using: pip install google-generativeai") | |
| exit() | |
| # Pillow is required for image format conversion and normalization. | |
| # Please install it using: pip install Pillow | |
| try: | |
| from PIL import Image | |
| except ImportError: | |
| print("Pillow library not found. Please install it using: pip install Pillow") | |
| exit() | |
| # --- Configuration --- | |
| # It is recommended to set these as environment variables for security. | |
| # For ImgBB: used to upload the final image and get a public URL. | |
| IMGBB_API_KEY = os.getenv("IMGBB_API_KEY") | |
| # For Google AI: your API key for accessing the Gemini model. | |
| GEMINI_API_KEY = os.getenv("GEMINI_API_KEY") | |
| # Configure the Gemini client library | |
| if GEMINI_API_KEY: | |
| client = genai.Client(api_key=GEMINI_API_KEY) | |
| def upload_to_imgbb(image_path: str, file_name: str) -> Optional[str]: | |
| """ | |
| Uploads the image at image_path to ImgBB. | |
| Returns the public URL or None on failure. | |
| (This function is unchanged from the original script) | |
| """ | |
| if not IMGBB_API_KEY: | |
| print("Warning: IMGBB_API_KEY not set, skipping upload to ImgBB.") | |
| return None | |
| # requests is now only used for ImgBB uploads, so we import it here. | |
| import requests | |
| print(f"Uploading {file_name} to ImgBB...") | |
| try: | |
| with open(image_path, 'rb') as f: | |
| files = {"image": (file_name, f.read())} | |
| resp = requests.post( | |
| "https://api.imgbb.com/1/upload", | |
| params={"key": IMGBB_API_KEY}, | |
| files=files, | |
| timeout=30 | |
| ) | |
| resp.raise_for_status() | |
| data = resp.json().get("data", {}) | |
| url = data.get("url") | |
| if url: | |
| print(f"Successfully uploaded to ImgBB: {url}") | |
| return url | |
| else: | |
| print(f"Error: ImgBB API response missing 'url'. Response: {resp.json()}") | |
| return None | |
| except requests.exceptions.RequestException as e: | |
| print(f"Error: ImgBB upload failed: {e}") | |
| return None | |
| def _save_image_bytes(image_bytes: bytes, save_path: str) -> bool: | |
| """ | |
| Saves raw image bytes to a file. | |
| Args: | |
| image_bytes: The raw bytes of the image data. | |
| save_path: The local path to save the image. | |
| Returns: | |
| True if saving was successful, False otherwise. | |
| """ | |
| print(f"Saving generated image to: {save_path}") | |
| try: | |
| with open(save_path, 'wb') as f: | |
| f.write(image_bytes) | |
| print("Image successfully saved.") | |
| return True | |
| except IOError as e: | |
| print(f"Error saving image file: {e}") | |
| return False | |
| def generate_image( | |
| prompt_text: str, | |
| image_path: str, | |
| download_path: Optional[str] = None | |
| ) -> Optional[Dict[str, Any]]: | |
| """ | |
| Sends a request to the Gemini API using the Python SDK to modify an image, | |
| optionally saves the result, and uploads it to ImgBB. | |
| Args: | |
| prompt_text: The instructional text for image modification. | |
| image_path: The file path to the input image (any common format). | |
| download_path: If provided, the path to save the generated image. | |
| Returns: | |
| A dictionary containing a simplified API response and the ImgBB URL, | |
| or None on error. | |
| """ | |
| if not GEMINI_API_KEY: | |
| print("Error: GEMINI_API_KEY environment variable not set.") | |
| return None | |
| try: | |
| # --- Image Loading --- | |
| print(f"Processing image: {image_path}") | |
| img = Image.open(image_path) | |
| except FileNotFoundError: | |
| print(f"Error: Image file not found at {image_path}") | |
| return None | |
| except Exception as e: | |
| print(f"Error processing image file. Ensure it's a valid image. Details: {e}") | |
| return None | |
| try: | |
| # --- API Call via Python SDK --- | |
| print("Initializing Gemini model...") | |
| print("Sending request to Gemini API via Python SDK...") | |
| # --- Process Gemini API Response --- | |
| # Convert the PIL Image to bytes (JPEG format) | |
| img_byte_arr = BytesIO() | |
| img.save(img_byte_arr, format='JPEG') | |
| img_bytes = img_byte_arr.getvalue() | |
| response = client.models.generate_content( | |
| model='gemini-2.0-flash-preview-image-generation', | |
| contents=[ | |
| types.Part.from_text(text=prompt_text), | |
| types.Part.from_bytes(data=img_bytes, mime_type='image/jpeg'), | |
| ], | |
| config=types.GenerateContentConfig( | |
| response_modalities=["TEXT", "IMAGE"] | |
| ) | |
| ) | |
| # DEBUG: print the response parts to inspect structure | |
| # print(response.candidates[0].content.parts) | |
| # Extract the image bytes from the response parts | |
| generated_image_bytes = None | |
| for part in response.candidates[0].content.parts: | |
| if hasattr(part, "inline_data") and part.inline_data and hasattr(part.inline_data, "data"): | |
| generated_image_bytes = part.inline_data.data | |
| break | |
| print(generated_image_bytes) | |
| imgbb_url = None | |
| # --- Download & Upload Logic --- | |
| if download_path and generated_image_bytes: | |
| if _save_image_bytes(generated_image_bytes, download_path): | |
| # If save is successful, upload the saved file to ImgBB | |
| file_name = os.path.basename(download_path) | |
| imgbb_url = upload_to_imgbb(download_path, file_name) | |
| # Prepare a final dictionary similar to the original script's output | |
| final_result = { | |
| "api_response": { | |
| "candidates": [{ | |
| "finish_reason": response.candidates[0].finish_reason.name | |
| }] | |
| }, | |
| "imgbb_url": imgbb_url | |
| } | |
| return final_result | |
| except Exception as e: | |
| print(f"Gemini API request failed: {e}") | |
| return None | |