SurfSense / README.md
JW55's picture
Update README.md
f5708db verified
|
Raw History Blame Contribute Delete
13.3 kB

A newer version of the Gradio SDK is available: 6.31.0

Upgrade
metadata
title: SurfSense
emoji: πŸ„
colorFrom: blue
colorTo: indigo
sdk: gradio
sdk_version: 6.19.0
app_file: app_gradio.py
pinned: false

πŸ„ SurfSense - AI Surf Trip Planning Assistant

Python 3.10+

A terminal-based conversational AI assistant that helps surfers plan trips by analyzing surf forecasts, evaluating conditions against skill levels, and creating optimized multi-day itineraries. Powered by Azure OpenAI GPT-4o-mini with function-calling, delegating to deterministic sub-agents for data aggregation, condition assessment, and trip planning.

🌊 Features

  • πŸ€– Azure OpenAI Orchestrator: GPT-4o-mini with function-calling manages dialogue and delegates to specialized sub-agents
  • πŸ” Dynamic Spot Research: Tavily-powered web search + LLM extraction β€” ask about any surf spot worldwide, no pre-built database needed
  • πŸ’¬ Terminal Chat Interface: Natural conversation β€” no slash commands needed, just describe your trip
  • 🌊 Multi-Source Forecasts: Integrates Stormglass (paid) and Open-Meteo (free, no API key) for wave, swell, wind, and tide data
  • πŸ“Š Skill-Level Safety: Deterministic scoring evaluates conditions against beginner/intermediate/advanced thresholds
  • πŸ“… Trip Optimization: Greedy multi-day itinerary planning with travel-time penalties (Haversine) and spot diversity
  • πŸ–οΈ Contextual Data: Parking, accessibility, reviews, and safety information for surf spots

πŸ“‹ Prerequisites

  • Python 3.10+
  • Azure OpenAI API access (GPT-4o-mini deployment with function-calling support)
  • Tavily API key (free tier: 1,000 searches/month β€” get one at tavily.com)
  • macOS, Linux, or Windows

πŸš€ Quick Start

1. Clone and Setup

git clone <repository-url>
cd SurfSense

# Create virtual environment
python -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate

2. Install Dependencies

make install
# Or manually:
pip install -r requirements.txt

3. Configure

cp .env.example .env
# Edit .env with your credentials:
#   AZURE_OPENAI_ENDPOINT=https://<your-resource>.openai.azure.com/
#   AZURE_OPENAI_API_KEY=<your-key>
#   AZURE_OPENAI_DEPLOYMENT_NAME=gpt-4o
#   TAVILY_API_KEY=tvly-<your-key>

4. Verify API Connections

make check-api
# Or:
pytest tests/test_api_connections.py -v

This pings every external service (Azure OpenAI / OpenAI, Tavily, Stormglass, Open-Meteo, NOAA) and confirms your API keys are valid. Fix any failures before starting the app.

5. Start Chatting!

make run
# Or:
python -m app

πŸ’¬ Example Conversation

============================================================
πŸ„ SurfSense - AI Surf Trip Planning Assistant
============================================================

Version: 0.1.0

πŸ“‹ Configuration Summary:
   Azure OpenAI Deployment: gpt-4o

βœ… Ready! Type 'quit' or 'exit' to leave.

------------------------------------------------------------

πŸ§‘ You: How's Caparica looking this weekend? I'm an intermediate surfer.

πŸ€– SurfSense: Let me research that spot and check the forecast...

   πŸ“ Costa da Caparica, Portugal (beach break, sand bottom)
   Skill level: Beginner–Intermediate friendly

   Saturday: 3-4ft waves, light E wind (offshore), 12s period
   Rating: βœ… Ideal for intermediate β€” clean conditions all morning

   Sunday: 2-3ft, NW wind picking up by noon
   Rating: ⚠️ Suitable until 11am, then conditions deteriorate

   Best window: Saturday 7am–12pm (score: 82/100)

   Hazards: rip currents near the northern end
   Parking: free lots along the coast road

πŸ§‘ You: quit

πŸ‘‹ Goodbye!

πŸ“ Project Structure

SurfSense/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ __init__.py              # Package info and version
β”‚   β”œβ”€β”€ __main__.py              # Terminal chat entry point
β”‚   β”œβ”€β”€ agents/
β”‚   β”‚   β”œβ”€β”€ orchestrator.py      # LLM-powered orchestrator (function-calling)
β”‚   β”‚   β”œβ”€β”€ research_agent.py    # Dynamic spot research (Tavily + LLM)
β”‚   β”‚   β”œβ”€β”€ forecast_data_agent.py   # Data aggregation sub-agent
β”‚   β”‚   β”œβ”€β”€ condition_agent.py       # Condition assessment sub-agent
β”‚   β”‚   └── trip_planning_agent.py   # Trip planning sub-agent
β”‚   β”œβ”€β”€ core/
β”‚   β”‚   β”œβ”€β”€ llm_service.py       # Azure OpenAI + fallback providers
β”‚   β”‚   └── logger.py            # Structured logging with redaction
β”‚   β”œβ”€β”€ forecasting/
β”‚   β”‚   β”œβ”€β”€ models.py            # Unified forecast data models (Pydantic)
β”‚   β”‚   β”œβ”€β”€ openmeteo_client.py  # Open-Meteo API (free, no key)
β”‚   β”‚   β”œβ”€β”€ stormglass_client.py # Stormglass API (paid, 10 req/day free)
β”‚   β”‚   └── noaa_client.py       # NOAA Marine Weather (US only)
β”‚   β”œβ”€β”€ contextual/
β”‚   β”‚   β”œβ”€β”€ parking.py           # Parking data provider
β”‚   β”‚   β”œβ”€β”€ accessibility.py     # Accessibility data provider
β”‚   β”‚   β”œβ”€β”€ reviews.py           # Reviews data provider
β”‚   β”‚   └── safety.py            # Safety/hazard data provider
β”‚   β”œβ”€β”€ planning/
β”‚   β”‚   β”œβ”€β”€ condition_assessor.py    # Deterministic condition scoring
β”‚   β”‚   β”œβ”€β”€ window_finder.py         # Surf window identification
β”‚   β”‚   β”œβ”€β”€ trip_planner.py          # Multi-day itinerary optimization
β”‚   β”‚   └── travel_utils.py          # Haversine distance calculations
β”‚   └── knowledge/
β”‚       └── spot_database.py     # Legacy spot database (deprecated)
β”œβ”€β”€ config/
β”‚   └── settings.py              # Type-safe Pydantic configuration
β”œβ”€β”€ data/
β”‚   └── spots.json               # Legacy spot metadata (deprecated)
β”œβ”€β”€ tests/                       # Unit tests for sub-agents
β”œβ”€β”€ requirements.txt             # Python dependencies
β”œβ”€β”€ .env.example                 # Configuration template
β”œβ”€β”€ Makefile                     # Common commands
└── README.md

βš™οΈ Configuration

All settings are in .env (copy from .env.example):

Azure OpenAI (Required)

Variable Default Description
AZURE_OPENAI_ENDPOINT (empty) Azure OpenAI endpoint URL
AZURE_OPENAI_API_KEY (empty) Azure OpenAI API key
AZURE_OPENAI_DEPLOYMENT_NAME gpt-4o Azure deployment name
AZURE_OPENAI_API_VERSION 2024-10-21 API version
AZURE_OPENAI_TEMPERATURE 0.7 Sampling temperature (0.0–2.0)
AZURE_OPENAI_MAX_TOKENS 2000 Max tokens in LLM response

Tavily Search (Required)

Variable Default Description
TAVILY_API_KEY (empty) Tavily API key (get free key)
TAVILY_SEARCH_DEPTH basic Search depth: basic (fast) or advanced (thorough)
TAVILY_MAX_RESULTS 5 Number of search results per query (1–10)

Forecast API (Optional)

Variable Default Description
FORECAST_API_KEY (empty) Stormglass API key. Open-Meteo is used as free fallback

Skill Thresholds

Variable Default Description
BEGINNER_MAX_WAVE_HEIGHT 1.5 Max wave height (m) for beginner
BEGINNER_MAX_WIND_SPEED 15 Max wind speed (kph) for beginner
INTERMEDIATE_MAX_WAVE_HEIGHT 2.5 Max wave height (m) for intermediate
INTERMEDIATE_MAX_WIND_SPEED 20 Max wind speed (kph) for intermediate
ADVANCED_MAX_WAVE_HEIGHT 5.0 Max wave height (m) for advanced
ADVANCED_MAX_WIND_SPEED 30 Max wind speed (kph) for advanced

πŸ› οΈ Development

Make Commands

make help      # Show all available commands
make install   # Install dependencies
make run       # Start the chat application
make test      # Run test suite
make check-api # Verify all API connections
make clean     # Remove cache files

Chat Commands

Command Description
/reset Clear conversation history and cached data
/help Show available commands
quit / exit Exit the application

πŸ—οΈ Architecture

SurfSense follows a single-orchestrator, multi-agent pattern:

User (Terminal)
      β”‚
      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚          Orchestrator (LLM-powered)              β”‚
β”‚  Azure OpenAI GPT-4o-mini with function-calling       β”‚
β”‚  β€’ Manages dialogue and preference elicitation   β”‚
β”‚  β€’ Selects which sub-agent tool to call          β”‚
β”‚  β€’ Synthesises sub-agent outputs into responses  β”‚
β””β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
   β”‚          β”‚              β”‚              β”‚
   β–Ό          β–Ό              β–Ό              β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚Researchβ”‚ β”‚  Forecast & β”‚ β”‚  Condition   β”‚ β”‚    Trip      β”‚
β”‚ Agent  β”‚ β”‚    Data     β”‚ β”‚  Assessment  β”‚ β”‚  Planning    β”‚
β”‚        β”‚ β”‚ Aggregation β”‚ β”‚    Agent     β”‚ β”‚    Agent     β”‚
β”‚researchβ”‚ β”‚    Agent    β”‚ β”‚              β”‚ β”‚              β”‚
β”‚_spot   β”‚ β”‚             β”‚ β”‚ β€’ assess_    β”‚ β”‚ β€’ find_surf_ β”‚
β”‚        β”‚ β”‚ β€’ fetch_    β”‚ β”‚   conditions β”‚ β”‚   windows    β”‚
β”‚Tavily +β”‚ β”‚   forecast  β”‚ β”‚ β€’ check_    β”‚ β”‚ β€’ plan_      β”‚
β”‚LLM     β”‚ β”‚ β€’ fetch_    β”‚ β”‚   safety    β”‚ β”‚   itinerary  β”‚
β”‚extract β”‚ β”‚   context   β”‚ β”‚ β€’ get_skill_β”‚ β”‚ β€’ rank_spots β”‚
β”‚        β”‚ β”‚ β€’ get_spot_ β”‚ β”‚   thresholdsβ”‚ β”‚              β”‚
β”‚        β”‚ β”‚   metadata  β”‚ β”‚              β”‚ β”‚              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
   β”‚              β”‚                β”‚                  β”‚
   β–Ό              β–Ό                β–Ό                  β–Ό
 Tavily       External APIs    config/settings.py   Haversine +
 Web Search   (Open-Meteo,     (SkillLevel          greedy
              Stormglass)      Thresholds)         optimisation

Data Flow

When a user mentions any surf spot, the orchestrator follows this sequence:

  1. research_spot β†’ Tavily web search + LLM extraction β†’ structured spot data (coordinates, break type, hazards, skill levels)
  2. fetch_forecast β†’ uses coordinates from step 1 β†’ hourly wave/wind/swell data
  3. assess_conditions β†’ scores each hour against the user's skill level
  4. find_surf_windows / plan_itinerary β†’ identifies best times and builds schedules

Design Principles

  • Single LLM point: Only the orchestrator calls Azure OpenAI β€” predictable token costs, no non-determinism in safety scoring
  • Dynamic knowledge: No hardcoded spot database β€” the ResearchAgent discovers spot information at conversation time via web search
  • Function-calling as delegation: GPT-4o-mini decides which tools to invoke; tool results feed back into the conversation
  • Deterministic sub-agents: Python classes with scoring formulas, API calls, and optimization algorithms β€” no LLM calls (except ResearchAgent's extraction step)

πŸ§ͺ Testing

# Run all tests
make test

# Or with pytest directly
pytest tests/ -v

Verify API Connections

Before your first run (or after changing .env), check that every external service is reachable and your keys are valid:

make check-api

This runs one lightweight ping per API:

Test Service Key required?
TestLLMConnection Azure OpenAI / OpenAI βœ…
TestTavilyConnection Tavily web search βœ…
TestStormglassConnection Stormglass forecast Optional
TestOpenMeteoConnection Open-Meteo forecast ❌ Free
TestNOAAConnection NOAA weather ❌ Free

πŸ†˜ Troubleshooting

Azure OpenAI Connection Error?

Run make check-api to pinpoint which service is failing.

Verify your credentials in .env:

# Test your Azure OpenAI setup
python -c "from openai import AzureOpenAI; print('OK')"

Ensure your deployment supports function-calling (GPT-4o-mini recommended).

Import Errors?

# Ensure venv is activated and dependencies installed
source .venv/bin/activate
pip install -r requirements.txt

Forecast Data Unavailable?

Open-Meteo (free, no API key) is used as the default forecast source. If it's down, configure Stormglass as a fallback:

# In .env:
FORECAST_API_KEY=<your-stormglass-key>

Built with ❀️ for the surfing community 🌊