feat: add on-demand format conversion support (FBX, STL, USDZ, MP4, GIF)
- Discover /creations/resourceConvert endpoint via browser inspection - Add resource_convert() method to api.py and api_complete.py - Extend MODEL_FORMAT_KEYS with fbx, stl, usdz, mp4, gif - Update get_model_urls() and download_model() with include_converted flag - Update CLI with --converted flag for formats and download commands - Update reverse engineering docs with native vs converted format tables
This commit is contained in:
+55
-5
@@ -19,7 +19,9 @@ API_BASE = f"{BASE_URL}/api/3d"
|
||||
class Hunyuan3DAPI:
|
||||
"""腾讯混元3D API客户端"""
|
||||
|
||||
# 模型下载格式键名(与腾讯混元3D API返回的 urlResult 字段对应)
|
||||
# 模型下载格式键名
|
||||
# 原生格式:直接来自 API urlResult
|
||||
# 转换格式:通过 /creations/resourceConvert 从 OBJ(zip) 转换得到
|
||||
MODEL_FORMAT_KEYS = [
|
||||
"glb", # 带PBR贴图的GLB二进制模型
|
||||
"obj", # OBJ模型(通常打包在zip中)
|
||||
@@ -35,6 +37,11 @@ class Hunyuan3DAPI:
|
||||
"pbrNormalImage", # PBR法线贴图
|
||||
"invisible_wall", # 不可见碰撞墙
|
||||
"air_wall", # 空气墙(碰撞体)
|
||||
"fbx", # FBX 格式(转换)
|
||||
"stl", # STL 格式(转换)
|
||||
"usdz", # USDZ 格式(转换,用于 iOS AR)
|
||||
"mp4", # MP4 视频格式(转换)
|
||||
"gif", # GIF 动图格式(转换)
|
||||
]
|
||||
|
||||
def __init__(self, cookies: Optional[str] = None):
|
||||
@@ -200,10 +207,41 @@ class Hunyuan3DAPI:
|
||||
"creationsId": creation_id
|
||||
})
|
||||
|
||||
def get_model_urls(self, creation_id: str) -> Dict[str, Optional[str]]:
|
||||
def resource_convert(self, source_url: str, target_formats: List[str]) -> Dict[str, str]:
|
||||
"""
|
||||
调用资源转换接口将 OBJ(zip) 转换为其他格式
|
||||
|
||||
Args:
|
||||
source_url: OBJ zip 文件的 URL(来自 urlResult['obj'])
|
||||
target_formats: 目标格式列表,如 ["usdz", "fbx"]
|
||||
|
||||
Returns:
|
||||
格式键名 -> 转换后下载URL 的字典
|
||||
"""
|
||||
data = {
|
||||
"sourceResource": [
|
||||
{"format": "zip", "url": source_url}
|
||||
],
|
||||
"targetFormatList": target_formats
|
||||
}
|
||||
resp = self._make_request("POST", "/creations/resourceConvert", data=data)
|
||||
result = {}
|
||||
for item in resp.get("convertResult", []):
|
||||
fmt = item.get("format")
|
||||
url = item.get("url")
|
||||
if fmt and url:
|
||||
result[fmt] = url
|
||||
return result
|
||||
|
||||
def get_model_urls(self, creation_id: str, include_converted: bool = False) -> Dict[str, Optional[str]]:
|
||||
"""
|
||||
获取指定创作所有可用格式的下载URL
|
||||
|
||||
Args:
|
||||
creation_id: 创作ID
|
||||
include_converted: 是否包含转换格式(fbx/stl/usdz/mp4/gif),
|
||||
启用时会调用 resourceConvert 接口
|
||||
|
||||
Returns:
|
||||
格式键名 -> 下载URL 的字典,空值已被过滤
|
||||
"""
|
||||
@@ -220,14 +258,26 @@ class Hunyuan3DAPI:
|
||||
return {}
|
||||
|
||||
url_result = result_list[0].get("urlResult", {})
|
||||
return {
|
||||
urls = {
|
||||
key: val
|
||||
for key in self.MODEL_FORMAT_KEYS
|
||||
if (val := url_result.get(key)) and val not in (None, "", {})
|
||||
}
|
||||
|
||||
if include_converted:
|
||||
obj_url = urls.get("obj")
|
||||
if obj_url:
|
||||
converted = self.resource_convert(
|
||||
obj_url,
|
||||
["fbx", "stl", "usdz", "mp4", "gif"]
|
||||
)
|
||||
urls.update(converted)
|
||||
|
||||
return urls
|
||||
|
||||
def download_model(self, creation_id: str, format_key: str = "glb",
|
||||
output_path: Optional[str] = None) -> str:
|
||||
output_path: Optional[str] = None,
|
||||
include_converted: bool = False) -> str:
|
||||
"""
|
||||
下载指定格式的模型文件
|
||||
|
||||
@@ -239,7 +289,7 @@ class Hunyuan3DAPI:
|
||||
Returns:
|
||||
实际保存的本地文件路径
|
||||
"""
|
||||
urls = self.get_model_urls(creation_id)
|
||||
urls = self.get_model_urls(creation_id, include_converted=include_converted)
|
||||
if format_key not in urls:
|
||||
available = ", ".join(urls.keys())
|
||||
raise ValueError(
|
||||
|
||||
Reference in New Issue
Block a user