优化 img 转3D 相应代码
This commit is contained in:
@@ -234,13 +234,29 @@ async def triop_api_img_to_3D(request_data: Tripo3dApiModel, background_tasks: B
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
### 错误输出
|
||||||
|
参考文档: https://platform.tripo3d.ai/docs/error-handling
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 2010,
|
||||||
|
"msg": "OK!",
|
||||||
|
"data": {
|
||||||
|
"code": 2010,
|
||||||
|
"message": "You don't have enough credit to create this task",
|
||||||
|
"suggestion": "Please purchase more credit",
|
||||||
|
"success": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
logger.info(f"img_to_3D_v2 request: {json.dumps(request_data.model_dump(), indent=4)}")
|
logger.info(f"img_to_3D_v2 request: {json.dumps(request_data.model_dump(), indent=4)}")
|
||||||
if request_data.model == "single":
|
if request_data.model == "single":
|
||||||
api_task_id = await create_single_task(input_data=request_data)
|
task_resp = await create_single_task(input_data=request_data)
|
||||||
else:
|
else:
|
||||||
api_task_id = await create_multi_task(input_data=request_data)
|
task_resp = await create_multi_task(input_data=request_data)
|
||||||
|
|
||||||
|
if task_resp.get("state") == "success":
|
||||||
|
api_task_id = task_resp.get("task_id")
|
||||||
background_tasks.add_task(get_task_result_async, request_data, request_data.task_id, api_task_id, request_data.callback_url)
|
background_tasks.add_task(get_task_result_async, request_data, request_data.task_id, api_task_id, request_data.callback_url)
|
||||||
result = {
|
result = {
|
||||||
"state": "success",
|
"state": "success",
|
||||||
@@ -249,6 +265,8 @@ async def triop_api_img_to_3D(request_data: Tripo3dApiModel, background_tasks: B
|
|||||||
}
|
}
|
||||||
state_code = 200
|
state_code = 200
|
||||||
return ResponseModel(data=result, code=state_code)
|
return ResponseModel(data=result, code=state_code)
|
||||||
|
else:
|
||||||
|
return ResponseModel(data=task_resp, code=task_resp.get("code"))
|
||||||
|
|
||||||
# @router.post("/img_to_3D")
|
# @router.post("/img_to_3D")
|
||||||
# async def img_to_3D(request_data: ImageTo3DRequest):
|
# async def img_to_3D(request_data: ImageTo3DRequest):
|
||||||
|
|||||||
@@ -44,26 +44,29 @@ class Triop3dApiServer:
|
|||||||
return self.async_client
|
return self.async_client
|
||||||
|
|
||||||
async def request_json(self, method: str, endpoint: str, request_timeout: float, **kwargs) -> Dict[str, Any]:
|
async def request_json(self, method: str, endpoint: str, request_timeout: float, **kwargs) -> Dict[str, Any]:
|
||||||
"""异步请求核心方法"""
|
"""异步请求核心方法 - 直接返回原始 resp(成功或失败都不抛异常)"""
|
||||||
url = f"{self.base_url}{endpoint}"
|
url = f"{self.base_url}{endpoint}"
|
||||||
client = await self._get_client()
|
client = await self._get_client()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
resp = await client.request(method=method, url=url, timeout=request_timeout, **kwargs)
|
resp = await client.request(method=method, url=url, timeout=request_timeout, **kwargs)
|
||||||
except httpx.RequestError as e:
|
except httpx.RequestError as e:
|
||||||
raise TripoAPIError(f"请求失败: {method} {url} | {e}") from e
|
# 网络层错误也包装成类似 API 的格式返回
|
||||||
|
return {
|
||||||
if not resp.is_success:
|
"code": -1,
|
||||||
try:
|
"message": f"网络请求失败: {method} {url}",
|
||||||
err_payload = resp.json()
|
"detail": str(e)
|
||||||
except Exception:
|
}
|
||||||
err_payload = resp.text
|
|
||||||
raise TripoAPIError(f"HTTP {resp.status_code} | {method} {url} | {extract_error_message(err_payload)}")
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return resp.json()
|
return resp.json()
|
||||||
except Exception as e:
|
except Exception:
|
||||||
raise TripoAPIError(f"响应不是合法 JSON: {method} {url}") from e
|
# 非 JSON 返回也包装返回
|
||||||
|
return {
|
||||||
|
"code": -2,
|
||||||
|
"message": f"响应不是合法 JSON: HTTP {resp.status_code}",
|
||||||
|
"raw": resp.text[:500] # 截取一部分避免过长
|
||||||
|
}
|
||||||
|
|
||||||
async def upload_image(self, image_path: str, request_timeout: float) -> str:
|
async def upload_image(self, image_path: str, request_timeout: float) -> str:
|
||||||
"""
|
"""
|
||||||
@@ -107,7 +110,6 @@ class Triop3dApiServer:
|
|||||||
request_timeout=request_timeout,
|
request_timeout=request_timeout,
|
||||||
files=files
|
files=files
|
||||||
)
|
)
|
||||||
|
|
||||||
data = payload.get("data") or {}
|
data = payload.get("data") or {}
|
||||||
file_token = data.get("image_token")
|
file_token = data.get("image_token")
|
||||||
|
|
||||||
@@ -152,13 +154,34 @@ class Triop3dApiServer:
|
|||||||
|
|
||||||
return file_tokens
|
return file_tokens
|
||||||
|
|
||||||
async def create_task(self, payload: Dict[str, Any], request_timeout: float) -> str:
|
async def create_task(self, payload: Dict[str, Any], request_timeout: float) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
创建任务
|
||||||
|
- 成功时返回原始响应(包含 code: 0 和 data.task_id)
|
||||||
|
- 失败时也返回原始响应,并确保错误码(code)被带上
|
||||||
|
"""
|
||||||
resp = await self.request_json("POST", "/task", request_timeout=request_timeout, json=payload)
|
resp = await self.request_json("POST", "/task", request_timeout=request_timeout, json=payload)
|
||||||
data = resp.get("data") or {}
|
|
||||||
task_id = data.get("task_id")
|
# 如果是成功响应(通常 code == 0),直接返回
|
||||||
if not task_id:
|
if isinstance(resp, dict) and resp.get("code") == 0:
|
||||||
raise TripoAPIError(f"未返回 task_id: {json.dumps(resp, ensure_ascii=False)}")
|
return resp
|
||||||
return task_id
|
|
||||||
|
# 失败情况:确保错误码存在,并返回完整响应(不抛异常)
|
||||||
|
if not isinstance(resp, dict):
|
||||||
|
resp = {"code": -3, "message": "未知错误", "raw_response": str(resp)}
|
||||||
|
|
||||||
|
# 如果响应中没有 code 字段,补充一个
|
||||||
|
if "code" not in resp:
|
||||||
|
resp["code"] = resp.get("error", {}).get("code") or -999
|
||||||
|
|
||||||
|
# 可选:统一加上一个更明显的错误标识(方便上层判断)
|
||||||
|
if resp.get("code") != 0:
|
||||||
|
resp.setdefault("success", False)
|
||||||
|
# 如果有 suggestion,可以保留
|
||||||
|
if "suggestion" not in resp and isinstance(resp.get("error"), dict):
|
||||||
|
resp["suggestion"] = resp["error"].get("suggestion")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
# step 3 查询任务状态
|
# step 3 查询任务状态
|
||||||
async def poll_task(self, task_id: str, poll_interval: float, poll_timeout: float, request_timeout: float, callback_url: str) -> Dict[str, Any]:
|
async def poll_task(self, task_id: str, poll_interval: float, poll_timeout: float, request_timeout: float, callback_url: str) -> Dict[str, Any]:
|
||||||
@@ -456,7 +479,7 @@ def load_mesh_from_minio(object_name: str, bucket_name: str = "fida-user"):
|
|||||||
return vertices
|
return vertices
|
||||||
|
|
||||||
|
|
||||||
async def create_single_task(input_data: Tripo3dApiModel) -> str:
|
async def create_single_task(input_data: Tripo3dApiModel):
|
||||||
"""
|
"""
|
||||||
异步版本:创建单个图片转 3D 的任务
|
异步版本:创建单个图片转 3D 的任务
|
||||||
"""
|
"""
|
||||||
@@ -490,19 +513,17 @@ async def create_single_task(input_data: Tripo3dApiModel) -> str:
|
|||||||
payload = input_payload | input_data.model_dump(exclude_unset=True)
|
payload = input_payload | input_data.model_dump(exclude_unset=True)
|
||||||
|
|
||||||
# Step 3: 提交任务(异步)
|
# Step 3: 提交任务(异步)
|
||||||
print("正在提交 Tripo3D 任务...")
|
|
||||||
logger.info("正在提交 Tripo3D 任务...")
|
logger.info("正在提交 Tripo3D 任务...")
|
||||||
task_id = await server.create_task(
|
|
||||||
|
resp = await server.create_task(
|
||||||
payload=payload,
|
payload=payload,
|
||||||
request_timeout=input_data.request_timeout
|
request_timeout=input_data.request_timeout
|
||||||
)
|
)
|
||||||
print(f"✅ 任务创建成功 | task_id: {task_id}")
|
|
||||||
logger.info(f"✅ 任务创建成功 | task_id: {task_id}")
|
|
||||||
|
|
||||||
return task_id
|
return resp
|
||||||
|
|
||||||
|
|
||||||
async def create_multi_task(input_data: Tripo3dApiModel) -> str:
|
async def create_multi_task(input_data: Tripo3dApiModel):
|
||||||
"""
|
"""
|
||||||
异步版本:创建多图转 3D 的任务
|
异步版本:创建多图转 3D 的任务
|
||||||
"""
|
"""
|
||||||
@@ -546,12 +567,9 @@ async def create_multi_task(input_data: Tripo3dApiModel) -> str:
|
|||||||
# Step 3: 提交任务(异步)
|
# Step 3: 提交任务(异步)
|
||||||
logger.info(f"正在提交多图 Tripo3D 任务...{payload}")
|
logger.info(f"正在提交多图 Tripo3D 任务...{payload}")
|
||||||
print(f"正在提交多图 Tripo3D 任务...{payload}")
|
print(f"正在提交多图 Tripo3D 任务...{payload}")
|
||||||
task_id = await server.create_task(payload=payload, request_timeout=input_data.request_timeout)
|
resp = await server.create_task(payload=payload, request_timeout=input_data.request_timeout)
|
||||||
|
|
||||||
logger.info(f"✅ 多图任务创建成功 | task_id: {task_id}")
|
return resp
|
||||||
print(f"✅ 多图任务创建成功 | task_id: {task_id}")
|
|
||||||
|
|
||||||
return task_id
|
|
||||||
|
|
||||||
|
|
||||||
async def get_task_result_async(input_data: Tripo3dApiModel, task_id: str, api_task_id: str, callback_url: str):
|
async def get_task_result_async(input_data: Tripo3dApiModel, task_id: str, api_task_id: str, callback_url: str):
|
||||||
|
|||||||
Reference in New Issue
Block a user