bae705aa97
- 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
251 lines
7.2 KiB
Python
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'])}")
|