From f421260bfcc00059f6ebd56bfc13f062b44ce8d7 Mon Sep 17 00:00:00 2001 From: shiva raj badu Date: Fri, 19 Dec 2025 00:41:55 +0545 Subject: [PATCH] feat: nano banana image generation model integration --- servers/fastapi/enums/image_provider.py | 1 + .../services/image_generation_service.py | 23 +++++++++++++++---- servers/fastapi/utils/image_provider.py | 4 ++++ servers/nextjs/components/Home.tsx | 2 ++ servers/nextjs/components/LLMSelection.tsx | 5 ++++ servers/nextjs/utils/providerConstants.ts | 11 ++++++++- servers/nextjs/utils/storeHelpers.ts | 2 ++ 7 files changed, 42 insertions(+), 6 deletions(-) diff --git a/servers/fastapi/enums/image_provider.py b/servers/fastapi/enums/image_provider.py index 3c037214..36025007 100644 --- a/servers/fastapi/enums/image_provider.py +++ b/servers/fastapi/enums/image_provider.py @@ -4,5 +4,6 @@ class ImageProvider(Enum): PEXELS = "pexels" PIXABAY = "pixabay" GEMINI_FLASH = "gemini_flash" + NANOBANANA_PRO = "nanobanana_pro" # Google's gemini-3-pro-image-preview DALLE3 = "dall-e-3" COMFYUI = "comfyui" diff --git a/servers/fastapi/services/image_generation_service.py b/servers/fastapi/services/image_generation_service.py index c0ace751..802585a5 100644 --- a/servers/fastapi/services/image_generation_service.py +++ b/servers/fastapi/services/image_generation_service.py @@ -18,6 +18,7 @@ from utils.image_provider import ( is_pixels_selected, is_pixabay_selected, is_gemini_flash_selected, + is_nanobanana_pro_selected, is_dalle3_selected, is_comfyui_selected, ) @@ -39,7 +40,9 @@ class ImageGenerationService: elif is_pixels_selected(): return self.get_image_from_pexels elif is_gemini_flash_selected(): - return self.generate_image_google + return self.generate_image_gemini_flash + elif is_nanobanana_pro_selected(): + return self.generate_image_nanobanana_pro elif is_dalle3_selected(): return self.generate_image_openai elif is_comfyui_selected(): @@ -95,10 +98,11 @@ class ImageGenerationService: print(f"Error generating image: {e}") return "/static/images/placeholder.jpg" - async def generate_image_openai(self, prompt: str, output_directory: str) -> str: + async def generate_image_openai(self, prompt: str, output_directory: str,model: str = "dall-e-3") -> str: + client = AsyncOpenAI() result = await client.images.generate( - model="dall-e-3", + model=model, prompt=prompt, n=1, quality="standard", @@ -107,11 +111,12 @@ class ImageGenerationService: image_url = result.data[0].url return await download_file(image_url, output_directory) - async def generate_image_google(self, prompt: str, output_directory: str) -> str: + async def _generate_image_google(self, prompt: str, output_directory: str, model: str) -> str: + """Base method for Google image generation models.""" client = genai.Client() response = await asyncio.to_thread( client.models.generate_content, - model="gemini-2.5-flash-image-preview", + model=model, contents=[prompt], config=GenerateContentConfig(response_modalities=["TEXT", "IMAGE"]), ) @@ -126,6 +131,14 @@ class ImageGenerationService: return image_path + async def generate_image_gemini_flash(self, prompt: str, output_directory: str) -> str: + """Generate image using Gemini Flash (gemini-2.5-flash-image-preview).""" + return await self._generate_image_google(prompt, output_directory, "gemini-2.5-flash-image-preview") + + async def generate_image_nanobanana_pro(self, prompt: str, output_directory: str) -> str: + """Generate image using NanoBanana Pro (gemini-3-pro-image-preview).""" + return await self._generate_image_google(prompt, output_directory, "gemini-3-pro-image-preview") + async def get_image_from_pexels(self, prompt: str) -> str: async with aiohttp.ClientSession(trust_env=True) as session: response = await session.get( diff --git a/servers/fastapi/utils/image_provider.py b/servers/fastapi/utils/image_provider.py index c30e716e..1be28bc5 100644 --- a/servers/fastapi/utils/image_provider.py +++ b/servers/fastapi/utils/image_provider.py @@ -27,6 +27,10 @@ def is_gemini_flash_selected() -> bool: return ImageProvider.GEMINI_FLASH == get_selected_image_provider() +def is_nanobanana_pro_selected() -> bool: + return ImageProvider.NANOBANANA_PRO == get_selected_image_provider() + + def is_dalle3_selected() -> bool: return ImageProvider.DALLE3 == get_selected_image_provider() diff --git a/servers/nextjs/components/Home.tsx b/servers/nextjs/components/Home.tsx index 27f34409..71a833cc 100644 --- a/servers/nextjs/components/Home.tsx +++ b/servers/nextjs/components/Home.tsx @@ -65,7 +65,9 @@ export default function Home() { })); // API: save config trackEvent(MixpanelEvent.Home_SaveConfiguration_API_Call); + // API CALL: save config await handleSaveLLMConfig(llmConfig); + if (llmConfig.LLM === "ollama" && llmConfig.OLLAMA_MODEL) { // API: check model pulled trackEvent(MixpanelEvent.Home_CheckOllamaModelPulled_API_Call); diff --git a/servers/nextjs/components/LLMSelection.tsx b/servers/nextjs/components/LLMSelection.tsx index 64ed6835..28aa3e49 100644 --- a/servers/nextjs/components/LLMSelection.tsx +++ b/servers/nextjs/components/LLMSelection.tsx @@ -74,6 +74,7 @@ export default function LLMProviderSelection({ ( (llmConfig.IMAGE_PROVIDER === "dall-e-3" && !llmConfig.OPENAI_API_KEY) || (llmConfig.IMAGE_PROVIDER === "gemini_flash" && !llmConfig.GOOGLE_API_KEY) || + (llmConfig.IMAGE_PROVIDER === "nanobanana_pro" && !llmConfig.GOOGLE_API_KEY) || (llmConfig.IMAGE_PROVIDER === "pexels" && !llmConfig.PEXELS_API_KEY) || (llmConfig.IMAGE_PROVIDER === "pixabay" && !llmConfig.PIXABAY_API_KEY) ); @@ -340,6 +341,10 @@ export default function LLMProviderSelection({ return <>; } + if (provider.value === "nanobanana_pro" && llmConfig.LLM === "google") { + return <>; + } + // Show ComfyUI configuration if (provider.value === "comfyui") { return ( diff --git a/servers/nextjs/utils/providerConstants.ts b/servers/nextjs/utils/providerConstants.ts index dd7cd561..349cacf1 100644 --- a/servers/nextjs/utils/providerConstants.ts +++ b/servers/nextjs/utils/providerConstants.ts @@ -55,7 +55,16 @@ export const IMAGE_PROVIDERS: Record = { gemini_flash: { value: "gemini_flash", label: "Gemini Flash", - description: "Google's primary image generation model", + description: "Google's fast image generation model", + icon: "/icons/google.png", + requiresApiKey: true, + apiKeyField: "GOOGLE_API_KEY", + apiKeyFieldLabel: "Google API Key" + }, + nanobanana_pro: { + value: "nanobanana_pro", + label: "NanoBanana Pro", + description: "Google's advanced image generation (4K, better quality)", icon: "/icons/google.png", requiresApiKey: true, apiKeyField: "GOOGLE_API_KEY", diff --git a/servers/nextjs/utils/storeHelpers.ts b/servers/nextjs/utils/storeHelpers.ts index 5c927c47..9a0a00f9 100644 --- a/servers/nextjs/utils/storeHelpers.ts +++ b/servers/nextjs/utils/storeHelpers.ts @@ -73,6 +73,8 @@ export const hasValidLLMConfig = (llmConfig: LLMConfig) => { return llmConfig.OPENAI_API_KEY && llmConfig.OPENAI_API_KEY !== ""; case "gemini_flash": return llmConfig.GOOGLE_API_KEY && llmConfig.GOOGLE_API_KEY !== ""; + case "nanobanana_pro": + return llmConfig.GOOGLE_API_KEY && llmConfig.GOOGLE_API_KEY !== ""; case "comfyui": return llmConfig.COMFYUI_URL && llmConfig.COMFYUI_URL !== ""; default: