fix: map high precision seeds to API int32 range
This commit is contained in:
@@ -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
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user