Metadata-Version: 2.4
Name: datex-nl-geo-fr
Version: 1.2.0
Summary: Conversion canonique NL ↔ DATEX II v3 ↔ GeoJSON pour la signalisation routière française
Author-email: CEREMA Méditerranée — Nicolas LAVAL <nicolas.laval@cerema.fr>
License: EUPL-1.2
Project-URL: Homepage, https://gitlab.cerema.fr/nicolas.laval/datex-nl-geo-fr
Project-URL: Repository, https://gitlab.cerema.fr/nicolas.laval/datex-nl-geo-fr
Project-URL: Issues, https://gitlab.cerema.fr/nicolas.laval/datex-nl-geo-fr/-/issues
Keywords: datex,datex-ii,openlr,bd-topo,ign,signalisation,routier,geojson
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: European Union Public Licence 1.2 (EUPL 1.2)
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: GIS
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.27
Requires-Dist: pydantic>=2.0
Requires-Dist: shapely>=2.0
Requires-Dist: lxml>=4.9
Requires-Dist: openlr>=1.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"
Provides-Extra: postgis
Requires-Dist: psycopg[binary]>=3.1; extra == "postgis"
Dynamic: license-file

# datex-nl-geo-fr

**Conversion canonique entre langage naturel, DATEX II v3 et GeoJSON pour la signalisation routière française.**

Bibliothèque Python autonome extraite du projet [audit-iisr](https://gitlab.cerema.fr/nicolas.laval/audit-iisr) pour servir de brique réutilisable par tout outil traitant de la signalisation routière en France (gestionnaires de voirie, plateformes territoriales, applications de mobilité, exploitants DATEX II).

## Vue d'ensemble

```
                         ┌─── GeoSituation (modèle pivot canonique) ──┐
       ┌─────────┐       │                                              │      ┌──────────┐
       │  Texte  │ ─────▶│ from_pipeline_result / from_carto_click /  │ ────▶│ DATEX II │
       │   NL    │       │ from_carto_polygon                          │      │   v3 XML │
       └─────────┘       │                                              │      └──────────┘
                         │ to_text / to_datex_xml / to_geojson /       │
       ┌─────────┐       │ to_pivot_context                             │      ┌──────────┐
       │  Carto  │ ─────▶│                                              │ ────▶│ GeoJSON  │
       │ (clic)  │       │ merge() — patches NL + carto                 │      │ RFC 7946 │
       └─────────┘       └────────────────────────────────────────────┘      └──────────┘
```

## Installation

```bash
pip install datex-nl-geo-fr
```

ou depuis la source :

```bash
git clone https://gitlab.cerema.fr/nicolas.laval/datex-nl-geo-fr.git
cd datex-nl-geo-fr
pip install -e .[dev]
```

## Utilisation rapide

### Configuration LLM (provider-agnostique)

```python
import os
from datex_nl_geo_fr.llm import OpenAICompatibleClient, set_default_llm

# Albert (DINUM) — recommandé secteur public français
set_default_llm(OpenAICompatibleClient(
    base_url="https://albert.api.etalab.gouv.fr/v1",
    api_key=os.environ["ALBERT_API_KEY"],
    model="mistralai/Mistral-Small-3.2-24B-Instruct-2506",
))

# Ou OpenAI :
# set_default_llm(OpenAICompatibleClient(
#     base_url="https://api.openai.com/v1",
#     api_key=os.environ["OPENAI_API_KEY"],
#     model="gpt-4o-mini",
# ))

# Ou Ollama local :
# set_default_llm(OpenAICompatibleClient(
#     base_url="http://localhost:11434/v1",
#     model="qwen2.5:14b",
# ))

# Ou un adapter custom (Anthropic SDK, vLLM custom, etc.) en
# implémentant le protocole LLMClient
```

### NL → DATEX II + GeoJSON

```python
import asyncio
from datex_nl_geo_fr.pipeline import resolve_location
from datex_nl_geo_fr.translator import GeoDatexTranslator

async def main():
    text = "Zone 30 permanente avenue Pasteur à Bordeaux du numéro 10 au numéro 50"
    result = await resolve_location(text)  # utilise le LLM par défaut configuré
    situation = GeoDatexTranslator.from_pipeline_result(result)

    # Projections vers les formats cibles
    print(GeoDatexTranslator.to_text(situation))
    print(GeoDatexTranslator.to_geojson(situation))
    print(GeoDatexTranslator.to_datex_xml(situation))

asyncio.run(main())
```

### Cache géocodage personnalisé

```python
from datex_nl_geo_fr.cache import GeoCache, set_default_cache

class RedisGeoCache:
    """Backend Redis pour partage inter-processus."""
    def __init__(self, redis_url): ...
    def get(self, key): ...
    def set(self, key, value, ttl_seconds=86400): ...

set_default_cache(RedisGeoCache("redis://localhost:6379"))
# Désormais geocode_ban() et tous les drivers utilisent ce cache.
```

### Sélection runtime du driver de référentiel routier

```bash
# Production (BD TOPO IGN Géoplateforme — recommandé)
export IISR_GEO_DRIVER=ign

# Fallback hors ligne
export IISR_GEO_DRIVER=osm

# PostGIS local (post-MVP, pour gros volumes)
export IISR_GEO_DRIVER=pgis
export PGIS_DSN="postgres://user@localhost/bdtopo"
```

## Architecture

### `GeoSituation` — modèle pivot canonique

Tout passe par cette structure Pydantic v2. Les méthodes `from_*` produisent une `GeoSituation`, les méthodes `to_*` la projettent vers un format cible. Les round-trips sont testés en CI.

| Champ | Type | Description |
|---|---|---|
| `troncons` | `list[TronconMatch]` | Tronçons BD TOPO matchés (cleabs pérennes) |
| `repere_debut`, `repere_fin` | `Optional[PointRepere]` | PR autoroute, numéro de voirie, BAN, etc. |
| `polygon_geojson` | `Optional[dict]` | Polygone si zone dessinée |
| `commune_nom`, `commune_insee` | `str` | Localisation administrative |
| `gestionnaires` | `list[str]` | Domanialité (commune / dept / État) |
| `nature_voie`, `numero_route`, `nom_voie` | `str` | Attributs métier |
| `sens` | `Literal["aller","retour","bidirectionnel"]` | Sens de circulation |
| `type_zone` | `Literal["lineaire","ponctuel","rayon","polygon"]` | Topologie |

### Drivers de référentiel routier

| Driver | Source | Usage |
|---|---|---|
| `ign_geoplateforme` | WFS BD TOPO IGN | **Recommandé prod** — `cleabs` pérennes officiels |
| `osm_overpass` | Overpass API | Fallback hors ligne, démos rapides |
| `bdtopo_postgis` | PostGIS local | Volumes massifs (>10k tronçons par requête) |

Tous exposent la même interface : `pick_at_point`, `troncons_by_name_in_commune`, `commune_geom`, `pois_around`, etc.

## Modules

| Module | Rôle |
|---|---|
| `translator.py` | `GeoDatexTranslator` — façade unique des conversions |
| `schema.py` | Modèles Pydantic v2 (`GeoSituation`, `TronconMatch`, `PointRepere`, `POI`) |
| `datex_builder.py` | Construction XML DATEX II v3 (`linearByCode` + `linearByCoordinates` + `areaExtension`) |
| `datex_merger.py` | Fusion DATEX importé + extraction interne |
| `openlr_encoder.py` | Encodeur OpenLR base64 pour `linearByCode` |
| `extractor.py` | Extraction NL → schema (LLM-driven optionnel) |
| `geocoders.py` | Wrappers BAN api-adresse, Nominatim |
| `map_matcher.py` | Map matching tronçons à partir d'un set de coordonnées |
| `pipeline.py` | Orchestration 4 phases (extraction → géocodage → matching → encodage) |
| `pipeline_inverse.py` | DATEX → NL via VLM PDF + résolution multi-voies BD TOPO |
| `drivers/` | Plug-ins référentiels routiers |
| `cli.py` | Commande `datex-geo` standalone |

## Tests

```bash
# Tests unitaires (sans réseau)
pytest -m "not network"

# Tests intégration (BAN + IGN WFS — vérité terrain)
pytest -m network
```

## Licence

Distribué sous **EUPL-1.2** (Licence Publique de l'Union Européenne) — compatible avec l'ouverture des composants logiciels du secteur public français.

## Contributions

Issues et merge requests bienvenus sur [gitlab.cerema.fr/nicolas.laval/datex-nl-geo-fr](https://gitlab.cerema.fr/nicolas.laval/datex-nl-geo-fr).

## Crédits

Extrait du projet **audit-iisr** (CEREMA Méditerranée) — outil d'audit et de rédaction juridique pour la signalisation routière française. Voir [CHANGELOG.md](CHANGELOG.md) pour l'historique de cette extraction.
