feat(GeminiImage-ApiNode): add aspect_ratio and release version of model (#10255)

This commit is contained in:
Alexander Piskun 2025-10-11 02:17:20 +03:00 committed by GitHub
parent cdfc25a160
commit aa895db7e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 28 additions and 13 deletions

View File

@ -1,19 +1,22 @@
from __future__ import annotations from typing import Optional
from typing import List, Optional
from comfy_api_nodes.apis import GeminiGenerationConfig, GeminiContent, GeminiSafetySetting, GeminiSystemInstructionContent, GeminiTool, GeminiVideoMetadata from comfy_api_nodes.apis import GeminiGenerationConfig, GeminiContent, GeminiSafetySetting, GeminiSystemInstructionContent, GeminiTool, GeminiVideoMetadata
from pydantic import BaseModel from pydantic import BaseModel
class GeminiImageConfig(BaseModel):
aspectRatio: Optional[str] = None
class GeminiImageGenerationConfig(GeminiGenerationConfig): class GeminiImageGenerationConfig(GeminiGenerationConfig):
responseModalities: Optional[List[str]] = None responseModalities: Optional[list[str]] = None
imageConfig: Optional[GeminiImageConfig] = None
class GeminiImageGenerateContentRequest(BaseModel): class GeminiImageGenerateContentRequest(BaseModel):
contents: List[GeminiContent] contents: list[GeminiContent]
generationConfig: Optional[GeminiImageGenerationConfig] = None generationConfig: Optional[GeminiImageGenerationConfig] = None
safetySettings: Optional[List[GeminiSafetySetting]] = None safetySettings: Optional[list[GeminiSafetySetting]] = None
systemInstruction: Optional[GeminiSystemInstructionContent] = None systemInstruction: Optional[GeminiSystemInstructionContent] = None
tools: Optional[List[GeminiTool]] = None tools: Optional[list[GeminiTool]] = None
videoMetadata: Optional[GeminiVideoMetadata] = None videoMetadata: Optional[GeminiVideoMetadata] = None

View File

@ -26,7 +26,7 @@ from comfy_api_nodes.apis import (
GeminiPart, GeminiPart,
GeminiMimeType, GeminiMimeType,
) )
from comfy_api_nodes.apis.gemini_api import GeminiImageGenerationConfig, GeminiImageGenerateContentRequest from comfy_api_nodes.apis.gemini_api import GeminiImageGenerationConfig, GeminiImageGenerateContentRequest, GeminiImageConfig
from comfy_api_nodes.apis.client import ( from comfy_api_nodes.apis.client import (
ApiEndpoint, ApiEndpoint,
HttpMethod, HttpMethod,
@ -63,6 +63,7 @@ class GeminiImageModel(str, Enum):
""" """
gemini_2_5_flash_image_preview = "gemini-2.5-flash-image-preview" gemini_2_5_flash_image_preview = "gemini-2.5-flash-image-preview"
gemini_2_5_flash_image = "gemini-2.5-flash-image"
def get_gemini_endpoint( def get_gemini_endpoint(
@ -538,7 +539,7 @@ class GeminiImage(ComfyNodeABC):
{ {
"tooltip": "The Gemini model to use for generating responses.", "tooltip": "The Gemini model to use for generating responses.",
"options": [model.value for model in GeminiImageModel], "options": [model.value for model in GeminiImageModel],
"default": GeminiImageModel.gemini_2_5_flash_image_preview.value, "default": GeminiImageModel.gemini_2_5_flash_image.value,
}, },
), ),
"seed": ( "seed": (
@ -579,6 +580,14 @@ class GeminiImage(ComfyNodeABC):
# "tooltip": "How many images to generate", # "tooltip": "How many images to generate",
# }, # },
# ), # ),
"aspect_ratio": (
IO.COMBO,
{
"tooltip": "Defaults to matching the output image size to that of your input image, or otherwise generates 1:1 squares.",
"options": ["auto", "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"],
"default": "auto",
},
),
}, },
"hidden": { "hidden": {
"auth_token": "AUTH_TOKEN_COMFY_ORG", "auth_token": "AUTH_TOKEN_COMFY_ORG",
@ -600,15 +609,17 @@ class GeminiImage(ComfyNodeABC):
images: Optional[IO.IMAGE] = None, images: Optional[IO.IMAGE] = None,
files: Optional[list[GeminiPart]] = None, files: Optional[list[GeminiPart]] = None,
n=1, n=1,
aspect_ratio: str = "auto",
unique_id: Optional[str] = None, unique_id: Optional[str] = None,
**kwargs, **kwargs,
): ):
# Validate inputs
validate_string(prompt, strip_whitespace=True, min_length=1) validate_string(prompt, strip_whitespace=True, min_length=1)
# Create parts list with text prompt as the first part
parts: list[GeminiPart] = [create_text_part(prompt)] parts: list[GeminiPart] = [create_text_part(prompt)]
# Add other modal parts if not aspect_ratio:
aspect_ratio = "auto" # for backward compatability with old workflows; to-do remove this in December
image_config = GeminiImageConfig(aspectRatio=aspect_ratio)
if images is not None: if images is not None:
image_parts = create_image_parts(images) image_parts = create_image_parts(images)
parts.extend(image_parts) parts.extend(image_parts)
@ -625,7 +636,8 @@ class GeminiImage(ComfyNodeABC):
), ),
], ],
generationConfig=GeminiImageGenerationConfig( generationConfig=GeminiImageGenerationConfig(
responseModalities=["TEXT","IMAGE"] responseModalities=["TEXT","IMAGE"],
imageConfig=None if aspect_ratio == "auto" else image_config,
) )
), ),
auth_kwargs=kwargs, auth_kwargs=kwargs,