- Ajout de convert_to_cog() et generate_cog_metadata() dans rendering.py - Nouveau module viewer.py: génération HTML MapLibre GL JS avec couches et opacité - Nouveau module server.py: serveur FastAPI avec TiTiler pour tuiles COG - Pipeline: étapes 5 (COGs) et 6 (viewer web) après le rapport PDF - CLI: flag --no-viewer pour désactiver la génération du viewer - run.sh: commande 'serve' pour démarrer le serveur sur port 8000 - Dockerfile: ajout de rio-cogeo, titiler.core, fastapi, uvicorn, piexif - setup.py: point d'entrée lidar-server Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
117 lines
4.1 KiB
Python
117 lines
4.1 KiB
Python
"""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(
|
|
'<html><head><title>LiDAR Server</title>'
|
|
'<style>body{font-family:sans-serif;max-width:600px;margin:40px auto;padding:0 20px}'
|
|
'h1{color:#1a1a2e}a{color:#4fc3f7}</style></head>'
|
|
'<body>'
|
|
'<h1>Serveur LiDAR Archéologique</h1>'
|
|
'<p><a href="/viewer">Visualisations</a></p>'
|
|
'<p>TiTiler API: <a href="/cog/">/cog/</a></p>'
|
|
'</body></html>'
|
|
)
|
|
|
|
@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'<li><a href="/viewer/{f.stem}">{f.stem}</a></li>'
|
|
for f in viewers
|
|
)
|
|
return HTMLResponse(
|
|
f'<html><head><title>LiDAR Viewer</title>'
|
|
f'<style>body{{font-family:sans-serif;max-width:600px;margin:40px auto;padding:0 20px}}'
|
|
f'h1{{color:#1a1a2e}}li{{margin:8px 0}}a{{color:#4fc3f7}}</style></head>'
|
|
f'<body><h1>Visualisations LiDAR</h1><ul>{links}</ul></body></html>'
|
|
)
|
|
return HTMLResponse('<html><body><p>Aucun viewer disponible</p></body></html>')
|
|
|
|
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() |