David de la Iglesia Castro commited on
Commit
9ff5413
·
unverified ·
1 Parent(s): 0b1aa61

Add `surf-spot-finder-no-framework`. (#42)

Browse files

* Add `surf-spot-finder-no-framework`.

```
surf-spot-finder-no-framework "Vigo" 2 "2025-04-02T12:00"
```

* Add `no_framework` docs.

docs/api.md CHANGED
@@ -4,6 +4,8 @@
4
 
5
  ::: surf_spot_finder.config.Config
6
 
 
 
7
  ## Tools
8
 
9
  ::: surf_spot_finder.tools.openmeteo
 
4
 
5
  ::: surf_spot_finder.config.Config
6
 
7
+ ::: surf_spot_finder.no_framework
8
+
9
  ## Tools
10
 
11
  ::: surf_spot_finder.tools.openmeteo
pyproject.toml CHANGED
@@ -54,4 +54,5 @@ dev = [
54
 
55
  [project.scripts]
56
  surf-spot-finder = "surf_spot_finder.cli:main"
 
57
  surf-spot-finder-evaluate = "surf_spot_finder.evaluation.evaluate:main"
 
54
 
55
  [project.scripts]
56
  surf-spot-finder = "surf_spot_finder.cli:main"
57
+ surf-spot-finder-no-framework = "surf_spot_finder.no_framework:main"
58
  surf-spot-finder-evaluate = "surf_spot_finder.evaluation.evaluate:main"
src/surf_spot_finder/no_framework.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ from datetime import datetime
3
+
4
+ from fire import Fire
5
+ from litellm import completion
6
+ from loguru import logger
7
+ from pydantic import BaseModel
8
+
9
+ from any_agent.tools.web_browsing import search_web, visit_webpage
10
+ from surf_spot_finder.tools.openmeteo import get_wave_forecast, get_wind_forecast
11
+ from surf_spot_finder.tools.openstreetmap import (
12
+ driving_hours_to_meters,
13
+ get_area_lat_lon,
14
+ get_surfing_spots,
15
+ )
16
+
17
+
18
+ spot_info_pattern = r"\[.*?\]\((https:\/\/www\.surf-forecast\.com\/breaks\/[^)/]+)\)"
19
+
20
+
21
+ class SpotScore(BaseModel):
22
+ score: int
23
+ reason: str
24
+
25
+
26
+ @logger.catch(reraise=True)
27
+ def find_surf_spot_no_framework(
28
+ location: str, max_driving_hours: int, date: datetime, model_id: str
29
+ ) -> list[SpotScore]:
30
+ """Find the best surf spot based on the given `location` and `date`.
31
+
32
+ Uses the following tools:
33
+
34
+ - any_agent.tools.web_browsing
35
+ - [surf_spot_finder.tools.openmeteo][]
36
+ - [surf_spot_finder.tools.openstreetmap][]
37
+
38
+ To find nearby spots along with the forecast and
39
+ recommended conditions for the spot.
40
+
41
+ Then, uses `litellm` with the provided `model_id` to score
42
+ each spot based on the available information.
43
+
44
+ Args:
45
+ location: The place of interest.
46
+ max_driving_hours: Used to limit the surf spots based on
47
+ the distance to `location`.
48
+ date: Used to filter the forecast results.
49
+ model_id: Can be any of the [litellm providers](https://docs.litellm.ai/docs/providers).
50
+
51
+ Returns:
52
+ A list of spot scores and reasons for the value.
53
+ """
54
+ max_driving_meters = driving_hours_to_meters(max_driving_hours)
55
+ lat, lon = get_area_lat_lon(location)
56
+
57
+ logger.info(f"Getting surfing spots around {location}")
58
+ surf_spots = get_surfing_spots(lat, lon, max_driving_meters)
59
+
60
+ if not surf_spots:
61
+ logger.warning("No surfing spots found around {location}")
62
+ return None
63
+
64
+ spots_scores = []
65
+ for spot_name, (spot_lat, spot_lon) in surf_spots:
66
+ logger.info(f"Processing {spot_name}")
67
+ logger.debug("Getting wave forecast...")
68
+ wave_forecast = get_wave_forecast(spot_lat, spot_lon, date)
69
+ logger.debug("Getting wind forecast...")
70
+ wind_forecast = get_wind_forecast(spot_lat, spot_lon, date)
71
+
72
+ logger.debug("Searching web for spot information")
73
+ search_result = search_web(f"surf-forecast.com spot info {spot_name}")
74
+ match = re.search(spot_info_pattern, search_result)
75
+ if match:
76
+ extracted_url = match.group(1)
77
+ logger.debug(f"Visiting {extracted_url}")
78
+ spot_info = visit_webpage(extracted_url)
79
+ else:
80
+ logger.debug(f"Couldn't find spot info for {spot_name}")
81
+ continue
82
+
83
+ logger.debug("Scoring conditions with LLM")
84
+ response = completion(
85
+ model="openai/gpt-4o-mini",
86
+ messages=[
87
+ {
88
+ "content": "Given the wind and wave forecast along with the spot information, "
89
+ "rate from 1 to 5 the expected surfing conditions."
90
+ f"Wind forecast:\n{wind_forecast}\n"
91
+ f"Wave forecast:\n{wave_forecast}\n"
92
+ f"Spot Information:\n{spot_info}",
93
+ "role": "user",
94
+ }
95
+ ],
96
+ response_format=SpotScore,
97
+ )
98
+ spot_score = SpotScore.model_validate_json(response.choices[0].message.content)
99
+ logger.debug(spot_score)
100
+ spots_scores.append(spot_score)
101
+
102
+ return spots_scores
103
+
104
+
105
+ def main():
106
+ Fire(find_surf_spot_no_framework)
107
+
108
+
109
+ if __name__ == "__main__":
110
+ main()