mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-01-03 02:30:52 +08:00
* Support Combo outputs in a more sane way * Remove test validate_inputs function on test node * Make curr_prefix be a list of strings instead of string for easier parsing as keys get added to dynamic types * Start to account for id prefixes from frontend, need to fix bug with nested dynamics * Ensure inputs/outputs/hidden are lists in schema finalize function, remove no longer needed 'is not None' checks * Add raw_link and extra_dict to all relevant Inputs * Make nested DynamicCombos work properly with prefixed keys on latest frontend; breaks old Autogrow, but is pretty much ready for upcoming Autogrow keys * Replace ... usage with a MISSING sentinel for clarity in nodes_logic.py * Added CustomCombo node in backend to reflect frontend node * Prepare Autogrow's expand_schema_for_dynamic to work with upcoming frontend changes * Prepare for look up table for dynamic input stuff * More progress towards dynamic input lookup function stuff * Finished converting _expand_schema_for_dynamic to be done via lookup instead of OOP to guarantee working with process isolation, did refactoring to remove old implementation + cleaning INPUT_TYPES definition including v3 hidden definition * Change order of functions * Removed some unneeded functions after dynamic refactor * Make MatchType's output default displayname "MATCHTYPE" * Fix DynamicSlot get_all * Removed redundant code - dynamic stuff no longer happens in OOP way * Natively support AnyType (*) without __ne__ hacks * Remove stray code that made it in * Remove expand_schema_for_dynamic left over on DynamicInput class * get_dynamic() on DynamicInput/Output was not doing anything anymore, so removed it * Make validate_inputs validate combo input correctly * Temporarily comment out conversion to 'new' (9 month old) COMBO format in get_input_info * Remove refrences to resources feature scrapped from V3 * Expose DynamicCombo in public API * satisfy ruff after some code got commented out * Make missing input error prettier for dynamic types * Created a Switch2 node as a side-by-side test, will likely go with Switch2 as the initial switch node * Figured out Switch situation * Pass in v3_data in IsChangedCache.get function's fingerprint_inputs, add a from_v3_data helper method to HiddenHolder * Switch order of Switch and Soft Switch nodes in file * Temp test node for MatchType * Fix missing v3_data for v1 nodes in validation * For now, remove chacking duplicate id's for dynamic types * Add Resize Image/Mask node that thanks to MatchType+DynamicCombo is 16-nodes-in-1 * Made DynamicCombo references in DCTestNode use public interface * Add an AnyTypeTestNode * Make lazy status for specific inputs on DynamicInputs work by having the values of the dictionary for check_lazy_status be a tuple, where the second element is the key of the input that can be returned * Comment out test logic nodes * Make primitive float's step make more sense * Add (and leave commented out) some potential logic nodes * Change default crop option to "center" on Resize Image/Mask node * Changed copy.copy(d) to d.copy() * Autogrow is available in stable frontend, so exposing it in public API * Use outputs id as display_name if no display_name present, remove v3 outputs id restriction that made them have to have unique IDs from the inputs * Enable Custom Combo node as stable frontend now supports it * Make id properly act like display_name on outputs * Add Batch Images/Masks/Latents node * Comment out Batch Images/Masks/Latents node for now, as Autogrow has a bug with MatchType where top connection is disconnected upon refresh * Removed code for a couple test nodes in nodes_logic.py * Add Batch Images, Batch Masks, and Batch Latents nodes with Autogrow, deprecate old Batch Images + LatentBatch nodes
134 lines
4.4 KiB
Python
134 lines
4.4 KiB
Python
from __future__ import annotations
|
|
|
|
from abc import ABC, abstractmethod
|
|
from typing import TYPE_CHECKING
|
|
from comfy_api.internal import ComfyAPIBase
|
|
from comfy_api.internal.singleton import ProxiedSingleton
|
|
from comfy_api.internal.async_to_sync import create_sync_class
|
|
from ._input import ImageInput, AudioInput, MaskInput, LatentInput, VideoInput
|
|
from ._input_impl import VideoFromFile, VideoFromComponents
|
|
from ._util import VideoCodec, VideoContainer, VideoComponents, MESH, VOXEL
|
|
from . import _io_public as io
|
|
from . import _ui_public as ui
|
|
from comfy_execution.utils import get_executing_context
|
|
from comfy_execution.progress import get_progress_state, PreviewImageTuple
|
|
from PIL import Image
|
|
from comfy.cli_args import args
|
|
import numpy as np
|
|
|
|
|
|
class ComfyAPI_latest(ComfyAPIBase):
|
|
VERSION = "latest"
|
|
STABLE = False
|
|
|
|
class Execution(ProxiedSingleton):
|
|
async def set_progress(
|
|
self,
|
|
value: float,
|
|
max_value: float,
|
|
node_id: str | None = None,
|
|
preview_image: Image.Image | ImageInput | None = None,
|
|
ignore_size_limit: bool = False,
|
|
) -> None:
|
|
"""
|
|
Update the progress bar displayed in the ComfyUI interface.
|
|
|
|
This function allows custom nodes and API calls to report their progress
|
|
back to the user interface, providing visual feedback during long operations.
|
|
|
|
Migration from previous API: comfy.utils.PROGRESS_BAR_HOOK
|
|
"""
|
|
executing_context = get_executing_context()
|
|
if node_id is None and executing_context is not None:
|
|
node_id = executing_context.node_id
|
|
if node_id is None:
|
|
raise ValueError("node_id must be provided if not in executing context")
|
|
|
|
# Convert preview_image to PreviewImageTuple if needed
|
|
to_display: PreviewImageTuple | Image.Image | ImageInput | None = preview_image
|
|
if to_display is not None:
|
|
# First convert to PIL Image if needed
|
|
if isinstance(to_display, ImageInput):
|
|
# Convert ImageInput (torch.Tensor) to PIL Image
|
|
# Handle tensor shape [B, H, W, C] -> get first image if batch
|
|
tensor = to_display
|
|
if len(tensor.shape) == 4:
|
|
tensor = tensor[0]
|
|
|
|
# Convert to numpy array and scale to 0-255
|
|
image_np = (tensor.cpu().numpy() * 255).astype(np.uint8)
|
|
to_display = Image.fromarray(image_np)
|
|
|
|
if isinstance(to_display, Image.Image):
|
|
# Detect image format from PIL Image
|
|
image_format = to_display.format if to_display.format else "JPEG"
|
|
# Use None for preview_size if ignore_size_limit is True
|
|
preview_size = None if ignore_size_limit else args.preview_size
|
|
to_display = (image_format, to_display, preview_size)
|
|
|
|
get_progress_state().update_progress(
|
|
node_id=node_id,
|
|
value=value,
|
|
max_value=max_value,
|
|
image=to_display,
|
|
)
|
|
|
|
execution: Execution
|
|
|
|
class ComfyExtension(ABC):
|
|
async def on_load(self) -> None:
|
|
"""
|
|
Called when an extension is loaded.
|
|
This should be used to initialize any global resources needed by the extension.
|
|
"""
|
|
|
|
@abstractmethod
|
|
async def get_node_list(self) -> list[type[io.ComfyNode]]:
|
|
"""
|
|
Returns a list of nodes that this extension provides.
|
|
"""
|
|
|
|
class Input:
|
|
Image = ImageInput
|
|
Audio = AudioInput
|
|
Mask = MaskInput
|
|
Latent = LatentInput
|
|
Video = VideoInput
|
|
|
|
class InputImpl:
|
|
VideoFromFile = VideoFromFile
|
|
VideoFromComponents = VideoFromComponents
|
|
|
|
class Types:
|
|
VideoCodec = VideoCodec
|
|
VideoContainer = VideoContainer
|
|
VideoComponents = VideoComponents
|
|
MESH = MESH
|
|
VOXEL = VOXEL
|
|
|
|
ComfyAPI = ComfyAPI_latest
|
|
|
|
# Create a synchronous version of the API
|
|
if TYPE_CHECKING:
|
|
import comfy_api.latest.generated.ComfyAPISyncStub # type: ignore
|
|
|
|
ComfyAPISync: type[comfy_api.latest.generated.ComfyAPISyncStub.ComfyAPISyncStub]
|
|
ComfyAPISync = create_sync_class(ComfyAPI_latest)
|
|
|
|
# create new aliases for io and ui
|
|
IO = io
|
|
UI = ui
|
|
|
|
__all__ = [
|
|
"ComfyAPI",
|
|
"ComfyAPISync",
|
|
"Input",
|
|
"InputImpl",
|
|
"Types",
|
|
"ComfyExtension",
|
|
"io",
|
|
"IO",
|
|
"ui",
|
|
"UI",
|
|
]
|