joe4ai commited on
Commit
9fa5d00
Β·
verified Β·
1 Parent(s): c7fe5e0

Create main.py

Browse files
Files changed (1) hide show
  1. main.py +570 -0
main.py ADDED
@@ -0,0 +1,570 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import urllib.parse
3
+ import os
4
+ from langchain_google_genai import ChatGoogleGenerativeAI
5
+ from langchain_google_genai import GoogleGenerativeAIEmbeddings
6
+ from langchain_community.vectorstores import Chroma
7
+ from langchain.schema import Document
8
+ from langchain_core.prompts import PromptTemplate
9
+ from langchain_core.runnables import RunnablePassthrough
10
+ from langchain_core.output_parsers import StrOutputParser
11
+ from langchain.memory import ConversationBufferMemory
12
+ from typing import Dict, Any, List
13
+ from dotenv import load_dotenv
14
+ import datetime
15
+
16
+ load_dotenv()
17
+
18
+ # Set your API key here
19
+ os.environ["GOOGLE_API_KEY"] = os.getenv("GOOGLE_API_KEY")
20
+
21
+ # Initialize Gemini model
22
+ gemini = ChatGoogleGenerativeAI(
23
+ model="gemini-1.5-pro",
24
+ temperature=0.2,
25
+ max_output_tokens=1024
26
+ )
27
+
28
+ # Initialize Gemini embeddings
29
+ embeddings = GoogleGenerativeAIEmbeddings(
30
+ model="models/embedding-001" # Gemini's embedding model
31
+ )
32
+
33
+ # Create memory for conversation history
34
+ memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
35
+
36
+ class RAGSystem:
37
+ def __init__(self):
38
+ self.vector_store = None
39
+ self.retriever = None
40
+ self.qa_chain = None
41
+ self.initialize_vector_store()
42
+
43
+ def initialize_vector_store(self):
44
+ try:
45
+ self.vector_store = Chroma(
46
+ collection_name="graphhopper_routes",
47
+ embedding_function=embeddings,
48
+ persist_directory="./vector_db"
49
+ )
50
+ print("Vector store loaded successfully")
51
+ except Exception as e:
52
+ print(f"Creating new vector store: {e}")
53
+ self.vector_store = Chroma(
54
+ collection_name="graphhopper_routes",
55
+ embedding_function=embeddings,
56
+ persist_directory="./vector_db"
57
+ )
58
+
59
+ self.retriever = self.vector_store.as_retriever(
60
+ search_type="mmr",
61
+ search_kwargs={"k": 5, "fetch_k": 10}
62
+ )
63
+
64
+ # Setup updated QA chain with LCEL (LangChain Expression Language)
65
+ self.template = """
66
+ You are a helpful transportation assistant using route data.
67
+ Based on the given context information about routes, directions, and locations,
68
+ provide a helpful and natural response to the user's query.
69
+
70
+ Chat History: {chat_history}
71
+
72
+ Retrieved route information:
73
+ {context}
74
+
75
+ User Query: {question}
76
+
77
+ User's Transportation Preference: {transport_preference}
78
+
79
+ Please provide a detailed response that includes:
80
+ 1. Clear directions in a conversational tone focused on the user's preferred mode of transport
81
+ 2. Relevant information about points of interest along the route
82
+ 3. Any necessary warnings, tips, or special considerations for the transportation mode
83
+ 4. Time and distance comparisons between different transport options if relevant
84
+ 5. Schedule information for public transportation if available
85
+ 6. Cost estimates if available
86
+
87
+ Response:
88
+ """
89
+
90
+ self.prompt = PromptTemplate.from_template(self.template)
91
+
92
+ # LCEL chain is set up in query method to avoid issues
93
+
94
+ def format_docs(self, docs):
95
+ """Format documents into a single string"""
96
+ return "\n\n".join(doc.page_content for doc in docs)
97
+
98
+ def store_route_data(self, paths_data, orig_loc, dest_loc, vehicle):
99
+ """Store route data in vector database for RAG"""
100
+ if "paths" not in paths_data or len(paths_data["paths"]) == 0:
101
+ print("No valid path data to store")
102
+ return
103
+
104
+ documents = []
105
+ path = paths_data["paths"][0]
106
+
107
+ # Create a unique ID for this route
108
+ route_id = f"{orig_loc}_to_{dest_loc}_{vehicle}"
109
+
110
+ # Store route metadata
111
+ miles = (path["distance"]) / 1000 / 1.61
112
+ km = (path["distance"]) / 1000
113
+ sec = int(path["time"] / 1000 % 60)
114
+ min = int(path["time"] / 1000 / 60 % 60)
115
+ hr = int(path["time"] / 1000 / 60 / 60)
116
+
117
+ route_meta = f"""
118
+ Route Information:
119
+ Origin: {orig_loc}
120
+ Destination: {dest_loc}
121
+ Transportation Mode: {vehicle}
122
+ Distance: {km:.1f} km ({miles:.1f} miles)
123
+ Duration: {hr:02d}:{min:02d}:{sec:02d}
124
+ Timestamp: {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
125
+ """
126
+
127
+ documents.append(Document(page_content=route_meta, metadata={
128
+ "type": "route_metadata",
129
+ "origin": orig_loc,
130
+ "destination": dest_loc,
131
+ "mode": vehicle,
132
+ "route_id": route_id
133
+ }))
134
+
135
+ # Store directions
136
+ if "instructions" in path:
137
+ for idx, instruction in enumerate(path["instructions"]):
138
+ text = instruction["text"]
139
+ distance = instruction["distance"]
140
+
141
+ direction = f"""
142
+ Step {idx+1}: {text}
143
+ Distance: {distance/1000:.1f} km ({distance/1000/1.61:.1f} miles)
144
+ Transportation Mode: {vehicle}
145
+ """
146
+
147
+ documents.append(Document(page_content=direction, metadata={
148
+ "type": "direction",
149
+ "step_number": idx+1,
150
+ "route_id": route_id,
151
+ "mode": vehicle
152
+ }))
153
+
154
+ # Store overall route summary
155
+ summary = f"""
156
+ Complete route from {orig_loc} to {dest_loc} by {vehicle}:
157
+ - Total distance: {km:.1f} km ({miles:.1f} miles)
158
+ - Estimated travel time: {hr:02d}:{min:02d}:{sec:02d}
159
+ - Number of steps: {len(path.get('instructions', []))}
160
+ """
161
+
162
+ documents.append(Document(page_content=summary, metadata={
163
+ "type": "route_summary",
164
+ "route_id": route_id,
165
+ "mode": vehicle
166
+ }))
167
+
168
+ # Add documents to vector store
169
+ self.vector_store.add_documents(documents)
170
+ print(f"Added {len(documents)} documents to vector store for {vehicle} mode")
171
+
172
+ def store_additional_transport_info(self, orig_loc, dest_loc, vehicle, distance, duration):
173
+ """Store estimated data for modes not directly supported by GraphHopper"""
174
+ documents = []
175
+
176
+ # Create a unique ID for this route
177
+ route_id = f"{orig_loc}_to_{dest_loc}_{vehicle}"
178
+
179
+ # Store route metadata with estimated information
180
+ miles = distance / 1.61
181
+ km = distance
182
+ hr, min_remainder = divmod(duration, 60)
183
+ min, sec = divmod(min_remainder, 1)
184
+ sec *= 60
185
+
186
+ route_meta = f"""
187
+ Route Information (Estimated):
188
+ Origin: {orig_loc}
189
+ Destination: {dest_loc}
190
+ Transportation Mode: {vehicle}
191
+ Distance: {km:.1f} km ({miles:.1f} miles)
192
+ Duration: {int(hr):02d}:{int(min):02d}:{int(sec):02d}
193
+ Note: This is an estimated route as {vehicle} is not directly supported by the routing API.
194
+ Timestamp: {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
195
+ """
196
+
197
+ documents.append(Document(page_content=route_meta, metadata={
198
+ "type": "route_metadata",
199
+ "origin": orig_loc,
200
+ "destination": dest_loc,
201
+ "mode": vehicle,
202
+ "route_id": route_id,
203
+ "estimated": True
204
+ }))
205
+
206
+ # Store additional mode-specific information
207
+ if vehicle == "bus":
208
+ bus_info = f"""
209
+ Bus Travel Information from {orig_loc} to {dest_loc}:
210
+ - Estimated distance: {km:.1f} km ({miles:.1f} miles)
211
+ - Estimated travel time: {int(hr):02d}:{int(min):02d}:{int(sec):02d}
212
+ - Bus routes may vary by city and time of day
213
+ - Consider checking local bus schedules for precise timing
214
+ - Typical bus fare might range from $2-$5 depending on the city
215
+ - Buses generally make more stops than direct car routes
216
+ """
217
+ documents.append(Document(page_content=bus_info, metadata={
218
+ "type": "transport_info",
219
+ "mode": "bus",
220
+ "route_id": route_id
221
+ }))
222
+
223
+ elif vehicle == "airplane":
224
+ plane_info = f"""
225
+ Air Travel Information from {orig_loc} to {dest_loc}:
226
+ - Flight distance: {km:.1f} km ({miles:.1f} miles)
227
+ - Estimated flight time: {int(hr):02d}:{int(min):02d}:{int(sec):02d}
228
+ - Add approximately 2-3 hours for airport security and boarding procedures
229
+ - Ticket prices typically range from $150-$500 depending on advance booking
230
+ - Consider booking flights in advance for better rates
231
+ - Check with airlines for baggage restrictions and fees
232
+ """
233
+ documents.append(Document(page_content=plane_info, metadata={
234
+ "type": "transport_info",
235
+ "mode": "airplane",
236
+ "route_id": route_id
237
+ }))
238
+
239
+ # Add documents to vector store
240
+ self.vector_store.add_documents(documents)
241
+ print(f"Added {len(documents)} estimated documents to vector store for {vehicle} mode")
242
+
243
+ def query(self, user_query, transport_preference=None, user_location=None):
244
+ """Answer questions about routes with focus on preferred transport mode"""
245
+ # Enhance query with user location if available
246
+ query_context = []
247
+ if user_location:
248
+ query_context.append(f"User is currently at {user_location}")
249
+
250
+ if transport_preference:
251
+ query_context.append(f"User prefers {transport_preference} transportation")
252
+
253
+ if query_context:
254
+ enhanced_query = f"{user_query} ({'; '.join(query_context)})"
255
+ else:
256
+ enhanced_query = user_query
257
+
258
+ try:
259
+ # Build the chain fresh each time to avoid reference issues
260
+ # Get documents from retriever
261
+ docs = self.retriever.get_relevant_documents(enhanced_query)
262
+ context = self.format_docs(docs)
263
+
264
+ # Get chat history
265
+ chat_history = memory.load_memory_variables({})["chat_history"]
266
+
267
+ # Create inputs dict
268
+ inputs = {
269
+ "context": context,
270
+ "question": enhanced_query,
271
+ "chat_history": chat_history,
272
+ "transport_preference": transport_preference if transport_preference else "any"
273
+ }
274
+
275
+ # Format prompt
276
+ formatted_prompt = self.prompt.format(**inputs)
277
+
278
+ # Call the model directly
279
+ model_response = gemini.invoke(formatted_prompt)
280
+
281
+ # Convert to string
282
+ result = str(model_response.content)
283
+
284
+ return {
285
+ "answer": result,
286
+ "sources": []
287
+ }
288
+ except Exception as e:
289
+ import traceback
290
+ traceback.print_exc()
291
+ print(f"Error querying RAG system: {e}")
292
+ return {
293
+ "answer": "I'm sorry, I couldn't process your request at this time.",
294
+ "sources": []
295
+ }
296
+
297
+ # Initialize RAG system
298
+ rag_system = RAGSystem()
299
+
300
+ # Original GraphHopper functions
301
+ def geocoding(location, key):
302
+ while location == "":
303
+ location = input("Enter the location again: ")
304
+
305
+ geocode_url = "https://graphhopper.com/api/1/geocode?"
306
+ url = geocode_url + urllib.parse.urlencode({"q": location, "limit": "1", "key": key})
307
+ replydata = requests.get(url)
308
+ json_data = replydata.json()
309
+ json_status = replydata.status_code
310
+
311
+ print("Geocoding API URL for " + location + ":\n" + url)
312
+
313
+ if json_status == 200 and len(json_data["hits"]) != 0:
314
+ lat = json_data["hits"][0]["point"]["lat"]
315
+ lng = json_data["hits"][0]["point"]["lng"]
316
+ name = json_data["hits"][0]["name"]
317
+ value = json_data["hits"][0]["osm_value"]
318
+
319
+ if "country" in json_data["hits"][0]:
320
+ country = json_data["hits"][0]["country"]
321
+ else:
322
+ country = ""
323
+
324
+ if "state" in json_data["hits"][0]:
325
+ state = json_data["hits"][0]["state"]
326
+ else:
327
+ state = ""
328
+
329
+ if len(state) != 0 and len(country) != 0:
330
+ new_loc = name + ", " + state + ", " + country
331
+ elif len(state) != 0:
332
+ new_loc = name + ", " + country
333
+ else:
334
+ new_loc = name
335
+
336
+ print("Geocoding API URL for " + new_loc + " (Location Type: " + value + ")\n" + url)
337
+ else:
338
+ lat = "null"
339
+ lng = "null"
340
+ new_loc = location
341
+
342
+ if json_status != 200:
343
+ print("Geocode API status: " + str(json_status) + "\nError message: " + json_data["message"])
344
+
345
+ return json_status, lat, lng, new_loc
346
+
347
+ def calculate_additional_transport_times(distance_km, mode):
348
+ """Calculate estimated times for transport modes not supported by GraphHopper"""
349
+ if mode == "bus":
350
+ # Bus is typically slower than car due to stops and traffic
351
+ # Average speed ~20-30 km/h in urban areas
352
+ avg_speed_kmh = 25
353
+ duration_minutes = (distance_km / avg_speed_kmh) * 60
354
+ return duration_minutes
355
+
356
+ elif mode == "airplane":
357
+ # Flight calculations are more complex
358
+ # 1. Base flight time (cruising at ~800 km/h)
359
+ # 2. Add taxi, takeoff, landing time (about 30 min)
360
+ # Note: Very short flights aren't realistic, so min 30 min flight time
361
+
362
+ if distance_km < 100:
363
+ # Too short for flight, use placeholder
364
+ return 30 # minimum flight time in minutes
365
+
366
+ # Average cruising speed ~800 km/h, but effective speed lower due to takeoff/landing
367
+ avg_speed_kmh = 700
368
+ flight_time_minutes = (distance_km / avg_speed_kmh) * 60
369
+
370
+ # Add taxi, takeoff, landing time
371
+ total_time_minutes = flight_time_minutes + 30
372
+
373
+ return max(30, total_time_minutes) # Minimum 30 minutes
374
+
375
+ return 0 # Default fallback
376
+
377
+ # Main function with enhanced multi-mode routing
378
+ def main():
379
+ route_url = "https://graphhopper.com/api/1/route?"
380
+ key = os.getenv("TRACE") # GraphHopper API key
381
+
382
+ # Define supported profiles
383
+ api_supported_profiles = ["car", "bike", "foot"]
384
+ additional_profiles = ["bus", "airplane"]
385
+ all_profiles = api_supported_profiles + additional_profiles
386
+
387
+ while True:
388
+ print("\n============================================")
389
+ print("🌍 MULTI-MODE TRANSPORTATION PLANNER 🌍")
390
+ print("============================================")
391
+ print("Available transportation modes:")
392
+ print("Direct routing: car, bike, foot")
393
+ print("Estimated routing: bus, airplane")
394
+ print("============================================")
395
+
396
+ choice = input("What would you like to do?\n1. Plan a new route\n2. Query about existing routes\n3. Quit\nEnter choice (1-3): ")
397
+
398
+ if choice == "3" or choice.lower() in ["quit", "q", "exit"]:
399
+ print("Thank you for using the Transportation Planner. Goodbye!")
400
+ break
401
+
402
+ elif choice == "2" or choice.lower() in ["query", "ask"]:
403
+ # Query mode - ask questions about stored routes
404
+ user_query = input("What would you like to know about your routes? ")
405
+ if user_query.lower() in ["quit", "q", "exit"]:
406
+ break
407
+
408
+ # Get current location if available
409
+ current_loc = input("Your current location (optional, press Enter to skip): ")
410
+ if current_loc.lower() in ["quit", "q", "exit"]:
411
+ break
412
+
413
+ # Get transport preference if any
414
+ transport_pref = input("Do you have a preferred mode of transport? (car/bike/foot/bus/airplane or press Enter for any): ")
415
+ if transport_pref.lower() in ["quit", "q", "exit"]:
416
+ break
417
+
418
+ if transport_pref.lower() not in all_profiles:
419
+ transport_pref = None
420
+
421
+ # Query the RAG system
422
+ response = rag_system.query(
423
+ user_query,
424
+ transport_pref if transport_pref else None,
425
+ current_loc if current_loc else None
426
+ )
427
+
428
+ print("\n=================================================")
429
+ print("πŸ€– AI ASSISTANT RESPONSE:")
430
+ print("=================================================")
431
+ print(response["answer"])
432
+ print("=================================================")
433
+ continue
434
+
435
+ elif choice == "1":
436
+ # Route planning mode
437
+ loc1 = input("Starting Location: ")
438
+ if loc1.lower() in ["quit", "q", "exit"]:
439
+ break
440
+
441
+ orig = geocoding(loc1, key)
442
+
443
+ loc2 = input("Destination: ")
444
+ if loc2.lower() in ["quit", "q", "exit"]:
445
+ break
446
+
447
+ dest = geocoding(loc2, key)
448
+
449
+ if orig[0] != 200 or dest[0] != 200:
450
+ print("Error with geocoding one or both locations. Please try again.")
451
+ continue
452
+
453
+ print("\nFetching routes for all transportation modes...")
454
+ print("=================================================")
455
+
456
+ # Store the resulting paths data for each mode
457
+ all_paths_data = {}
458
+ base_car_distance = None
459
+
460
+ # First get routes for API-supported modes
461
+ for vehicle in api_supported_profiles:
462
+ op = "&point=" + str(orig[1]) + "%2C" + str(orig[2])
463
+ dp = "&point=" + str(dest[1]) + "%2C" + str(dest[2])
464
+
465
+ paths_url = route_url + urllib.parse.urlencode({"key": key, "vehicle": vehicle}) + op + dp
466
+ paths_response = requests.get(paths_url)
467
+ paths_status = paths_response.status_code
468
+
469
+ if paths_status == 200:
470
+ paths_data = paths_response.json()
471
+ all_paths_data[vehicle] = paths_data
472
+
473
+ # Store car distance for estimating other modes
474
+ if vehicle == "car" and "paths" in paths_data and len(paths_data["paths"]) > 0:
475
+ base_car_distance = paths_data["paths"][0]["distance"] / 1000 # km
476
+
477
+ # Store in RAG system
478
+ rag_system.store_route_data(paths_data, orig[3], dest[3], vehicle)
479
+ else:
480
+ print(f"Error fetching {vehicle} route: {paths_response.json().get('message', 'Unknown error')}")
481
+
482
+ # Now estimate for additional modes if we have car data
483
+ if base_car_distance:
484
+ for vehicle in additional_profiles:
485
+ # Calculate estimated times based on the car distance
486
+ duration_minutes = calculate_additional_transport_times(base_car_distance, vehicle)
487
+
488
+ # Store in RAG system with estimated data
489
+ rag_system.store_additional_transport_info(
490
+ orig[3], dest[3], vehicle,
491
+ base_car_distance, # Use car distance as estimate
492
+ duration_minutes
493
+ )
494
+
495
+ # Display summary of all routes
496
+ print("\n=================================================")
497
+ print(f"ROUTE SUMMARY: {orig[3]} to {dest[3]}")
498
+ print("=================================================")
499
+
500
+ for vehicle in api_supported_profiles:
501
+ if vehicle in all_paths_data and "paths" in all_paths_data[vehicle] and len(all_paths_data[vehicle]["paths"]) > 0:
502
+ path_data = all_paths_data[vehicle]["paths"][0]
503
+ miles = path_data["distance"] / 1000 / 1.61
504
+ km = path_data["distance"] / 1000
505
+ sec = int(path_data["time"] / 1000 % 60)
506
+ min = int(path_data["time"] / 1000 / 60 % 60)
507
+ hr = int(path_data["time"] / 1000 / 60 / 60)
508
+
509
+ print(f"πŸ”Ή {vehicle.upper()}: {hr:02d}:{min:02d}:{sec:02d} - {km:.1f} km ({miles:.1f} miles)")
510
+
511
+ # Show estimated times for additional modes
512
+ if base_car_distance:
513
+ for vehicle in additional_profiles:
514
+ duration_minutes = calculate_additional_transport_times(base_car_distance, vehicle)
515
+ hr, min_remainder = divmod(duration_minutes, 60)
516
+ min, sec = divmod(min_remainder * 60, 60)
517
+ miles = base_car_distance / 1.61
518
+
519
+ print(f"πŸ”Έ {vehicle.upper()} (estimated): {int(hr):02d}:{int(min):02d}:{int(sec):02d} - {base_car_distance:.1f} km ({miles:.1f} miles)")
520
+
521
+ print("=================================================")
522
+
523
+ # Ask for detailed route information of preferred mode
524
+ pref_mode = input("\nWhich mode of transport would you like detailed directions for? ")
525
+ if pref_mode.lower() in ["quit", "q", "exit"]:
526
+ break
527
+
528
+ # Default to car if input is not valid
529
+ if pref_mode.lower() not in all_profiles:
530
+ print(f"'{pref_mode}' is not a valid mode. Showing car directions by default.")
531
+ pref_mode = "car"
532
+
533
+ # Display detailed directions for API-supported modes
534
+ if pref_mode in api_supported_profiles and pref_mode in all_paths_data:
535
+ paths_data = all_paths_data[pref_mode]
536
+
537
+ print("\n=================================================")
538
+ print(f"DETAILED {pref_mode.upper()} DIRECTIONS:")
539
+ print("=================================================")
540
+
541
+ if "paths" in paths_data and len(paths_data["paths"]) > 0 and "instructions" in paths_data["paths"][0]:
542
+ for each in range(len(paths_data["paths"][0]["instructions"])):
543
+ path = paths_data["paths"][0]["instructions"][each]["text"]
544
+ distance = paths_data["paths"][0]["instructions"][each]["distance"]
545
+ print(f"{each+1}. {path} ({distance/1000:.1f} km / {distance/1000/1.61:.1f} miles)")
546
+ else:
547
+ print("No detailed directions available.")
548
+ else:
549
+ print(f"\n{pref_mode.upper()} directions are estimated and don't have turn-by-turn navigation.")
550
+ print("Consider using the AI assistant to get more information.")
551
+
552
+ # Ask if user wants AI-enhanced information
553
+ enhance = input("\nWould you like AI-enhanced information about this route? (y/n): ")
554
+ if enhance.lower() == "y":
555
+ # Create a proper query for the AI assistant
556
+ query = f"Tell me about the route from {orig[3]} to {dest[3]} with a focus on {pref_mode} transportation"
557
+ response = rag_system.query(query, pref_mode)
558
+
559
+ print("\n=================================================")
560
+ print("πŸ€– AI-ENHANCED ROUTE INFORMATION:")
561
+ print("=================================================")
562
+ print(response["answer"])
563
+ print("=================================================")
564
+
565
+ print("\n*************************************************")
566
+ else:
567
+ print("Invalid choice. Please try again.")
568
+
569
+ if __name__ == "__main__":
570
+ main()