Files
boc/iom/sdk/python/landvex.py
T
Bernt bae705aa97 ARCHITECTURE: NFC roadmap, edge AI, audit logging
- Add NFC ePassport roadmap (ICAO 9303, eIDAS)
- Add TensorFlow.js edge face detection (BlazeFace)
- Add structured audit logger (GDPR-compliant)
- Risk scoring support

Part of KYC Apple Native UX v1.1.0
2026-06-29 16:24:48 +00:00

251 lines
7.2 KiB
Python

"""
Landvex Python SDK
Official Python client for Landvex API
"""
import requests
from typing import Optional, List, Dict, Any
from dataclasses import dataclass
from datetime import datetime
@dataclass
class Observation:
"""Observation data model"""
id: str
lat: float
lng: float
condition: int
obj_type: str
zoomer: str
status: str
date: str
rgi: Optional[float] = None
@dataclass
class Mission:
"""Mission data model"""
id: str
title: str
description: str
category: str
difficulty: str
reward_usd: float
total_observations: int
completed_observations: int
deadline: str
class LandvexClient:
"""Landvex API Client"""
def __init__(self, api_key: str, base_url: str = "https://api.landvex.com/v1"):
self.api_key = api_key
self.base_url = base_url.rstrip("/")
self.session = requests.Session()
self.session.headers.update({
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
})
def _request(self, method: str, endpoint: str, **kwargs) -> Dict[str, Any]:
"""Make API request"""
url = f"{self.base_url}/{endpoint.lstrip('/')}"
response = self.session.request(method, url, **kwargs)
response.raise_for_status()
return response.json()
# === Observations ===
def list_observations(
self,
lat: Optional[float] = None,
lng: Optional[float] = None,
radius: Optional[float] = None,
limit: int = 100,
status: Optional[str] = None,
) -> List[Observation]:
"""List observations with optional filtering"""
params = {"limit": limit}
if lat is not None:
params["lat"] = lat
if lng is not None:
params["lng"] = lng
if radius is not None:
params["radius"] = radius
if status is not None:
params["status"] = status
data = self._request("GET", "/observations", params=params)
return [
Observation(
id=obs["id"],
lat=obs["lat"],
lng=obs["lng"],
condition=obs["condition"],
obj_type=obs["type"],
zoomer=obs["zoomer"],
status=obs["status"],
date=obs["date"],
rgi=obs.get("rgi"),
)
for obs in data.get("observations", [])
]
def get_observation(self, observation_id: str) -> Observation:
"""Get single observation by ID"""
data = self._request("GET", f"/observations/{observation_id}")
obs = data["observation"]
return Observation(
id=obs["id"],
lat=obs["lat"],
lng=obs["lng"],
condition=obs["condition"],
obj_type=obs["type"],
zoomer=obs["zoomer"],
status=obs["status"],
date=obs["date"],
rgi=obs.get("rgi"),
)
def create_observation(
self,
lat: float,
lng: float,
image_url: Optional[str] = None,
evidence: Optional[Dict] = None,
) -> Observation:
"""Create new observation"""
payload = {
"lat": lat,
"lng": lng,
}
if image_url:
payload["image_url"] = image_url
if evidence:
payload["evidence"] = evidence
data = self._request("POST", "/observations", json=payload)
return self.get_observation(data["id"])
# === Missions ===
def list_missions(self, status: Optional[str] = None) -> List[Mission]:
"""List available missions"""
params = {}
if status:
params["status"] = status
data = self._request("GET", "/missions", params=params)
return [
Mission(
id=m["id"],
title=m["title"],
description=m["description"],
category=m["category"],
difficulty=m["difficulty"],
reward_usd=m["reward_usd"],
total_observations=m["total_observations"],
completed_observations=m["completed_observations"],
deadline=m["deadline"],
)
for m in data.get("missions", [])
]
def accept_mission(self, mission_id: str) -> Dict:
"""Accept a mission"""
return self._request("POST", f"/missions/{mission_id}/accept")
# === Indexes ===
def get_rgi(self, lat: float, lng: float) -> Dict:
"""Get Reality Gap Index for location"""
return self._request("GET", "/indexes/rgi", params={"lat": lat, "lng": lng})
def get_umi(self, lat: float, lng: float) -> Dict:
"""Get Urban Morphology Index for location"""
return self._request("GET", "/indexes/umi", params={"lat": lat, "lng": lng})
# === Visual Geolocation ===
def analyze_image(
self,
image_path: str,
image_id: Optional[str] = None,
) -> Dict:
"""Analyze image with visual geolocation"""
payload = {"image_path": image_path}
if image_id:
payload["image_id"] = image_id
return self._request("POST", "/visual-geolocation/analyze", json=payload)
def batch_analyze(self, images: List[Dict]) -> Dict:
"""Batch analyze multiple images"""
return self._request("POST", "/visual-geolocation/batch", json={"images": images})
# === Decisions ===
def get_recommendations(
self,
stakeholder: str,
lat: float,
lng: float,
) -> Dict:
"""Get decision recommendations"""
return self._request("POST", "/decisions/recommend", json={
"stakeholder": stakeholder,
"lat": lat,
"lng": lng,
})
# === Stats ===
def get_stats(self) -> Dict:
"""Get dashboard statistics"""
return self._request("GET", "/stats")
def get_earnings(self) -> Dict:
"""Get earnings data"""
return self._request("GET", "/stats/earnings")
# === Health ===
def health_check(self) -> Dict:
"""Check API health"""
return self._request("GET", "/health")
# Convenience functions
def create_client(api_key: str, base_url: Optional[str] = None) -> LandvexClient:
"""Create Landvex client"""
if base_url:
return LandvexClient(api_key, base_url)
return LandvexClient(api_key)
# Example usage
if __name__ == "__main__":
# Initialize client
client = create_client("your-api-key")
# Check health
health = client.health_check()
print(f"API Status: {health['status']}")
# List observations
observations = client.list_observations(lat=59.3293, lng=18.0686, radius=1000)
print(f"Found {len(observations)} observations")
# Get RGI
rgi = client.get_rgi(59.3293, 18.0686)
print(f"RGI Score: {rgi['rgi']}")
# Get recommendations
recommendations = client.get_recommendations("municipality", 59.3293, 18.0686)
print(f"Recommendations: {len(recommendations['recommendations'])}")