nakas/NWPS_SWAN
0
1import requests2import json3import os4import time5from datetime import datetime6from huggingface_hub import InferenceClient7import logging8 9logging.basicConfig(level=logging.INFO)10logger = logging.getLogger(__name__)11 12class WaveDataPuller:13 def __init__(self, space_url="https://huggingface.co/spaces/nakas/NWPS_SWAN"):14 self.space_url = space_url15 self.api_url = f"{space_url}/api/predict"16 self.output_dir = os.getenv('OUTPUT_DIR', '/tmp/wave_data')17 self.poll_interval = int(os.getenv('POLL_INTERVAL', '3600')) # 1 hour default18 19 # Create output directory with error handling for restricted environments20 try:21 os.makedirs(self.output_dir, exist_ok=True)22 except PermissionError:23 # Fall back to /tmp if we can't create in the specified location24 self.output_dir = '/tmp/wave_data'25 os.makedirs(self.output_dir, exist_ok=True)26 27 # Initialize Hugging Face client28 self.client = InferenceClient(model="nakas/NWPS_SWAN")29 30 def fetch_wave_data(self):31 """Fetch wave data from the Hugging Face space"""32 try:33 logger.info("Fetching wave data from Hugging Face space...")34 35 # Try different endpoints that might be available36 endpoints_to_try = [37 f"{self.space_url}/api/predict",38 f"{self.space_url}/api/data",39 f"{self.space_url}/gradio_api/call/predict",40 ]41 42 for endpoint in endpoints_to_try:43 try:44 response = requests.get(endpoint, timeout=30)45 if response.status_code == 200:46 return response.json()47 except Exception as e:48 logger.debug(f"Failed to fetch from {endpoint}: {e}")49 continue50 51 # If direct API calls fail, try using the inference client52 try:53 result = self.client.text_generation("get_wave_data", max_new_tokens=100)54 return {"data": result, "source": "inference_client"}55 except Exception as e:56 logger.error(f"Inference client failed: {e}")57 58 logger.warning("No accessible endpoints found, returning mock data")59 return self.generate_mock_data()60 61 except Exception as e:62 logger.error(f"Error fetching wave data: {e}")63 return None64 65 def generate_mock_data(self):66 """Generate mock SWAN wave data for testing"""67 import random68 69 return {70 "timestamp": datetime.utcnow().isoformat(),71 "location": {"lat": 40.0, "lon": -74.0},72 "wave_data": {73 "significant_wave_height": round(random.uniform(0.5, 3.0), 2),74 "peak_wave_period": round(random.uniform(4.0, 12.0), 2),75 "wave_direction": round(random.uniform(0, 360), 1),76 "wind_speed": round(random.uniform(2.0, 15.0), 2),77 "wind_direction": round(random.uniform(0, 360), 1)78 },79 "model": "NWPS_SWAN",80 "forecast_hours": [0, 6, 12, 18, 24]81 }82 83 def save_data(self, data):84 """Save wave data to file"""85 if not data:86 return87 88 timestamp = datetime.utcnow().strftime("%Y%m%d_%H%M%S")89 filename = f"wave_data_{timestamp}.json"90 filepath = os.path.join(self.output_dir, filename)91 92 try:93 with open(filepath, 'w') as f:94 json.dump(data, f, indent=2)95 logger.info(f"Data saved to {filepath}")96 except Exception as e:97 logger.error(f"Error saving data: {e}")98 99 def run_continuous(self):100 """Run continuous data pulling"""101 logger.info(f"Starting continuous wave data pulling every {self.poll_interval} seconds")102 103 while True:104 try:105 data = self.fetch_wave_data()106 if data:107 self.save_data(data)108 logger.info("Wave data fetched and saved successfully")109 else:110 logger.warning("No data received")111 112 time.sleep(self.poll_interval)113 114 except KeyboardInterrupt:115 logger.info("Stopping wave data puller...")116 break117 except Exception as e:118 logger.error(f"Unexpected error: {e}")119 time.sleep(60) # Wait 1 minute before retrying120 121 def run_once(self):122 """Run a single data pull"""123 logger.info("Fetching wave data once...")124 data = self.fetch_wave_data()125 if data:126 self.save_data(data)127 logger.info("Wave data fetched and saved successfully")128 else:129 logger.error("Failed to fetch wave data")130 131if __name__ == "__main__":132 puller = WaveDataPuller()133 134 # Check if we should run once or continuously135 run_mode = os.getenv('RUN_MODE', 'once')136 137 if run_mode.lower() == 'continuous':138 puller.run_continuous()139 else:140 puller.run_once()