sasan commited on
Commit
187a965
1 Parent(s): 63ec258

feat: Update skills package and add vehicle status functionality

Browse files
apis.py CHANGED
@@ -1,5 +1,3 @@
1
- import requests
2
-
3
  from geopy.geocoders import Nominatim
4
 
5
 
@@ -53,287 +51,4 @@ def check_city_coordinates(lat = "", lon = "", city = "", **kwargs):
53
  lon = coord.longitude
54
  return lat, lon, city
55
 
56
- # Select coordinates at equal distance, including the last one
57
- def select_equally_spaced_coordinates(coords, number_of_points=10):
58
- n = len(coords)
59
- selected_coords = []
60
- interval = max((n - 1) / (number_of_points - 1), 1)
61
- for i in range(number_of_points):
62
- # Calculate the index, ensuring it doesn't exceed the bounds of the list
63
- index = int(round(i * interval))
64
- if index < n:
65
- selected_coords.append(coords[index])
66
- return selected_coords
67
-
68
- def find_points_of_interest(lat="0", lon="0", city="", type_of_poi="restaurant", **kwargs):
69
- """
70
- Return some of the closest points of interest for a specific location and type of point of interest. The more parameters there are, the more precise.
71
- :param lat (string): latitude
72
- :param lon (string): longitude
73
- :param city (string): Required. city
74
- :param type_of_poi (string): Required. type of point of interest depending on what the user wants to do.
75
- """
76
- lat, lon, city = check_city_coordinates(lat,lon,city)
77
-
78
- r = requests.get(f'https://api.tomtom.com/search/2/search/{type_of_poi}'
79
- '.json?key={0}&lat={1}&lon={2}&radius=10000&idxSet=POI&limit=100'.format(
80
- TOMTOM_KEY,
81
- lat,
82
- lon
83
- ))
84
-
85
- # Parse JSON from the response
86
- data = r.json()
87
- #print(data)
88
- # Extract results
89
- results = data['results']
90
-
91
- # Sort the results based on distance
92
- sorted_results = sorted(results, key=lambda x: x['dist'])
93
- #print(sorted_results)
94
-
95
- # Format and limit to top 5 results
96
- formatted_results = [
97
- f"The {type_of_poi} {result['poi']['name']} is {int(result['dist'])} meters away"
98
- for result in sorted_results[:5]
99
- ]
100
-
101
-
102
- return ". ".join(formatted_results)
103
-
104
- def find_route(lat_depart="0", lon_depart="0", city_depart="", address_destination="", depart_time ="", **kwargs):
105
- """
106
- Return the distance and the estimated time to go to a specific destination from the current place, at a specified depart time.
107
- :param lat_depart (string): latitude of depart
108
- :param lon_depart (string): longitude of depart
109
- :param city_depart (string): Required. city of depart
110
- :param address_destination (string): Required. The destination
111
- :param depart_time (string): departure hour, in the format '08:00:20'.
112
- """
113
- print(address_destination)
114
- date = "2025-03-29T"
115
- departure_time = '2024-02-01T' + depart_time
116
- lat, lon, city = check_city_coordinates(lat_depart,lon_depart,city_depart)
117
- lat_dest, lon_dest = find_coordinates(address_destination)
118
- #print(lat_dest, lon_dest)
119
-
120
- #print(departure_time)
121
-
122
- r = requests.get('https://api.tomtom.com/routing/1/calculateRoute/{0},{1}:{2},{3}/json?key={4}&departAt={5}'.format(
123
- lat_depart,
124
- lon_depart,
125
- lat_dest,
126
- lon_dest,
127
- TOMTOM_KEY,
128
- departure_time
129
- ))
130
-
131
- # Parse JSON from the response
132
- data = r.json()
133
- #print(data)
134
-
135
- #print(data)
136
-
137
- result = data['routes'][0]['summary']
138
-
139
- # Calculate distance in kilometers (1 meter = 0.001 kilometers)
140
- distance_km = result['lengthInMeters'] * 0.001
141
-
142
- # Calculate travel time in minutes (1 second = 1/60 minutes)
143
- time_minutes = result['travelTimeInSeconds'] / 60
144
- if time_minutes < 60:
145
- time_display = f"{time_minutes:.0f} minutes"
146
- else:
147
- hours = int(time_minutes / 60)
148
- minutes = int(time_minutes % 60)
149
- time_display = f"{hours} hours" + (f" and {minutes} minutes" if minutes > 0 else "")
150
-
151
- # Extract arrival time from the JSON structure
152
- arrival_time_str = result['arrivalTime']
153
-
154
- # Convert string to datetime object
155
- arrival_time = datetime.fromisoformat(arrival_time_str)
156
-
157
- # Extract and display the arrival hour in HH:MM format
158
- arrival_hour_display = arrival_time.strftime("%H:%M")
159
-
160
-
161
- # return the distance and time
162
- return(f"The route to go to {address_destination} is {distance_km:.2f} km and {time_display}. Leaving now, the arrival time is estimated at {arrival_hour_display} " )
163
-
164
-
165
- # Sort the results based on distance
166
- #sorted_results = sorted(results, key=lambda x: x['dist'])
167
-
168
- #return ". ".join(formatted_results)
169
-
170
-
171
- def search_along_route(latitude_depart, longitude_depart, city_destination, type_of_poi):
172
- """
173
- Return some of the closest points of interest along the route from the depart point, specified by its coordinates and a city destination.
174
- :param latitude_depart (string): Required. Latitude of depart location
175
- :param longitude_depart (string): Required. Longitude of depart location
176
- :param city_destination (string): Required. City destination
177
- :param type_of_poi (string): Required. type of point of interest depending on what the user wants to do.
178
- """
179
-
180
- lat_dest, lon_dest = find_coordinates(city_destination)
181
- print(lat_dest)
182
-
183
- r = requests.get('https://api.tomtom.com/routing/1/calculateRoute/{0},{1}:{2},{3}/json?key={4}'.format(
184
- latitude_depart,
185
- longitude_depart,
186
- lat_dest,
187
- lon_dest,
188
- TOMTOM_KEY
189
- ))
190
-
191
- coord_route = select_equally_spaced_coordinates(r.json()['routes'][0]['legs'][0]['points'])
192
-
193
- # The API endpoint for searching along a route
194
- url = f'https://api.tomtom.com/search/2/searchAlongRoute/{type_of_poi}.json?key={TOMTOM_KEY}&maxDetourTime=700&limit=20&sortBy=detourTime'
195
-
196
- # The data payload
197
- payload = {
198
- "route": {
199
- "points": [
200
- {"lat": float(latitude_depart), "lon": float(longitude_depart)},
201
- {"lat": float(coord_route[1]['latitude']), "lon": float(coord_route[1]['longitude'])},
202
- {"lat": float(coord_route[2]['latitude']), "lon": float(coord_route[2]['longitude'])},
203
- {"lat": float(coord_route[3]['latitude']), "lon": float(coord_route[3]['longitude'])},
204
- {"lat": float(coord_route[4]['latitude']), "lon": float(coord_route[4]['longitude'])},
205
- {"lat": float(coord_route[5]['latitude']), "lon": float(coord_route[5]['longitude'])},
206
- {"lat": float(coord_route[6]['latitude']), "lon": float(coord_route[6]['longitude'])},
207
- {"lat": float(coord_route[7]['latitude']), "lon": float(coord_route[7]['longitude'])},
208
- {"lat": float(coord_route[8]['latitude']), "lon": float(coord_route[8]['longitude'])},
209
- {"lat": float(lat_dest), "lon": float(lon_dest)},
210
- ]
211
- }
212
- }
213
-
214
- # Make the POST request
215
- response = requests.post(url, json=payload)
216
-
217
- # Check if the request was successful
218
- if response.status_code == 200:
219
- # Parse the JSON response
220
- data = response.json()
221
- print(json.dumps(data, indent=4))
222
- else:
223
- print('Failed to retrieve data:', response.status_code)
224
- answer = ""
225
- for result in data['results']:
226
- name = result['poi']['name']
227
- address = result['address']['freeformAddress']
228
- detour_time = result['detourTime']
229
- answer = answer + f" \nAlong the route to {city_destination}, there is the {name} at {address} that would represent a detour of {int(detour_time/60)} minutes."
230
-
231
- return answer
232
-
233
-
234
- #current weather API
235
- def get_weather(city_name:str= "", **kwargs):
236
- """
237
- Returns the CURRENT weather in a specified city.
238
- Args:
239
- city_name (string) : Required. The name of the city.
240
- """
241
- # The endpoint URL provided by WeatherAPI
242
- url = f"http://api.weatherapi.com/v1/current.json?key={WEATHER_API_KEY}&q={city_name}&aqi=no"
243
-
244
- # Make the API request
245
- response = requests.get(url)
246
-
247
- if response.status_code == 200:
248
- # Parse the JSON response
249
- weather_data = response.json()
250
-
251
- # Extracting the necessary pieces of data
252
- location = weather_data['location']['name']
253
- region = weather_data['location']['region']
254
- country = weather_data['location']['country']
255
- time = weather_data['location']['localtime']
256
- temperature_c = weather_data['current']['temp_c']
257
- condition_text = weather_data['current']['condition']['text']
258
- wind_mph = weather_data['current']['wind_mph']
259
- humidity = weather_data['current']['humidity']
260
- feelslike_c = weather_data['current']['feelslike_c']
261
-
262
- # Formulate the sentences
263
- weather_sentences = (
264
- f"The current weather in {location}, {region}, {country} is {condition_text} "
265
- f"with a temperature of {temperature_c}°C that feels like {feelslike_c}°C. "
266
- f"Humidity is at {humidity}%. "
267
- f"Wind speed is {wind_mph} mph."
268
- )
269
- return weather_sentences
270
- else:
271
- # Handle errors
272
- return f"Failed to get weather data: {response.status_code}, {response.text}"
273
-
274
-
275
-
276
- #weather forecast API
277
- def get_forecast(city_name:str= "", when = 0, **kwargs):
278
- """
279
- Returns the weather forecast in a specified number of days for a specified city .
280
- Args:
281
- city_name (string) : Required. The name of the city.
282
- when (int) : Required. in number of days (until the day for which we want to know the forecast) (example: tomorrow is 1, in two days is 2, etc.)
283
- """
284
- #print(when)
285
- when +=1
286
- # The endpoint URL provided by WeatherAPI
287
- url = f"http://api.weatherapi.com/v1/forecast.json?key={WEATHER_API_KEY}&q={city_name}&days={str(when)}&aqi=no"
288
-
289
-
290
- # Make the API request
291
- response = requests.get(url)
292
-
293
- if response.status_code == 200:
294
- # Parse the JSON response
295
- data = response.json()
296
-
297
- # Initialize an empty string to hold our result
298
- forecast_sentences = ""
299
-
300
- # Extract city information
301
- location = data.get('location', {})
302
- city_name = location.get('name', 'the specified location')
303
-
304
- #print(data)
305
-
306
-
307
- # Extract the forecast days
308
- forecast_days = data.get('forecast', {}).get('forecastday', [])[when-1:]
309
- #number = 0
310
-
311
- #print (forecast_days)
312
-
313
- for day in forecast_days:
314
- date = day.get('date', 'a specific day')
315
- conditions = day.get('day', {}).get('condition', {}).get('text', 'weather conditions')
316
- max_temp_c = day.get('day', {}).get('maxtemp_c', 'N/A')
317
- min_temp_c = day.get('day', {}).get('mintemp_c', 'N/A')
318
- chance_of_rain = day.get('day', {}).get('daily_chance_of_rain', 'N/A')
319
-
320
- if when == 1:
321
- number_str = 'today'
322
- elif when == 2:
323
- number_str = 'tomorrow'
324
- else:
325
- number_str = f'in {when-1} days'
326
-
327
- # Generate a sentence for the day's forecast
328
- forecast_sentence = f"On {date} ({number_str}) in {city_name}, the weather will be {conditions} with a high of {max_temp_c}°C and a low of {min_temp_c}°C. There's a {chance_of_rain}% chance of rain. "
329
-
330
- #number = number + 1
331
- # Add the sentence to the result
332
- forecast_sentences += forecast_sentence
333
- return forecast_sentences
334
- else:
335
- # Handle errors
336
- print( f"Failed to get weather data: {response.status_code}, {response.text}")
337
- return f'error {response.status_code}'
338
-
339
 
 
 
 
1
  from geopy.geocoders import Nominatim
2
 
3
 
 
51
  lon = coord.longitude
52
  return lat, lon, city
53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
car_assistant_eta.ipynb CHANGED
@@ -2,7 +2,7 @@
2
  "cells": [
3
  {
4
  "cell_type": "code",
5
- "execution_count": null,
6
  "metadata": {},
7
  "outputs": [],
8
  "source": [
@@ -11,14 +11,14 @@
11
  },
12
  {
13
  "cell_type": "code",
14
- "execution_count": 41,
15
  "metadata": {},
16
  "outputs": [],
17
  "source": [
18
  "from langchain_community.llms import Ollama\n",
19
  "from langchain.tools.base import StructuredTool\n",
20
  "\n",
21
- "from skills import get_weather, find_route, get_forecast, vehicle_status, vehicle\n",
22
  "from skills import extract_func_args\n",
23
  "\n",
24
  "# llm = Ollama(model=\"new-nexus\")\n",
@@ -27,7 +27,7 @@
27
  },
28
  {
29
  "cell_type": "code",
30
- "execution_count": 42,
31
  "metadata": {},
32
  "outputs": [],
33
  "source": [
@@ -35,12 +35,13 @@
35
  " StructuredTool.from_function(get_weather),\n",
36
  " StructuredTool.from_function(find_route),\n",
37
  " StructuredTool.from_function(vehicle_status),\n",
 
38
  "]"
39
  ]
40
  },
41
  {
42
  "cell_type": "code",
43
- "execution_count": 43,
44
  "metadata": {},
45
  "outputs": [],
46
  "source": [
@@ -56,7 +57,7 @@
56
  },
57
  {
58
  "cell_type": "code",
59
- "execution_count": 44,
60
  "metadata": {},
61
  "outputs": [],
62
  "source": [
@@ -71,7 +72,7 @@
71
  },
72
  {
73
  "cell_type": "code",
74
- "execution_count": 45,
75
  "metadata": {},
76
  "outputs": [],
77
  "source": [
@@ -91,7 +92,7 @@
91
  },
92
  {
93
  "cell_type": "code",
94
- "execution_count": 78,
95
  "metadata": {},
96
  "outputs": [],
97
  "source": [
@@ -104,16 +105,16 @@
104
  },
105
  {
106
  "cell_type": "code",
107
- "execution_count": 46,
108
  "metadata": {},
109
  "outputs": [],
110
  "source": [
111
- "pp = get_prompt(RAVEN_PROMPT_FUNC, \"What is the weather like in New York?\", \"\", tools)"
112
  ]
113
  },
114
  {
115
  "cell_type": "code",
116
- "execution_count": 47,
117
  "metadata": {},
118
  "outputs": [],
119
  "source": [
@@ -122,7 +123,27 @@
122
  },
123
  {
124
  "cell_type": "code",
125
- "execution_count": 63,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  "metadata": {},
127
  "outputs": [],
128
  "source": [
@@ -133,41 +154,43 @@
133
  },
134
  {
135
  "cell_type": "code",
136
- "execution_count": 79,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  "metadata": {},
138
  "outputs": [
139
  {
140
  "name": "stdout",
141
  "output_type": "stream",
142
  "text": [
143
- "http://api.weatherapi.com/v1/current.json?key=d1c4d0d8ef6847339a0125737240903&q=New York&aqi=no\n"
144
  ]
145
  },
146
  {
147
  "data": {
148
  "text/plain": [
149
- "('The current weather in New York, New York, United States of America is Partly cloudy with a temperature of 13.9°C that feels like 12.5°C. Humidity is at 57%. Wind speed is 3.6 kph.',\n",
150
- " {'location': {'name': 'New York',\n",
151
- " 'region': 'New York',\n",
152
- " 'country': 'United States of America',\n",
153
- " 'lat': 40.71,\n",
154
- " 'lon': -74.01,\n",
155
- " 'tz_id': 'America/New_York',\n",
156
- " 'localtime_epoch': 1714856966,\n",
157
- " 'localtime': '2024-05-04 17:09'},\n",
158
- " 'current': {'last_updated': '2024-05-04 17:00',\n",
159
- " 'temp_c': 13.9,\n",
160
- " 'condition': {'text': 'Partly cloudy'},\n",
161
- " 'wind_kph': 3.6,\n",
162
- " 'wind_dir': 'N',\n",
163
- " 'precip_mm': 0.0,\n",
164
- " 'precip_in': 0.0,\n",
165
- " 'humidity': 57,\n",
166
- " 'cloud': 75,\n",
167
- " 'feelslike_c': 12.5}})"
168
  ]
169
  },
170
- "execution_count": 79,
171
  "metadata": {},
172
  "output_type": "execute_result"
173
  }
@@ -178,13 +201,130 @@
178
  },
179
  {
180
  "cell_type": "code",
181
- "execution_count": 55,
182
  "metadata": {},
183
  "outputs": [],
184
  "source": [
185
  "#getattr(skills, func_name)(*args)"
186
  ]
187
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  {
189
  "cell_type": "markdown",
190
  "metadata": {},
 
2
  "cells": [
3
  {
4
  "cell_type": "code",
5
+ "execution_count": 6,
6
  "metadata": {},
7
  "outputs": [],
8
  "source": [
 
11
  },
12
  {
13
  "cell_type": "code",
14
+ "execution_count": 1,
15
  "metadata": {},
16
  "outputs": [],
17
  "source": [
18
  "from langchain_community.llms import Ollama\n",
19
  "from langchain.tools.base import StructuredTool\n",
20
  "\n",
21
+ "from skills import get_weather, find_route, get_forecast, vehicle_status, search_points_of_interests, vehicle, search_along_route_w_coordinates\n",
22
  "from skills import extract_func_args\n",
23
  "\n",
24
  "# llm = Ollama(model=\"new-nexus\")\n",
 
27
  },
28
  {
29
  "cell_type": "code",
30
+ "execution_count": 2,
31
  "metadata": {},
32
  "outputs": [],
33
  "source": [
 
35
  " StructuredTool.from_function(get_weather),\n",
36
  " StructuredTool.from_function(find_route),\n",
37
  " StructuredTool.from_function(vehicle_status),\n",
38
+ " StructuredTool.from_function(search_points_of_interests),\n",
39
  "]"
40
  ]
41
  },
42
  {
43
  "cell_type": "code",
44
+ "execution_count": 3,
45
  "metadata": {},
46
  "outputs": [],
47
  "source": [
 
57
  },
58
  {
59
  "cell_type": "code",
60
+ "execution_count": 4,
61
  "metadata": {},
62
  "outputs": [],
63
  "source": [
 
72
  },
73
  {
74
  "cell_type": "code",
75
+ "execution_count": 5,
76
  "metadata": {},
77
  "outputs": [],
78
  "source": [
 
92
  },
93
  {
94
  "cell_type": "code",
95
+ "execution_count": 6,
96
  "metadata": {},
97
  "outputs": [],
98
  "source": [
 
105
  },
106
  {
107
  "cell_type": "code",
108
+ "execution_count": 7,
109
  "metadata": {},
110
  "outputs": [],
111
  "source": [
112
+ "pp = get_prompt(RAVEN_PROMPT_FUNC, \"Are there any italian restaurants nearby?\", \"\", tools)"
113
  ]
114
  },
115
  {
116
  "cell_type": "code",
117
+ "execution_count": 8,
118
  "metadata": {},
119
  "outputs": [],
120
  "source": [
 
123
  },
124
  {
125
  "cell_type": "code",
126
+ "execution_count": 9,
127
+ "metadata": {},
128
+ "outputs": [
129
+ {
130
+ "data": {
131
+ "text/plain": [
132
+ "\"Call: search_points_of_interests(search_query='italian restaurant') \""
133
+ ]
134
+ },
135
+ "execution_count": 9,
136
+ "metadata": {},
137
+ "output_type": "execute_result"
138
+ }
139
+ ],
140
+ "source": [
141
+ "llm_response"
142
+ ]
143
+ },
144
+ {
145
+ "cell_type": "code",
146
+ "execution_count": 10,
147
  "metadata": {},
148
  "outputs": [],
149
  "source": [
 
154
  },
155
  {
156
  "cell_type": "code",
157
+ "execution_count": 11,
158
+ "metadata": {},
159
+ "outputs": [
160
+ {
161
+ "data": {
162
+ "text/plain": [
163
+ "('search_points_of_interests', {'search_query': 'italian restaurant'})"
164
+ ]
165
+ },
166
+ "execution_count": 11,
167
+ "metadata": {},
168
+ "output_type": "execute_result"
169
+ }
170
+ ],
171
+ "source": [
172
+ "func_name, kwargs"
173
+ ]
174
+ },
175
+ {
176
+ "cell_type": "code",
177
+ "execution_count": 12,
178
  "metadata": {},
179
  "outputs": [
180
  {
181
  "name": "stdout",
182
  "output_type": "stream",
183
  "text": [
184
+ "POI search vehicle's lat: 49.6002, lon: 6.1296\n"
185
  ]
186
  },
187
  {
188
  "data": {
189
  "text/plain": [
190
+ "'There are 30 options in the vicinity. The most relevant are: Luci-Italian Restaurant is 823 meters away.\\n La Briscola is 171 meters away.\\n Casa Giuditta is 92 meters away'"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  ]
192
  },
193
+ "execution_count": 12,
194
  "metadata": {},
195
  "output_type": "execute_result"
196
  }
 
201
  },
202
  {
203
  "cell_type": "code",
204
+ "execution_count": 13,
205
  "metadata": {},
206
  "outputs": [],
207
  "source": [
208
  "#getattr(skills, func_name)(*args)"
209
  ]
210
  },
211
+ {
212
+ "cell_type": "markdown",
213
+ "metadata": {},
214
+ "source": [
215
+ "## Categories POI"
216
+ ]
217
+ },
218
+ {
219
+ "cell_type": "code",
220
+ "execution_count": 14,
221
+ "metadata": {},
222
+ "outputs": [],
223
+ "source": [
224
+ "import requests\n",
225
+ "from skills.common import config"
226
+ ]
227
+ },
228
+ {
229
+ "cell_type": "code",
230
+ "execution_count": 15,
231
+ "metadata": {},
232
+ "outputs": [],
233
+ "source": [
234
+ "res = requests.get(f\"https://api.tomtom.com/search/2/poiCategories.json?key={config.TOMTOM_API_KEY}\")"
235
+ ]
236
+ },
237
+ {
238
+ "cell_type": "code",
239
+ "execution_count": 16,
240
+ "metadata": {},
241
+ "outputs": [],
242
+ "source": [
243
+ "data = res.json()"
244
+ ]
245
+ },
246
+ {
247
+ "cell_type": "code",
248
+ "execution_count": 17,
249
+ "metadata": {},
250
+ "outputs": [],
251
+ "source": [
252
+ "data = data[\"poiCategories\"]"
253
+ ]
254
+ },
255
+ {
256
+ "cell_type": "code",
257
+ "execution_count": 18,
258
+ "metadata": {},
259
+ "outputs": [],
260
+ "source": [
261
+ "categories = [dict(id=category[\"id\"],name=category[\"name\"]) for category in data]"
262
+ ]
263
+ },
264
+ {
265
+ "cell_type": "code",
266
+ "execution_count": 19,
267
+ "metadata": {},
268
+ "outputs": [],
269
+ "source": [
270
+ "def search_categories(categories, search_term):\n",
271
+ " return [category for category in categories if search_term.lower() in category[\"name\"].lower()]"
272
+ ]
273
+ },
274
+ {
275
+ "cell_type": "code",
276
+ "execution_count": 20,
277
+ "metadata": {},
278
+ "outputs": [
279
+ {
280
+ "data": {
281
+ "text/plain": [
282
+ "[{'id': 7315044, 'name': 'Spanish Restaurant'}]"
283
+ ]
284
+ },
285
+ "execution_count": 20,
286
+ "metadata": {},
287
+ "output_type": "execute_result"
288
+ }
289
+ ],
290
+ "source": [
291
+ "search_categories(categories, \"spa\")"
292
+ ]
293
+ },
294
+ {
295
+ "cell_type": "markdown",
296
+ "metadata": {},
297
+ "source": [
298
+ "## Test POI Along Route"
299
+ ]
300
+ },
301
+ {
302
+ "cell_type": "code",
303
+ "execution_count": 21,
304
+ "metadata": {},
305
+ "outputs": [
306
+ {
307
+ "name": "stdout",
308
+ "output_type": "stream",
309
+ "text": [
310
+ "lat_dest: 49.5206, lon_dest: 6.29716\n",
311
+ "lat_depart: 49.6002, lon_depart: 6.1296\n"
312
+ ]
313
+ }
314
+ ],
315
+ "source": [
316
+ "output, points = find_route(\"Ellange, Luxembourg\")"
317
+ ]
318
+ },
319
+ {
320
+ "cell_type": "code",
321
+ "execution_count": null,
322
+ "metadata": {},
323
+ "outputs": [],
324
+ "source": [
325
+ "search"
326
+ ]
327
+ },
328
  {
329
  "cell_type": "markdown",
330
  "metadata": {},
skills/__init__.py CHANGED
@@ -3,6 +3,7 @@ import inspect
3
  from .common import execute_function_call, extract_func_args, vehicle
4
  from .weather import get_weather, get_forecast
5
  from .routing import find_route
 
6
  from .vehicle import vehicle_status
7
 
8
 
@@ -22,4 +23,4 @@ def format_functions_for_prompt_raven(*functions):
22
  return "\n".join(formatted_functions)
23
 
24
 
25
- SKILLS_PROMPT = format_functions_for_prompt_raven(get_weather, get_forecast, find_route)
 
3
  from .common import execute_function_call, extract_func_args, vehicle
4
  from .weather import get_weather, get_forecast
5
  from .routing import find_route
6
+ from .poi import search_points_of_interests, search_along_route_w_coordinates
7
  from .vehicle import vehicle_status
8
 
9
 
 
23
  return "\n".join(formatted_functions)
24
 
25
 
26
+ SKILLS_PROMPT = format_functions_for_prompt_raven(get_weather, get_forecast, find_route, search_points_of_interests)
skills/common.py CHANGED
@@ -59,4 +59,4 @@ vehicle = VehicleStatus(
59
  date="2025-03-29",
60
  time="08:00:20",
61
  destination="Kirchberg Campus, Kirchberg"
62
- )
 
59
  date="2025-03-29",
60
  time="08:00:20",
61
  destination="Kirchberg Campus, Kirchberg"
62
+ )
skills/poi.py CHANGED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import requests
3
+ from .common import config, vehicle
4
+
5
+
6
+ # Select coordinates at equal distance, including the last one
7
+ def select_equally_spaced_coordinates(coords, number_of_points=10):
8
+ n = len(coords)
9
+ selected_coords = []
10
+ interval = max((n - 1) / (number_of_points - 1), 1)
11
+ for i in range(number_of_points):
12
+ # Calculate the index, ensuring it doesn't exceed the bounds of the list
13
+ index = int(round(i * interval))
14
+ if index < n:
15
+ selected_coords.append(coords[index])
16
+ return selected_coords
17
+
18
+
19
+ def search_points_of_interests(search_query="french restaurant"):
20
+ """
21
+ Return some of the closest points of interest matching the query.
22
+ :param search_query (string): Required. Describing the type of point of interest depending on what the user wants to do. Make sure to include the type of POI you are looking for. For example italian restaurant, grocery shop, etc.
23
+ """
24
+
25
+ # Extract the latitude and longitude of the vehicle
26
+ vehicle_coordinates = getattr(vehicle, "location_coordinates")
27
+ lat, lon = vehicle_coordinates
28
+ print(f"POI search vehicle's lat: {lat}, lon: {lon}")
29
+
30
+ # https://developer.tomtom.com/search-api/documentation/search-service/search
31
+ r = requests.get(
32
+ f"https://api.tomtom.com/search/2/search/{search_query}.json?key={config.TOMTOM_API_KEY}&lat={lat}&lon={lon}&category&radius=1000&limit=100",
33
+ timeout=5,
34
+ )
35
+
36
+ # Parse JSON from the response
37
+ data = r.json()
38
+ # Extract results
39
+ results = data["results"]
40
+
41
+ # TODO: Handle the no results case.
42
+ if not results:
43
+ return "No results found in the vicinity."
44
+
45
+ # Sort the results based on distance
46
+ # sorted_results = sorted(results, key=lambda x: x["dist"])
47
+ # print(sorted_results)
48
+
49
+ # Format and limit to top 5 results
50
+ formatted_results = [
51
+ f"{result['poi']['name']} is {int(result['dist'])} meters away"
52
+ for result in results[:3]
53
+ ]
54
+
55
+ output = (
56
+ f"There are {len(results)} options in the vicinity. The most relevant are: "
57
+ )
58
+ return output + ".\n ".join(formatted_results)
59
+
60
+
61
+ def find_points_of_interest(lat="0", lon="0", type_of_poi="restaurant"):
62
+ """
63
+ Return some of the closest points of interest for a specific location and type of point of interest. The more parameters there are, the more precise.
64
+ :param lat (string): latitude
65
+ :param lon (string): longitude
66
+ :param city (string): Required. city
67
+ :param type_of_poi (string): Required. type of point of interest depending on what the user wants to do.
68
+ """
69
+ # https://developer.tomtom.com/search-api/documentation/search-service/points-of-interest-search
70
+ r = requests.get(
71
+ f"https://api.tomtom.com/search/2/search/{type_of_poi}"
72
+ ".json?key={0}&lat={1}&lon={2}&radius=10000&vehicleTypeSet=Car&idxSet=POI&limit=100".format(
73
+ config.TOMTOM_API_KEY, lat, lon
74
+ )
75
+ )
76
+
77
+ # Parse JSON from the response
78
+ data = r.json()
79
+ # print(data)
80
+ # Extract results
81
+ results = data["results"]
82
+
83
+ # Sort the results based on distance
84
+ sorted_results = sorted(results, key=lambda x: x["dist"])
85
+ # print(sorted_results)
86
+
87
+ # Format and limit to top 5 results
88
+ formatted_results = [
89
+ f"The {type_of_poi} {result['poi']['name']} is {int(result['dist'])} meters away"
90
+ for result in sorted_results[:5]
91
+ ]
92
+
93
+ return ". ".join(formatted_results)
94
+
95
+
96
+ def search_along_route_w_coordinates(points: list[tuple[float, float]], query: str):
97
+ """
98
+ Return some of the closest points of interest along the route from the depart point, specified by its coordinates.
99
+ :param points (list[tuple(float, float)]): Required. List of tuples of latitude and longitude of the points along the route.
100
+ :param query (string): Required. type of point of interest depending on what the user wants to do.
101
+ """
102
+
103
+ # The API endpoint for searching along a route
104
+ url = f"https://api.tomtom.com/search/2/searchAlongRoute/{query}.json?key={config.TOMTOM_API_KEY}&maxDetourTime=360&limit=20&sortBy=detourTime"
105
+
106
+ points = select_equally_spaced_coordinates(points, number_of_points=20)
107
+
108
+ # The data payload
109
+ payload = {
110
+ "route": {
111
+ "points": [{"lat": pt["latitude"], "lon": pt["longitude"]} for pt in points]
112
+ }
113
+ }
114
+
115
+ # Make the POST request
116
+ response = requests.post(url, json=payload, timeout=5)
117
+
118
+ # Check if the request was successful
119
+ if response.status_code == 200:
120
+ # Parse the JSON response
121
+ data = response.json()
122
+ # print(json.dumps(data, indent=4))
123
+ else:
124
+ print("Failed to retrieve data:", response.status_code)
125
+ return "Failed to retrieve data. Please try again."
126
+ answer = ""
127
+ if not data["results"]:
128
+ return "No results found along the way."
129
+
130
+ if len(data["results"]) == 20:
131
+ answer = "There more than 20 results along the way. Here are the top 3 results:"
132
+ elif len(data["results"]) > 3:
133
+ answer = f"There are {len(data['results'])} results along the way. Here are the top 3 results:"
134
+ for result in data["results"][:3]:
135
+ name = result["poi"]["name"]
136
+ address = result["address"]["freeformAddress"]
137
+ detour_time = result["detourTime"]
138
+ answer = (
139
+ answer
140
+ + f" \n{name} at {address} would require a detour of {int(detour_time/60)} minutes."
141
+ )
142
+
143
+ return answer
skills/routing.py CHANGED
@@ -1,7 +1,5 @@
1
  from datetime import datetime
2
-
3
  import requests
4
-
5
  from .common import config, vehicle
6
 
7
 
@@ -10,6 +8,7 @@ def find_coordinates(address):
10
  Find the coordinates of a specific address.
11
  :param address (string): Required. The address
12
  """
 
13
  url = f"https://api.tomtom.com/search/2/geocode/{address}.json?key={config.TOMTOM_API_KEY}"
14
  response = requests.get(url)
15
  data = response.json()
@@ -19,11 +18,10 @@ def find_coordinates(address):
19
 
20
 
21
  def calculate_route():
22
- api_key = "api_key"
23
  origin = "49.631997,6.171029"
24
  destination = "49.586745,6.140002"
25
 
26
- url = f"https://api.tomtom.com/routing/1/calculateRoute/{origin}:{destination}/json?key={api_key}"
27
  response = requests.get(url)
28
  data = response.json()
29
 
@@ -65,7 +63,8 @@ def find_route_tomtom(
65
  :param lon_dest (string): longitude of destination
66
  :param depart_time (string): departure hour, in the format '08:00:20'.
67
  """
68
-
 
69
  r = requests.get(
70
  f"https://api.tomtom.com/routing/1/calculateRoute/{lat_depart},{lon_depart}:{lat_dest},{lon_dest}/json?key={config.TOMTOM_API_KEY}&departAt={depart_datetime}",
71
  timeout=5,
@@ -132,4 +131,4 @@ def find_route(destination=""):
132
  arrival_hour_display = arrival_time.strftime("%H:%M")
133
 
134
  # return the distance and time
135
- return f"This is the answer you must copy exactly as is: The route to {destination} is {distance_km:.2f} km and {time_display}. Leaving now, the arrival time is estimated at {arrival_hour_display} "
 
1
  from datetime import datetime
 
2
  import requests
 
3
  from .common import config, vehicle
4
 
5
 
 
8
  Find the coordinates of a specific address.
9
  :param address (string): Required. The address
10
  """
11
+ # https://developer.tomtom.com/geocoding-api/documentation/geocode
12
  url = f"https://api.tomtom.com/search/2/geocode/{address}.json?key={config.TOMTOM_API_KEY}"
13
  response = requests.get(url)
14
  data = response.json()
 
18
 
19
 
20
  def calculate_route():
 
21
  origin = "49.631997,6.171029"
22
  destination = "49.586745,6.140002"
23
 
24
+ url = f"https://api.tomtom.com/routing/1/calculateRoute/{origin}:{destination}/json?key={config.TOMTOM_API_KEY}"
25
  response = requests.get(url)
26
  data = response.json()
27
 
 
63
  :param lon_dest (string): longitude of destination
64
  :param depart_time (string): departure hour, in the format '08:00:20'.
65
  """
66
+ # https://developer.tomtom.com/routing-api/documentation/routing/calculate-route
67
+ # https://developer.tomtom.com/routing-api/documentation/routing/guidance-instructions
68
  r = requests.get(
69
  f"https://api.tomtom.com/routing/1/calculateRoute/{lat_depart},{lon_depart}:{lat_dest},{lon_dest}/json?key={config.TOMTOM_API_KEY}&departAt={depart_datetime}",
70
  timeout=5,
 
131
  arrival_hour_display = arrival_time.strftime("%H:%M")
132
 
133
  # return the distance and time
134
+ return f"The route to {destination} is {distance_km:.2f} km and {time_display}. Leaving now, the arrival time is estimated at {arrival_hour_display}.", raw_response["routes"][0]["legs"][0]["points"]
skills/vehicle.py CHANGED
@@ -1,4 +1,4 @@
1
- from skills import vehicle
2
 
3
 
4
  STATUS_TEMPLATE = """We are at {location}, current time: {time}, current date: {date} and our destination is: {destination}.
 
1
+ from .common import vehicle
2
 
3
 
4
  STATUS_TEMPLATE = """We are at {location}, current time: {time}, current date: {date} and our destination is: {destination}.