mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-03-27 20:13:32 +08:00
fix(api-nodes): added "texture_image" output to TencentTextToModel and TencentImageToModel nodes. Fixed OBJ output when it is zipped
This commit is contained in:
parent
e4b0bb8305
commit
858977ab10
@ -1,3 +1,6 @@
|
|||||||
|
import zipfile
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
|
|
||||||
from comfy_api.latest import IO, ComfyExtension, Input, Types
|
from comfy_api.latest import IO, ComfyExtension, Input, Types
|
||||||
@ -17,6 +20,8 @@ from comfy_api_nodes.apis.hunyuan3d import (
|
|||||||
)
|
)
|
||||||
from comfy_api_nodes.util import (
|
from comfy_api_nodes.util import (
|
||||||
ApiEndpoint,
|
ApiEndpoint,
|
||||||
|
bytesio_to_image_tensor,
|
||||||
|
download_url_to_bytesio,
|
||||||
download_url_to_file_3d,
|
download_url_to_file_3d,
|
||||||
downscale_image_tensor_by_max_side,
|
downscale_image_tensor_by_max_side,
|
||||||
poll_op,
|
poll_op,
|
||||||
@ -36,6 +41,29 @@ def _is_tencent_rate_limited(status: int, body: object) -> bool:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def download_and_extract_obj_zip(url: str) -> tuple[Types.File3D, Input.Image | None]:
|
||||||
|
"""The Tencent API returns OBJ results as ZIP archives containing the .obj mesh, and a texture image."""
|
||||||
|
data = BytesIO()
|
||||||
|
await download_url_to_bytesio(url, data)
|
||||||
|
data.seek(0)
|
||||||
|
if not zipfile.is_zipfile(data):
|
||||||
|
data.seek(0)
|
||||||
|
return Types.File3D(source=data, file_format="obj"), None
|
||||||
|
data.seek(0)
|
||||||
|
obj_bytes = None
|
||||||
|
texture_tensor = None
|
||||||
|
with zipfile.ZipFile(data) as zf:
|
||||||
|
for name in zf.namelist():
|
||||||
|
lower = name.lower()
|
||||||
|
if lower.endswith(".obj"):
|
||||||
|
obj_bytes = zf.read(name)
|
||||||
|
elif any(lower.endswith(ext) for ext in (".png", ".jpg", ".jpeg", ".bmp", ".tiff", ".webp")):
|
||||||
|
texture_tensor = bytesio_to_image_tensor(BytesIO(zf.read(name)), mode="RGB")
|
||||||
|
if obj_bytes is None:
|
||||||
|
raise ValueError("ZIP archive does not contain an OBJ file.")
|
||||||
|
return Types.File3D(source=BytesIO(obj_bytes), file_format="obj"), texture_tensor
|
||||||
|
|
||||||
|
|
||||||
def get_file_from_response(
|
def get_file_from_response(
|
||||||
response_objs: list[ResultFile3D], file_type: str, raise_if_not_found: bool = True
|
response_objs: list[ResultFile3D], file_type: str, raise_if_not_found: bool = True
|
||||||
) -> ResultFile3D | None:
|
) -> ResultFile3D | None:
|
||||||
@ -93,6 +121,7 @@ class TencentTextToModelNode(IO.ComfyNode):
|
|||||||
IO.String.Output(display_name="model_file"), # for backward compatibility only
|
IO.String.Output(display_name="model_file"), # for backward compatibility only
|
||||||
IO.File3DGLB.Output(display_name="GLB"),
|
IO.File3DGLB.Output(display_name="GLB"),
|
||||||
IO.File3DOBJ.Output(display_name="OBJ"),
|
IO.File3DOBJ.Output(display_name="OBJ"),
|
||||||
|
IO.Image.Output(display_name="texture_image"),
|
||||||
],
|
],
|
||||||
hidden=[
|
hidden=[
|
||||||
IO.Hidden.auth_token_comfy_org,
|
IO.Hidden.auth_token_comfy_org,
|
||||||
@ -151,14 +180,16 @@ class TencentTextToModelNode(IO.ComfyNode):
|
|||||||
response_model=To3DProTaskResultResponse,
|
response_model=To3DProTaskResultResponse,
|
||||||
status_extractor=lambda r: r.Status,
|
status_extractor=lambda r: r.Status,
|
||||||
)
|
)
|
||||||
|
obj_file, texture_image = await download_and_extract_obj_zip(
|
||||||
|
get_file_from_response(result.ResultFile3Ds, "obj").Url
|
||||||
|
)
|
||||||
return IO.NodeOutput(
|
return IO.NodeOutput(
|
||||||
f"{task_id}.glb",
|
f"{task_id}.glb",
|
||||||
await download_url_to_file_3d(
|
await download_url_to_file_3d(
|
||||||
get_file_from_response(result.ResultFile3Ds, "glb").Url, "glb", task_id=task_id
|
get_file_from_response(result.ResultFile3Ds, "glb").Url, "glb", task_id=task_id
|
||||||
),
|
),
|
||||||
await download_url_to_file_3d(
|
obj_file,
|
||||||
get_file_from_response(result.ResultFile3Ds, "obj").Url, "obj", task_id=task_id
|
texture_image,
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -211,6 +242,7 @@ class TencentImageToModelNode(IO.ComfyNode):
|
|||||||
IO.String.Output(display_name="model_file"), # for backward compatibility only
|
IO.String.Output(display_name="model_file"), # for backward compatibility only
|
||||||
IO.File3DGLB.Output(display_name="GLB"),
|
IO.File3DGLB.Output(display_name="GLB"),
|
||||||
IO.File3DOBJ.Output(display_name="OBJ"),
|
IO.File3DOBJ.Output(display_name="OBJ"),
|
||||||
|
IO.Image.Output(display_name="texture_image"),
|
||||||
],
|
],
|
||||||
hidden=[
|
hidden=[
|
||||||
IO.Hidden.auth_token_comfy_org,
|
IO.Hidden.auth_token_comfy_org,
|
||||||
@ -304,14 +336,16 @@ class TencentImageToModelNode(IO.ComfyNode):
|
|||||||
response_model=To3DProTaskResultResponse,
|
response_model=To3DProTaskResultResponse,
|
||||||
status_extractor=lambda r: r.Status,
|
status_extractor=lambda r: r.Status,
|
||||||
)
|
)
|
||||||
|
obj_file, texture_image = await download_and_extract_obj_zip(
|
||||||
|
get_file_from_response(result.ResultFile3Ds, "obj").Url
|
||||||
|
)
|
||||||
return IO.NodeOutput(
|
return IO.NodeOutput(
|
||||||
f"{task_id}.glb",
|
f"{task_id}.glb",
|
||||||
await download_url_to_file_3d(
|
await download_url_to_file_3d(
|
||||||
get_file_from_response(result.ResultFile3Ds, "glb").Url, "glb", task_id=task_id
|
get_file_from_response(result.ResultFile3Ds, "glb").Url, "glb", task_id=task_id
|
||||||
),
|
),
|
||||||
await download_url_to_file_3d(
|
obj_file,
|
||||||
get_file_from_response(result.ResultFile3Ds, "obj").Url, "obj", task_id=task_id
|
texture_image,
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user