vincentiusyoshuac commited on
Commit
4687ad4
·
verified ·
1 Parent(s): 59c425e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +159 -71
app.py CHANGED
@@ -1,43 +1,72 @@
1
  import streamlit as st
2
- from transformers import pipeline
3
  import folium
4
  import numpy as np
5
  from scipy.optimize import linear_sum_assignment
6
- import pandas as pd
7
  from folium import plugins
 
 
 
8
 
9
- def calculate_distances(coordinates):
10
- """Calculate distances between all points using Haversine formula"""
11
- n = len(coordinates)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  distances = np.zeros((n, n))
 
13
 
14
  for i in range(n):
15
  for j in range(n):
16
  if i != j:
17
- lat1, lon1 = coordinates[i]
18
- lat2, lon2 = coordinates[j]
19
 
20
- R = 6371 # Earth's radius in kilometers
21
 
22
- dlat = np.radians(lat2 - lat1)
23
- dlon = np.radians(lon2 - lon1)
24
-
25
- a = np.sin(dlat/2)**2 + np.cos(np.radians(lat1)) * np.cos(np.radians(lat2)) * np.sin(dlon/2)**2
26
- c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1-a))
27
- distances[i,j] = R * c
28
-
29
- return distances
 
 
30
 
31
- def optimize_route(coordinates):
32
  """Optimize route using Hungarian algorithm"""
33
- distances = calculate_distances(coordinates)
34
  row_ind, col_ind = linear_sum_assignment(distances)
35
  return col_ind
36
 
37
  def get_place_coordinates(place_name):
38
  """Get coordinates using Nominatim geocoding"""
39
  try:
40
- from geopy.geocoders import Nominatim
41
  geolocator = Nominatim(user_agent="my_travel_app")
42
  location = geolocator.geocode(place_name)
43
  return (location.latitude, location.longitude) if location else None
@@ -55,8 +84,18 @@ def create_numbered_marker(number):
55
  inner_icon_style='margin-top:0;'
56
  )
57
 
 
 
 
 
 
 
 
 
 
 
58
  def main():
59
- st.title("AI Travel Route Optimizer")
60
 
61
  # Sidebar for inputs
62
  st.sidebar.header("Travel Parameters")
@@ -71,64 +110,113 @@ def main():
71
  coordinates = get_place_coordinates(place)
72
  if coordinates:
73
  places.append((place, coordinates))
 
 
74
 
75
  # Only proceed if we have all places
76
  if len(places) == num_places and num_places >= 2:
77
 
78
- # Extract coordinates for optimization
79
- coordinates = [coord for _, coord in places]
80
-
81
- # Optimize route
82
- optimized_indices = optimize_route(coordinates)
83
-
84
- # Create map
85
- center_lat = sum(coord[0] for coord in coordinates) / len(coordinates)
86
- center_lon = sum(coord[1] for coord in coordinates) / len(coordinates)
87
-
88
- m = folium.Map(location=[center_lat, center_lon], zoom_start=4)
89
-
90
- # Create optimized itinerary list first
91
- optimized_places = [(i+1, places[idx][0]) for i, idx in enumerate(optimized_indices)]
92
-
93
- # Add markers and route lines
94
- for i in range(len(optimized_indices)):
95
- current_idx = optimized_indices[i]
96
- next_idx = optimized_indices[(i + 1) % len(optimized_indices)]
97
 
98
- # Add numbered marker
99
- place_name, (lat, lon) = places[current_idx]
100
- folium.Marker(
101
- [lat, lon],
102
- popup=f"Stop {i+1}: {place_name}",
103
- icon=create_numbered_marker(i+1)
104
- ).add_to(m)
105
 
106
- # Add line to next point
107
- next_lat, next_lon = coordinates[next_idx]
108
- folium.PolyLine(
109
- locations=[[lat, lon], [next_lat, next_lon]],
110
- weight=2,
111
- color='blue',
112
- opacity=0.8
113
- ).add_to(m)
114
-
115
- # Display map
116
- st.components.v1.html(m._repr_html_(), height=600)
117
-
118
- # Display optimized itinerary
119
- st.header("Optimized Itinerary")
120
- for stop_num, place_name in optimized_places:
121
- st.write(f"{stop_num}. {place_name}")
122
-
123
- # Calculate total distance
124
- total_distance = 0
125
- distances = calculate_distances(coordinates)
126
- for i in range(len(optimized_indices)):
127
- current_idx = optimized_indices[i]
128
- next_idx = optimized_indices[(i + 1) % len(optimized_indices)]
129
- total_distance += distances[current_idx][next_idx]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
- st.write(f"\nTotal distance: {total_distance:.2f} km")
 
 
 
132
 
133
  if __name__ == "__main__":
134
  main()
 
1
  import streamlit as st
 
2
  import folium
3
  import numpy as np
4
  from scipy.optimize import linear_sum_assignment
 
5
  from folium import plugins
6
+ import requests
7
+ from datetime import datetime
8
+ from geopy.geocoders import Nominatim
9
 
10
+ def get_route_from_osrm(coord1, coord2):
11
+ """Get route information from OSRM"""
12
+ # OSRM expects coordinates in format: longitude,latitude
13
+ url = f"http://router.project-osrm.org/route/v1/driving/{coord1[1]},{coord1[0]};{coord2[1]},{coord2[0]}"
14
+ params = {
15
+ "overview": "full",
16
+ "geometries": "polyline",
17
+ "steps": "true",
18
+ "annotations": "true"
19
+ }
20
+
21
+ try:
22
+ response = requests.get(url, params=params)
23
+ if response.status_code == 200:
24
+ data = response.json()
25
+ if data["code"] == "Ok" and len(data["routes"]) > 0:
26
+ route = data["routes"][0]
27
+ return {
28
+ 'distance': route['distance'] / 1000, # Convert to km
29
+ 'duration': route['duration'] / 60, # Convert to minutes
30
+ 'geometry': route['geometry'],
31
+ 'steps': route['legs'][0]['steps']
32
+ }
33
+ except:
34
+ pass
35
+ return None
36
+
37
+ def calculate_real_distances(places):
38
+ """Calculate real driving distances using OSRM"""
39
+ n = len(places)
40
  distances = np.zeros((n, n))
41
+ routing_info = {}
42
 
43
  for i in range(n):
44
  for j in range(n):
45
  if i != j:
46
+ origin = places[i][1] # coordinates
47
+ destination = places[j][1] # coordinates
48
 
49
+ route_data = get_route_from_osrm(origin, destination)
50
 
51
+ if route_data:
52
+ distances[i,j] = route_data['distance']
53
+ routing_info[(i,j)] = {
54
+ 'distance_km': f"{route_data['distance']:.1f} km",
55
+ 'duration_mins': f"{route_data['duration']:.0f} mins",
56
+ 'geometry': route_data['geometry'],
57
+ 'steps': route_data['steps']
58
+ }
59
+
60
+ return distances, routing_info
61
 
62
+ def optimize_route(distances):
63
  """Optimize route using Hungarian algorithm"""
 
64
  row_ind, col_ind = linear_sum_assignment(distances)
65
  return col_ind
66
 
67
  def get_place_coordinates(place_name):
68
  """Get coordinates using Nominatim geocoding"""
69
  try:
 
70
  geolocator = Nominatim(user_agent="my_travel_app")
71
  location = geolocator.geocode(place_name)
72
  return (location.latitude, location.longitude) if location else None
 
84
  inner_icon_style='margin-top:0;'
85
  )
86
 
87
+ def format_instructions(steps):
88
+ """Format routing instructions from OSRM steps"""
89
+ instructions = []
90
+ for step in steps:
91
+ if 'maneuver' in step:
92
+ instruction = step.get('maneuver', {}).get('instruction', '')
93
+ if instruction:
94
+ instructions.append(instruction)
95
+ return instructions
96
+
97
  def main():
98
+ st.title("AI Travel Route Optimizer (with OSRM)")
99
 
100
  # Sidebar for inputs
101
  st.sidebar.header("Travel Parameters")
 
110
  coordinates = get_place_coordinates(place)
111
  if coordinates:
112
  places.append((place, coordinates))
113
+ else:
114
+ st.error(f"Couldn't find coordinates for {place}")
115
 
116
  # Only proceed if we have all places
117
  if len(places) == num_places and num_places >= 2:
118
 
119
+ with st.spinner("Calculating optimal route..."):
120
+ # Calculate real distances
121
+ distances, routing_info = calculate_real_distances(places)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
+ # Optimize route
124
+ optimized_indices = optimize_route(distances)
 
 
 
 
 
125
 
126
+ # Create map
127
+ center_lat = sum(coord[0] for _, coord in places) / len(places)
128
+ center_lon = sum(coord[1] for _, coord in places) / len(places)
129
+
130
+ m = folium.Map(location=[center_lat, center_lon], zoom_start=4)
131
+
132
+ # Create optimized itinerary list
133
+ optimized_places = [(i+1, places[idx][0]) for i, idx in enumerate(optimized_indices)]
134
+
135
+ # Add markers and route lines
136
+ for i in range(len(optimized_indices)):
137
+ current_idx = optimized_indices[i]
138
+ next_idx = optimized_indices[(i + 1) % len(optimized_indices)]
139
+
140
+ # Add numbered marker
141
+ place_name, (lat, lon) = places[current_idx]
142
+ next_place = places[next_idx]
143
+
144
+ # Get routing info for this segment
145
+ segment_info = routing_info.get((current_idx, next_idx), {})
146
+
147
+ # Create detailed popup content
148
+ popup_content = f"""
149
+ <b>Stop {i+1}: {place_name}</b><br>
150
+ To next stop:<br>
151
+ Distance: {segment_info.get('distance_km', 'N/A')}<br>
152
+ Duration: {segment_info.get('duration_mins', 'N/A')}
153
+ """
154
+
155
+ folium.Marker(
156
+ [lat, lon],
157
+ popup=folium.Popup(popup_content, max_width=300),
158
+ icon=create_numbered_marker(i+1)
159
+ ).add_to(m)
160
+
161
+ # Draw route line using polyline from OSRM
162
+ if 'geometry' in segment_info:
163
+ try:
164
+ import polyline
165
+ route_coords = polyline.decode(segment_info['geometry'])
166
+ folium.PolyLine(
167
+ route_coords,
168
+ weight=2,
169
+ color='blue',
170
+ opacity=0.8
171
+ ).add_to(m)
172
+ except:
173
+ # Fallback to straight line if polyline decoding fails
174
+ folium.PolyLine(
175
+ [[lat, lon], [next_place[1][0], next_place[1][1]]],
176
+ weight=2,
177
+ color='red',
178
+ opacity=0.8
179
+ ).add_to(m)
180
+
181
+ # Display map
182
+ st.components.v1.html(m._repr_html_(), height=600)
183
+
184
+ # Display optimized itinerary with route information
185
+ st.header("Optimized Itinerary")
186
+
187
+ total_distance = 0
188
+ total_duration = 0
189
+
190
+ for i in range(len(optimized_indices)):
191
+ current_idx = optimized_indices[i]
192
+ next_idx = optimized_indices[(i + 1) % len(optimized_indices)]
193
+
194
+ place_name = places[current_idx][0]
195
+ segment_info = routing_info.get((current_idx, next_idx), {})
196
+
197
+ st.write(f"{i+1}. {place_name}")
198
+
199
+ if i < len(optimized_indices) - 1:
200
+ st.write(f" ↓ ({segment_info.get('distance_km', 'N/A')}, "
201
+ f"Duration: {segment_info.get('duration_mins', 'N/A')})")
202
+
203
+ # Display turn-by-turn instructions
204
+ if 'steps' in segment_info:
205
+ with st.expander(f"Route instructions to next stop"):
206
+ instructions = format_instructions(segment_info['steps'])
207
+ for idx, instruction in enumerate(instructions, 1):
208
+ st.write(f"{idx}. {instruction}")
209
+
210
+ # Add to totals
211
+ if 'distance_km' in segment_info:
212
+ total_distance += float(segment_info['distance_km'].split()[0])
213
+ if 'duration_mins' in segment_info:
214
+ total_duration += float(segment_info['duration_mins'].split()[0])
215
 
216
+ # Display totals
217
+ st.write("\nSummary:")
218
+ st.write(f"Total distance: {total_distance:.1f} km")
219
+ st.write(f"Total estimated duration: {total_duration:.0f} minutes ({total_duration/60:.1f} hours)")
220
 
221
  if __name__ == "__main__":
222
  main()