GMaps API searchText
This commit is contained in:
parent
bd8e0c2578
commit
028b9ab64f
@ -97,13 +97,13 @@ class PendingTOTP(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class GooglePlaceResult(BaseModel):
|
class GooglePlaceResult(BaseModel):
|
||||||
id: str | None = None
|
|
||||||
name: str | None = None
|
name: str | None = None
|
||||||
lat: float | None = None
|
lat: float | None = None
|
||||||
lng: float | None = None
|
lng: float | None = None
|
||||||
price: float | None = None
|
price: float | None = None
|
||||||
|
allowsdog: bool | None = None
|
||||||
|
description: str | None = None
|
||||||
types: list[str] = []
|
types: list[str] = []
|
||||||
allows_dogs: bool | None = None
|
|
||||||
|
|
||||||
|
|
||||||
class ImageBase(SQLModel):
|
class ImageBase(SQLModel):
|
||||||
@ -198,6 +198,7 @@ class UserUpdate(UserBase):
|
|||||||
map_lng: float | None = None
|
map_lng: float | None = None
|
||||||
currency: str | None = None
|
currency: str | None = None
|
||||||
do_not_display: list[str] | None = None
|
do_not_display: list[str] | None = None
|
||||||
|
google_apikey: str | None = None
|
||||||
|
|
||||||
|
|
||||||
class UserRead(UserBase):
|
class UserRead(UserBase):
|
||||||
@ -219,7 +220,7 @@ class UserRead(UserBase):
|
|||||||
mode_dark=obj.mode_dark,
|
mode_dark=obj.mode_dark,
|
||||||
mode_gpx_in_place=obj.mode_gpx_in_place,
|
mode_gpx_in_place=obj.mode_gpx_in_place,
|
||||||
totp_enabled=obj.totp_enabled,
|
totp_enabled=obj.totp_enabled,
|
||||||
google_apikey=True if obj.google_apikey else False
|
google_apikey=True if obj.google_apikey else False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,12 +6,14 @@ from sqlmodel import select
|
|||||||
|
|
||||||
from ..config import settings
|
from ..config import settings
|
||||||
from ..deps import SessionDep, get_current_username
|
from ..deps import SessionDep, get_current_username
|
||||||
from ..models.models import (Category, Image, GooglePlaceResult, Place, PlaceCreate,
|
from ..models.models import (Category, GooglePlaceResult, Image, Place,
|
||||||
PlaceRead, PlacesCreate, PlaceUpdate)
|
PlaceCreate, PlaceRead, PlacesCreate, PlaceUpdate,
|
||||||
|
User)
|
||||||
from ..security import verify_exists_and_owns
|
from ..security import verify_exists_and_owns
|
||||||
|
from ..utils.gmaps import (compute_avg_price, compute_description,
|
||||||
|
gmaps_textsearch)
|
||||||
from ..utils.utils import (b64img_decode, download_file, patch_image,
|
from ..utils.utils import (b64img_decode, download_file, patch_image,
|
||||||
save_image_to_file)
|
save_image_to_file)
|
||||||
from ..utils.gmaps import compute_avg_price, gmaps_textsearch
|
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/places", tags=["places"])
|
router = APIRouter(prefix="/api/places", tags=["places"])
|
||||||
|
|
||||||
@ -111,25 +113,26 @@ async def create_places(
|
|||||||
return [PlaceRead.serialize(p) for p in new_places]
|
return [PlaceRead.serialize(p) for p in new_places]
|
||||||
|
|
||||||
|
|
||||||
@router.get("/google-search", response_model=list[GooglePlaceResult])
|
@router.get("/google-search")
|
||||||
async def google_search_text(q: str, session: SessionDep, current_user: Annotated[str, Depends(get_current_username)]) -> list[GooglePlaceResult]:
|
async def google_search_text(
|
||||||
|
q: str, session: SessionDep, current_user: Annotated[str, Depends(get_current_username)]
|
||||||
|
):
|
||||||
db_user = session.get(User, current_user)
|
db_user = session.get(User, current_user)
|
||||||
if not db_user or not db_user.google_apikey:
|
if not db_user or not db_user.google_apikey:
|
||||||
raise HTTPException(status_code=400, detail="Google Maps API key not configured")
|
raise HTTPException(status_code=400, detail="Google Maps API key not configured")
|
||||||
|
|
||||||
data = await gmaps_textsearch(q, db_user.google_apikey)
|
data = await gmaps_textsearch(q, db_user.google_apikey)
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
for place in data:
|
for place in data:
|
||||||
loc = place.get("location", {})
|
loc = place.get("location", {})
|
||||||
result = GooglePlaceResult(
|
result = GooglePlaceResult(
|
||||||
id=place.get("id"),
|
name=place.get("displayName", {}).get("text"),
|
||||||
name=place.get("displayName", {}).get('text'),
|
lat=loc.get("latitude", None),
|
||||||
lat=loc.get("latitude"),
|
lng=loc.get("longitude", None),
|
||||||
lng=loc.get("longitude"),
|
|
||||||
price=compute_avg_price(place.get("priceRange")),
|
price=compute_avg_price(place.get("priceRange")),
|
||||||
types=place.get("types", []),
|
types=place.get("types", []),
|
||||||
allow_dogs=place.get("allowDogs")
|
allowdog=place.get("allowDogs"),
|
||||||
|
description=compute_description(place),
|
||||||
)
|
)
|
||||||
results.append(result)
|
results.append(result)
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
# https://developers.google.com/maps/documentation/places/web-service/nearby-search
|
|
||||||
# https://developers.google.com/maps/documentation/places/web-service/text-search
|
|
||||||
# https://developers.google.com/maps/documentation/places/web-service/place-details
|
|
||||||
# https://developers.google.com/maps/documentation/places/web-service/place-photos
|
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
|
|
||||||
@ -14,7 +10,7 @@ def compute_avg_price(price_range: dict | None) -> float | None:
|
|||||||
|
|
||||||
start = price_range.get("startPrice", {}).get("units")
|
start = price_range.get("startPrice", {}).get("units")
|
||||||
end = price_range.get("endPrice", {}).get("units")
|
end = price_range.get("endPrice", {}).get("units")
|
||||||
|
|
||||||
if start and end:
|
if start and end:
|
||||||
return (int(start) + int(end)) / 2
|
return (int(start) + int(end)) / 2
|
||||||
elif start:
|
elif start:
|
||||||
@ -25,15 +21,28 @@ def compute_avg_price(price_range: dict | None) -> float | None:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def compute_description(place: dict[str, Any]):
|
||||||
|
description = ""
|
||||||
|
address = place.get("formattedAddress")
|
||||||
|
phone = place.get("internationalPhoneNumber")
|
||||||
|
website = place.get("websiteUri")
|
||||||
|
|
||||||
|
if address:
|
||||||
|
description += f"{address}\n"
|
||||||
|
if phone:
|
||||||
|
description += f"Phone: {phone}\n"
|
||||||
|
if website:
|
||||||
|
description += f"Website: {website}"
|
||||||
|
return description.rstrip()
|
||||||
|
|
||||||
|
|
||||||
async def gmaps_textsearch(search: str, api_key: str) -> list[dict[str, Any]]:
|
async def gmaps_textsearch(search: str, api_key: str) -> list[dict[str, Any]]:
|
||||||
url = "https://places.googleapis.com/v1/places:searchText"
|
url = "https://places.googleapis.com/v1/places:searchText"
|
||||||
body = {
|
body = {"textQuery": search}
|
||||||
"textQuery": search
|
|
||||||
}
|
|
||||||
headers = {
|
headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Goog-Api-Key": api_key,
|
"X-Goog-Api-Key": api_key,
|
||||||
"X-Goog-FieldMask": "places.id,places.types,places.location,places.priceRange,places.displayName,places.allowsDogs"
|
"X-Goog-FieldMask": "places.id,places.types,places.location,places.priceRange,places.formattedAddress,places.websiteUri,places.internationalPhoneNumber,places.displayName,places.allowsDogs",
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -41,6 +50,6 @@ async def gmaps_textsearch(search: str, api_key: str) -> list[dict[str, Any]]:
|
|||||||
response = await client.post(url, json=body, headers=headers)
|
response = await client.post(url, json=body, headers=headers)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
data = response.json()
|
data = response.json()
|
||||||
return data.get('places', [])
|
return data.get("places", [])
|
||||||
except Exception:
|
except Exception:
|
||||||
raise HTTPException(status_code=400, detail="Bad Request")
|
raise HTTPException(status_code=400, detail="Bad Request")
|
||||||
Loading…
x
Reference in New Issue
Block a user