diff --git a/src/routers/generate_3D.py b/src/routers/generate_3D.py index ab6f2ad..527ca44 100755 --- a/src/routers/generate_3D.py +++ b/src/routers/generate_3D.py @@ -234,21 +234,39 @@ 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)}") 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: - api_task_id = await create_multi_task(input_data=request_data) + task_resp = await create_multi_task(input_data=request_data) - background_tasks.add_task(get_task_result_async, request_data, request_data.task_id, api_task_id, request_data.callback_url) - result = { - "state": "success", - "task_id": request_data.task_id, - "message": "任务已成功提交,正在后台处理...", - } - state_code = 200 - return ResponseModel(data=result, code=state_code) + 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) + result = { + "state": "success", + "task_id": request_data.task_id, + "message": "任务已成功提交,正在后台处理...", + } + state_code = 200 + return ResponseModel(data=result, code=state_code) + else: + return ResponseModel(data=task_resp, code=task_resp.get("code")) # @router.post("/img_to_3D") # async def img_to_3D(request_data: ImageTo3DRequest): diff --git a/src/server/canvas_generate_3D/triop3d_api_server.py b/src/server/canvas_generate_3D/triop3d_api_server.py index c428bc0..41b6e3c 100644 --- a/src/server/canvas_generate_3D/triop3d_api_server.py +++ b/src/server/canvas_generate_3D/triop3d_api_server.py @@ -44,26 +44,29 @@ class Triop3dApiServer: return self.async_client async def request_json(self, method: str, endpoint: str, request_timeout: float, **kwargs) -> Dict[str, Any]: - """异步请求核心方法""" + """异步请求核心方法 - 直接返回原始 resp(成功或失败都不抛异常)""" url = f"{self.base_url}{endpoint}" client = await self._get_client() try: resp = await client.request(method=method, url=url, timeout=request_timeout, **kwargs) except httpx.RequestError as e: - raise TripoAPIError(f"请求失败: {method} {url} | {e}") from e - - if not resp.is_success: - try: - err_payload = resp.json() - except Exception: - err_payload = resp.text - raise TripoAPIError(f"HTTP {resp.status_code} | {method} {url} | {extract_error_message(err_payload)}") + # 网络层错误也包装成类似 API 的格式返回 + return { + "code": -1, + "message": f"网络请求失败: {method} {url}", + "detail": str(e) + } try: return resp.json() - except Exception as e: - raise TripoAPIError(f"响应不是合法 JSON: {method} {url}") from e + except Exception: + # 非 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: """ @@ -107,7 +110,6 @@ class Triop3dApiServer: request_timeout=request_timeout, files=files ) - data = payload.get("data") or {} file_token = data.get("image_token") @@ -152,13 +154,34 @@ class Triop3dApiServer: 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) - data = resp.get("data") or {} - task_id = data.get("task_id") - if not task_id: - raise TripoAPIError(f"未返回 task_id: {json.dumps(resp, ensure_ascii=False)}") - return task_id + + # 如果是成功响应(通常 code == 0),直接返回 + if isinstance(resp, dict) and resp.get("code") == 0: + return resp + + # 失败情况:确保错误码存在,并返回完整响应(不抛异常) + 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 查询任务状态 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 -async def create_single_task(input_data: Tripo3dApiModel) -> str: +async def create_single_task(input_data: Tripo3dApiModel): """ 异步版本:创建单个图片转 3D 的任务 """ @@ -490,19 +513,17 @@ async def create_single_task(input_data: Tripo3dApiModel) -> str: payload = input_payload | input_data.model_dump(exclude_unset=True) # Step 3: 提交任务(异步) - print("正在提交 Tripo3D 任务...") logger.info("正在提交 Tripo3D 任务...") - task_id = await server.create_task( + + resp = await server.create_task( payload=payload, 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 的任务 """ @@ -546,12 +567,9 @@ async def create_multi_task(input_data: Tripo3dApiModel) -> str: # Step 3: 提交任务(异步) logger.info(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}") - print(f"✅ 多图任务创建成功 | task_id: {task_id}") - - return task_id + return resp async def get_task_result_async(input_data: Tripo3dApiModel, task_id: str, api_task_id: str, callback_url: str):