fix(image): validate output sizes

This commit is contained in:
silveroxides
2026-09-01 12:02:11 +02:00
parent 6048af0e6c
commit 6cb3dd9ef3
2 changed files with 38 additions and 1 deletions
+10 -1
View File
@@ -206,6 +206,11 @@ class SSL_GeminiTextPrompt(IO.ComfyNode):
"gemini-3.1-flash-image", "gemini-3.1-flash-lite-image",
"gemini-3-pro-image-preview", "gemini-3-pro-image",
]
IMAGE_SIZE_BY_SELECTABLE_MODEL = {
"gemini-3.1-flash-image": ("512", "1K", "2K", "4K"),
"gemini-3.1-flash-lite-image": ("1K",),
"gemini-3-pro-image": ("1K", "2K", "4K"),
}
MEDIA_RES_MODELS = [
"gemini-3.1-flash-lite", "gemini-3-flash-preview", "gemini-3.1-pro-preview",
"gemini-3.5-flash", "gemini-pro-latest", "gemini-flash-latest", "gemini-flash-lite-latest"
@@ -248,7 +253,7 @@ class SSL_GeminiTextPrompt(IO.ComfyNode):
IO.String.Input("retry_pattern", default="", optional=True, multiline=False, tooltip="Regex pattern to match in response text. If matched, retry with new seed. Leave empty to disable."),
IO.Int.Input("max_retries", default=3, min=0, max=10, step=1, tooltip="Maximum number of retry attempts when pattern matches. 0 disables retry."),
IO.String.Input("timeout_fallback_text", default="", optional=True, multiline=True, tooltip="Text returned when the Gemini request times out. Leave empty to return the standard timeout message."),
IO.Combo.Input("image_size", options=["None", "512", "1K", "2K", "4K"], default="None", tooltip="Generated image resolution. Gemini 3.1 Flash Lite Image supports only 1K; 512 is supported only by Gemini 3.1 Flash Image."),
IO.Combo.Input("image_size", options=["None", "512", "1K", "2K", "4K"], default="None", optional=True, tooltip="Generated image resolution. Gemini 3.1 Flash Lite Image supports only 1K; 512 is supported only by Gemini 3.1 Flash Image."),
cls.GeminiVideoConfig.Input("video", optional=True, tooltip="Optional configured Gemini video input with embedded audio and sampling FPS."),
IO.Autogrow.Input(
"image_inputs",
@@ -718,6 +723,10 @@ class SSL_GeminiTextPrompt(IO.ComfyNode):
if aspect_ratio not in (None, "None"):
image_config["aspect_ratio"] = aspect_ratio
if image_size not in (None, "None"):
supported_image_sizes = cls.IMAGE_SIZE_BY_SELECTABLE_MODEL.get(model)
if supported_image_sizes is not None and image_size not in supported_image_sizes:
allowed = ", ".join(supported_image_sizes)
raise ValueError(f"{model} image_size must be one of: {allowed}.")
image_config["image_size"] = image_size
if allow_all_people:
image_config["person_generation"] = "ALLOW_ALL"
+28
View File
@@ -975,6 +975,34 @@ def test_image_config_preserves_requested_image_size():
assert config.image_config.image_size == "2K"
@pytest.mark.parametrize(
("model", "image_size", "allowed"),
[
("gemini-3.1-flash-lite-image", "2K", "1K"),
("gemini-3-pro-image", "512", "1K, 2K, 4K"),
],
)
def test_image_config_rejects_unsupported_image_size(model, image_size, allowed):
with pytest.raises(ValueError, match=rf"^{model} image_size must be one of: {allowed}\.$"):
gemini_nodes.SSL_GeminiTextPrompt._build_generate_content_config(
model=model,
temperature=1.0,
top_p=0.95,
top_k=40,
max_output_tokens=8192,
seed=7,
include_images=True,
response_modalities=["IMAGE", "TEXT"],
aspect_ratio="None",
padded_system_instruction="system",
thinking_level="None",
thinking_budget=0,
include_thoughts=False,
media_resolution="unspecified",
image_size=image_size,
)
def test_enterprise_image_config_allows_all_people():
config = gemini_nodes.SSL_GeminiTextPrompt._build_generate_content_config(
model="gemini-3.1-flash-image",