diff --git a/backend/__init__.py b/backend/__init__.py new file mode 100644 index 0000000..06d7405 Binary files /dev/null and b/backend/__init__.py differ diff --git a/backend/config.py b/backend/config.py new file mode 100644 index 0000000..45e24f4 --- /dev/null +++ b/backend/config.py @@ -0,0 +1,32 @@ +import os +from pathlib import Path + +# URL Potree - configurée via variable d'environnement POTREE_URL +# Pour le développement local : POTREE_URL=http://localhost:8090 +# Pour la production : POTREE_URL=http://potree_server:8090 + +def load_potree_config(): + """Charge la configuration Potree depuis les variables d'environnement.""" + return os.getenv( + "POTREE_URL", "http://localhost:8090" + ).strip().rstrip("/") + +def get_entwine_path(): + """Retourne le chemin de entwine ou None si non trouvé""" + path = os.getenv("ENTWINE_PATH") + if path: + return path.strip() + return None + +BASE_DIR = Path(__file__).resolve().parent +DATA_DIR = BASE_DIR / "data" +UPLOADS_DIR = DATA_DIR / "uploads" +EPT_DIR = DATA_DIR / "ept" # était POTREE_DIR + +UPLOADS_DIR.mkdir(parents=True, exist_ok=True) +EPT_DIR.mkdir(parents=True, exist_ok=True) + +SUPPORTED_FORMATS = [".las", ".laz", ".ply", ".xyz", ".pts"] + +POTREE_URL = load_potree_config() +ENTWINE_PATH = get_entwine_path() diff --git a/backend/main.py b/backend/main.py new file mode 100644 index 0000000..8980be4 --- /dev/null +++ b/backend/main.py @@ -0,0 +1,94 @@ +from fastapi import FastAPI +from fastapi.staticfiles import StaticFiles +from fastapi.responses import HTMLResponse, RedirectResponse +from config import EPT_DIR +from routes import upload, viewer, admin +from utils.disk import get_disk_usage, get_entwine_path +import subprocess + +ENTWINE_PATH = get_entwine_path() + +app = FastAPI(title="PointCloud Backend") +app.mount("/ept_data", StaticFiles(directory=str(EPT_DIR)), name="ept_data") +app.mount("/static", StaticFiles(directory="static"), name="static") +app.mount("/potree", StaticFiles(directory="static/potree"), name="potree") + +# ── Fichiers Potree dans /static ───────────────────────────────────────────── +app.mount("/static/potree", StaticFiles(directory="static/potree"), name="static_potree") + +app.include_router(upload.router) +app.include_router(viewer.router) +app.include_router(admin.router) + +@app.get("/api") +def home(): + return RedirectResponse(url="/docs") + +@app.get("/health") +def health(): + return { + "ok": True, + "entwine_available": ENTWINE_PATH is not None, + "entwine_path": ENTWINE_PATH, + "disk_free_gb": get_disk_usage(), + } + +def get_pdal_info() -> dict: + """Retourne version et path de pdal via subprocess.""" + info = {"path": None, "version": None} + + try: + result = subprocess.run( + ["which", "pdal"], + capture_output=True, text=True, check=False + ) + if result.returncode == 0: + info["path"] = result.stdout.strip() + except Exception: + pass + + try: + result = subprocess.run( + ["pdal", "--version"], + capture_output=True, text=True, check=False + ) + if result.returncode == 0: + # Sortie : "---\npdal 2.10.0 (git-version: 22e6b2)\n---" + lines = [l.strip() for l in result.stdout.strip().splitlines() + if l.strip() and not l.startswith("-")] + if lines: + info["version"] = lines[0] + except Exception: + pass + + return info + + +@app.get("/", response_class=HTMLResponse) +def home(): + entwine_path = get_entwine_path() + pdal = get_pdal_info() + + return f""" + +
+ + +