-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsimple_api.py
More file actions
158 lines (134 loc) · 5.4 KB
/
Copy pathsimple_api.py
File metadata and controls
158 lines (134 loc) · 5.4 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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
from flask import Flask, request, jsonify
import weaviate
from geopy.geocoders import Nominatim
from geopy.exc import GeocoderTimedOut
import time
import math
# Import the setup_weaviate_client function
from simple_schema import setup_weaviate_client
app = Flask(__name__)
client = setup_weaviate_client()
def geocode_address(address, attempt=1, max_attempts=3):
"""Convert an address to geocoordinates using Nominatim."""
# Initialize the geolocator
geolocator = Nominatim(user_agent="hotel_finder")
try:
# Try to geocode the address
location = geolocator.geocode(address)
if location:
return {
"latitude": location.latitude,
"longitude": location.longitude,
"address": location.address
}
else:
print(f"Could not geocode address: {address}")
return None
except GeocoderTimedOut:
if attempt <= max_attempts:
print(f"Timeout geocoding {address}. Attempt {attempt} of {max_attempts}")
time.sleep(1) # Wait for 1 second before retrying
return geocode_address(address, attempt + 1, max_attempts)
else:
print(f"Failed to geocode {address} after {max_attempts} attempts")
return None
except Exception as e:
print(f"Error geocoding {address}: {e}")
return None
def haversine_distance(lat1, lon1, lat2, lon2):
"""Calculate the great circle distance between two points on earth (specified in decimal degrees)"""
# Convert decimal degrees to radians
lat1, lon1, lat2, lon2 = map(math.radians, [lat1, lon1, lat2, lon2])
# Haversine formula
dlon = lon2 - lon1
dlat = lat2 - lat1
a = math.sin(dlat/2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon/2)**2
c = 2 * math.asin(math.sqrt(a))
r = 6371 # Radius of earth in kilometers
return c * r
def find_nearest_hotels(client, lat, lon, limit=2):
"""Find the nearest hotels using Weaviate's nearVector search."""
# Use nearObject to find hotels near the specified coordinates
result = client.query.get(
"Hotel", ["name", "address", "phoneNumber"]
).with_near_vector({
"vector": client.query.get(
"Hotel", ["name"]
).with_near_object({
"className": "Hotel",
"distance": 0.8, # Adjust this threshold as needed
"properties": [
{"path": ["location"], "value": {
"latitude": lat,
"longitude": lon
}}
]
}).do()['data']['Get']['Hotel'][0]['_additional']['vector'] if client.query.get(
"Hotel", ["name"]
).with_near_object({
"className": "Hotel",
"distance": 0.8,
"properties": [
{"path": ["location"], "value": {
"latitude": lat,
"longitude": lon
}}
]
}).do()['data']['Get']['Hotel'] else None
}).with_limit(limit).do()
if result and 'data' in result and 'Get' in result['data'] and 'Hotel' in result['data']['Get']:
return result['data']['Get']['Hotel']
# Fallback: If nearObject search doesn't work, get all hotels and calculate distances manually
all_hotels = client.query.get(
"Hotel", ["name", "address", "phoneNumber", "location"]
).do()
if all_hotels and 'data' in all_hotels and 'Get' in all_hotels['data'] and 'Hotel' in all_hotels['data']['Get']:
hotels = all_hotels['data']['Get']['Hotel']
# Calculate distance for each hotel
hotels_with_distance = []
for hotel in hotels:
if hotel.get("location"):
hotel_lat = hotel["location"]["latitude"]
hotel_lon = hotel["location"]["longitude"]
distance = haversine_distance(lat, lon, hotel_lat, hotel_lon)
hotel["distance"] = distance
hotels_with_distance.append(hotel)
# Sort by distance
hotels_with_distance.sort(key=lambda x: x.get("distance", float('inf')))
# Return the closest hotels
return hotels_with_distance[:limit]
return []
@app.route('/api/findhotels', methods=['POST'])
def find_hotels():
data = request.json
address = data.get('address', '')
if not address:
return jsonify({
"message": "Address is required",
"count": 0,
"hotels": []
})
print(f"User address: {address}")
# Geocode the address
coordinates = geocode_address(address)
if not coordinates:
return jsonify({
"message": "Could not geocode the provided address",
"count": 0,
"hotels": []
})
print(f"Geocoded to: {coordinates['latitude']}, {coordinates['longitude']}")
# Find nearest hotels
hotels = find_nearest_hotels(client, coordinates['latitude'], coordinates['longitude'], limit=2)
# Prepare response
response = {
"message": f"Found {len(hotels)} nearby hotels.",
"count": len(hotels),
"address": coordinates.get("address", address),
"hotels": hotels
}
if not hotels:
response["message"] = "No hotels found near the provided address."
return jsonify(response)
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=6001)