Files
eric-venti-seeds-Sphere-Lig…/tools/test_decode.py
T
Christopher Connock e53f000286 feat: client-side graph-driven inputs (replace the browser round-trip)
The server round-trip (render_bridge + is_driven + send_sync + POST) could never
detect the common driver: ComfyUI inlines a Primitive's value as a literal in the
prompt and strips the node, so is_driven (which looks for a [id,slot] link) was
blind to it — nothing drove. Proven in a live ComfyUI via browser automation.

Replace it with a client-side approach:
- getAngles() reads a connected input's value by following the graph link to its
  source (Primitive/static), else the widget — a connection wins over the control.
- A graphToPrompt wrapper refreshes each node's render_b64 from current values
  before every run, so the driven value (incl. increment animation) is baked into
  the image for that queue. execute() just decodes render_b64, unchanged.
- heading/city (hidden behind the compass/search overlays) are auto-exposed as
  input sockets via convertWidgetToInput, guarded against reload double-convert;
  their manual controls still drive when unconnected. Persistence verified across
  save/reload.

Removes render_bridge.py, js/driven.js, is_driven, the hidden node_id/prompt
inputs, renderWith, and their tests. Verified end-to-end (real queue, output
brightness tracks driven intensity 0.3->133, 3.0->255) in the live ComfyUI.
2026-07-09 21:10:23 -04:00

31 lines
1.1 KiB
Python

import sys, types, importlib.util, os, base64, io
import numpy as np
from PIL import Image
# Stub torch so __init__.py imports without the real dependency.
faketorch = types.ModuleType("torch")
class FT:
def __init__(self, a): self.a = a
def unsqueeze(self, d): return FT(np.expand_dims(self.a, d))
@property
def shape(self): return self.a.shape
faketorch.from_numpy = lambda a: FT(a)
sys.modules["torch"] = faketorch
NODE = os.path.join(os.path.dirname(__file__), "..", "__init__.py")
spec = importlib.util.spec_from_file_location("slnode", NODE)
mod = importlib.util.module_from_spec(spec); spec.loader.exec_module(mod)
# Empty input -> gray fallback, correct shape.
t = mod.decode_render_b64("")
assert tuple(t.shape) == (1, 1024, 1024, 3), t.shape
# A tiny red PNG data-URI decodes to the target size.
buf = io.BytesIO()
Image.new("RGB", (4, 4), (255, 0, 0)).save(buf, format="PNG")
uri = "data:image/png;base64," + base64.b64encode(buf.getvalue()).decode()
t2 = mod.decode_render_b64(uri)
assert tuple(t2.shape) == (1, 1024, 1024, 3), t2.shape
print("test_decode: OK")