fix: migrate Places and Routes to new GCP APIs

Switch from legacy Places textsearch and Directions APIs (disabled on
this project) to Places API (New) and Routes API (New). Both places.py
and the assistant's _places_search helper updated. Also fixes uid()
recursive self-call in trips page and adds Places API response logging.
This commit is contained in:
Logan
2026-06-21 14:35:12 -04:00
parent 522748f07a
commit 21268ab477
2 changed files with 66 additions and 36 deletions
+45 -23
View File
@@ -5,8 +5,9 @@ from app.internal.logger import logger
router = APIRouter(prefix="/places", tags=["places"])
PLACES_SEARCH_URL = "https://maps.googleapis.com/maps/api/place/textsearch/json"
DIRECTIONS_URL = "https://maps.googleapis.com/maps/api/directions/json"
_PLACES_SEARCH_URL = "https://places.googleapis.com/v1/places:searchText"
_ROUTES_URL = "https://routes.googleapis.com/directions/v2:computeRoutes"
_PLACES_FIELDS = "places.id,places.displayName,places.formattedAddress,places.rating,places.googleMapsUri,places.location"
@router.get("/search")
@@ -17,9 +18,13 @@ async def search_places(query: str = Query(...), near: str = Query("")):
full_query = f"{query} {near}".strip()
try:
async with httpx.AsyncClient(timeout=10) as client:
r = await client.get(
PLACES_SEARCH_URL,
params={"query": full_query, "key": settings.google_maps_api_key},
r = await client.post(
_PLACES_SEARCH_URL,
json={"textQuery": full_query},
headers={
"X-Goog-Api-Key": settings.google_maps_api_key,
"X-Goog-FieldMask": _PLACES_FIELDS,
},
)
r.raise_for_status()
data = r.json()
@@ -29,15 +34,15 @@ async def search_places(query: str = Query(...), near: str = Query("")):
return [
{
"name": p.get("name"),
"address": p.get("formatted_address"),
"place_id": p.get("place_id"),
"lat": p.get("geometry", {}).get("location", {}).get("lat"),
"lng": p.get("geometry", {}).get("location", {}).get("lng"),
"maps_link": f"https://www.google.com/maps/place/?q=place_id:{p.get('place_id')}",
"name": p.get("displayName", {}).get("text"),
"address": p.get("formattedAddress"),
"place_id": p.get("id"),
"lat": p.get("location", {}).get("latitude"),
"lng": p.get("location", {}).get("longitude"),
"maps_link": p.get("googleMapsUri"),
"rating": p.get("rating"),
}
for p in data.get("results", [])[:6]
for p in data.get("places", [])[:6]
]
@@ -51,13 +56,16 @@ async def get_directions(
try:
async with httpx.AsyncClient(timeout=10) as client:
r = await client.get(
DIRECTIONS_URL,
params={
"origin": origin,
"destination": destination,
"mode": "driving",
"key": settings.google_maps_api_key,
r = await client.post(
_ROUTES_URL,
json={
"origin": {"address": origin},
"destination": {"address": destination},
"travelMode": "DRIVE",
},
headers={
"X-Goog-Api-Key": settings.google_maps_api_key,
"X-Goog-FieldMask": "routes.duration,routes.distanceMeters",
},
)
r.raise_for_status()
@@ -70,9 +78,23 @@ async def get_directions(
if not routes:
return {"duration_text": None, "duration_seconds": None, "distance_text": None}
leg = routes[0]["legs"][0]
route = routes[0]
duration_seconds = int(route.get("duration", "0s").rstrip("s") or 0)
distance_m = route.get("distanceMeters", 0)
# Format human-readable strings
hours, rem = divmod(duration_seconds, 3600)
mins = rem // 60
if hours:
duration_text = f"{hours} hr {mins} min" if mins else f"{hours} hr"
else:
duration_text = f"{mins} min"
miles = distance_m / 1609.34
distance_text = f"{miles:.1f} mi"
return {
"duration_text": leg["duration"]["text"],
"duration_seconds": leg["duration"]["value"],
"distance_text": leg["distance"]["text"],
"duration_text": duration_text,
"duration_seconds": duration_seconds,
"distance_text": distance_text,
}