""" Mobile SDK for quiXzoom app iOS/Android integration with IOM platform """ from typing import Dict, List, Optional from dataclasses import dataclass import json @dataclass class MobileConfig: """Configuration for mobile SDK""" api_url: str api_key: str timeout: int = 30 max_image_size: int = 10 * 1024 * 1024 # 10MB cache_enabled: bool = True offline_mode: bool = False class IOMMobileSDK: """ Mobile SDK for quiXzoom app Features: - Offline observation capture - Image compression - GPS tagging - Batch sync - Push notifications - Visual geolocation (NEW) - Evidence package extraction (NEW) """ def __init__(self, config: MobileConfig): self.config = config self.offline_queue: List[Dict] = [] self.cache: Dict = {} self.visual_geo_enabled = True def capture_observation( self, image_data: bytes, latitude: float, longitude: float, notes: Optional[str] = None ) -> Dict: """ Capture observation from mobile device Args: image_data: JPEG/PNG image bytes latitude: GPS latitude longitude: GPS longitude notes: Optional notes Returns: Observation data """ # Compress image compressed = self._compress_image(image_data) # Extract visual geolocation evidence (NEW) evidence_package = None if self.visual_geo_enabled: evidence_package = self._extract_evidence(compressed) # Create observation with evidence observation = { "id": f"OBS-MOB-{self._generate_id()}", "timestamp": self._get_timestamp(), "latitude": latitude, "longitude": longitude, "image_size": len(compressed), "notes": notes, "status": "pending", "evidence_package": evidence_package, # NEW "visual_geolocation": { "enabled": self.visual_geo_enabled, "evidence_layers": len(evidence_package) if evidence_package else 0 } } # Queue for sync if self.config.offline_mode: self.offline_queue.append(observation) return {"status": "queued", "observation": observation} # Sync immediately return self._sync_observation(observation, compressed) def sync_offline_queue(self) -> Dict: """Sync queued observations""" results = [] for observation in self.offline_queue: result = self._sync_observation(observation, None) results.append(result) self.offline_queue.clear() return { "synced": len(results), "results": results } def get_dashboard(self) -> Dict: """Get mobile-optimized dashboard""" return { "stats": { "missions_completed": 12, "missions_available": 34, "earnings_usd": 245.50, "rating": 4.8 }, "nearby_missions": [ { "id": "MIS-001", "title": "Street lighting inspection", "distance_m": 450, "reward_usd": 15.00, "deadline": "2026-06-27T18:00:00Z" }, { "id": "MIS-002", "title": "Sidewalk condition survey", "distance_m": 890, "reward_usd": 20.00, "deadline": "2026-06-28T12:00:00Z" } ], "notifications": [ { "type": "mission_available", "message": "New mission near you!", "timestamp": "2026-06-26T11:00:00Z" } ] } def submit_mission( self, mission_id: str, observations: List[Dict], metadata: Optional[Dict] = None ) -> Dict: """Submit completed mission""" submission = { "mission_id": mission_id, "submitted_at": self._get_timestamp(), "observations": observations, "metadata": metadata or {}, "status": "submitted" } # In production, send to API return { "status": "submitted", "submission_id": f"SUB-{self._generate_id()}", "estimated_review_time": "24h" } def get_mission_details(self, mission_id: str) -> Dict: """Get mission details""" return { "id": mission_id, "title": "Street lighting inspection", "description": "Inspect and photograph street lighting in your area", "requirements": [ "iPhone 12+ or Android 12MP+", "Daylight photos", "GPS enabled" ], "reward_usd": 15.00, "deadline": "2026-06-27T18:00:00Z", "location": { "latitude": 59.3293, "longitude": 18.0686, "radius_m": 500 } } def _extract_evidence(self, image_data: bytes) -> Dict: """Extract evidence package from image (NEW)""" # In production, call visual geolocation API # For now, return simulated evidence return { "visual_objects": [], "semantic_objects": [], "text_detections": [], "geometric_features": [], "environmental_signals": [], "temporal_signals": {} } def _compress_image(self, image_data: bytes) -> bytes: """Compress image for mobile upload""" # In production, use PIL to compress # For now, return as-is return image_data def _sync_observation(self, observation: Dict, image_data: Optional[bytes]) -> Dict: """Sync observation to server""" # In production, send to API return { "status": "synced", "observation_id": observation["id"] } def _generate_id(self) -> str: """Generate unique ID""" import uuid return uuid.uuid4().hex[:8] def _get_timestamp(self) -> str: """Get current timestamp""" from datetime import datetime return datetime.utcnow().isoformat() # Example usage def example_mobile_sdk(): """Example: Mobile SDK usage""" print("=== Mobile SDK Demo ===\n") config = MobileConfig( api_url="https://api.iom.landvex.com", api_key="mobile_api_key", offline_mode=True ) sdk = IOMMobileSDK(config) # Capture observation print("Capturing observation...") result = sdk.capture_observation( image_data=b"fake_image_data", latitude=59.3293, longitude=18.0686, notes="Broken street light" ) print(f"Status: {result['status']}") # Get dashboard print("\nGetting dashboard...") dashboard = sdk.get_dashboard() print(f"Missions available: {dashboard['stats']['missions_available']}") print(f"Earnings: ${dashboard['stats']['earnings_usd']}") # Sync offline queue print("\nSyncing offline queue...") sync_result = sdk.sync_offline_queue() print(f"Synced: {sync_result['synced']} observations") return sdk if __name__ == '__main__': example_mobile_sdk()