Files
Artificial-Sweetener-Simple…/simple_syrup/runtime/guided_sampling.py
T
Artificial Sweetener 027efb8eef feat(latent): add learned upscaling and captured noise reuse
Add provenance recovery, coordinated native sampler-state capture, frequency-completed noise reuse, and optional full-resolution inversion finishing. Support automatic SesquiLSR selection and native bislerp fallback for unknown latents.

Verify exported Anima and Krea CD workflows with zero VAE encodes. Finishing outputs reproduce prior images exactly; reuse-only outputs match independent references at the agreed capture coordinates. All 3813 Python tests and 115 frontend tests pass alongside required quality gates.
2026-10-04 00:14:54 -04:00

149 lines
4.5 KiB
Python

# SimpleSyrup - workflow-focused ComfyUI extensions for image generation
# Copyright (C) 2026 Artificial Sweetener and contributors
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Select ComfyUI's CFG or positive-only guider for latent sampling."""
from __future__ import annotations
from importlib import import_module
from typing import Any, cast
import torch
from ..domain.noise_inversion import NoiseInversionOptions
from ..shared.logging import get_logger
from .noise_inversion import InversionModelFactory, invert_sampling_noise
from .noise_reuse_sampling import prepare_reused_noise
from .noise_reuse_scope import current_noise_reuse
LOGGER = get_logger(__name__)
def sample_with_optional_negative(
*,
comfy_sample: Any,
model: Any,
noise: torch.Tensor,
cfg: float,
sampler: Any,
sigmas: torch.Tensor,
positive: Any,
negative: Any | None,
latent_image: torch.Tensor,
noise_mask: Any = None,
callback: Any = None,
disable_pbar: bool = False,
seed: int | None = None,
noise_inversion: NoiseInversionOptions | None = None,
inversion_model_factory: InversionModelFactory | None = None,
) -> torch.Tensor:
"""Prepare optional source-derived noise and select the actual Comfy guider."""
reuse = current_noise_reuse()
if reuse is not None:
if noise_inversion is not None:
raise ValueError(
"Noise reuse and full noise inversion cannot own the same "
"sampling pass."
)
noise, expected = prepare_reused_noise(
execution=reuse,
model=model,
fresh=noise,
latent=latent_image,
sigmas=sigmas,
positive=positive,
negative=negative,
cfg=cfg,
seed=seed,
noise_mask=noise_mask,
model_factory=inversion_model_factory,
)
original_callback = callback
def observe_start(
step: int, denoised: torch.Tensor, state: torch.Tensor, total: int
) -> None:
"""Check the actual first state to catch double-noising or schedule
mismatch.
"""
if step == 0 and noise_mask is None:
error = float((state.detach().float().cpu() - expected).abs().max())
if error > 2e-5:
raise ValueError(
f"Noise reuse starting state differs from native "
f"reconstruction: {error:.6g}."
)
LOGGER.info(
"Noise reuse starting state verified",
extra={"operation": "noise_reuse_start", "max_error": error},
)
if original_callback is not None:
original_callback(step, denoised, state, total)
callback = observe_start
if noise_inversion is not None:
inversion = invert_sampling_noise(
model=model,
latent=latent_image,
forward_sigmas=sigmas,
positive=positive,
negative=negative,
cfg=cfg,
seed=seed,
options=noise_inversion,
model_factory=inversion_model_factory,
noise_mask=noise_mask,
)
noise = inversion.noise.to(noise)
if negative is not None:
return cast(
torch.Tensor,
comfy_sample.sample_custom(
model,
noise,
cfg,
sampler,
sigmas,
positive,
negative,
latent_image,
noise_mask=noise_mask,
callback=callback,
disable_pbar=disable_pbar,
seed=seed,
),
)
comfy_samplers = import_module("comfy.samplers")
model_management = import_module("comfy.model_management")
guider = comfy_samplers.CFGGuider(model)
guider.inner_set_conds({"positive": positive})
samples = guider.sample(
noise,
latent_image,
sampler,
sigmas,
denoise_mask=noise_mask,
callback=callback,
disable_pbar=disable_pbar,
seed=seed,
)
LOGGER.debug(
"Positive-only ComfyUI guider selected",
extra={
"operation": "sample_with_optional_negative",
"guidance_mode": "positive_only",
},
)
return cast(
torch.Tensor,
samples.to(
device=model_management.intermediate_device(),
dtype=model_management.intermediate_dtype(),
),
)