fix: map high precision seeds to API int32 range

This commit is contained in:
silveroxides
2026-09-15 02:01:48 +02:00
parent 46aa38ed40
commit a754a74916
3 changed files with 40 additions and 6 deletions
+1 -1
View File
@@ -77,7 +77,7 @@ If you are in China or other regions requiring a proxy:
- `cache_ttl_minutes`: Number of minutes Gemini retains cached context.
- `cache_seed`: Generation seed used while `use_cache` is enabled.
Generated seeds use a dedicated CPU `torch.Generator`, without Python-random/NumPy seed generation or global RNG reseeding. Existing API-seed selection, dispatch behavior, input fingerprinting, and cached-result reuse are preserved.
Generated seeds use a dedicated CPU `torch.Generator`, without Python-random/NumPy seed generation or global RNG reseeding. Full input seeds remain in the input fingerprint. Nonzero seeds outside the API's INT32 range deterministically seed the local generator, which produces an INT32-safe API seed; already valid positive seeds remain unchanged. Zero retains its fresh-seed behavior. `final_actual_seed` reports the selected API seed when seeding is enabled.
### Video Input Configuration Node
+11 -5
View File
@@ -562,16 +562,19 @@ class SSL_GeminiTextPrompt(IO.ComfyNode):
if not use_seed:
print("[INFO] Seed not used")
return None
if seed != 0:
if 0 < seed < 2**31:
print(f"[INFO] Using specified seed: {seed}")
return seed
generator = torch.Generator(device="cpu")
generator.seed()
if seed == 0:
generator.seed()
else:
generator.manual_seed(seed)
actual_seed = torch.randint(
0, 2147483647, (), generator=generator, device="cpu", dtype=torch.int64
).item()
print(f"[INFO] Generated random seed: {actual_seed}")
print(f"[INFO] Generated API seed: {actual_seed}")
return actual_seed
@classmethod
@@ -872,7 +875,7 @@ class SSL_GeminiTextPrompt(IO.ComfyNode):
cached_gemini_seed = cls._seed_map_cache.get(seed_cache_key)
if cached_gemini_seed is not None:
print(f"[INFO] Using cached successful gemini seed {cached_gemini_seed} for input seed {input_seed}")
actual_seed = cached_gemini_seed
actual_seed = cls._handle_seed(True, cached_gemini_seed)
text_output = ""
thoughts_output = ""
@@ -1101,7 +1104,7 @@ class SSL_GeminiTextPrompt(IO.ComfyNode):
top_p=top_p,
top_k=top_k,
max_output_tokens=max_output_tokens,
seed=api_seed,
seed=actual_seed if use_seed else api_seed,
include_images=include_images,
response_modalities=response_modalities,
aspect_ratio=aspect_ratio,
@@ -1134,6 +1137,9 @@ class SSL_GeminiTextPrompt(IO.ComfyNode):
result_queue: "queue.Queue[Tuple[str, Any]]" = queue.Queue()
def generate_once():
# Apply the wire limit even on legacy unseeded image branches.
if generate_content_config.seed is not None and not -(2**31) <= generate_content_config.seed < 2**31:
generate_content_config.seed = cls._handle_seed(True, generate_content_config.seed)
if not use_cache or skip_context_cache:
return client.models.generate_content(
model=model,
+28
View File
@@ -279,6 +279,34 @@ def test_torch_seed_generation_preserves_request_and_fingerprint(structured_clie
assert torch.equal(before, torch.get_rng_state())
@pytest.mark.parametrize("value", [130610794845696, 450167232274663, 303772010844099, 854079365259032])
@pytest.mark.parametrize("use_cache", [False, True])
def test_high_precision_seed_is_retained_in_fingerprint_but_mapped_for_api(structured_client, use_cache, value):
node = gemini_nodes.SSL_GeminiTextPrompt
args = _execute_kwargs(_config(use_cache=use_cache, cache_seed=value))
args.update(use_seed=True, seed=value)
first = node.execute(**args)
wire_seed = structured_client.calls[-1]["config"].seed
assert 0 <= wire_seed < 2**31
assert first[2] == wire_seed
fingerprint = next(iter(node._cache))
assert fingerprint[14] == value
if use_cache:
assert fingerprint[17] == value
node.execute(**args)
assert len(structured_client.calls) == 1
node._cache.clear()
assert node.execute(**args)[2] == wire_seed
assert structured_client.calls[-1]["config"].seed == wire_seed
def test_unseeded_image_branch_also_respects_wire_seed_range(structured_client):
args = _execute_kwargs(_config())
args.update(model="gemini-3-pro-image", include_images=True, use_seed=False, seed=854079365259032)
gemini_nodes.SSL_GeminiTextPrompt.execute(**args)
assert 0 <= structured_client.calls[-1]["config"].seed < 2**31
def _execute_kwargs(config):
return {
"config": config,