fix(image): correct Gemini image requests
This commit is contained in:
+2
-1
@@ -190,4 +190,5 @@ cython_debug/
|
||||
.ruff_cache/
|
||||
|
||||
# PyPI configuration file
|
||||
.pypirc
|
||||
.pypirc
|
||||
AGENTS-LOCAL.md
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# Agent Instructions
|
||||
|
||||
Read `AGENTS-LOCAL.md` when present. It contains repository-machine-specific
|
||||
operating rules and must remain local only; do not stage or commit it.
|
||||
|
||||
Use `$comfyui-custom-node-development` for all development, testing, review, and packaging work in this repository.
|
||||
|
||||
If the skill is unavailable, stop and tell the user that it must be installed before continuing.
|
||||
@@ -16,6 +19,37 @@ python_executable: C:\Users\ishim\Tools\ComfyUI\.venv\Scripts\python.exe
|
||||
|
||||
## Repository-Specific Instructions
|
||||
|
||||
### Evidence and claim discipline
|
||||
|
||||
- Do not present assumptions, plausible explanations, remembered behavior, or
|
||||
pattern-based guesses as established facts.
|
||||
- Before making a causal, behavioral, compatibility, or architectural claim,
|
||||
verify it against direct evidence covering the relevant path. Inspect the
|
||||
actual source, configuration, inputs, consumers, connections, and runtime
|
||||
assembly needed to support the claim.
|
||||
- Distinguish verified facts, supported inferences, and unknowns explicitly.
|
||||
When required evidence is unavailable, state that the conclusion cannot yet
|
||||
be determined instead of filling the gap with a likely explanation.
|
||||
- Do not infer an end-to-end result from an isolated helper, preset, schema,
|
||||
unit test, string-construction test, or passing test suite. Verify the actual
|
||||
integration and consumer behavior before generalizing beyond what was tested.
|
||||
- Do not invent workflow topology, data flow, precedence, model behavior, or
|
||||
user intent. Inspect the relevant artifact or ask for the specific missing
|
||||
evidence when it cannot be discovered locally.
|
||||
- Do not generalize a model or prompt protocol from a shared tokenizer, helper,
|
||||
socket type, or similarly named node. Verify the target model, node contract,
|
||||
template assembly, and consuming path. A node-specific prefix or label does
|
||||
not establish generic encoder behavior.
|
||||
- When correcting an unsupported claim, identify exactly which parts were
|
||||
verified and which parts were assumed. Do not replace one unsupported
|
||||
explanation with another.
|
||||
- Accept failure and request guidance or advice on the approach when continued
|
||||
attempts are unlikely to work and are being made only to force the task toward
|
||||
apparent completion; do not continue speculative trial-and-error to avoid
|
||||
acknowledging that the current approach has failed.
|
||||
|
||||
### Test selection
|
||||
|
||||
- Use `tests/run_tests.py` for all Python test selection.
|
||||
- During iteration, run an exact test or one explicit group.
|
||||
- Before handoff, run `tests/run_tests.py --changed` once for accumulated changes.
|
||||
|
||||
+12
-5
@@ -202,9 +202,9 @@ class SSL_GeminiTextPrompt(IO.ComfyNode):
|
||||
"gemini-3-flash-preview", "gemini-3.5-flash", "gemini-3.5-flash-lite", "gemini-3.6-flash", GEMINI_3_7_FLASH, GEMINI_4_FLASH_PREVIEW
|
||||
]
|
||||
IMAGE_MODELS = [
|
||||
"gemini-2.5-flash-image-preview", "gemini-2.5-flash-image",
|
||||
"gemini-2.5-flash-image",
|
||||
"gemini-3.1-flash-image", "gemini-3.1-flash-lite-image",
|
||||
"gemini-3-pro-image-preview", "gemini-3-pro-image", "nano-banana-pro-preview",
|
||||
"gemini-3-pro-image-preview", "gemini-3-pro-image",
|
||||
]
|
||||
MEDIA_RES_MODELS = [
|
||||
"gemini-3.1-flash-lite", "gemini-3-flash-preview", "gemini-3.1-pro-preview",
|
||||
@@ -227,7 +227,7 @@ class SSL_GeminiTextPrompt(IO.ComfyNode):
|
||||
cls.GemConfig.Input("config"),
|
||||
IO.String.Input("prompt", multiline=True),
|
||||
IO.String.Input("system_instruction", default="You are a helpful AI assistant.", multiline=True),
|
||||
IO.Combo.Input("model", options=["gemini-1.5-pro-002", "gemini-2.0-flash", "gemini-2.0-flash-lite", "gemini-2.5-flash-preview-04-17", "gemini-2.5-pro-exp-03-25", "gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.5-flash-lite", "gemini-3-flash-preview", "gemini-3.1-flash-lite", "gemini-3.1-pro-preview", "gemini-3.5-flash", "gemini-3.5-flash-lite", "gemini-3.6-flash", cls.GEMINI_3_7_FLASH, "gemini-2.5-flash-image-preview", "gemini-3.1-flash-image", "gemini-3.1-flash-lite-image", "gemini-3-pro-image", "nano-banana-pro-preview", "gemini-pro-latest", "gemini-flash-latest", "gemini-flash-lite-latest"], default="gemini-2.5-flash"),
|
||||
IO.Combo.Input("model", options=["gemini-1.5-pro-002", "gemini-2.0-flash", "gemini-2.0-flash-lite", "gemini-2.5-flash-preview-04-17", "gemini-2.5-pro-exp-03-25", "gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.5-flash-lite", "gemini-3-flash-preview", "gemini-3.1-flash-lite", "gemini-3.1-pro-preview", "gemini-3.5-flash", "gemini-3.5-flash-lite", "gemini-3.6-flash", cls.GEMINI_3_7_FLASH, "gemini-3.1-flash-image", "gemini-3.1-flash-lite-image", "gemini-3-pro-image", "gemini-pro-latest", "gemini-flash-latest", "gemini-flash-lite-latest"], default="gemini-2.5-flash"),
|
||||
IO.Float.Input("temperature", default=1.0, min=0.0, max=1.0, step=0.01),
|
||||
IO.Float.Input("top_p", default=0.95, min=0.0, max=1.0, step=0.01),
|
||||
IO.Int.Input("top_k", default=40, min=1, max=100, step=1),
|
||||
@@ -697,7 +697,8 @@ class SSL_GeminiTextPrompt(IO.ComfyNode):
|
||||
@classmethod
|
||||
def _build_generate_content_config(cls, model, temperature, top_p, top_k, max_output_tokens, seed,
|
||||
include_images, response_modalities, aspect_ratio, padded_system_instruction,
|
||||
thinking_level, thinking_budget, include_thoughts, media_resolution):
|
||||
thinking_level, thinking_budget, include_thoughts, media_resolution,
|
||||
allow_all_people=False):
|
||||
# Centralized builder for GenerateContentConfig used by different model/feature branches
|
||||
safety = [
|
||||
types.SafetySetting(category="HARM_CATEGORY_HARASSMENT", threshold="BLOCK_NONE"),
|
||||
@@ -709,6 +710,11 @@ class SSL_GeminiTextPrompt(IO.ComfyNode):
|
||||
|
||||
# Modified: Only trigger image config if include_images is True AND the model is actually an image model
|
||||
if include_images and model in cls.IMAGE_MODELS:
|
||||
image_config = {}
|
||||
if aspect_ratio not in (None, "None"):
|
||||
image_config["aspect_ratio"] = aspect_ratio
|
||||
if allow_all_people:
|
||||
image_config["person_generation"] = "ALLOW_ALL"
|
||||
return types.GenerateContentConfig(
|
||||
temperature=temperature,
|
||||
top_p=top_p,
|
||||
@@ -717,7 +723,7 @@ class SSL_GeminiTextPrompt(IO.ComfyNode):
|
||||
max_output_tokens=max_output_tokens,
|
||||
safety_settings=safety,
|
||||
response_modalities=response_modalities,
|
||||
image_config=types.ImageConfig(aspect_ratio=aspect_ratio),
|
||||
image_config=types.ImageConfig(**image_config) if image_config else None,
|
||||
system_instruction=[types.Part.from_text(text=padded_system_instruction)],
|
||||
)
|
||||
|
||||
@@ -1071,6 +1077,7 @@ class SSL_GeminiTextPrompt(IO.ComfyNode):
|
||||
thinking_budget=thinking_budget,
|
||||
include_thoughts=include_thoughts,
|
||||
media_resolution=media_resolution,
|
||||
allow_all_people=bool(config.get("use_vertexai_env", False) or config.get("vertexai_express", False)),
|
||||
)
|
||||
|
||||
if use_seed and actual_seed is not None:
|
||||
|
||||
@@ -883,9 +883,11 @@ def test_proxy_uses_sdk_http_options_without_mutating_environment(monkeypatch):
|
||||
assert gemini_nodes.os.environ["HTTP_PROXY"] == "http://existing-proxy:9000"
|
||||
|
||||
|
||||
def test_confirmed_current_models_are_visible_without_removing_legacy_ids():
|
||||
def test_confirmed_current_models_are_visible_without_deprecated_image_aliases():
|
||||
schema = gemini_nodes.SSL_GeminiTextPrompt.define_schema()
|
||||
model_input = next(input_ for input_ in schema.inputs if input_.id == "model")
|
||||
input_ids = [input_.id for input_ in schema.inputs]
|
||||
aspect_ratio = next(input_ for input_ in schema.inputs if input_.id == "aspect_ratio")
|
||||
|
||||
for model in (
|
||||
"gemini-3.7-flash",
|
||||
@@ -893,10 +895,81 @@ def test_confirmed_current_models_are_visible_without_removing_legacy_ids():
|
||||
"gemini-3.1-flash-image",
|
||||
"gemini-3.1-flash-lite-image",
|
||||
"gemini-3-pro-image",
|
||||
"gemini-2.5-flash-image-preview",
|
||||
):
|
||||
assert model in model_input.options
|
||||
|
||||
assert "gemini-2.5-flash-image-preview" not in model_input.options
|
||||
assert "nano-banana-pro-preview" not in model_input.options
|
||||
assert input_ids[input_ids.index("include_images") + 1] == "aspect_ratio"
|
||||
assert aspect_ratio.options == ["None", "1:1", "9:16", "16:9", "3:4", "4:3", "3:2", "2:3", "5:4", "4:5", "21:9"]
|
||||
assert aspect_ratio.default == "None"
|
||||
|
||||
|
||||
def test_image_config_omits_none_aspect_ratio():
|
||||
config = gemini_nodes.SSL_GeminiTextPrompt._build_generate_content_config(
|
||||
model="gemini-3.1-flash-image",
|
||||
temperature=1.0,
|
||||
top_p=0.95,
|
||||
top_k=40,
|
||||
max_output_tokens=8192,
|
||||
seed=7,
|
||||
include_images=True,
|
||||
response_modalities=["TEXT", "IMAGE"],
|
||||
aspect_ratio="None",
|
||||
padded_system_instruction="system",
|
||||
thinking_level="None",
|
||||
thinking_budget=0,
|
||||
include_thoughts=False,
|
||||
media_resolution="unspecified",
|
||||
)
|
||||
|
||||
assert config.response_modalities == ["TEXT", "IMAGE"]
|
||||
assert config.image_config is None
|
||||
|
||||
|
||||
def test_image_config_preserves_concrete_aspect_ratio():
|
||||
config = gemini_nodes.SSL_GeminiTextPrompt._build_generate_content_config(
|
||||
model="gemini-3-pro-image",
|
||||
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="16:9",
|
||||
padded_system_instruction="system",
|
||||
thinking_level="None",
|
||||
thinking_budget=0,
|
||||
include_thoughts=False,
|
||||
media_resolution="unspecified",
|
||||
)
|
||||
|
||||
assert config.image_config.aspect_ratio == "16:9"
|
||||
|
||||
|
||||
def test_enterprise_image_config_allows_all_people():
|
||||
config = gemini_nodes.SSL_GeminiTextPrompt._build_generate_content_config(
|
||||
model="gemini-3.1-flash-image",
|
||||
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",
|
||||
allow_all_people=True,
|
||||
)
|
||||
|
||||
assert config.image_config.aspect_ratio is None
|
||||
assert config.image_config.person_generation == "ALLOW_ALL"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("selected_level", "expected_level"),
|
||||
|
||||
Reference in New Issue
Block a user