Skip to content
bvmcodePublic

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Stormy AI

Stormy AI is a LangGraph weather-briefing agent. You give it a place name; it geocodes the location, pulls live NOAA and partner data (NWS products, GFS, HRRR, MRMS, NEXRAD, GOES GLM, model soundings), runs deterministic precipitation diagnostics, and uses a configurable LLM (local Ollama or Hugging Face Inference Providers) to write a detailed markdown briefing.


What you get

Each run produces a structured weather briefing with:

  • Headline and bottom line
  • Forecast area (NWS forecast-zone locator map)
  • Active NWS alerts
  • Current weather (surface obs + radar/precip/lightning + diagnosis)
  • Current synoptic setup (Area Forecast Discussion plus latest-cycle GFS)
  • GFS regional charts and point guidance through 72 hours
  • HRRR analysis and HRRR-derived model sounding
  • Outlook from the forecast discussion
  • Day-by-day forecast for the next three days

Briefings are written locally under briefings/ and, by default, uploaded to S3. Each saved file includes Updated and Next update times aligned to the EventBridge cadence (hourly 8am–8pm US Eastern, plus 4am overnight). After upload, a bucket-root latest.txt pointer is updated with the newest briefing s3:// URI. Radar PNGs from plot_nexrad_level2, METAR station-model PNGs from plot_metar_observations, GFS chart PNGs from get_gfs_guidance, and cached forecast-zone maps from get_forecast are uploaded to the same bucket. Embedded images in the markdown use public HTTPS URLs. Pass --local (or set storage.upload_to_s3: false) to keep briefings and plots on disk only.


How it works (short)

User (CLI or ECS task)
    → briefing.run_briefing(location)
        → LangGraph: reset → agent ⇄ tools → collect_weather → agent
            → LLM + 12 weather tools
            → diagnose_precipitation when MRMS + HRRR are ready
        → markdown briefing (+ forecast-zone / radar / GFS images)
        → local file (+ S3 upload / latest.txt when upload_to_s3 is enabled)
  • LangGraph orchestrates the tool loop and shared weather state.
  • Tools fetch facts from public APIs and open data (no weather API keys).
  • Diagnostics fuse MRMS/HRRR/(optional NEXRAD/GLM) into an authoritative precip/storm JSON block injected into the system prompt.
  • The LLM narrates and structures the briefing; it is instructed not to invent observations.

Deep dive: docs/AGENT.md. Per-tool docs: docs/tools/. Deployment: docs/DEPLOYMENT.md.


Requirements

  • Python ≥ 3.14
  • uv (recommended) or pip
  • LLM backend — one of:
    • Ollama running locally with a chat model (e.g. gemma4:latest), or
    • Hugging Face Inference Providers with HF_TOKEN set (see Configuration)
  • System libraries for GRIB/NetCDF and cartography as needed by cfgrib / eccodes / Cartopy / Py-ART on your OS
  • AWS credentials (optional locally) — required only when S3 uploads are enabled (storage.upload_to_s3: true, the default)

Setup

# Install core package + dependencies (add --group dev for LangSmith Studio / lint)
uv sync

# Copy secrets template; add HF_TOKEN and LANGSMITH_API_KEY as needed
cp .env.example .env

# For Ollama: pull / start the model (name must match config.yaml llm.model)
ollama pull gemma4:latest

Run a briefing (CLI)

python main.py                     # default: Atco, NJ 08004
python main.py "Denver, CO"
python main.py --local             # local files only; skip S3 uploads
python main.py --local "Denver, CO"

The CLI prints the briefing and writes a timestamped file under briefings/. With S3 uploads enabled (default), it also uploads the briefing and plot images when credentials are available, and updates s3://<bucket>/latest.txt with the new briefing URI. Forecast-zone, radar, and GFS images are embedded as sized HTML <img> tags (zone maps use width="480"; radar/GFS use 720) — public HTTPS URLs when uploaded, otherwise local absolute paths. With --local, artifacts stay under briefings/, radar_plots/, metar_plots/, model_plots/, and forecast_zones/.


LangSmith Studio (langgraph dev)

langgraph.json registers the compiled graph (src/stormy_ai/agent.py:graph) so you can inspect and invoke it in LangSmith Studio.

# Installs langgraph-cli[inmem] from the dev dependency group
uv sync --group dev

# Ensure .env has LANGSMITH_API_KEY (see .env.example)
uv run langgraph dev

The CLI starts a local Agent Server and prints a Studio URL (typically https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024). In Studio, select the agent graph and invoke it with a messages input — for example a human message asking for a weather briefing for a location (same shape as graph.invoke in briefing.py).

On Safari, use uv run langgraph dev --tunnel if Studio cannot reach localhost.


Makefile

Docker builds, linting, and ECS/Terraform helpers live in the Makefile. List every target and what it does:

make help

Running plain make (no target) shows the same summary.


Docker

Build and run the agent container (linux/arm64):

make build
make local_run                     # uses HF_TOKEN and AWS creds from .env / aws configure

Or build and run directly (pass a location as the final argument):

docker buildx build --platform linux/arm64 -t wx_briefing_agent .
docker run --rm \
  -e HF_TOKEN=... \
  -e AWS_ACCESS_KEY_ID=... \
  -e AWS_SECRET_ACCESS_KEY=... \
  -e AWS_DEFAULT_REGION=us-east-1 \
  wx_briefing_agent "Denver, CO"

See docs/DEPLOYMENT.md for ECR push, ECS Fargate, and the EventBridge Scheduler cadence (hourly 8am–8pm ET, plus 4am overnight).


Configuration

Settings live in config.yaml. Copy .env.example to .env for secrets.

LLM providers

Ollama — local model, no API key:

llm:
  provider: ollama
  model: gemma4:latest

Hugging Face Inference Providers — cloud model via the HF router:

llm:
  provider: huggingface
  model: zai-org/GLM-5.3-Flash
  huggingface:
    inference_provider: baseten

Set HF_TOKEN in .env (create a token at huggingface.co/settings/tokens). inference_provider is appended to the model ID (:baseten) for the HF router.

Environment variables override config.yaml when set:

Variable Purpose
STORMY_CONFIG Path to config file (default: config.yaml)
STORMY_LLM_PROVIDER ollama or huggingface
STORMY_LLM_MODEL Model ID / Ollama tag
STORMY_LLM_TEMPERATURE Chat temperature
STORMY_HF_INFERENCE_PROVIDER HF Inference Provider (e.g. baseten, deepinfra)
HF_TOKEN Hugging Face API token (required for huggingface provider)
OLLAMA_MODEL Ollama model tag (legacy override for llm.model)
OLLAMA_BASE_URL Ollama API base URL

Paths and storage

Variable Default Purpose
BRIEFING_DIR briefings Local markdown output directory
BRIEFING_IMAGE_WIDTH 720 Default width (px) for embedded <img> tags (forecast-zone maps use 480)
RADAR_PLOT_DIR radar_plots Local NEXRAD PNG directory
METAR_PLOT_DIR metar_plots Local METAR station-model PNG directory
GFS_MODEL_PLOT_DIR model_plots Local GFS chart PNG directory
FORECAST_ZONE_PLOT_DIR forecast_zones Local forecast-zone PNG cache directory
STORMY_UPLOAD_TO_S3 true Upload briefings/plots to S3 (false = same as --local)
BRIEFING_S3_BUCKET stormy-ai-files S3 bucket for briefing uploads
BRIEFING_S3_PREFIX briefings Key prefix for briefing markdown
BRIEFING_LATEST_S3_KEY latest.txt Bucket-root key holding the newest briefing s3:// URI
RADAR_S3_BUCKET stormy-ai-files S3 bucket for radar plot uploads
RADAR_S3_PREFIX radar Key prefix for radar PNGs
METAR_S3_BUCKET stormy-ai-files S3 bucket for METAR plot uploads
METAR_S3_PREFIX metar Key prefix for METAR PNGs
GFS_S3_BUCKET stormy-ai-files S3 bucket for GFS chart uploads
GFS_S3_PREFIX models/gfs Key prefix for GFS chart uploads
FORECAST_ZONE_S3_BUCKET same as briefing bucket S3 bucket for cached forecast-zone PNGs
FORECAST_ZONE_S3_PREFIX forecast_zones Key prefix (<prefix>/<ZONE_ID>.png)
STORMY_S3_PUBLIC_BASE (empty) Override HTTPS base for embed URLs (e.g. CloudFront)

In config.yaml, the same toggle is storage.upload_to_s3 (default true).

S3 object layout:

s3://stormy-ai-files/briefings/<YYYY-MM-DD>/<zip_code>/<HH_MM>.md
s3://stormy-ai-files/latest.txt                              ← s3:// URI of newest briefing
s3://stormy-ai-files/radar/<YYYY-MM-DD>/<HH>_<MM>.png
s3://stormy-ai-files/metar/<YYYY-MM-DD>/<HH>_<MM>.png
s3://stormy-ai-files/models/gfs/<YYYY-MM-DD>/<image_type>/<forecast_hour>.png
s3://stormy-ai-files/forecast_zones/<ZONE_ID>.png            ← cached; reused across briefings

Public embeds require a bucket policy that allows s3:GetObject on briefings/*, radar/*, metar/*, models/*, and forecast_zones/*.

No API keys are required for NWS, Open-Meteo geocoding, MRMS, HRRR (via Herbie), NEXRAD, or GLM open data. The NWS client sends a fixed User-Agent.


Development

make help      # list all Makefile targets
make lint      # flake8 + isort check
make format    # black + isort
uv run python -m unittest discover -s tests -v
uv run langgraph dev   # LangSmith Studio (requires uv sync --group dev)

Tools at a glance

Tool Why it is used
geocode_location Place name → lat/lon for every other tool
current_conditions Official nearest METAR/ASOS observation
get_alerts Authoritative watches / warnings / advisories
get_forecast Official 12-hour periods + hourly rows (~3 days) + cached forecast-zone map
forecast_discussion WFO reasoning for synoptic setup and outlook
get_mrms_precipitation Current precip rate and nearby echoes (CONUS)
get_hrrr_environment Model thermo, precip-type flags, CAPE/CIN
get_gfs_guidance Latest coherent GFS cycle, point guidance, and day 1–3 surface/500/850/300-mb charts
analyze_nexrad_level2 Site radar structure and dual-pol detail
plot_nexrad_level2 Radar image for the briefing (local; S3 when uploads enabled)
plot_metar_observations Regional METAR/ASOS station-model map
get_lightning Recent GLM total-lightning activity
analyze_current_skewt Full MetPy sounding analysis from HRRR

After MRMS and HRRR return, diagnose_precipitation builds the deterministic diagnosis the model must respect for current precip and storm character. See docs/tools/DIAGNOSTICS.md.


Project layout

stormy_ai/
├── main.py                 CLI entry
├── config.yaml             LLM, briefing, paths, and storage settings
├── langgraph.json          LangGraph CLI / LangSmith Studio config
├── .env.example            Secrets template (copy to .env)
├── Dockerfile              Container image (linux/arm64)
├── Makefile                Docker build, lint, Terraform/ECS helpers
├── README.md               This file
├── pyproject.toml          Package and dependencies
├── infra/                  Terraform for ECS Fargate + EventBridge Scheduler
├── docs/
│   ├── AGENT.md            LangGraph agent orchestration
│   ├── DEPLOYMENT.md       Docker, ECR, and ECS Fargate
│   └── tools/              Per-tool and diagnostics docs
├── tests/                  Unit tests
├── briefings/              Generated markdown briefings
├── radar_plots/            Generated radar PNGs
├── metar_plots/            Generated METAR station-model PNGs
├── model_plots/            Generated regional GFS chart PNGs
├── forecast_zones/         Cached forecast-zone PNGs (local)
└── src/stormy_ai/
    ├── agent.py            LangGraph definition (`graph`; Studio entry)
    ├── briefing.py         run_briefing(), markdown + optional S3 output
    ├── config.py           config.yaml loader (`upload_to_s3`, paths)
    ├── llm.py              LLM provider factory
    ├── utils.py            S3 upload (gated), tool-content parsing
    ├── diagnostics.py      Deterministic precip / storm fusion
    ├── prompts/            SYSTEM_PROMPT
    └── tools/              LangChain tool implementations

Documentation map

Doc Contents
docs/AGENT.md LangGraph graph, state, tool loop, diagnosis injection
docs/DEPLOYMENT.md Docker image, ECR, Terraform, ECS Fargate, scheduled runs
docs/tools/GEOCODE.md Open-Meteo place → lat/lon
docs/tools/NWS.md Forecast, zone maps, alerts, obs, AFD
docs/tools/MRMS.md Current precip / reflectivity mosaic
docs/tools/HRRR.md Model environment and precip-type guidance
docs/tools/GFS.md GFS point guidance and regional charts
docs/tools/NEXRAD.md Level II analysis and plots
docs/tools/METAR.md Regional METAR station-model plots
docs/tools/LIGHTNING.md GOES GLM
docs/tools/SKEWT.md HRRR model sounding + MetPy
docs/tools/DIAGNOSTICS.md Deterministic multi-source fusion

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages