update Tripo nodes to use File3DGLB

This commit is contained in:
bigcat88 2026-02-02 12:06:51 +02:00
parent 9574fa144c
commit be8676e500

View File

@ -1,10 +1,6 @@
import os
from typing import Optional
import torch
from typing_extensions import override from typing_extensions import override
from comfy_api.latest import IO, ComfyExtension from comfy_api.latest import IO, ComfyExtension, Input
from comfy_api_nodes.apis.tripo import ( from comfy_api_nodes.apis.tripo import (
TripoAnimateRetargetRequest, TripoAnimateRetargetRequest,
TripoAnimateRigRequest, TripoAnimateRigRequest,
@ -26,12 +22,11 @@ from comfy_api_nodes.apis.tripo import (
) )
from comfy_api_nodes.util import ( from comfy_api_nodes.util import (
ApiEndpoint, ApiEndpoint,
download_url_as_bytesio, download_url_to_file_3d,
poll_op, poll_op,
sync_op, sync_op,
upload_images_to_comfyapi, upload_images_to_comfyapi,
) )
from folder_paths import get_output_directory
def get_model_url_from_response(response: TripoTaskResponse) -> str: def get_model_url_from_response(response: TripoTaskResponse) -> str:
@ -45,7 +40,7 @@ def get_model_url_from_response(response: TripoTaskResponse) -> str:
async def poll_until_finished( async def poll_until_finished(
node_cls: type[IO.ComfyNode], node_cls: type[IO.ComfyNode],
response: TripoTaskResponse, response: TripoTaskResponse,
average_duration: Optional[int] = None, average_duration: int | None = None,
) -> IO.NodeOutput: ) -> IO.NodeOutput:
"""Polls the Tripo API endpoint until the task reaches a terminal state, then returns the response.""" """Polls the Tripo API endpoint until the task reaches a terminal state, then returns the response."""
if response.code != 0: if response.code != 0:
@ -69,12 +64,8 @@ async def poll_until_finished(
) )
if response_poll.data.status == TripoTaskStatus.SUCCESS: if response_poll.data.status == TripoTaskStatus.SUCCESS:
url = get_model_url_from_response(response_poll) url = get_model_url_from_response(response_poll)
bytesio = await download_url_as_bytesio(url) file_glb = await download_url_to_file_3d(url, "glb", task_id=task_id)
# Save the downloaded model file return IO.NodeOutput(file_glb, task_id, file_glb)
model_file = f"tripo_model_{task_id}.glb"
with open(os.path.join(get_output_directory(), model_file), "wb") as f:
f.write(bytesio.getvalue())
return IO.NodeOutput(model_file, task_id)
raise RuntimeError(f"Failed to generate mesh: {response_poll}") raise RuntimeError(f"Failed to generate mesh: {response_poll}")
@ -107,8 +98,9 @@ class TripoTextToModelNode(IO.ComfyNode):
IO.Combo.Input("geometry_quality", default="standard", options=["standard", "detailed"], optional=True), IO.Combo.Input("geometry_quality", default="standard", options=["standard", "detailed"], optional=True),
], ],
outputs=[ outputs=[
IO.String.Output(display_name="model_file"), IO.String.Output(display_name="model_file"), # for backward compatibility only
IO.Custom("MODEL_TASK_ID").Output(display_name="model task_id"), IO.Custom("MODEL_TASK_ID").Output(display_name="model task_id"),
IO.File3DGLB.Output(display_name="GLB"),
], ],
hidden=[ hidden=[
IO.Hidden.auth_token_comfy_org, IO.Hidden.auth_token_comfy_org,
@ -155,18 +147,18 @@ class TripoTextToModelNode(IO.ComfyNode):
async def execute( async def execute(
cls, cls,
prompt: str, prompt: str,
negative_prompt: Optional[str] = None, negative_prompt: str | None = None,
model_version=None, model_version=None,
style: Optional[str] = None, style: str | None = None,
texture: Optional[bool] = None, texture: bool | None = None,
pbr: Optional[bool] = None, pbr: bool | None = None,
image_seed: Optional[int] = None, image_seed: int | None = None,
model_seed: Optional[int] = None, model_seed: int | None = None,
texture_seed: Optional[int] = None, texture_seed: int | None = None,
texture_quality: Optional[str] = None, texture_quality: str | None = None,
geometry_quality: Optional[str] = None, geometry_quality: str | None = None,
face_limit: Optional[int] = None, face_limit: int | None = None,
quad: Optional[bool] = None, quad: bool | None = None,
) -> IO.NodeOutput: ) -> IO.NodeOutput:
style_enum = None if style == "None" else style style_enum = None if style == "None" else style
if not prompt: if not prompt:
@ -232,8 +224,9 @@ class TripoImageToModelNode(IO.ComfyNode):
IO.Combo.Input("geometry_quality", default="standard", options=["standard", "detailed"], optional=True), IO.Combo.Input("geometry_quality", default="standard", options=["standard", "detailed"], optional=True),
], ],
outputs=[ outputs=[
IO.String.Output(display_name="model_file"), IO.String.Output(display_name="model_file"), # for backward compatibility only
IO.Custom("MODEL_TASK_ID").Output(display_name="model task_id"), IO.Custom("MODEL_TASK_ID").Output(display_name="model task_id"),
IO.File3DGLB.Output(display_name="GLB"),
], ],
hidden=[ hidden=[
IO.Hidden.auth_token_comfy_org, IO.Hidden.auth_token_comfy_org,
@ -279,19 +272,19 @@ class TripoImageToModelNode(IO.ComfyNode):
@classmethod @classmethod
async def execute( async def execute(
cls, cls,
image: torch.Tensor, image: Input.Image,
model_version: Optional[str] = None, model_version: str | None = None,
style: Optional[str] = None, style: str | None = None,
texture: Optional[bool] = None, texture: bool | None = None,
pbr: Optional[bool] = None, pbr: bool | None = None,
model_seed: Optional[int] = None, model_seed: int | None = None,
orientation=None, orientation=None,
texture_seed: Optional[int] = None, texture_seed: int | None = None,
texture_quality: Optional[str] = None, texture_quality: str | None = None,
geometry_quality: Optional[str] = None, geometry_quality: str | None = None,
texture_alignment: Optional[str] = None, texture_alignment: str | None = None,
face_limit: Optional[int] = None, face_limit: int | None = None,
quad: Optional[bool] = None, quad: bool | None = None,
) -> IO.NodeOutput: ) -> IO.NodeOutput:
style_enum = None if style == "None" else style style_enum = None if style == "None" else style
if image is None: if image is None:
@ -368,8 +361,9 @@ class TripoMultiviewToModelNode(IO.ComfyNode):
IO.Combo.Input("geometry_quality", default="standard", options=["standard", "detailed"], optional=True), IO.Combo.Input("geometry_quality", default="standard", options=["standard", "detailed"], optional=True),
], ],
outputs=[ outputs=[
IO.String.Output(display_name="model_file"), IO.String.Output(display_name="model_file"), # for backward compatibility only
IO.Custom("MODEL_TASK_ID").Output(display_name="model task_id"), IO.Custom("MODEL_TASK_ID").Output(display_name="model task_id"),
IO.File3DGLB.Output(display_name="GLB"),
], ],
hidden=[ hidden=[
IO.Hidden.auth_token_comfy_org, IO.Hidden.auth_token_comfy_org,
@ -411,21 +405,21 @@ class TripoMultiviewToModelNode(IO.ComfyNode):
@classmethod @classmethod
async def execute( async def execute(
cls, cls,
image: torch.Tensor, image: Input.Image,
image_left: Optional[torch.Tensor] = None, image_left: Input.Image | None = None,
image_back: Optional[torch.Tensor] = None, image_back: Input.Image | None = None,
image_right: Optional[torch.Tensor] = None, image_right: Input.Image | None = None,
model_version: Optional[str] = None, model_version: str | None = None,
orientation: Optional[str] = None, orientation: str | None = None,
texture: Optional[bool] = None, texture: bool | None = None,
pbr: Optional[bool] = None, pbr: bool | None = None,
model_seed: Optional[int] = None, model_seed: int | None = None,
texture_seed: Optional[int] = None, texture_seed: int | None = None,
texture_quality: Optional[str] = None, texture_quality: str | None = None,
geometry_quality: Optional[str] = None, geometry_quality: str | None = None,
texture_alignment: Optional[str] = None, texture_alignment: str | None = None,
face_limit: Optional[int] = None, face_limit: int | None = None,
quad: Optional[bool] = None, quad: bool | None = None,
) -> IO.NodeOutput: ) -> IO.NodeOutput:
if image is None: if image is None:
raise RuntimeError("front image for multiview is required") raise RuntimeError("front image for multiview is required")
@ -487,8 +481,9 @@ class TripoTextureNode(IO.ComfyNode):
), ),
], ],
outputs=[ outputs=[
IO.String.Output(display_name="model_file"), IO.String.Output(display_name="model_file"), # for backward compatibility only
IO.Custom("MODEL_TASK_ID").Output(display_name="model task_id"), IO.Custom("MODEL_TASK_ID").Output(display_name="model task_id"),
IO.File3DGLB.Output(display_name="GLB"),
], ],
hidden=[ hidden=[
IO.Hidden.auth_token_comfy_org, IO.Hidden.auth_token_comfy_org,
@ -512,11 +507,11 @@ class TripoTextureNode(IO.ComfyNode):
async def execute( async def execute(
cls, cls,
model_task_id, model_task_id,
texture: Optional[bool] = None, texture: bool | None = None,
pbr: Optional[bool] = None, pbr: bool | None = None,
texture_seed: Optional[int] = None, texture_seed: int | None = None,
texture_quality: Optional[str] = None, texture_quality: str | None = None,
texture_alignment: Optional[str] = None, texture_alignment: str | None = None,
) -> IO.NodeOutput: ) -> IO.NodeOutput:
response = await sync_op( response = await sync_op(
cls, cls,
@ -547,8 +542,9 @@ class TripoRefineNode(IO.ComfyNode):
IO.Custom("MODEL_TASK_ID").Input("model_task_id", tooltip="Must be a v1.4 Tripo model"), IO.Custom("MODEL_TASK_ID").Input("model_task_id", tooltip="Must be a v1.4 Tripo model"),
], ],
outputs=[ outputs=[
IO.String.Output(display_name="model_file"), IO.String.Output(display_name="model_file"), # for backward compatibility only
IO.Custom("MODEL_TASK_ID").Output(display_name="model task_id"), IO.Custom("MODEL_TASK_ID").Output(display_name="model task_id"),
IO.File3DGLB.Output(display_name="GLB"),
], ],
hidden=[ hidden=[
IO.Hidden.auth_token_comfy_org, IO.Hidden.auth_token_comfy_org,
@ -583,8 +579,9 @@ class TripoRigNode(IO.ComfyNode):
category="api node/3d/Tripo", category="api node/3d/Tripo",
inputs=[IO.Custom("MODEL_TASK_ID").Input("original_model_task_id")], inputs=[IO.Custom("MODEL_TASK_ID").Input("original_model_task_id")],
outputs=[ outputs=[
IO.String.Output(display_name="model_file"), IO.String.Output(display_name="model_file"), # for backward compatibility only
IO.Custom("RIG_TASK_ID").Output(display_name="rig task_id"), IO.Custom("RIG_TASK_ID").Output(display_name="rig task_id"),
IO.File3DGLB.Output(display_name="GLB"),
], ],
hidden=[ hidden=[
IO.Hidden.auth_token_comfy_org, IO.Hidden.auth_token_comfy_org,
@ -642,8 +639,9 @@ class TripoRetargetNode(IO.ComfyNode):
), ),
], ],
outputs=[ outputs=[
IO.String.Output(display_name="model_file"), IO.String.Output(display_name="model_file"), # for backward compatibility only
IO.Custom("RETARGET_TASK_ID").Output(display_name="retarget task_id"), IO.Custom("RETARGET_TASK_ID").Output(display_name="retarget task_id"),
IO.File3DGLB.Output(display_name="GLB"),
], ],
hidden=[ hidden=[
IO.Hidden.auth_token_comfy_org, IO.Hidden.auth_token_comfy_org,