import os import sys import uvicorn from fastapi import FastAPI, HTTPException from pydantic import BaseModel, Field from typing import List, Optional # Ensure the project root is in sys.path sys.path.append(os.path.dirname(os.path.abspath(__file__))) try: # Attempt to import the entrypoint from the existing script # This assumes the environment is set up correctly with all dependencies from embodied_gen.scripts.imageto3d import entrypoint except ImportError as e: print(f"Error importing embodied_gen: {e}") print("Please ensure you are running this script from the project root and environment is configured.") sys.exit(1) app = FastAPI(title="Image to 3D Service") class ImageTo3DRequest(BaseModel): image_paths: List[str] = Field(..., description="Path to the input images (e.g. apps/assets/example_image/sample_00.jpg)") output_root: str = Field(..., description="Root directory for saving outputs (e.g. outputs/imageto3d)") n_retry: int = Field(2, description="Number of retries") # Optional parameters mirroring the CLI arguments height_range: Optional[str] = None mass_range: Optional[str] = None asset_type: Optional[List[str]] = None skip_exists: bool = False version: Optional[str] = None keep_intermediate: bool = False seed: int = 0 disable_decompose_convex: bool = False texture_size: int = 2048 @app.post("/process") async def process_images(request: ImageTo3DRequest): """ HTTP wrapper for img3d-cli. """ # 1. Validate inputs for path in request.image_paths: if not os.path.exists(path): raise HTTPException(status_code=400, detail=f"Image path does not exist: {path}") # 2. Invoke the processing logic try: # entrypoint() in imageto3d.py accepts **kwargs to override parsed args entrypoint( image_path=request.image_paths, output_root=request.output_root, n_retry=request.n_retry, # Optional args height_range=request.height_range, mass_range=request.mass_range, asset_type=request.asset_type, skip_exists=request.skip_exists, version=request.version, keep_intermediate=request.keep_intermediate, seed=request.seed, disable_decompose_convex=request.disable_decompose_convex, texture_size=request.texture_size ) return { "status": "success", "message": "Processing completed.", "output_root": request.output_root, "inputs": request.image_paths } except Exception as e: # Catch errors from the processing pipeline raise HTTPException(status_code=500, detail=f"Processing failed: {str(e)}") @app.get("/health") def health(): return {"status": "ok"} if __name__ == "__main__": # Run server on port 8000 uvicorn.run(app, host="0.0.0.0", port=8000)