"""TiTiler-based web server for serving LiDAR COG visualizations. Provides: - COG tile serving via TiTiler API - Static file serving for viewer HTML - CORS headers for local development Usage: python -m lidar_pipeline.server /path/to/output [--port 8000] """ import logging import sys from pathlib import Path logger = logging.getLogger("lidar") def create_app(output_dir): """Create the FastAPI application with TiTiler and static file serving. Args: output_dir: Path to the output directory containing visualisations/ and viewer/. Returns: FastAPI application instance. """ from fastapi import FastAPI from fastapi.responses import HTMLResponse, FileResponse, JSONResponse from fastapi.middleware.cors import CORSMiddleware from titiler.core.factory import TilerFactory output_dir = Path(output_dir).resolve() # TiTiler COG endpoint cog = TilerFactory(router_prefix="/cog") app = FastAPI(title="LiDAR Archéologique", docs_url="/docs") # CORS for local development app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"]) # Mount TiTiler routes app.include_router(cog.router, prefix="/cog") @app.get("/") async def index(): """Landing page with links.""" return HTMLResponse( '
TiTiler API: /cog/
' '' ) @app.get("/viewer/{basename}") @app.get("/viewer") async def serve_viewer(basename: str = ""): """Serve viewer HTML files.""" if not basename: # List available viewers viewer_dir = output_dir / 'visualisations' / 'viewer' if viewer_dir.exists(): viewers = sorted(viewer_dir.glob('*.html')) if viewers: links = ''.join( f'Aucun viewer disponible
') viewer_file = output_dir / 'visualisations' / 'viewer' / f"{basename}.html" if viewer_file.exists(): return FileResponse(str(viewer_file), media_type='text/html') return JSONResponse({'error': f'Viewer not found: {basename}'}, status_code=404) return app def main(): """Entry point for the LiDAR web server.""" import argparse import uvicorn parser = argparse.ArgumentParser(description='Serveur cartographique LiDAR') parser.add_argument('output_dir', help='Répertoire de sortie contenant les visualisations') parser.add_argument('--host', default='0.0.0.0', help='Hôte (défaut: 0.0.0.0)') parser.add_argument('--port', type=int, default=8000, help='Port (défaut: 8000)') args = parser.parse_args() output_dir = Path(args.output_dir) if not output_dir.exists(): logger.error(f"Répertoire introuvable: {output_dir}") sys.exit(1) app = create_app(output_dir) print(f"Serveur LiDAR Archéologique") print(f" Viewer: http://{args.host}:{args.port}/viewer") print(f" TiTiler: http://{args.host}:{args.port}/cog/") print(f" Répertoire: {output_dir}") uvicorn.run(app, host=args.host, port=args.port, log_level='info') if __name__ == '__main__': main()