-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathexternal.py
More file actions
137 lines (120 loc) · 4.88 KB
/
external.py
File metadata and controls
137 lines (120 loc) · 4.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
# SPDX-License-Identifier: AGPL-3.0-or-later
import typing
from typing import Optional
import datetime
import urllib.parse
from time import sleep
import httpx
from langchain_core.tools import tool
from nc_py_api import Nextcloud
from ex_app.lib.all_tools.lib.decorator import safe_tool
def get_tools(nc: Nextcloud):
@tool
@safe_tool
def get_coordinates_for_address(address: str) -> (str, str):
"""
Calculates the coordinates for a given address
:param address: the address to calculate the coordinates for
:return: a tuple of latitude and longitude
"""
res = httpx.get('https://nominatim.openstreetmap.org/search', params={'q': address, 'format': 'json', 'addressdetails': '1', 'extratags': '1', 'namedetails': '1', 'limit': '1'})
json = res.json()
if 'error' in json:
raise Exception(json['error'])
if len(json) == 0:
raise Exception(f'No results for address {address}')
return json[0]['lat'], json[0]['lon']
@tool
@safe_tool
def get_current_weather_for_coordinates(lat: str, lon: str) -> dict[str, typing.Any]:
"""
Retrieve the current weather for a given latitude and longitude
:param lat: Latitude
:param lon: Longitude
:return:
"""
res = httpx.get('https://api.met.no/weatherapi/locationforecast/2.0/compact', params={
'lat': lat,
'lon': lon,
},
headers={
'User-Agent': 'NextcloudWeatherStatus/ContextAgent nextcloud.com'
})
json = res.json()
if not 'properties' in json or not 'timeseries' in json['properties'] or not json['properties']['timeseries']:
raise Exception('Could not retrieve weather for coordinates')
return json['properties']['timeseries'][0]['data']['instant']['details']
@tool
@safe_tool
def get_public_transport_route_for_coordinates(origin_lat: str, origin_lon: str, destination_lat: str, destination_lon: str, routes: int, departure_time: str | None = None):
"""
Retrieve a public transport route between two coordinates
:param origin_lat: Latitude of the starting point
:param origin_lon: Longitude of the starting point
:param destination_lat: Latitude of the destination
:param destination_lon: Longitude of the destination
:param routes: the number of routes returned
:param departure_time: time of departure, formatted like '2019-06-24T01:23:45'. Optional, leave empty for the next routes from now
:return: the routes, times are given in local time according to origin and destination
"""
if departure_time is None:
departure_time = urllib.parse.quote_plus(datetime.datetime.now(datetime.UTC).isoformat())
api_key = nc.appconfig_ex.get_value('here_api')
res = httpx.get('https://transit.hereapi.com/v8/routes?transportMode=car&origin='
+ origin_lat + ',' + origin_lon + '&destination=' + destination_lat + ',' + destination_lon
+ '&alternatives=' + str(routes-1) + '&departureTime=' + departure_time + '&apikey=' + api_key)
json = res.json()
return json
@tool
@safe_tool
def get_osm_route(profile: str, origin_lat: str, origin_lon: str, destination_lat: str, destination_lon: str,):
"""
Retrieve a route between two coordinates traveled by foot, car or bike
:param profile: the kind of transport used to travel the route. Available are 'routed-bike', 'routed-foot', 'routed-car'
:param origin_lat: Latitude of the starting point
:param origin_lon: Longitude of the starting point
:param destination_lat: Latitude of the destination
:param destination_lon: Longitude of the destination
:return: a JSON description of the route and a URL to show the route on a map
"""
match profile:
case "routed-car":
profile_num = "0"
case "routed-bike":
profile_num = "1"
case "routed-foot":
profile_num = "2"
case _:
profile = "routed-foot"
profile_num = "2"
url = f'https://routing.openstreetmap.de/{profile}/route/v1/driving/{origin_lon},{origin_lat};{destination_lon},{destination_lat}?overview=false&steps=true'
map_url = f' https://routing.openstreetmap.de/?loc={origin_lat}%2C{origin_lon}&loc={destination_lat}%2C{destination_lon}&srv={profile_num}'
res = httpx.get(url)
json = res.json()
return {'route_json_description': json, 'map_url': map_url}
@tool
@safe_tool
def get_osm_link(location: str):
"""
Retrieve a URL for a map of a given location.
:param location: location name or address
:return: URL
"""
res = httpx.get('https://nominatim.openstreetmap.org/search', params={'q': location, 'format': 'json','limit': '1'})
json = res.json()
if 'error' in json:
raise Exception(json['error'])
if len(json) == 0:
raise Exception(f'No results for address {address}')
osm_id = json[0]['osm_id']
osm_type = json[0]['osm_type']
link = f'https://www.openstreetmap.org/{osm_type}/{osm_id}'
return link
return [
get_coordinates_for_address,
get_current_weather_for_coordinates,
get_public_transport_route_for_coordinates,
get_osm_route,
get_osm_link,
]