Spaces:
Running
Running
| # app.py | |
| import os | |
| import gradio as gr | |
| from openai import OpenAI | |
| from PIL import Image | |
| from io import BytesIO | |
| import base64 | |
| # --- Config --- | |
| MODEL = "google/gemini-2.5-flash-image-preview" | |
| OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY") # set in HF Space secrets | |
| client = OpenAI( | |
| base_url="https://openrouter.ai/api/v1", | |
| api_key=OPENROUTER_API_KEY, | |
| ) | |
| def analyze(prompt, img): | |
| msg_content = [{"type": "text", "text": prompt}] | |
| if img: | |
| # img is a file path → open and encode as base64 | |
| with open(img, "rb") as f: | |
| b64data = base64.b64encode(f.read()).decode("utf-8") | |
| image_url = f"data:image/png;base64,{b64data}" # assumes PNG | |
| msg_content.append({ | |
| "type": "image_url", | |
| "image_url": {"url": image_url} | |
| }) | |
| try: | |
| # 👇 Print user input | |
| print("=== USER PROMPT ===") | |
| print(prompt) | |
| print("Has image?", bool(img)) | |
| completion = client.chat.completions.create( | |
| model=MODEL, | |
| messages=[{"role": "user", "content": msg_content}], | |
| ) | |
| response_text = completion.choices[0].message.content | |
| # 👇 Print raw response | |
| print("=== MODEL RESPONSE ===") | |
| print(response_text) | |
| # --- Extract image if present --- | |
| image_obj = None | |
| msg = completion.choices[0].message | |
| if hasattr(msg, "images") and msg.images: | |
| first_img = msg.images[0] | |
| url = first_img.get("image_url", {}).get("url") | |
| if url and url.startswith("data:image"): | |
| header, b64data = url.split(",", 1) | |
| image_bytes = base64.b64decode(b64data) | |
| image_obj = Image.open(BytesIO(image_bytes)) | |
| return response_text, image_obj | |
| except Exception as e: | |
| return f"Error: {e}", None | |
| with gr.Blocks(theme=gr.themes.Soft()) as demo: | |
| gr.Markdown("## Gemini 2.5 Flash Image (Preview) — via OpenRouter") | |
| gr.Markdown( | |
| "Generate **and** edit images with Google’s latest Gemini 2.5 Flash Image model " | |
| "(a.k.a. *nano-banana*). Try text-based edits (remove objects, restyle, relight), " | |
| "maintain character consistency, or **fuse multiple images** into one.\n\n" | |
| "**Notes:** The model is in preview; quality and output format may evolve. " | |
| "Images include Google’s SynthID watermark for provenance.\n\n" | |
| "— built with ❤️ by [xhaheen](https://www.linkedin.com/in/sallu-mandya/)" | |
| ) | |
| with gr.Row(): | |
| chatbot = gr.Chatbot(label="Conversation", show_copy_button=True) | |
| with gr.Row(): | |
| txt = gr.Textbox(label="Prompt", scale=4) | |
| img = gr.Image(type="filepath", label="Optional Image", scale=1) | |
| send_btn = gr.Button("Send") | |
| output_image = gr.Image(label="Generated Image", interactive=False) | |
| def user_interact(history, prompt, image): | |
| if not prompt and not image: | |
| return gr.update(value=history), None, "" | |
| response, gen_img = analyze(prompt, image) | |
| history = history or [] | |
| history.append((prompt, response)) | |
| return history, gen_img, "" | |
| send_btn.click( | |
| user_interact, | |
| inputs=[chatbot, txt, img], | |
| outputs=[chatbot, output_image, txt], | |
| ) | |
| if __name__ == "__main__": | |
| demo.queue() | |
| demo.launch(debug=True) | |