mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-04-20 07:22:34 +08:00
Merge upstream/master, keep local README.md
This commit is contained in:
commit
137660ea10
@ -102,19 +102,7 @@ class VideoConv3d(nn.Module):
|
|||||||
return self.conv(x)
|
return self.conv(x)
|
||||||
|
|
||||||
def interpolate_up(x, scale_factor):
|
def interpolate_up(x, scale_factor):
|
||||||
try:
|
return torch.nn.functional.interpolate(x, scale_factor=scale_factor, mode="nearest")
|
||||||
return torch.nn.functional.interpolate(x, scale_factor=scale_factor, mode="nearest")
|
|
||||||
except: #operation not implemented for bf16
|
|
||||||
orig_shape = list(x.shape)
|
|
||||||
out_shape = orig_shape[:2]
|
|
||||||
for i in range(len(orig_shape) - 2):
|
|
||||||
out_shape.append(round(orig_shape[i + 2] * scale_factor[i]))
|
|
||||||
out = torch.empty(out_shape, dtype=x.dtype, layout=x.layout, device=x.device)
|
|
||||||
split = 8
|
|
||||||
l = out.shape[1] // split
|
|
||||||
for i in range(0, out.shape[1], l):
|
|
||||||
out[:,i:i+l] = torch.nn.functional.interpolate(x[:,i:i+l].to(torch.float32), scale_factor=scale_factor, mode="nearest").to(x.dtype)
|
|
||||||
return out
|
|
||||||
|
|
||||||
class Upsample(nn.Module):
|
class Upsample(nn.Module):
|
||||||
def __init__(self, in_channels, with_conv, conv_op=ops.Conv2d, scale_factor=2.0):
|
def __init__(self, in_channels, with_conv, conv_op=ops.Conv2d, scale_factor=2.0):
|
||||||
|
|||||||
@ -374,6 +374,31 @@ def pad_tensor_to_shape(tensor: torch.Tensor, new_shape: list[int]) -> torch.Ten
|
|||||||
|
|
||||||
return padded_tensor
|
return padded_tensor
|
||||||
|
|
||||||
|
def calculate_shape(patches, weight, key, original_weights=None):
|
||||||
|
current_shape = weight.shape
|
||||||
|
|
||||||
|
for p in patches:
|
||||||
|
v = p[1]
|
||||||
|
offset = p[3]
|
||||||
|
|
||||||
|
# Offsets restore the old shape; lists force a diff without metadata
|
||||||
|
if offset is not None or isinstance(v, list):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isinstance(v, weight_adapter.WeightAdapterBase):
|
||||||
|
adapter_shape = v.calculate_shape(key)
|
||||||
|
if adapter_shape is not None:
|
||||||
|
current_shape = adapter_shape
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Standard diff logic with padding
|
||||||
|
if len(v) == 2:
|
||||||
|
patch_type, patch_data = v[0], v[1]
|
||||||
|
if patch_type == "diff" and len(patch_data) > 1 and patch_data[1]['pad_weight']:
|
||||||
|
current_shape = patch_data[0].shape
|
||||||
|
|
||||||
|
return current_shape
|
||||||
|
|
||||||
def calculate_weight(patches, weight, key, intermediate_dtype=torch.float32, original_weights=None):
|
def calculate_weight(patches, weight, key, intermediate_dtype=torch.float32, original_weights=None):
|
||||||
for p in patches:
|
for p in patches:
|
||||||
strength = p[0]
|
strength = p[0]
|
||||||
|
|||||||
@ -1514,8 +1514,10 @@ class ModelPatcherDynamic(ModelPatcher):
|
|||||||
|
|
||||||
weight, _, _ = get_key_weight(self.model, key)
|
weight, _, _ = get_key_weight(self.model, key)
|
||||||
if weight is None:
|
if weight is None:
|
||||||
return 0
|
return (False, 0)
|
||||||
if key in self.patches:
|
if key in self.patches:
|
||||||
|
if comfy.lora.calculate_shape(self.patches[key], weight, key) != weight.shape:
|
||||||
|
return (True, 0)
|
||||||
setattr(m, param_key + "_lowvram_function", LowVramPatch(key, self.patches))
|
setattr(m, param_key + "_lowvram_function", LowVramPatch(key, self.patches))
|
||||||
num_patches += 1
|
num_patches += 1
|
||||||
else:
|
else:
|
||||||
@ -1529,7 +1531,13 @@ class ModelPatcherDynamic(ModelPatcher):
|
|||||||
model_dtype = getattr(m, param_key + "_comfy_model_dtype", None) or weight.dtype
|
model_dtype = getattr(m, param_key + "_comfy_model_dtype", None) or weight.dtype
|
||||||
weight._model_dtype = model_dtype
|
weight._model_dtype = model_dtype
|
||||||
geometry = comfy.memory_management.TensorGeometry(shape=weight.shape, dtype=model_dtype)
|
geometry = comfy.memory_management.TensorGeometry(shape=weight.shape, dtype=model_dtype)
|
||||||
return comfy.memory_management.vram_aligned_size(geometry)
|
return (False, comfy.memory_management.vram_aligned_size(geometry))
|
||||||
|
|
||||||
|
def force_load_param(self, param_key, device_to):
|
||||||
|
key = key_param_name_to_key(n, param_key)
|
||||||
|
if key in self.backup:
|
||||||
|
comfy.utils.set_attr_param(self.model, key, self.backup[key].weight)
|
||||||
|
self.patch_weight_to_device(key, device_to=device_to)
|
||||||
|
|
||||||
if hasattr(m, "comfy_cast_weights"):
|
if hasattr(m, "comfy_cast_weights"):
|
||||||
m.comfy_cast_weights = True
|
m.comfy_cast_weights = True
|
||||||
@ -1537,13 +1545,19 @@ class ModelPatcherDynamic(ModelPatcher):
|
|||||||
m.seed_key = n
|
m.seed_key = n
|
||||||
set_dirty(m, dirty)
|
set_dirty(m, dirty)
|
||||||
|
|
||||||
v_weight_size = 0
|
force_load, v_weight_size = setup_param(self, m, n, "weight")
|
||||||
v_weight_size += setup_param(self, m, n, "weight")
|
force_load_bias, v_weight_bias = setup_param(self, m, n, "bias")
|
||||||
v_weight_size += setup_param(self, m, n, "bias")
|
force_load = force_load or force_load_bias
|
||||||
|
v_weight_size += v_weight_bias
|
||||||
|
|
||||||
if vbar is not None and not hasattr(m, "_v"):
|
if force_load:
|
||||||
m._v = vbar.alloc(v_weight_size)
|
logging.info(f"Module {n} has resizing Lora - force loading")
|
||||||
allocated_size += v_weight_size
|
force_load_param(self, "weight", device_to)
|
||||||
|
force_load_param(self, "bias", device_to)
|
||||||
|
else:
|
||||||
|
if vbar is not None and not hasattr(m, "_v"):
|
||||||
|
m._v = vbar.alloc(v_weight_size)
|
||||||
|
allocated_size += v_weight_size
|
||||||
|
|
||||||
else:
|
else:
|
||||||
for param in params:
|
for param in params:
|
||||||
@ -1606,6 +1620,11 @@ class ModelPatcherDynamic(ModelPatcher):
|
|||||||
for m in self.model.modules():
|
for m in self.model.modules():
|
||||||
move_weight_functions(m, device_to)
|
move_weight_functions(m, device_to)
|
||||||
|
|
||||||
|
keys = list(self.backup.keys())
|
||||||
|
for k in keys:
|
||||||
|
bk = self.backup[k]
|
||||||
|
comfy.utils.set_attr_param(self.model, k, bk.weight)
|
||||||
|
|
||||||
def partially_load(self, device_to, extra_memory=0, force_patch_weights=False):
|
def partially_load(self, device_to, extra_memory=0, force_patch_weights=False):
|
||||||
assert not force_patch_weights #See above
|
assert not force_patch_weights #See above
|
||||||
with self.use_ejected(skip_and_inject_on_exit_only=True):
|
with self.use_ejected(skip_and_inject_on_exit_only=True):
|
||||||
|
|||||||
@ -49,6 +49,12 @@ class WeightAdapterBase:
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def calculate_shape(
|
||||||
|
self,
|
||||||
|
key
|
||||||
|
):
|
||||||
|
return None
|
||||||
|
|
||||||
def calculate_weight(
|
def calculate_weight(
|
||||||
self,
|
self,
|
||||||
weight,
|
weight,
|
||||||
|
|||||||
@ -214,6 +214,13 @@ class LoRAAdapter(WeightAdapterBase):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def calculate_shape(
|
||||||
|
self,
|
||||||
|
key
|
||||||
|
):
|
||||||
|
reshape = self.weights[5]
|
||||||
|
return tuple(reshape) if reshape is not None else None
|
||||||
|
|
||||||
def calculate_weight(
|
def calculate_weight(
|
||||||
self,
|
self,
|
||||||
weight,
|
weight,
|
||||||
|
|||||||
@ -45,17 +45,55 @@ class BriaEditImageRequest(BaseModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class BriaRemoveBackgroundRequest(BaseModel):
|
||||||
|
image: str = Field(...)
|
||||||
|
sync: bool = Field(False)
|
||||||
|
visual_input_content_moderation: bool = Field(
|
||||||
|
False, description="If true, returns 422 on input image moderation failure."
|
||||||
|
)
|
||||||
|
visual_output_content_moderation: bool = Field(
|
||||||
|
False, description="If true, returns 422 on visual output moderation failure."
|
||||||
|
)
|
||||||
|
seed: int = Field(...)
|
||||||
|
|
||||||
|
|
||||||
class BriaStatusResponse(BaseModel):
|
class BriaStatusResponse(BaseModel):
|
||||||
request_id: str = Field(...)
|
request_id: str = Field(...)
|
||||||
status_url: str = Field(...)
|
status_url: str = Field(...)
|
||||||
warning: str | None = Field(None)
|
warning: str | None = Field(None)
|
||||||
|
|
||||||
|
|
||||||
class BriaResult(BaseModel):
|
class BriaRemoveBackgroundResult(BaseModel):
|
||||||
|
image_url: str = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class BriaRemoveBackgroundResponse(BaseModel):
|
||||||
|
status: str = Field(...)
|
||||||
|
result: BriaRemoveBackgroundResult | None = Field(None)
|
||||||
|
|
||||||
|
|
||||||
|
class BriaImageEditResult(BaseModel):
|
||||||
structured_prompt: str = Field(...)
|
structured_prompt: str = Field(...)
|
||||||
image_url: str = Field(...)
|
image_url: str = Field(...)
|
||||||
|
|
||||||
|
|
||||||
class BriaResponse(BaseModel):
|
class BriaImageEditResponse(BaseModel):
|
||||||
status: str = Field(...)
|
status: str = Field(...)
|
||||||
result: BriaResult | None = Field(None)
|
result: BriaImageEditResult | None = Field(None)
|
||||||
|
|
||||||
|
|
||||||
|
class BriaRemoveVideoBackgroundRequest(BaseModel):
|
||||||
|
video: str = Field(...)
|
||||||
|
background_color: str = Field(default="transparent", description="Background color for the output video.")
|
||||||
|
output_container_and_codec: str = Field(...)
|
||||||
|
preserve_audio: bool = Field(True)
|
||||||
|
seed: int = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class BriaRemoveVideoBackgroundResult(BaseModel):
|
||||||
|
video_url: str = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class BriaRemoveVideoBackgroundResponse(BaseModel):
|
||||||
|
status: str = Field(...)
|
||||||
|
result: BriaRemoveVideoBackgroundResult | None = Field(None)
|
||||||
|
|||||||
@ -3,7 +3,11 @@ from typing_extensions import override
|
|||||||
from comfy_api.latest import IO, ComfyExtension, Input
|
from comfy_api.latest import IO, ComfyExtension, Input
|
||||||
from comfy_api_nodes.apis.bria import (
|
from comfy_api_nodes.apis.bria import (
|
||||||
BriaEditImageRequest,
|
BriaEditImageRequest,
|
||||||
BriaResponse,
|
BriaRemoveBackgroundRequest,
|
||||||
|
BriaRemoveBackgroundResponse,
|
||||||
|
BriaRemoveVideoBackgroundRequest,
|
||||||
|
BriaRemoveVideoBackgroundResponse,
|
||||||
|
BriaImageEditResponse,
|
||||||
BriaStatusResponse,
|
BriaStatusResponse,
|
||||||
InputModerationSettings,
|
InputModerationSettings,
|
||||||
)
|
)
|
||||||
@ -11,10 +15,12 @@ from comfy_api_nodes.util import (
|
|||||||
ApiEndpoint,
|
ApiEndpoint,
|
||||||
convert_mask_to_image,
|
convert_mask_to_image,
|
||||||
download_url_to_image_tensor,
|
download_url_to_image_tensor,
|
||||||
get_number_of_images,
|
download_url_to_video_output,
|
||||||
poll_op,
|
poll_op,
|
||||||
sync_op,
|
sync_op,
|
||||||
upload_images_to_comfyapi,
|
upload_image_to_comfyapi,
|
||||||
|
upload_video_to_comfyapi,
|
||||||
|
validate_video_duration,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -73,21 +79,15 @@ class BriaImageEditNode(IO.ComfyNode):
|
|||||||
IO.DynamicCombo.Input(
|
IO.DynamicCombo.Input(
|
||||||
"moderation",
|
"moderation",
|
||||||
options=[
|
options=[
|
||||||
|
IO.DynamicCombo.Option("false", []),
|
||||||
IO.DynamicCombo.Option(
|
IO.DynamicCombo.Option(
|
||||||
"true",
|
"true",
|
||||||
[
|
[
|
||||||
IO.Boolean.Input(
|
IO.Boolean.Input("prompt_content_moderation", default=False),
|
||||||
"prompt_content_moderation", default=False
|
IO.Boolean.Input("visual_input_moderation", default=False),
|
||||||
),
|
IO.Boolean.Input("visual_output_moderation", default=True),
|
||||||
IO.Boolean.Input(
|
|
||||||
"visual_input_moderation", default=False
|
|
||||||
),
|
|
||||||
IO.Boolean.Input(
|
|
||||||
"visual_output_moderation", default=True
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
IO.DynamicCombo.Option("false", []),
|
|
||||||
],
|
],
|
||||||
tooltip="Moderation settings",
|
tooltip="Moderation settings",
|
||||||
),
|
),
|
||||||
@ -127,50 +127,26 @@ class BriaImageEditNode(IO.ComfyNode):
|
|||||||
mask: Input.Image | None = None,
|
mask: Input.Image | None = None,
|
||||||
) -> IO.NodeOutput:
|
) -> IO.NodeOutput:
|
||||||
if not prompt and not structured_prompt:
|
if not prompt and not structured_prompt:
|
||||||
raise ValueError(
|
raise ValueError("One of prompt or structured_prompt is required to be non-empty.")
|
||||||
"One of prompt or structured_prompt is required to be non-empty."
|
|
||||||
)
|
|
||||||
if get_number_of_images(image) != 1:
|
|
||||||
raise ValueError("Exactly one input image is required.")
|
|
||||||
mask_url = None
|
mask_url = None
|
||||||
if mask is not None:
|
if mask is not None:
|
||||||
mask_url = (
|
mask_url = await upload_image_to_comfyapi(cls, convert_mask_to_image(mask), wait_label="Uploading mask")
|
||||||
await upload_images_to_comfyapi(
|
|
||||||
cls,
|
|
||||||
convert_mask_to_image(mask),
|
|
||||||
max_images=1,
|
|
||||||
mime_type="image/png",
|
|
||||||
wait_label="Uploading mask",
|
|
||||||
)
|
|
||||||
)[0]
|
|
||||||
response = await sync_op(
|
response = await sync_op(
|
||||||
cls,
|
cls,
|
||||||
ApiEndpoint(path="proxy/bria/v2/image/edit", method="POST"),
|
ApiEndpoint(path="proxy/bria/v2/image/edit", method="POST"),
|
||||||
data=BriaEditImageRequest(
|
data=BriaEditImageRequest(
|
||||||
instruction=prompt if prompt else None,
|
instruction=prompt if prompt else None,
|
||||||
structured_instruction=structured_prompt if structured_prompt else None,
|
structured_instruction=structured_prompt if structured_prompt else None,
|
||||||
images=await upload_images_to_comfyapi(
|
images=[await upload_image_to_comfyapi(cls, image, wait_label="Uploading image")],
|
||||||
cls,
|
|
||||||
image,
|
|
||||||
max_images=1,
|
|
||||||
mime_type="image/png",
|
|
||||||
wait_label="Uploading image",
|
|
||||||
),
|
|
||||||
mask=mask_url,
|
mask=mask_url,
|
||||||
negative_prompt=negative_prompt if negative_prompt else None,
|
negative_prompt=negative_prompt if negative_prompt else None,
|
||||||
guidance_scale=guidance_scale,
|
guidance_scale=guidance_scale,
|
||||||
seed=seed,
|
seed=seed,
|
||||||
model_version=model,
|
model_version=model,
|
||||||
steps_num=steps,
|
steps_num=steps,
|
||||||
prompt_content_moderation=moderation.get(
|
prompt_content_moderation=moderation.get("prompt_content_moderation", False),
|
||||||
"prompt_content_moderation", False
|
visual_input_content_moderation=moderation.get("visual_input_moderation", False),
|
||||||
),
|
visual_output_content_moderation=moderation.get("visual_output_moderation", False),
|
||||||
visual_input_content_moderation=moderation.get(
|
|
||||||
"visual_input_moderation", False
|
|
||||||
),
|
|
||||||
visual_output_content_moderation=moderation.get(
|
|
||||||
"visual_output_moderation", False
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
response_model=BriaStatusResponse,
|
response_model=BriaStatusResponse,
|
||||||
)
|
)
|
||||||
@ -178,7 +154,7 @@ class BriaImageEditNode(IO.ComfyNode):
|
|||||||
cls,
|
cls,
|
||||||
ApiEndpoint(path=f"/proxy/bria/v2/status/{response.request_id}"),
|
ApiEndpoint(path=f"/proxy/bria/v2/status/{response.request_id}"),
|
||||||
status_extractor=lambda r: r.status,
|
status_extractor=lambda r: r.status,
|
||||||
response_model=BriaResponse,
|
response_model=BriaImageEditResponse,
|
||||||
)
|
)
|
||||||
return IO.NodeOutput(
|
return IO.NodeOutput(
|
||||||
await download_url_to_image_tensor(response.result.image_url),
|
await download_url_to_image_tensor(response.result.image_url),
|
||||||
@ -186,11 +162,167 @@ class BriaImageEditNode(IO.ComfyNode):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class BriaRemoveImageBackground(IO.ComfyNode):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def define_schema(cls):
|
||||||
|
return IO.Schema(
|
||||||
|
node_id="BriaRemoveImageBackground",
|
||||||
|
display_name="Bria Remove Image Background",
|
||||||
|
category="api node/image/Bria",
|
||||||
|
description="Remove the background from an image using Bria RMBG 2.0.",
|
||||||
|
inputs=[
|
||||||
|
IO.Image.Input("image"),
|
||||||
|
IO.DynamicCombo.Input(
|
||||||
|
"moderation",
|
||||||
|
options=[
|
||||||
|
IO.DynamicCombo.Option("false", []),
|
||||||
|
IO.DynamicCombo.Option(
|
||||||
|
"true",
|
||||||
|
[
|
||||||
|
IO.Boolean.Input("visual_input_moderation", default=False),
|
||||||
|
IO.Boolean.Input("visual_output_moderation", default=True),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
tooltip="Moderation settings",
|
||||||
|
),
|
||||||
|
IO.Int.Input(
|
||||||
|
"seed",
|
||||||
|
default=0,
|
||||||
|
min=0,
|
||||||
|
max=2147483647,
|
||||||
|
display_mode=IO.NumberDisplay.number,
|
||||||
|
control_after_generate=True,
|
||||||
|
tooltip="Seed controls whether the node should re-run; "
|
||||||
|
"results are non-deterministic regardless of seed.",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
outputs=[IO.Image.Output()],
|
||||||
|
hidden=[
|
||||||
|
IO.Hidden.auth_token_comfy_org,
|
||||||
|
IO.Hidden.api_key_comfy_org,
|
||||||
|
IO.Hidden.unique_id,
|
||||||
|
],
|
||||||
|
is_api_node=True,
|
||||||
|
price_badge=IO.PriceBadge(
|
||||||
|
expr="""{"type":"usd","usd":0.018}""",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def execute(
|
||||||
|
cls,
|
||||||
|
image: Input.Image,
|
||||||
|
moderation: dict,
|
||||||
|
seed: int,
|
||||||
|
) -> IO.NodeOutput:
|
||||||
|
response = await sync_op(
|
||||||
|
cls,
|
||||||
|
ApiEndpoint(path="/proxy/bria/v2/image/edit/remove_background", method="POST"),
|
||||||
|
data=BriaRemoveBackgroundRequest(
|
||||||
|
image=await upload_image_to_comfyapi(cls, image, wait_label="Uploading image"),
|
||||||
|
sync=False,
|
||||||
|
visual_input_content_moderation=moderation.get("visual_input_moderation", False),
|
||||||
|
visual_output_content_moderation=moderation.get("visual_output_moderation", False),
|
||||||
|
seed=seed,
|
||||||
|
),
|
||||||
|
response_model=BriaStatusResponse,
|
||||||
|
)
|
||||||
|
response = await poll_op(
|
||||||
|
cls,
|
||||||
|
ApiEndpoint(path=f"/proxy/bria/v2/status/{response.request_id}"),
|
||||||
|
status_extractor=lambda r: r.status,
|
||||||
|
response_model=BriaRemoveBackgroundResponse,
|
||||||
|
)
|
||||||
|
return IO.NodeOutput(await download_url_to_image_tensor(response.result.image_url))
|
||||||
|
|
||||||
|
|
||||||
|
class BriaRemoveVideoBackground(IO.ComfyNode):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def define_schema(cls):
|
||||||
|
return IO.Schema(
|
||||||
|
node_id="BriaRemoveVideoBackground",
|
||||||
|
display_name="Bria Remove Video Background",
|
||||||
|
category="api node/video/Bria",
|
||||||
|
description="Remove the background from a video using Bria. ",
|
||||||
|
inputs=[
|
||||||
|
IO.Video.Input("video"),
|
||||||
|
IO.Combo.Input(
|
||||||
|
"background_color",
|
||||||
|
options=[
|
||||||
|
"Black",
|
||||||
|
"White",
|
||||||
|
"Gray",
|
||||||
|
"Red",
|
||||||
|
"Green",
|
||||||
|
"Blue",
|
||||||
|
"Yellow",
|
||||||
|
"Cyan",
|
||||||
|
"Magenta",
|
||||||
|
"Orange",
|
||||||
|
],
|
||||||
|
tooltip="Background color for the output video.",
|
||||||
|
),
|
||||||
|
IO.Int.Input(
|
||||||
|
"seed",
|
||||||
|
default=0,
|
||||||
|
min=0,
|
||||||
|
max=2147483647,
|
||||||
|
display_mode=IO.NumberDisplay.number,
|
||||||
|
control_after_generate=True,
|
||||||
|
tooltip="Seed controls whether the node should re-run; "
|
||||||
|
"results are non-deterministic regardless of seed.",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
outputs=[IO.Video.Output()],
|
||||||
|
hidden=[
|
||||||
|
IO.Hidden.auth_token_comfy_org,
|
||||||
|
IO.Hidden.api_key_comfy_org,
|
||||||
|
IO.Hidden.unique_id,
|
||||||
|
],
|
||||||
|
is_api_node=True,
|
||||||
|
price_badge=IO.PriceBadge(
|
||||||
|
expr="""{"type":"usd","usd":0.14,"format":{"suffix":"/second"}}""",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def execute(
|
||||||
|
cls,
|
||||||
|
video: Input.Video,
|
||||||
|
background_color: str,
|
||||||
|
seed: int,
|
||||||
|
) -> IO.NodeOutput:
|
||||||
|
validate_video_duration(video, max_duration=60.0)
|
||||||
|
response = await sync_op(
|
||||||
|
cls,
|
||||||
|
ApiEndpoint(path="/proxy/bria/v2/video/edit/remove_background", method="POST"),
|
||||||
|
data=BriaRemoveVideoBackgroundRequest(
|
||||||
|
video=await upload_video_to_comfyapi(cls, video),
|
||||||
|
background_color=background_color,
|
||||||
|
output_container_and_codec="mp4_h264",
|
||||||
|
seed=seed,
|
||||||
|
),
|
||||||
|
response_model=BriaStatusResponse,
|
||||||
|
)
|
||||||
|
response = await poll_op(
|
||||||
|
cls,
|
||||||
|
ApiEndpoint(path=f"/proxy/bria/v2/status/{response.request_id}"),
|
||||||
|
status_extractor=lambda r: r.status,
|
||||||
|
response_model=BriaRemoveVideoBackgroundResponse,
|
||||||
|
)
|
||||||
|
return IO.NodeOutput(await download_url_to_video_output(response.result.video_url))
|
||||||
|
|
||||||
|
|
||||||
class BriaExtension(ComfyExtension):
|
class BriaExtension(ComfyExtension):
|
||||||
@override
|
@override
|
||||||
async def get_node_list(self) -> list[type[IO.ComfyNode]]:
|
async def get_node_list(self) -> list[type[IO.ComfyNode]]:
|
||||||
return [
|
return [
|
||||||
BriaImageEditNode,
|
BriaImageEditNode,
|
||||||
|
BriaRemoveImageBackground,
|
||||||
|
BriaRemoveVideoBackground,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -57,7 +57,7 @@ def tensor_to_bytesio(
|
|||||||
image: torch.Tensor,
|
image: torch.Tensor,
|
||||||
*,
|
*,
|
||||||
total_pixels: int | None = 2048 * 2048,
|
total_pixels: int | None = 2048 * 2048,
|
||||||
mime_type: str = "image/png",
|
mime_type: str | None = "image/png",
|
||||||
) -> BytesIO:
|
) -> BytesIO:
|
||||||
"""Converts a torch.Tensor image to a named BytesIO object.
|
"""Converts a torch.Tensor image to a named BytesIO object.
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import logging
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
from comfy_api.latest import ComfyExtension, io
|
from comfy_api.latest import ComfyExtension, io
|
||||||
|
from tqdm.auto import trange
|
||||||
|
|
||||||
CLAMP_QUANTILE = 0.99
|
CLAMP_QUANTILE = 0.99
|
||||||
|
|
||||||
@ -49,12 +50,22 @@ LORA_TYPES = {"standard": LORAType.STANDARD,
|
|||||||
"full_diff": LORAType.FULL_DIFF}
|
"full_diff": LORAType.FULL_DIFF}
|
||||||
|
|
||||||
def calc_lora_model(model_diff, rank, prefix_model, prefix_lora, output_sd, lora_type, bias_diff=False):
|
def calc_lora_model(model_diff, rank, prefix_model, prefix_lora, output_sd, lora_type, bias_diff=False):
|
||||||
comfy.model_management.load_models_gpu([model_diff], force_patch_weights=True)
|
comfy.model_management.load_models_gpu([model_diff])
|
||||||
sd = model_diff.model_state_dict(filter_prefix=prefix_model)
|
sd = model_diff.model_state_dict(filter_prefix=prefix_model)
|
||||||
|
|
||||||
for k in sd:
|
sd_keys = list(sd.keys())
|
||||||
if k.endswith(".weight"):
|
for index in trange(len(sd_keys), unit="weight"):
|
||||||
|
k = sd_keys[index]
|
||||||
|
op_keys = sd_keys[index].rsplit('.', 1)
|
||||||
|
if len(op_keys) < 2 or op_keys[1] not in ["weight", "bias"] or (op_keys[1] == "bias" and not bias_diff):
|
||||||
|
continue
|
||||||
|
op = comfy.utils.get_attr(model_diff.model, op_keys[0])
|
||||||
|
if hasattr(op, "comfy_cast_weights") and not getattr(op, "comfy_patched_weights", False):
|
||||||
|
weight_diff = model_diff.patch_weight_to_device(k, model_diff.load_device, return_weight=True)
|
||||||
|
else:
|
||||||
weight_diff = sd[k]
|
weight_diff = sd[k]
|
||||||
|
|
||||||
|
if op_keys[1] == "weight":
|
||||||
if lora_type == LORAType.STANDARD:
|
if lora_type == LORAType.STANDARD:
|
||||||
if weight_diff.ndim < 2:
|
if weight_diff.ndim < 2:
|
||||||
if bias_diff:
|
if bias_diff:
|
||||||
@ -69,8 +80,8 @@ def calc_lora_model(model_diff, rank, prefix_model, prefix_lora, output_sd, lora
|
|||||||
elif lora_type == LORAType.FULL_DIFF:
|
elif lora_type == LORAType.FULL_DIFF:
|
||||||
output_sd["{}{}.diff".format(prefix_lora, k[len(prefix_model):-7])] = weight_diff.contiguous().half().cpu()
|
output_sd["{}{}.diff".format(prefix_lora, k[len(prefix_model):-7])] = weight_diff.contiguous().half().cpu()
|
||||||
|
|
||||||
elif bias_diff and k.endswith(".bias"):
|
elif bias_diff and op_keys[1] == "bias":
|
||||||
output_sd["{}{}.diff_b".format(prefix_lora, k[len(prefix_model):-5])] = sd[k].contiguous().half().cpu()
|
output_sd["{}{}.diff_b".format(prefix_lora, k[len(prefix_model):-5])] = weight_diff.contiguous().half().cpu()
|
||||||
return output_sd
|
return output_sd
|
||||||
|
|
||||||
class LoraSave(io.ComfyNode):
|
class LoraSave(io.ComfyNode):
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
comfyui-frontend-package==1.38.14
|
comfyui-frontend-package==1.38.14
|
||||||
comfyui-workflow-templates==0.8.38
|
comfyui-workflow-templates==0.8.42
|
||||||
comfyui-embedded-docs==0.4.1
|
comfyui-embedded-docs==0.4.1
|
||||||
torch
|
torch
|
||||||
torchsde
|
torchsde
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user