|
|
from __future__ import annotations |
|
|
|
|
|
from abc import ABC, abstractmethod |
|
|
from typing import Type, 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 comfy_api.latest._input import ImageInput, AudioInput, MaskInput, LatentInput, VideoInput |
|
|
from comfy_api.latest._input_impl import VideoFromFile, VideoFromComponents |
|
|
from comfy_api.latest._util import VideoCodec, VideoContainer, VideoComponents |
|
|
from . import _io as io |
|
|
from . import _ui 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") |
|
|
|
|
|
|
|
|
to_display: PreviewImageTuple | Image.Image | ImageInput | None = preview_image |
|
|
if to_display is not None: |
|
|
|
|
|
if isinstance(to_display, ImageInput): |
|
|
|
|
|
|
|
|
tensor = to_display |
|
|
if len(tensor.shape) == 4: |
|
|
tensor = tensor[0] |
|
|
|
|
|
|
|
|
image_np = (tensor.cpu().numpy() * 255).astype(np.uint8) |
|
|
to_display = Image.fromarray(image_np) |
|
|
|
|
|
if isinstance(to_display, Image.Image): |
|
|
|
|
|
image_format = to_display.format if to_display.format else "JPEG" |
|
|
|
|
|
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 neeeded 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 |
|
|
|
|
|
ComfyAPI = ComfyAPI_latest |
|
|
|
|
|
|
|
|
if TYPE_CHECKING: |
|
|
import comfy_api.latest.generated.ComfyAPISyncStub |
|
|
|
|
|
ComfyAPISync: Type[comfy_api.latest.generated.ComfyAPISyncStub.ComfyAPISyncStub] |
|
|
ComfyAPISync = create_sync_class(ComfyAPI_latest) |
|
|
|
|
|
|
|
|
IO = io |
|
|
UI = ui |
|
|
|
|
|
__all__ = [ |
|
|
"ComfyAPI", |
|
|
"ComfyAPISync", |
|
|
"Input", |
|
|
"InputImpl", |
|
|
"Types", |
|
|
"ComfyExtension", |
|
|
"io", |
|
|
"IO", |
|
|
"ui", |
|
|
"UI", |
|
|
] |
|
|
|