Spaces:
Sleeping
Sleeping
""" | |
Radar Data Downloader via Gradio | |
================================== | |
This script mimics part of Supercell Wx’s functionality by downloading the latest | |
radar data file (Level 2 or Level 3) from public AWS S3 buckets. It uses boto3 in unsigned mode, | |
so no AWS credentials or API keys are required. The Gradio interface lets you select the | |
data type, radar station, and date (in UTC) to download a file. | |
""" | |
import datetime | |
import io | |
import boto3 | |
from botocore import UNSIGNED | |
from botocore.client import Config | |
import gradio as gr | |
def fetch_latest_radar_data(radar_type, station, date_str): | |
""" | |
Downloads the latest radar data file from the appropriate S3 bucket. | |
Parameters: | |
radar_type (str): Either "Level 2" or "Level 3". | |
station (str): Radar station identifier (e.g. "KTLX"). | |
date_str (str): Date string in the format "YYYY-MM-DD". If blank, uses current UTC date. | |
Returns: | |
str: A text summary including the S3 key, file size, last modified date, | |
and a hex preview of the first 64 bytes of the file. | |
""" | |
# Parse the date (default to current UTC if empty) | |
if not date_str.strip(): | |
date_obj = datetime.datetime.utcnow() | |
else: | |
try: | |
date_obj = datetime.datetime.strptime(date_str, "%Y-%m-%d") | |
except ValueError: | |
return "Error: Date must be in YYYY-MM-DD format." | |
year = date_obj.strftime("%Y") | |
month = date_obj.strftime("%m") | |
day = date_obj.strftime("%d") | |
# Choose the appropriate bucket based on radar type. | |
if radar_type == "Level 2": | |
bucket_name = "noaa-nexrad-level2" | |
# For Level 2, the folder structure is: YYYY/MM/DD/STATION/ | |
prefix = f"{year}/{month}/{day}/{station.upper()}/" | |
elif radar_type == "Level 3": | |
bucket_name = "unidata-nexrad-level3" | |
# For Level 3, the structure is similar. | |
prefix = f"{year}/{month}/{day}/{station.upper()}/" | |
else: | |
return "Error: Invalid radar type selected." | |
# Create an S3 client with unsigned requests. | |
s3 = boto3.client('s3', config=Config(signature_version=UNSIGNED)) | |
try: | |
response = s3.list_objects_v2(Bucket=bucket_name, Prefix=prefix) | |
except Exception as e: | |
return f"Error accessing bucket: {e}" | |
if 'Contents' not in response: | |
return f"No data found for station {station.upper()} on {date_str} in {radar_type}." | |
# Sort objects by LastModified and choose the latest file. | |
objects = response['Contents'] | |
objects_sorted = sorted(objects, key=lambda x: x['LastModified']) | |
latest_object = objects_sorted[-1] | |
file_key = latest_object['Key'] | |
file_size = latest_object['Size'] | |
last_modified = latest_object['LastModified'] | |
# Download the file into a BytesIO buffer. | |
buffer = io.BytesIO() | |
try: | |
s3.download_fileobj(bucket_name, file_key, buffer) | |
except Exception as e: | |
return f"Error downloading file: {e}" | |
buffer.seek(0) | |
# Read a short preview (first 64 bytes) and convert to hex. | |
data_preview = buffer.read(64) | |
hex_preview = data_preview.hex() | |
# Return a summary of the downloaded file. | |
summary = ( | |
f"Downloaded file: {file_key}\n" | |
f"Size: {file_size} bytes\n" | |
f"Last Modified (UTC): {last_modified}\n" | |
f"Hex preview (first 64 bytes):\n{hex_preview}" | |
) | |
return summary | |
# Create the Gradio interface. | |
interface = gr.Interface( | |
fn=fetch_latest_radar_data, | |
inputs=[ | |
gr.inputs.Radio(choices=["Level 2", "Level 3"], label="Radar Data Type"), | |
gr.inputs.Textbox(label="Radar Station (e.g. KTLX)", default="KTLX"), | |
gr.inputs.Textbox(label="Date (YYYY-MM-DD)", default=datetime.datetime.utcnow().strftime("%Y-%m-%d")) | |
], | |
outputs="text", | |
title="Radar Data Downloader", | |
description=( | |
"This tool downloads the latest radar data file from public AWS S3 buckets " | |
"used by Supercell Wx. Choose a radar data type (Level 2 or Level 3), enter a " | |
"radar station (e.g. KTLX), and a date (UTC). In future iterations, you can add " | |
"visualization using OpenStreetMap (which requires no API keys)." | |
) | |
) | |
if __name__ == "__main__": | |
interface.launch() |