mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-05-30 10:57:23 +08:00
Merge branch 'master' into feat/load3d-model-info-output
Some checks are pending
Python Linting / Run Ruff (push) Waiting to run
Python Linting / Run Pylint (push) Waiting to run
Build package / Build Test (3.10) (push) Waiting to run
Build package / Build Test (3.11) (push) Waiting to run
Build package / Build Test (3.12) (push) Waiting to run
Build package / Build Test (3.13) (push) Waiting to run
Build package / Build Test (3.14) (push) Waiting to run
Some checks are pending
Python Linting / Run Ruff (push) Waiting to run
Python Linting / Run Pylint (push) Waiting to run
Build package / Build Test (3.10) (push) Waiting to run
Build package / Build Test (3.11) (push) Waiting to run
Build package / Build Test (3.12) (push) Waiting to run
Build package / Build Test (3.13) (push) Waiting to run
Build package / Build Test (3.14) (push) Waiting to run
This commit is contained in:
commit
d9caddfcfc
24
.github/workflows/detect-unreviewed-merge.yml
vendored
Normal file
24
.github/workflows/detect-unreviewed-merge.yml
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
name: Detect Unreviewed Merge
|
||||
|
||||
# SOC 2 compliance — reusable workflow lives in Comfy-Org/github-workflows,
|
||||
# tracking issues are filed in Comfy-Org/unreviewed-merges.
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
|
||||
concurrency:
|
||||
group: detect-unreviewed-merge-${{ github.sha }}
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
detect:
|
||||
uses: Comfy-Org/github-workflows/.github/workflows/detect-unreviewed-merge.yml@4d9cb6b87f953bb7cd69954280e1465fb9bd2040 # v1
|
||||
with:
|
||||
approval-mode: latest-per-reviewer
|
||||
secrets:
|
||||
UNREVIEWED_MERGES_TOKEN: ${{ secrets.UNREVIEWED_MERGES_TOKEN }}
|
||||
@ -762,17 +762,17 @@ class Accumulation(ComfyTypeIO):
|
||||
@comfytype(io_type="LOAD3D_CAMERA")
|
||||
class Load3DCamera(ComfyTypeIO):
|
||||
class CameraInfo(TypedDict):
|
||||
position: dict[str, float | int]
|
||||
target: dict[str, float | int]
|
||||
zoom: int
|
||||
cameraType: str
|
||||
quaternion: NotRequired[dict[str, float | int]]
|
||||
rotation: NotRequired[dict[str, float | int | str]]
|
||||
fov: NotRequired[float | int]
|
||||
aspect: NotRequired[float | int]
|
||||
near: NotRequired[float | int]
|
||||
far: NotRequired[float | int]
|
||||
frustum: NotRequired[dict[str, float | int]]
|
||||
# Coordinate system: right-handed, Y-up, camera looks down -Z
|
||||
position: dict[str, float | int] # scene units
|
||||
target: dict[str, float | int] # scene units; OrbitControls focus point
|
||||
zoom: float | int # dimensionless, 1 = 100%
|
||||
cameraType: str # 'perspective' | 'orthographic'
|
||||
quaternion: NotRequired[dict[str, float | int]] # normalized, dimensionless; camera world rotation
|
||||
fov: NotRequired[float | int] # degrees, vertical FOV (perspective only)
|
||||
aspect: NotRequired[float | int] # width / height (perspective only)
|
||||
near: NotRequired[float | int] # scene units
|
||||
far: NotRequired[float | int] # scene units
|
||||
frustum: NotRequired[dict[str, float | int]] # orthographic only: {left, right, top, bottom} in scene units
|
||||
|
||||
Type = CameraInfo
|
||||
|
||||
|
||||
@ -206,7 +206,7 @@ class BeebleSwitchXVideoEdit(IO.ComfyNode):
|
||||
return IO.Schema(
|
||||
node_id="BeebleSwitchXVideoEdit",
|
||||
display_name="Beeble SwitchX Video Edit",
|
||||
category="api node/video/Beeble",
|
||||
category="video/partner/Beeble",
|
||||
description=(
|
||||
"Edit a video with Beeble SwitchX. Switches anything in the scene (background, "
|
||||
"lighting, costume) while preserving the original subject's pixels and motion. "
|
||||
@ -302,7 +302,7 @@ class BeebleSwitchXImageEdit(IO.ComfyNode):
|
||||
return IO.Schema(
|
||||
node_id="BeebleSwitchXImageEdit",
|
||||
display_name="Beeble SwitchX Image Edit",
|
||||
category="api node/image/Beeble",
|
||||
category="image/partner/Beeble",
|
||||
description=(
|
||||
"Edit a single image with Beeble SwitchX. Switches anything in the scene "
|
||||
"(background, lighting, costume) while preserving the original subject's pixels. "
|
||||
|
||||
@ -157,7 +157,7 @@ class LoadImageTextDataSetFromFolderNode(io.ComfyNode):
|
||||
return io.NodeOutput(output_tensor, captions)
|
||||
|
||||
|
||||
def save_images_to_folder(image_list, output_dir, prefix="image"):
|
||||
def save_images_to_folder(image_list, output_dir, prefix="image", overwrite=True):
|
||||
"""Utility function to save a list of image tensors to disk.
|
||||
|
||||
Args:
|
||||
@ -197,7 +197,11 @@ def save_images_to_folder(image_list, output_dir, prefix="image"):
|
||||
raise ValueError(f"Expected torch.Tensor, got {type(img_tensor)}")
|
||||
|
||||
# Save image
|
||||
filename = f"{prefix}_{idx:05d}.png"
|
||||
if overwrite:
|
||||
filename = f"{prefix}_{idx:05d}.png"
|
||||
else:
|
||||
_, _, counter, _, resolved_prefix = folder_paths.get_save_image_path(prefix, output_dir)
|
||||
filename = f"{resolved_prefix}_{counter:05}_{idx:05d}.png"
|
||||
filepath = os.path.join(output_dir, filename)
|
||||
img.save(filepath)
|
||||
saved_files.append(filename)
|
||||
@ -230,19 +234,26 @@ class SaveImageDataSetToFolderNode(io.ComfyNode):
|
||||
tooltip="Prefix for saved image filenames.",
|
||||
advanced=True,
|
||||
),
|
||||
io.Combo.Input(
|
||||
"mode",
|
||||
default="overwrite",
|
||||
options=["overwrite", "increment"],
|
||||
tooltip="Whether to overwrite existing files or increment filenames to avoid overwriting."
|
||||
),
|
||||
],
|
||||
outputs=[],
|
||||
is_deprecated=True, # This node is redundant and superseded by existing Save Image nodes where the target folder can be specified in the filename_prefix
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, images, folder_name, filename_prefix):
|
||||
def execute(cls, images, folder_name, filename_prefix, mode):
|
||||
# Extract scalar values
|
||||
folder_name = folder_name[0]
|
||||
filename_prefix = filename_prefix[0]
|
||||
mode = mode[0]
|
||||
|
||||
output_dir = os.path.join(folder_paths.get_output_directory(), folder_name)
|
||||
saved_files = save_images_to_folder(images, output_dir, filename_prefix)
|
||||
saved_files = save_images_to_folder(images, output_dir, filename_prefix, mode=='overwrite')
|
||||
|
||||
logging.info(f"Saved {len(saved_files)} images to {output_dir}.")
|
||||
return io.NodeOutput()
|
||||
@ -278,18 +289,25 @@ class SaveImageTextDataSetToFolderNode(io.ComfyNode):
|
||||
tooltip="Prefix for saved image filenames.",
|
||||
advanced=True,
|
||||
),
|
||||
io.Combo.Input(
|
||||
"mode",
|
||||
default="overwrite",
|
||||
options=["overwrite", "increment"],
|
||||
tooltip="Whether to overwrite existing files or increment filenames to avoid overwriting."
|
||||
),
|
||||
],
|
||||
outputs=[],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, images, folder_name, filename_prefix, texts=None):
|
||||
def execute(cls, images, folder_name, filename_prefix, mode, texts=None):
|
||||
# Extract scalar values
|
||||
folder_name = folder_name[0]
|
||||
filename_prefix = filename_prefix[0]
|
||||
mode = mode[0]
|
||||
|
||||
output_dir = os.path.join(folder_paths.get_output_directory(), folder_name)
|
||||
saved_files = save_images_to_folder(images, output_dir, filename_prefix)
|
||||
saved_files = save_images_to_folder(images, output_dir, filename_prefix, mode=='overwrite')
|
||||
|
||||
# Save captions
|
||||
if texts:
|
||||
|
||||
@ -21,7 +21,7 @@ psutil
|
||||
alembic
|
||||
SQLAlchemy>=2.0.0
|
||||
filelock
|
||||
av>=14.2.0
|
||||
av>=16.0.0
|
||||
comfy-kitchen>=0.2.8
|
||||
comfy-aimdo==0.4.5
|
||||
requests
|
||||
|
||||
Loading…
Reference in New Issue
Block a user