diff --git a/comfy_api_nodes/nodes_bytedance.py b/comfy_api_nodes/nodes_bytedance.py index 486801150636..2de28da29188 100644 --- a/comfy_api_nodes/nodes_bytedance.py +++ b/comfy_api_nodes/nodes_bytedance.py @@ -30,6 +30,7 @@ image_tensor_pair_to_batch, poll_op, sync_op, + upload_image_to_comfyapi, upload_images_to_comfyapi, validate_image_aspect_ratio, validate_image_dimensions, @@ -249,7 +250,7 @@ async def execute( if get_number_of_images(image) != 1: raise ValueError("Exactly one input image is required.") validate_image_aspect_ratio(image, (1, 3), (3, 1)) - source_url = (await upload_images_to_comfyapi(cls, image, max_images=1, mime_type="image/png"))[0] + source_url = await upload_image_to_comfyapi(cls, image, mime_type="image/png") payload = Image2ImageTaskCreationRequest( model=model, prompt=prompt, @@ -702,7 +703,7 @@ async def execute( validate_image_dimensions(image, min_width=300, min_height=300, max_width=6000, max_height=6000) validate_image_aspect_ratio(image, (2, 5), (5, 2), strict=False) # 0.4 to 2.5 - image_url = (await upload_images_to_comfyapi(cls, image, max_images=1))[0] + image_url = await upload_image_to_comfyapi(cls, image) prompt = ( f"{prompt} " f"--resolution {resolution} " diff --git a/comfy_api_nodes/nodes_kling.py b/comfy_api_nodes/nodes_kling.py index 3ec71530b030..1b9b32d61ae1 100644 --- a/comfy_api_nodes/nodes_kling.py +++ b/comfy_api_nodes/nodes_kling.py @@ -71,6 +71,7 @@ sync_op, tensor_to_base64_string, upload_audio_to_comfyapi, + upload_image_to_comfyapi, upload_images_to_comfyapi, upload_video_to_comfyapi, validate_image_aspect_ratio, @@ -958,7 +959,7 @@ async def execute( validate_image_aspect_ratio(first_frame, (1, 2.5), (2.5, 1)) image_list: list[OmniParamImage] = [ OmniParamImage( - image_url=(await upload_images_to_comfyapi(cls, first_frame, wait_label="Uploading first frame"))[0], + image_url=await upload_image_to_comfyapi(cls, first_frame, wait_label="Uploading first frame"), type="first_frame", ) ] @@ -967,7 +968,7 @@ async def execute( validate_image_aspect_ratio(end_frame, (1, 2.5), (2.5, 1)) image_list.append( OmniParamImage( - image_url=(await upload_images_to_comfyapi(cls, end_frame, wait_label="Uploading end frame"))[0], + image_url=await upload_image_to_comfyapi(cls, end_frame, wait_label="Uploading end frame"), type="end_frame", ) ) @@ -2365,7 +2366,7 @@ async def execute( response_model=TaskStatusResponse, data=ImageToVideoWithAudioRequest( model_name=model_name, - image=(await upload_images_to_comfyapi(cls, start_frame))[0], + image=await upload_image_to_comfyapi(cls, start_frame), prompt=prompt, mode=mode, duration=str(duration), @@ -2459,7 +2460,7 @@ async def execute( response_model=TaskStatusResponse, data=MotionControlRequest( prompt=prompt, - image_url=(await upload_images_to_comfyapi(cls, reference_image))[0], + image_url=await upload_image_to_comfyapi(cls, reference_image), video_url=await upload_video_to_comfyapi(cls, reference_video), keep_original_sound="yes" if keep_original_sound else "no", character_orientation=character_orientation, diff --git a/comfy_api_nodes/nodes_ltxv.py b/comfy_api_nodes/nodes_ltxv.py index c6424af92d71..0e6de8c319b7 100644 --- a/comfy_api_nodes/nodes_ltxv.py +++ b/comfy_api_nodes/nodes_ltxv.py @@ -8,7 +8,7 @@ ApiEndpoint, get_number_of_images, sync_op_raw, - upload_images_to_comfyapi, + upload_image_to_comfyapi, validate_string, ) @@ -187,7 +187,7 @@ async def execute( cls, ApiEndpoint("/proxy/ltx/v1/image-to-video", "POST"), data=ExecuteTaskRequest( - image_uri=(await upload_images_to_comfyapi(cls, image, max_images=1, mime_type="image/png"))[0], + image_uri=await upload_image_to_comfyapi(cls, image, mime_type="image/png"), prompt=prompt, model=MODELS_MAP[model], duration=duration, diff --git a/comfy_api_nodes/nodes_luma.py b/comfy_api_nodes/nodes_luma.py index 9ed6cd299396..9109e02d4d58 100644 --- a/comfy_api_nodes/nodes_luma.py +++ b/comfy_api_nodes/nodes_luma.py @@ -30,6 +30,7 @@ download_url_to_video_output, poll_op, sync_op, + upload_image_to_comfyapi, upload_images_to_comfyapi, validate_string, ) @@ -257,8 +258,8 @@ async def _convert_luma_refs(cls, luma_ref: LumaReferenceChain, max_refs: int): luma_urls = [] ref_count = 0 for ref in luma_ref.refs: - download_urls = await upload_images_to_comfyapi(cls, ref.image, max_images=1) - luma_urls.append(download_urls[0]) + download_url = await upload_image_to_comfyapi(cls, ref.image) + luma_urls.append(download_url) ref_count += 1 if ref_count >= max_refs: break @@ -340,8 +341,7 @@ async def execute( image_weight: float, seed, ) -> IO.NodeOutput: - download_urls = await upload_images_to_comfyapi(cls, image, max_images=1) - image_url = download_urls[0] + image_url = await upload_image_to_comfyapi(cls, image) response_api = await sync_op( cls, ApiEndpoint(path="/proxy/luma/generations/image", method="POST"), @@ -589,11 +589,9 @@ async def _convert_to_keyframes( frame0 = None frame1 = None if first_image is not None: - download_urls = await upload_images_to_comfyapi(cls, first_image, max_images=1) - frame0 = LumaImageReference(type="image", url=download_urls[0]) + frame0 = LumaImageReference(type="image", url=await upload_image_to_comfyapi(cls, first_image)) if last_image is not None: - download_urls = await upload_images_to_comfyapi(cls, last_image, max_images=1) - frame1 = LumaImageReference(type="image", url=download_urls[0]) + frame1 = LumaImageReference(type="image", url=await upload_image_to_comfyapi(cls, last_image)) return LumaKeyframes(frame0=frame0, frame1=frame1) diff --git a/comfy_api_nodes/nodes_meshy.py b/comfy_api_nodes/nodes_meshy.py index 740607983d24..428ed8c4e0eb 100644 --- a/comfy_api_nodes/nodes_meshy.py +++ b/comfy_api_nodes/nodes_meshy.py @@ -23,6 +23,7 @@ download_url_to_bytesio, poll_op, sync_op, + upload_image_to_comfyapi, upload_images_to_comfyapi, validate_string, ) @@ -197,7 +198,7 @@ async def execute( if texture_prompt: validate_string(texture_prompt, field_name="texture_prompt", max_length=600) if texture_image is not None: - texture_image_url = (await upload_images_to_comfyapi(cls, texture_image, wait_label="Uploading texture"))[0] + texture_image_url = await upload_image_to_comfyapi(cls, texture_image, wait_label="Uploading texture") response = await sync_op( cls, endpoint=ApiEndpoint(path="/proxy/meshy/openapi/v2/text-to-3d", method="POST"), @@ -344,17 +345,15 @@ async def execute( validate_string(should_texture["texture_prompt"], field_name="texture_prompt", max_length=600) texture_prompt = should_texture["texture_prompt"] if should_texture["texture_image"] is not None: - texture_image_url = ( - await upload_images_to_comfyapi( - cls, should_texture["texture_image"], wait_label="Uploading texture" - ) - )[0] + texture_image_url = await upload_image_to_comfyapi( + cls, should_texture["texture_image"], wait_label="Uploading texture" + ) response = await sync_op( cls, ApiEndpoint(path="/proxy/meshy/openapi/v1/image-to-3d", method="POST"), response_model=MeshyTaskResponse, data=MeshyImageToModelRequest( - image_url=(await upload_images_to_comfyapi(cls, image, wait_label="Uploading base image"))[0], + image_url=await upload_image_to_comfyapi(cls, image, wait_label="Uploading base image"), ai_model=model, topology=should_remesh.get("topology", None), target_polycount=should_remesh.get("target_polycount", None), @@ -505,11 +504,9 @@ async def execute( validate_string(should_texture["texture_prompt"], field_name="texture_prompt", max_length=600) texture_prompt = should_texture["texture_prompt"] if should_texture["texture_image"] is not None: - texture_image_url = ( - await upload_images_to_comfyapi( - cls, should_texture["texture_image"], wait_label="Uploading texture" - ) - )[0] + texture_image_url = await upload_image_to_comfyapi( + cls, should_texture["texture_image"], wait_label="Uploading texture" + ) response = await sync_op( cls, ApiEndpoint(path="/proxy/meshy/openapi/v1/multi-image-to-3d", method="POST"), @@ -595,7 +592,7 @@ async def execute( ) -> IO.NodeOutput: texture_image_url = None if texture_image is not None: - texture_image_url = (await upload_images_to_comfyapi(cls, texture_image, wait_label="Uploading texture"))[0] + texture_image_url = await upload_image_to_comfyapi(cls, texture_image, wait_label="Uploading texture") response = await sync_op( cls, endpoint=ApiEndpoint(path="/proxy/meshy/openapi/v1/rigging", method="POST"), @@ -746,7 +743,7 @@ async def execute( raise ValueError("Either text_style_prompt or image_style is required") image_style_url = None if image_style is not None: - image_style_url = (await upload_images_to_comfyapi(cls, image_style, wait_label="Uploading style"))[0] + image_style_url = await upload_image_to_comfyapi(cls, image_style, wait_label="Uploading style") response = await sync_op( cls, endpoint=ApiEndpoint(path="/proxy/meshy/openapi/v1/retexture", method="POST"), diff --git a/comfy_api_nodes/nodes_minimax.py b/comfy_api_nodes/nodes_minimax.py index b5d0b461fffa..fc72f3db123a 100644 --- a/comfy_api_nodes/nodes_minimax.py +++ b/comfy_api_nodes/nodes_minimax.py @@ -17,7 +17,7 @@ download_url_to_video_output, poll_op, sync_op, - upload_images_to_comfyapi, + upload_image_to_comfyapi, validate_string, ) @@ -39,12 +39,12 @@ async def _generate_mm_video( validate_string(prompt_text, field_name="prompt_text") image_url = None if image is not None: - image_url = (await upload_images_to_comfyapi(cls, image, max_images=1))[0] + image_url = await upload_image_to_comfyapi(cls, image) # TODO: figure out how to deal with subject properly, API returns invalid params when using S2V-01 model subject_reference = None if subject is not None: - subject_url = (await upload_images_to_comfyapi(cls, subject, max_images=1))[0] + subject_url = await upload_image_to_comfyapi(cls, subject) subject_reference = [SubjectReferenceItem(image=subject_url)] response = await sync_op( @@ -384,7 +384,7 @@ async def execute( # upload image, if passed in image_url = None if first_frame_image is not None: - image_url = (await upload_images_to_comfyapi(cls, first_frame_image, max_images=1))[0] + image_url = await upload_image_to_comfyapi(cls, first_frame_image) response = await sync_op( cls, diff --git a/comfy_api_nodes/nodes_moonvalley.py b/comfy_api_nodes/nodes_moonvalley.py index 08315fa2bb5d..5b32aab810f7 100644 --- a/comfy_api_nodes/nodes_moonvalley.py +++ b/comfy_api_nodes/nodes_moonvalley.py @@ -16,7 +16,7 @@ poll_op, sync_op, trim_video, - upload_images_to_comfyapi, + upload_image_to_comfyapi, upload_video_to_comfyapi, validate_container_format_is_mp4, validate_image_dimensions, @@ -267,7 +267,7 @@ async def execute( # Get MIME type from tensor - assuming PNG format for image tensors mime_type = "image/png" - image_url = (await upload_images_to_comfyapi(cls, image, max_images=1, mime_type=mime_type))[0] + image_url = await upload_image_to_comfyapi(cls, image, mime_type=mime_type) task_creation_response = await sync_op( cls, endpoint=ApiEndpoint(path=API_IMG2VIDEO_ENDPOINT, method="POST"), diff --git a/comfy_api_nodes/nodes_runway.py b/comfy_api_nodes/nodes_runway.py index 573170ba2d2c..a64597f3f2bd 100644 --- a/comfy_api_nodes/nodes_runway.py +++ b/comfy_api_nodes/nodes_runway.py @@ -36,6 +36,7 @@ validate_string, validate_image_dimensions, validate_image_aspect_ratio, + upload_image_to_comfyapi, upload_images_to_comfyapi, download_url_to_video_output, download_url_to_image_tensor, @@ -203,10 +204,9 @@ async def execute( validate_image_dimensions(start_frame, max_width=7999, max_height=7999) validate_image_aspect_ratio(start_frame, (1, 2), (2, 1)) - download_urls = await upload_images_to_comfyapi( + download_url = await upload_image_to_comfyapi( cls, start_frame, - max_images=1, mime_type="image/png", ) @@ -220,7 +220,7 @@ async def execute( duration=Duration(duration), ratio=AspectRatio(ratio), promptImage=RunwayPromptImageObject( - root=[RunwayPromptImageDetailedObject(uri=str(download_urls[0]), position="first")] + root=[RunwayPromptImageDetailedObject(uri=str(download_url), position="first")] ), ), ) @@ -297,10 +297,9 @@ async def execute( validate_image_dimensions(start_frame, max_width=7999, max_height=7999) validate_image_aspect_ratio(start_frame, (1, 2), (2, 1)) - download_urls = await upload_images_to_comfyapi( + download_url = await upload_image_to_comfyapi( cls, start_frame, - max_images=1, mime_type="image/png", ) @@ -314,7 +313,7 @@ async def execute( duration=Duration(duration), ratio=AspectRatio(ratio), promptImage=RunwayPromptImageObject( - root=[RunwayPromptImageDetailedObject(uri=str(download_urls[0]), position="first")] + root=[RunwayPromptImageDetailedObject(uri=str(download_url), position="first")] ), ), estimated_duration=AVERAGE_DURATION_FLF_SECONDS, @@ -488,13 +487,12 @@ async def execute( if reference_image is not None: validate_image_dimensions(reference_image, max_width=7999, max_height=7999) validate_image_aspect_ratio(reference_image, (1, 2), (2, 1)) - download_urls = await upload_images_to_comfyapi( + download_url = await upload_image_to_comfyapi( cls, reference_image, - max_images=1, mime_type="image/png", ) - reference_images = [ReferenceImage(uri=str(download_urls[0]))] + reference_images = [ReferenceImage(uri=str(download_url))] initial_response = await sync_op( cls, diff --git a/comfy_api_nodes/nodes_topaz.py b/comfy_api_nodes/nodes_topaz.py index c052e76561f7..49d04c4458ed 100644 --- a/comfy_api_nodes/nodes_topaz.py +++ b/comfy_api_nodes/nodes_topaz.py @@ -31,7 +31,7 @@ get_number_of_images, poll_op, sync_op, - upload_images_to_comfyapi, + upload_image_to_comfyapi, validate_container_format_is_mp4, ) @@ -169,9 +169,7 @@ async def execute( ) -> IO.NodeOutput: if get_number_of_images(image) != 1: raise ValueError("Only one input image is supported.") - download_url = await upload_images_to_comfyapi( - cls, image, max_images=1, mime_type="image/png", total_pixels=4096 * 4096 - ) + download_url = await upload_image_to_comfyapi(cls, image, mime_type="image/png", total_pixels=4096 * 4096) initial_response = await sync_op( cls, ApiEndpoint(path="/proxy/topaz/image/v1/enhance-gen/async", method="POST"), @@ -189,7 +187,7 @@ async def execute( creativity=creativity, face_preservation=str(face_preservation).lower(), color_preservation=str(color_preservation).lower(), - source_url=download_url[0], + source_url=download_url, output_format="png", ), content_type="multipart/form-data", diff --git a/comfy_api_nodes/nodes_tripo.py b/comfy_api_nodes/nodes_tripo.py index 5abf27b4dd66..d1b02aee29e8 100644 --- a/comfy_api_nodes/nodes_tripo.py +++ b/comfy_api_nodes/nodes_tripo.py @@ -29,7 +29,7 @@ download_url_as_bytesio, poll_op, sync_op, - upload_images_to_comfyapi, + upload_image_to_comfyapi, ) from folder_paths import get_output_directory @@ -298,7 +298,7 @@ async def execute( raise RuntimeError("Image is required") tripo_file = TripoFileReference( root=TripoUrlReference( - url=(await upload_images_to_comfyapi(cls, image, max_images=1))[0], + url=await upload_image_to_comfyapi(cls, image), type="jpeg", ) ) @@ -438,9 +438,7 @@ async def execute( if image_ is not None: images.append( TripoFileReference( - root=TripoUrlReference( - url=(await upload_images_to_comfyapi(cls, image_, max_images=1))[0], type="jpeg" - ) + root=TripoUrlReference(url=await upload_image_to_comfyapi(cls, image_), type="jpeg") ) ) else: @@ -637,7 +635,7 @@ def define_schema(cls): "preset:hexapod:walk", "preset:octopod:walk", "preset:serpentine:march", - "preset:aquatic:march" + "preset:aquatic:march", ], ), ], @@ -841,7 +839,7 @@ async def execute( # Parse part_names from comma-separated string to list part_names_list = None if part_names and part_names.strip(): - part_names_list = [name.strip() for name in part_names.split(',') if name.strip()] + part_names_list = [name.strip() for name in part_names.split(",") if name.strip()] response = await sync_op( cls, diff --git a/comfy_api_nodes/nodes_vidu.py b/comfy_api_nodes/nodes_vidu.py index 8edb02f39ba1..39ead70968fe 100644 --- a/comfy_api_nodes/nodes_vidu.py +++ b/comfy_api_nodes/nodes_vidu.py @@ -14,6 +14,7 @@ get_number_of_images, poll_op, sync_op, + upload_image_to_comfyapi, upload_images_to_comfyapi, validate_image_aspect_ratio, validate_image_dimensions, @@ -462,8 +463,7 @@ async def execute( movement_amplitude=movement_amplitude, ) payload.images = [ - (await upload_images_to_comfyapi(cls, frame, max_images=1, mime_type="image/png"))[0] - for frame in (first_frame, end_frame) + await upload_image_to_comfyapi(cls, frame, mime_type="image/png") for frame in (first_frame, end_frame) ] results = await execute_task(cls, VIDU_START_END_VIDEO, payload) return IO.NodeOutput(await download_url_to_video_output(results[0].url)) @@ -932,8 +932,7 @@ async def execute( resolution=resolution, movement_amplitude=movement_amplitude, images=[ - (await upload_images_to_comfyapi(cls, frame, max_images=1, mime_type="image/png"))[0] - for frame in (first_frame, end_frame) + await upload_image_to_comfyapi(cls, frame, mime_type="image/png") for frame in (first_frame, end_frame) ], ) results = await execute_task(cls, VIDU_START_END_VIDEO, payload) diff --git a/comfy_api_nodes/util/__init__.py b/comfy_api_nodes/util/__init__.py index 3649760009de..04e637cc9e5d 100644 --- a/comfy_api_nodes/util/__init__.py +++ b/comfy_api_nodes/util/__init__.py @@ -33,6 +33,7 @@ from .upload_helpers import ( upload_audio_to_comfyapi, upload_file_to_comfyapi, + upload_image_to_comfyapi, upload_images_to_comfyapi, upload_video_to_comfyapi, ) @@ -61,6 +62,7 @@ # Upload helpers "upload_audio_to_comfyapi", "upload_file_to_comfyapi", + "upload_image_to_comfyapi", "upload_images_to_comfyapi", "upload_video_to_comfyapi", # Download helpers diff --git a/comfy_api_nodes/util/upload_helpers.py b/comfy_api_nodes/util/upload_helpers.py index 2794be35c717..2190f96398a5 100644 --- a/comfy_api_nodes/util/upload_helpers.py +++ b/comfy_api_nodes/util/upload_helpers.py @@ -88,6 +88,28 @@ async def upload_images_to_comfyapi( return download_urls +async def upload_image_to_comfyapi( + cls: type[IO.ComfyNode], + image: torch.Tensor, + *, + mime_type: str | None = None, + wait_label: str | None = "Uploading", + total_pixels: int = 2048 * 2048, +) -> str: + """Uploads a single image to ComfyUI API and returns its download URL.""" + return ( + await upload_images_to_comfyapi( + cls, + image, + max_images=1, + mime_type=mime_type, + wait_label=wait_label, + show_batch_index=False, + total_pixels=total_pixels, + ) + )[0] + + async def upload_audio_to_comfyapi( cls: type[IO.ComfyNode], audio: Input.Audio,