Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions backend/adapters/openrouteservice_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ async def build_avoid_polygons(self, avoid_roads: List[str]):
async def get_directions(self,
origin: dict,
destination: dict,
option: dict,
option: str,
via: List[dict] = None,
avoid_roads: List[str] = None,
avoid_features: List[str] = None
Expand All @@ -387,10 +387,14 @@ async def get_directions(self,
coords.extend([[v["lng"], v["lat"]] for v in via])
coords.append([destination["lng"], destination["lat"]])

normalized_option = (option or "recommended").strip().lower()
if normalized_option not in {"recommended", "fastest", "shortest"}:
normalized_option = "recommended"

payload = {
"coordinates": coords,
"instructions": True,
"preference": option
"preference": normalized_option
}

# Request alternative routes if no waypoints included
Expand Down Expand Up @@ -418,16 +422,32 @@ async def get_directions(self,
}
start_time = time.perf_counter()
resp = await self.client.post(self.directions_url, json=payload, headers=headers)

data = resp.json()
end_time = time.perf_counter()
ors_ms = (end_time - start_time) * 1000

if resp.status_code != 200:
error_detail = resp.text
try:
error_data = resp.json()
if isinstance(error_data, dict):
error_obj = error_data.get("error", {})
error_detail = error_obj.get("message") or str(error_data)
else:
error_detail = str(error_data)
except Exception:
pass
raise RuntimeError(f"ORS directions failed ({resp.status_code}): {error_detail}")

data = resp.json()

routes_output = []
for route in data.get("routes", []):
# Decode the geometry to get all points
encoded_geom = route.get("geometry")
full_coords = []
matching_coords = []
mapbox_waypoints = []
turn_indices = []

# Decode polyline into coordinates
if encoded_geom:
Expand Down
3 changes: 2 additions & 1 deletion backend/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ async def store_audio_file(file_path: str, file_content: bytes):
"""

try:
normalized_file_path = file_path.replace("\\", "/")
# We specify the content_type so the browser knows it's audio later
response = supabase.storage.from_("voice_logs").upload(
path=file_path,
path=normalized_file_path,
file=file_content,
file_options={"content-type": "audio/wav", "upsert": "true"}
)
Expand Down
132 changes: 97 additions & 35 deletions backend/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -784,8 +784,8 @@ async def detect_intent(latest_input, mode, conversation_history, semantic_conte
error_type=type(e).__name__,
payload={"raw_gpt_output": raw_intents, "mode": mode}
))
return {k: False for k in ["clarifications","cancellation","generate_routes","trip_changes"
"start_nav","request_alternates","select_route"]}, intent_detect_latency
return {k: False for k in ["clarifications","cancellation","generate_routes","trip_changes",
"start_nav","request_alternates","select_route"]}, intent_detect_latency

async def resolve_semantic_places(user_input: str, semantic_context: dict, user_id: str):
"""
Expand Down Expand Up @@ -827,39 +827,101 @@ async def generate_route_and_response(user_id, session_id, origin, destination,
"""
routes_data = []
ors_latency = 0.0
try:
routes_data, ors_latency = await adapter.get_directions(
origin=origin,
destination=destination,
option=option,
via=via,
avoid_roads=avoid_roads,
avoid_features=avoid_features
normalized_option = (option or "recommended").strip().lower()
if normalized_option not in {"recommended", "fastest", "shortest"}:
normalized_option = "recommended"

attempts = [
{
"label": "primary",
"via": via,
"avoid_roads": avoid_roads,
"avoid_features": avoid_features,
}
]

if avoid_roads or avoid_features:
attempts.append(
{
"label": "retry_without_avoid",
"via": via,
"avoid_roads": [],
"avoid_features": [],
}
)
# THE GUARD: If no routes were found, stop and inform the user immediately
if not routes_data or len(routes_data) == 0:
response = "I found the locations, but I couldn't find a drivable route between them."
return [], {}, {"heyroute": response, "ors_latency": ors_latency, "user_id": user_id, "session_id": session_id}

# Check if the adapter returned an internal error dict instead of raising an exception
if isinstance(routes_data, dict) and "error" in routes_data:
raise Exception(routes_data["error"])

except Exception as e:
# FAILSAFE: Handle ORS Down / Connection Refused
asyncio.create_task(log_system_error(
user_id=user_id,
session_id=session_id,
function_name="generate_route_exception",
error_msg=str(e),
error_type=type(e).__name__,
payload={"routes_data": routes_data, "ors_latency": ors_latency}
))
response = (
"I'm sorry, I'm having trouble connecting to the server right now. "
"Please try again later."

if via:
attempts.append(
{
"label": "retry_without_via",
"via": [],
"avoid_roads": [],
"avoid_features": [],
}
)

for attempt in attempts:
try:
routes_data, ors_latency = await adapter.get_directions(
origin=origin,
destination=destination,
option=normalized_option,
via=attempt["via"],
avoid_roads=attempt["avoid_roads"],
avoid_features=attempt["avoid_features"],
)
except Exception as e:
asyncio.create_task(
log_system_error(
user_id=user_id,
session_id=session_id,
function_name="generate_route_exception",
error_msg=str(e),
error_type=type(e).__name__,
payload={
"attempt": attempt["label"],
"origin": origin,
"destination": destination,
"option": normalized_option,
"via": attempt["via"],
"avoid_roads": attempt["avoid_roads"],
"avoid_features": attempt["avoid_features"],
"ors_latency": ors_latency,
},
)
)
response = (
"I'm sorry, I'm having trouble connecting to the routing service right now. "
"Please try again later."
)
return {"error": str(e)}, {}, {"heyroute": response, "ors_latency": ors_latency, "user_id": user_id, "session_id": session_id}

if routes_data:
break

asyncio.create_task(
log_system_error(
user_id=user_id,
session_id=session_id,
function_name="generate_route_no_results",
error_msg="No routes returned from ORS for this attempt",
error_type="NoRouteFound",
payload={
"attempt": attempt["label"],
"origin": origin,
"destination": destination,
"option": normalized_option,
"via": attempt["via"],
"avoid_roads": attempt["avoid_roads"],
"avoid_features": attempt["avoid_features"],
"ors_latency": ors_latency,
},
)
)
return {"error": str(e)}, {}, {"heyroute": response, "ors_latency": ors_latency, "user_id": user_id, "session_id": session_id}

if not routes_data:
response = "I found the locations, but I couldn't find a drivable route between them."
return [], {}, {"heyroute": response, "ors_latency": ors_latency, "user_id": user_id, "session_id": session_id}

primary_route = routes_data[0] if routes_data else {}
if road:
Expand All @@ -873,7 +935,7 @@ async def generate_route_and_response(user_id, session_id, origin, destination,
route_summary = {
"origin": origin,
"destination": destination,
"option": option,
"option": normalized_option,
"via": primary_route.get("via"),
"distance": primary_route.get("distance"),
"duration": primary_route.get("duration")
Expand All @@ -886,7 +948,7 @@ async def generate_route_and_response(user_id, session_id, origin, destination,
event_type="ROUTE_GENERATED",
origin=origin,
destination=destination,
option=option,
option=normalized_option,
via=route.get("via"),
distance=route.get("distance"),
duration=route.get("duration")
Expand Down
2 changes: 1 addition & 1 deletion backend/prompts.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
6. Keep responses polite, concise, and professional.
7. You must **only** handle navigation-related queries (origin, destination, preferences, routes, reroutes, cancellations, deviations).
If the user asks something unrelated to navigation (e.g., weather, jokes, general chit-chat), respond with:
"I'm sorry, but I can't help you with your request."
"I can only help with navigation requests. Please ask for directions or route changes."
8. Always check if the navigation request is **realistic and safe**.
- Assume the user's origin is in the Philippines unless they specify otherwise.
- If the trip is outside the Philippines, requires crossing oceans or continents by car (e.g., "Take me to Manila from California", "Drive to Japan"),
Expand Down
4 changes: 2 additions & 2 deletions frontend/android/.settings/org.eclipse.buildship.core.prefs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
arguments=--init-script C\:\\Users\\GABSAN~1\\AppData\\Local\\Temp\\db3b08fc4a9ef609cb16b96b200fa13e563f396e9bb1ed0905fdab7bc3bc513b.gradle --init-script C\:\\Users\\GABSAN~1\\AppData\\Local\\Temp\\52cde0cfcf3e28b8b7510e992210d9614505e0911af0c190bd590d7158574963.gradle --init-script C\:\\Users\\GABSAN~1\\AppData\\Local\\Temp\\861a75667e10803d304a058d833cb7404195ca44013d0d61d3b653eb084379b8.gradle --init-script C\:\\Users\\GABSAN~1\\AppData\\Local\\Temp\\68eb1b6516fe21c6fbba58e63c99c3207ccfc918360613709367eecde56fa77f.gradle
arguments=--init-script C\:\\Users\\loury\\AppData\\Roaming\\Code\\User\\globalStorage\\redhat.java\\1.54.0\\config_win\\org.eclipse.osgi\\58\\0\\.cp\\gradle\\init\\init.gradle --init-script C\:\\Users\\loury\\AppData\\Roaming\\Code\\User\\globalStorage\\redhat.java\\1.54.0\\config_win\\org.eclipse.osgi\\58\\0\\.cp\\gradle\\protobuf\\init.gradle --init-script C\:\\Users\\loury\\AppData\\Roaming\\Code\\User\\globalStorage\\redhat.java\\1.54.0\\config_win\\org.eclipse.osgi\\58\\0\\.cp\\gradle\\kotlin\\init.gradle --init-script C\:\\Users\\loury\\AppData\\Roaming\\Code\\User\\globalStorage\\redhat.java\\1.54.0\\config_win\\org.eclipse.osgi\\58\\0\\.cp\\gradle\\groovy\\init.gradle --init-script C\:\\Users\\loury\\AppData\\Roaming\\Code\\User\\globalStorage\\redhat.java\\1.54.0\\config_win\\org.eclipse.osgi\\58\\0\\.cp\\gradle\\scala\\init.gradle
auto.sync=false
build.scans.enabled=false
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
connection.project.dir=
eclipse.preferences.version=1
gradle.user.home=
java.home=C\:/Program Files/Java/jdk-21
java.home=C\:/Program Files/Eclipse Adoptium/jdk-17.0.18.8-hotspot
jvm.arguments=
offline.mode=false
override.workspace.settings=true
Expand Down
2 changes: 1 addition & 1 deletion frontend/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyBNYHseJRqMJOMEgnU5yPuhGgsfJB5tH-8"/>
android:value="AIzaSyB2uAevrrpt4D2nRVfHh38kg_xDdlZDskc"/>
Comment on lines 28 to +30

<activity
android:name=".MainActivity"
Expand Down
Loading