Backend (Python)
In Blobit, backend nodes must inherit from node_utils.BaseNode. This base class handles data normalization (ensuring everything is a list of frames), progress reporting, and output packing.
Standard Template
Section titled “Standard Template”from node_utils import BaseNode
class MyCustomNode(BaseNode): def execute(self, data: dict, context=None) -> dict: # 1. Get Inputs (Using Standard Helper) # CRITICAL: Use self.get_input() - it checks Inputs > Widgets > Properties input_image = self.get_input(data, "InputImage") strength = self.get_input(data, "Strength", 1.0)
if not input_image: return {"success": False, "log": "No input provided"}
# 2. Normalize to frames (The Production Batch Pattern) # Even if you expect 1 item, always normalize. tl_image = self.normalize_to_frames(input_image)
# 3. Sync Timelines # Ensures all inputs match the "master" length (usually the image count) (s_image, total_frames) = self.sync_to_master(tl_image)
outputs = []
# 4. Iterate (Safe Batch Processing) for i in range(total_frames): self.report_progress((i / total_frames) * 100, f"Processing frame {i+1}/{total_frames}")
# Access safe frame data (handle potential None inputs in batch) img_path = s_image[i][0] if s_image[i] else None
if not img_path: outputs.append(None) continue
try: # 5. Logic # Load Image (handles URL/Path/Tensor automatically) pil_img = self.load_image(img_path)
# ... Do processing ... processed_img = self.do_something(pil_img, strength)
# 6. Save # Saves to temp and returns the HTTP path string saved_path = self.save_image(processed_img, prefix="output") outputs.append(saved_path)
except Exception as e: # Handle individual frame errors without crashing the whole batch print(f"Error frame {i}: {e}") outputs.append(None)
# 7. Pack and Return # Dictionary with "output": [list_of_paths] return self.pack_outputs(outputs)
# Factory function needed for dynamic loadingdef process(data, context=None): return MyCustomNode().process(data, context)Key Methods
Section titled “Key Methods”data Dictionary
Section titled “data Dictionary”The data argument contains all inputs sent from the frontend.
- Widgets: Values from sliders, text boxes.
- Inputs: Data from connected nodes.
self.get_input(data, name, default)
Section titled “self.get_input(data, name, default)”Safely retrieves an input by name. Checks Connections -> Widgets -> Properties -> Root.
threshold = self.get_input(data, "threshold", 0.5)self.normalize_to_frames(input)
Section titled “self.normalize_to_frames(input)”CRITICAL: Converts any input (single string, None, list) into a standard [[item], [item]] batch format.
- If input is
None-> returns[[]]. - If input is
"path/img.png"-> returns[["path/img.png"]]. - If input is
["A", "B"]-> returns[["A"], ["B"]].
Batching & Synchronization
Section titled “Batching & Synchronization”Blobit relies on frame synchronization to handle inputs of varying lengths (e.g., 1 image vs 10 prompts).
self.sync_to_master(master, *others)
Section titled “self.sync_to_master(master, *others)”Synchronizes multiple lists to match the length of the master list.
- Use Case: One primary input (e.g., Image) determines the frame count. Other inputs cycle to match.
(s_img, s_prompts, count) = self.sync_to_master(images, prompts)self.sync_frames(*timelines)
Section titled “self.sync_frames(*timelines)”Synchronizes all inputs to the maximum length found.
- Use Case: All inputs are equal peers. The result length is the maximum length of any input.
(s_img, s_mask, count) = self.sync_frames(images, masks)self.pack_outputs(output_list)
Section titled “self.pack_outputs(output_list)”Formats the result for the frontend.
output_listshould be a list where each element corresponds to an output slot.- Example:
self.pack_outputs(image_results, mask_results)for a node with two outputs.
Helper Functions
Section titled “Helper Functions”Blobit provides a suite of helper functions for data retrieval, file management, and synchronization.