Compare commits

..
2 Commits
Author SHA1 Message Date
Daisy d188a3764b chore(release): 1.9.1 [skip ci]
## [1.9.1](https://github.com/Artificial-Sweetener/SimpleSyrup/compare/v1.9.0...v1.9.1) (2026-09-20)

### Bug Fixes

* **contextual-diffusion:** project reference latents into views ([4cd780a](https://github.com/Artificial-Sweetener/SimpleSyrup/commit/4cd780a2451aa472ce826834e4426b65693c46e8))
2026-09-20 02:14:41 +00:00
Artificial Sweetener f1d0630729 fix(contextual-diffusion): project reference latents into views 2026-09-19 22:06:33 -04:00
10 changed files with 87 additions and 16 deletions
+7
View File
@@ -1,3 +1,10 @@
## [1.9.1](https://github.com/Artificial-Sweetener/SimpleSyrup/compare/v1.9.0...v1.9.1) (2026-09-20)
### Bug Fixes
* **contextual-diffusion:** project reference latents into views ([4cd780a](https://github.com/Artificial-Sweetener/SimpleSyrup/commit/4cd780a2451aa472ce826834e4426b65693c46e8))
# [1.9.0](https://github.com/Artificial-Sweetener/SimpleSyrup/compare/v1.8.0...v1.9.0) (2026-09-19)
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "simple-syrup-comfyui",
"version": "1.9.0",
"version": "1.9.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "simple-syrup-comfyui",
"version": "1.9.0",
"version": "1.9.1",
"license": "AGPL-3.0-or-later",
"devDependencies": {
"@eslint/js": "^9.39.1",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "simple-syrup-comfyui",
"version": "1.9.0",
"version": "1.9.1",
"private": true,
"license": "AGPL-3.0-or-later",
"type": "module",
+1 -1
View File
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "SimpleSyrup"
description = "Workflow-focused ComfyUI extensions for image generation."
version = "1.9.0"
version = "1.9.1"
license = "AGPL-3.0-or-later"
license-files = ["LICENSE"]
requires-python = ">=3.11"
+1 -1
View File
@@ -6,6 +6,6 @@
from __future__ import annotations
__version__ = "1.9.0"
__version__ = "1.9.1"
__all__: list[str] = ["__version__"]
@@ -49,6 +49,7 @@ class ContextualDiffusionModelWrapper:
self._tile_predictions = TilePredictionAccumulator(
plan.tile_plan,
diffusion_mode=diffusion_mode,
project_canvas_reference_latents=True,
)
@property
@@ -110,6 +111,7 @@ class ContextualDiffusionModelWrapper:
global_args = make_spatial_view_model_args(
args=args,
layout=global_layout,
project_canvas_reference_latents=True,
)
global_prediction = self._call_original(apply_model, global_args)
global_view = self._plan.global_view
@@ -34,8 +34,9 @@ def make_tiled_model_args(
input_batch_size: int,
latent_height: int,
latent_width: int,
project_canvas_reference_latents: bool = False,
) -> dict[str, Any]:
"""Create apply-model args for one spatial tile batch."""
"""Create tile arguments with optional canvas-reference projection."""
layout = tiled_batch_layout(
tiles=tiles,
@@ -63,6 +64,7 @@ def make_tiled_model_args(
conditioning=conditioning,
layout=layout,
view_timestep=tiled_timestep,
project_canvas_reference_latents=project_canvas_reference_latents,
)
tiled_args = args.copy()
tiled_args["input"] = tiled_x
@@ -114,8 +116,9 @@ def make_spatial_view_model_args(
*,
args: dict[str, Any],
layout: SpatialBatchLayout,
project_canvas_reference_latents: bool = False,
) -> dict[str, Any]:
"""Create apply-model arguments for equally shaped spatial views."""
"""Create equal-view arguments with optional canvas-reference projection."""
target_shape = (layout.views[0].model_height, layout.views[0].model_width)
if any(
@@ -149,6 +152,7 @@ def make_spatial_view_model_args(
conditioning=conditioning,
layout=layout,
view_timestep=view_timestep,
project_canvas_reference_latents=project_canvas_reference_latents,
)
view_args = args.copy()
view_args["input"] = view_x
@@ -172,14 +176,18 @@ def spatial_view_conditioning(
conditioning: dict[str, Any],
layout: SpatialBatchLayout,
view_timestep: torch.Tensor,
project_canvas_reference_latents: bool = False,
) -> dict[str, Any]:
"""Resize spatial conditioning alongside arbitrary latent views."""
"""Project spatial conditioning and optionally canvas-aligned references."""
transformed: dict[str, Any] = {}
for key, value in conditioning.items():
if key == "transformer_options":
continue
if key in SPATIAL_INVARIANT_CONDITIONING_KEYS:
if (
key in SPATIAL_INVARIANT_CONDITIONING_KEYS
and not project_canvas_reference_latents
):
transformed[key] = repeat_spatial_invariant_value(
value,
view_count=layout.view_count,
@@ -158,11 +158,18 @@ class TileBlendWeightCache:
class TilePredictionAccumulator:
"""Evaluate tiled model views and combine them with one selected policy."""
def __init__(self, plan: TiledDiffusionPlan, *, diffusion_mode: str) -> None:
"""Bind an immutable plan to its overlap weighting policy."""
def __init__(
self,
plan: TiledDiffusionPlan,
*,
diffusion_mode: str,
project_canvas_reference_latents: bool = False,
) -> None:
"""Bind a plan to its weighting and reference-projection policies."""
self._plan = plan
self._blend_weights = TileBlendWeightCache(plan, diffusion_mode)
self._project_canvas_reference_latents = project_canvas_reference_latents
def predict(
self,
@@ -183,6 +190,9 @@ class TilePredictionAccumulator:
input_batch_size=input_batch_size,
latent_height=self._plan.latent_height,
latent_width=self._plan.latent_width,
project_canvas_reference_latents=(
self._project_canvas_reference_latents
),
)
tile_output = evaluate(tiled_args)
for index, tile in enumerate(batch):
+18 -5
View File
@@ -182,11 +182,16 @@ def test_global_call_uses_one_full_source_reduced_model_layout(
*,
args: dict[str, Any],
layout: SpatialBatchLayout,
project_canvas_reference_latents: bool = False,
) -> dict[str, Any]:
"""Capture and apply the global model-argument layout."""
layouts.append(layout)
return transform(args=args, layout=layout)
return transform(
args=args,
layout=layout,
project_canvas_reference_latents=project_canvas_reference_latents,
)
monkeypatch.setattr(
wrapper_module,
@@ -389,8 +394,8 @@ def test_weighted_correction_formula_is_exact_for_both_local_fusion_modes(
assert torch.allclose(output[:, :, 1::2], torch.full((1, 1, 8, 32), 0.5))
def test_local_and_global_calls_receive_complete_reference_latents() -> None:
"""Keep independent reference images intact through both spatial views."""
def test_local_and_global_calls_project_canvas_reference_latents() -> None:
"""Give every Contextual Diffusion view its spatially aligned reference."""
reference = torch.arange(1 * 4 * 16 * 32, dtype=torch.float32).reshape(
(1, 4, 16, 32)
@@ -419,8 +424,16 @@ def test_local_and_global_calls_receive_complete_reference_latents() -> None:
)
assert len(received) == 2
assert torch.equal(received[0], torch.cat((reference, reference), dim=0))
assert torch.equal(received[1], reference)
assert torch.equal(
received[0],
torch.cat((reference[..., :16], reference[..., 16:]), dim=0),
)
expected_global = torch.nn.functional.interpolate(
reference.reshape(-1, 1, 16, 32),
size=(8, 16),
mode="nearest-exact",
).reshape(1, 4, 8, 16)
assert torch.equal(received[1], expected_global)
def test_one_tile_plan_delegates_to_one_original_evaluation() -> None:
@@ -144,6 +144,37 @@ def test_spatial_args_preserve_batch_metadata_references_and_source_args() -> No
assert "spatial_batch_layout" not in existing_namespace
def test_spatial_args_project_canvas_reference_latents_when_requested() -> None:
"""Crop canvas-aligned references while preserving independent references."""
canvas_reference = torch.arange(1 * 2 * 4 * 8, dtype=torch.float32).reshape(
(1, 2, 4, 8)
)
independent_reference = torch.full((1, 2, 3, 5), 7.0)
layout = _layout(_left_right_views(), input_batch_size=1)
transformed = make_spatial_view_model_args(
args={
"input": torch.zeros((1, 1, 4, 8)),
"timestep": torch.ones((1,)),
"c": {"ref_latents": [canvas_reference, independent_reference]},
},
layout=layout,
project_canvas_reference_latents=True,
)
references = transformed["c"]["ref_latents"]
assert isinstance(references, list)
assert torch.equal(
references[0],
torch.cat((canvas_reference[..., :4], canvas_reference[..., 4:]), dim=0),
)
assert torch.equal(
references[1],
torch.cat((independent_reference, independent_reference), dim=0),
)
@pytest.mark.parametrize(
("transformer_options", "message"),
[