obichimav commited on
Commit
00ce886
·
verified ·
1 Parent(s): 84790ab

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +254 -0
app.py ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ from typing import Dict, List, Tuple, Optional
4
+ from dotenv import load_dotenv
5
+ import requests
6
+ import folium
7
+ from folium import plugins
8
+ import polyline
9
+ from openai import OpenAI
10
+ import gradio as gr
11
+
12
+ # Load environment variables
13
+ load_dotenv()
14
+ OPENAI_API_KEY = os.getenv('OPENAI_API_KEY', 'your-key-here')
15
+ OSRM_SERVER = "http://router.project-osrm.org" # Public OSRM demo server
16
+
17
+ # Initialize OpenAI client
18
+ client = OpenAI(api_key=OPENAI_API_KEY)
19
+
20
+ # City database with coordinates
21
+ CITY_INFO = {
22
+ "New York": {"coordinates": (40.7128, -74.0060)},
23
+ "London": {"coordinates": (51.5074, -0.1278)},
24
+ "Paris": {"coordinates": (48.8566, 2.3522)},
25
+ "Berlin": {"coordinates": (52.5200, 13.4050)},
26
+ "Madrid": {"coordinates": (40.4168, -3.7038)},
27
+ "Rome": {"coordinates": (41.9028, 12.4964)},
28
+ "Amsterdam": {"coordinates": (52.3676, 4.9041)},
29
+ "Brussels": {"coordinates": (50.8503, 4.3517)},
30
+ "Vienna": {"coordinates": (48.2082, 16.3738)},
31
+ "Prague": {"coordinates": (50.0755, 14.4378)}
32
+ }
33
+
34
+ def get_route(start_coords: Tuple[float, float], end_coords: Tuple[float, float]) -> Dict:
35
+ """
36
+ Get route information between two points using OSRM.
37
+ """
38
+ # Format coordinates for OSRM API
39
+ coords = f"{start_coords[1]},{start_coords[0]};{end_coords[1]},{end_coords[0]}"
40
+ url = f"{OSRM_SERVER}/route/v1/driving/{coords}?overview=full&geometries=polyline"
41
+
42
+ try:
43
+ response = requests.get(url)
44
+ response.raise_for_status()
45
+ data = response.json()
46
+
47
+ if data["code"] != "Ok":
48
+ raise Exception("Route not found")
49
+
50
+ route = data["routes"][0]
51
+ return {
52
+ "distance": route["distance"], # meters
53
+ "duration": route["duration"], # seconds
54
+ "geometry": route["geometry"] # encoded polyline
55
+ }
56
+ except Exception as e:
57
+ raise Exception(f"Error getting route: {str(e)}")
58
+
59
+ def create_route_map(routes: List[Dict], cities: List[str], coords: List[Tuple[float, float]]) -> str:
60
+ """
61
+ Create an interactive map with the route visualization.
62
+ """
63
+ # Calculate map center
64
+ center_lat = sum(lat for lat, _ in coords) / len(coords)
65
+ center_lon = sum(lon for _, lon in coords) / len(coords)
66
+
67
+ # Create the map
68
+ m = folium.Map(location=[center_lat, center_lon], zoom_start=4)
69
+
70
+ # Colors for different route segments
71
+ colors = ['blue', 'red', 'green', 'purple', 'orange']
72
+
73
+ # Add route segments
74
+ for i, route in enumerate(routes):
75
+ # Decode the polyline
76
+ route_coords = polyline.decode(route["geometry"])
77
+
78
+ # Add the route line
79
+ color = colors[i % len(colors)]
80
+ folium.PolyLine(
81
+ route_coords,
82
+ weight=3,
83
+ color=color,
84
+ opacity=0.8,
85
+ popup=f"Distance: {route['distance']/1000:.1f}km\nDuration: {route['duration']/3600:.1f}h"
86
+ ).add_to(m)
87
+
88
+ # Add markers for cities
89
+ for i, (city, coord) in enumerate(zip(cities, coords)):
90
+ folium.Marker(
91
+ location=[coord[0], coord[1]],
92
+ popup=f"{city} (Stop {i+1})",
93
+ icon=folium.Icon(color='red', icon='info-sign')
94
+ ).add_to(m)
95
+
96
+ # Add automatic bounds
97
+ m.fit_bounds([[coord[0], coord[1]] for coord in coords])
98
+
99
+ return m._repr_html_()
100
+
101
+ def plan_route(cities: List[str]) -> Dict:
102
+ """
103
+ Plan a route through the given cities.
104
+ """
105
+ if len(cities) < 2:
106
+ return {"error": "Need at least 2 cities to plan a route"}
107
+
108
+ # Get coordinates for valid cities
109
+ coords = []
110
+ valid_cities = []
111
+ for city in cities:
112
+ if city in CITY_INFO:
113
+ coords.append(CITY_INFO[city]["coordinates"])
114
+ valid_cities.append(city)
115
+
116
+ if len(coords) < 2:
117
+ return {"error": "Not enough valid cities provided"}
118
+
119
+ try:
120
+ # Get routes between consecutive cities
121
+ routes = []
122
+ total_distance = 0
123
+ total_duration = 0
124
+
125
+ for i in range(len(coords) - 1):
126
+ route = get_route(coords[i], coords[i + 1])
127
+ routes.append(route)
128
+ total_distance += route["distance"]
129
+ total_duration += route["duration"]
130
+
131
+ # Create map visualization
132
+ map_html = create_route_map(routes, valid_cities, coords)
133
+
134
+ return {
135
+ "map_html": map_html,
136
+ "total_distance": total_distance,
137
+ "total_duration": total_duration,
138
+ "cities": valid_cities
139
+ }
140
+
141
+ except Exception as e:
142
+ return {"error": str(e)}
143
+
144
+ # OpenAI function definition
145
+ tools = [
146
+ {
147
+ "name": "plan_route",
148
+ "description": "Plans a route through multiple European cities and returns an interactive map.",
149
+ "parameters": {
150
+ "type": "object",
151
+ "properties": {
152
+ "cities": {
153
+ "type": "array",
154
+ "items": {"type": "string"},
155
+ "description": "List of city names to visit in order"
156
+ }
157
+ },
158
+ "required": ["cities"]
159
+ }
160
+ }
161
+ ]
162
+
163
+ system_message = """You are a Route Planning Assistant. When users request a route through cities:
164
+ 1. Extract the city names from their request
165
+ 2. Call plan_route with these cities in the order specified
166
+ 3. Explain the route details, including total distance and duration
167
+ Example: For 'Show me a route from Paris to Berlin via Amsterdam', call plan_route with cities=['Paris', 'Amsterdam', 'Berlin']."""
168
+
169
+ def chat_with_openai(message: str, history: List) -> tuple[str, Optional[str]]:
170
+ """Process chat messages and handle function calling."""
171
+ messages = [{"role": "system", "content": system_message}]
172
+
173
+ # Add conversation history
174
+ for human, assistant in history:
175
+ messages.extend([
176
+ {"role": "user", "content": human},
177
+ {"role": "assistant", "content": assistant}
178
+ ])
179
+
180
+ messages.append({"role": "user", "content": message})
181
+
182
+ try:
183
+ # Get initial response
184
+ response = client.chat.completions.create(
185
+ model="gpt-4",
186
+ messages=messages,
187
+ functions=tools,
188
+ function_call="auto"
189
+ )
190
+
191
+ # Handle function calling
192
+ if response.choices[0].message.function_call:
193
+ function_call = response.choices[0].message.function_call
194
+
195
+ # Parse and execute function
196
+ args = json.loads(function_call.arguments)
197
+ result = plan_route(args["cities"])
198
+
199
+ if "error" in result:
200
+ return f"Error: {result['error']}", None
201
+
202
+ # Format the response message
203
+ response_message = (
204
+ f"I've planned your route through {', '.join(result['cities'])}.\n"
205
+ f"Total distance: {result['total_distance']/1000:.1f} km\n"
206
+ f"Total duration: {result['total_duration']/3600:.1f} hours"
207
+ )
208
+
209
+ return response_message, result.get("map_html")
210
+
211
+ return response.choices[0].message.content, None
212
+
213
+ except Exception as e:
214
+ return f"An error occurred: {str(e)}", None
215
+
216
+ # Gradio interface
217
+ def create_gradio_interface():
218
+ """Creates and returns the Gradio interface."""
219
+ with gr.Blocks() as demo:
220
+ gr.Markdown("# Route Planning Assistant")
221
+ gr.Markdown("""
222
+ Enter a routing request. Examples:
223
+ - Show me a route from Paris to Berlin via Amsterdam
224
+ - Plan a trip from London to Rome through Paris and Vienna
225
+
226
+ Available cities: London, Paris, Berlin, Madrid, Rome, Amsterdam, Brussels, Vienna, Prague
227
+ """)
228
+
229
+ with gr.Row():
230
+ text_input = gr.Textbox(
231
+ label="Your Request",
232
+ placeholder="Enter your routing request..."
233
+ )
234
+
235
+ with gr.Row():
236
+ chatbot = gr.Chatbot(label="Conversation")
237
+ map_output = gr.HTML(label="Route Map")
238
+
239
+ def process_message(message, history):
240
+ answer, map_html = chat_with_openai(message, history)
241
+ history.append((message, answer))
242
+ return "", history, map_html or ""
243
+
244
+ text_input.submit(
245
+ process_message,
246
+ [text_input, chatbot],
247
+ [text_input, chatbot, map_output]
248
+ )
249
+
250
+ return demo
251
+
252
+ if __name__ == "__main__":
253
+ demo = create_gradio_interface()
254
+ demo.launch(share=True)