"""Phase 1 验收脚本:直接调用 Trellis,验证 .glb + color_video + normal_video 能下到本地。 用法(在 backend 目录激活 venv 之后): python scripts/test_trellis.py uploads/0e6fd7e47a524bb9ad18de0b72495e0e.png 不带参数时会尝试使用 uploads/ 下最新的 png 作为测试图。 成功标准: - 退出码 0 - 终端打印 glb_path / color_video_path / normal_video_path 均为 /generated/ 开头 - 实际到 backend/generated/ 目录能看到 3 个文件且 size > 0 """ import asyncio import json import sys from pathlib import Path # 允许直接 `python scripts/test_trellis.py` 跑 _BACKEND_ROOT = Path(__file__).resolve().parent.parent if str(_BACKEND_ROOT) not in sys.path: sys.path.insert(0, str(_BACKEND_ROOT)) # .env 加载(复用项目 main.py 的习惯) from dotenv import load_dotenv # noqa: E402 load_dotenv(_BACKEND_ROOT / ".env", override=True) from app.services import mesh_generator # noqa: E402 def _pick_default_image() -> str: uploads = _BACKEND_ROOT / "uploads" pngs = sorted(uploads.glob("*.png"), key=lambda p: p.stat().st_mtime, reverse=True) if not pngs: raise FileNotFoundError(f"uploads/ 下没有 png 文件,请显式传入图片路径") return str(pngs[0].relative_to(_BACKEND_ROOT)).replace("\\", "/") async def main() -> int: image_arg = sys.argv[1] if len(sys.argv) > 1 else _pick_default_image() # 规范化成 / 开头的 "本地相对 URL" 以便 to_data_uri 识别 if not image_arg.startswith("/") and not image_arg.startswith("data:") and not image_arg.startswith("http"): image_arg = "/" + image_arg.lstrip("./").replace("\\", "/") print(f"[test_trellis] 输入图:{image_arg}") print("[test_trellis] 开始调用 Trellis(预计 ~30s 起)...") result = await mesh_generator.generate_with_trellis(image_arg) print("[test_trellis] Trellis 返回:") print(json.dumps(result, ensure_ascii=False, indent=2)) if not result.get("success"): print("[test_trellis] 失败:", result.get("error")) return 1 generated_dir = _BACKEND_ROOT / "generated" for key in ("glb_path", "color_video_path", "normal_video_path"): rel = result.get(key) if not rel: print(f"[test_trellis] 警告:缺少 {key}") continue local = generated_dir / Path(rel).name size = local.stat().st_size if local.exists() else -1 print(f"[test_trellis] {key}: {rel} (本地大小: {size} bytes)") return 0 if __name__ == "__main__": sys.exit(asyncio.run(main()))