system-prompts-and-models-o.../dealix/auto_client_acquisition/providers/maps.py
2026-05-01 14:03:52 +03:00

122 lines
3.8 KiB
Python

"""MapsProvider chain — Google Places → SerpApi → Apify → Static."""
from __future__ import annotations
import logging
import os
from typing import Protocol, runtime_checkable
from auto_client_acquisition.connectors.google_maps import discover_local
from auto_client_acquisition.providers.base import ProviderResult
log = logging.getLogger(__name__)
@runtime_checkable
class MapsProvider(Protocol):
name: str
def is_available(self) -> bool: ...
async def discover(
self, *, industry: str, city: str, max_results: int = 20,
page_token: str | None = None, hydrate_details: bool = True,
custom_query: str | None = None,
) -> ProviderResult: ...
class GooglePlacesProvider:
name = "google_places"
def is_available(self) -> bool:
return bool(os.getenv("GOOGLE_MAPS_API_KEY", "").strip())
async def discover(
self, *, industry: str, city: str, max_results: int = 20,
page_token: str | None = None, hydrate_details: bool = True,
custom_query: str | None = None,
) -> ProviderResult:
resp = await discover_local(
industry=industry, city=city, max_results=max_results,
page_token=page_token, hydrate_details=hydrate_details,
custom_query=custom_query,
)
if resp.status == "ok":
return ProviderResult(provider=self.name, status="ok", data=resp.to_dict())
return ProviderResult(provider=self.name, status=resp.status, error=resp.error)
class SerpApiMapsProvider:
name = "serpapi_maps"
def is_available(self) -> bool:
return bool(os.getenv("SERPAPI_API_KEY", "").strip())
async def discover(self, **_: object) -> ProviderResult:
return ProviderResult(
provider=self.name, status="unsupported",
error="SerpApi adapter not yet implemented — stub only.",
)
class ApifyMapsProvider:
name = "apify_maps"
def is_available(self) -> bool:
return bool(os.getenv("APIFY_TOKEN", "").strip())
async def discover(self, **_: object) -> ProviderResult:
return ProviderResult(
provider=self.name, status="unsupported",
error="Apify adapter not yet implemented — stub only.",
)
class StaticMapsProvider:
name = "static_fallback"
def is_available(self) -> bool:
return True
async def discover(
self, *, industry: str, city: str, max_results: int = 20,
page_token: str | None = None, hydrate_details: bool = True,
custom_query: str | None = None,
) -> ProviderResult:
return ProviderResult(
provider=self.name, status="ok",
data={
"industry": industry, "city": city,
"query_used": custom_query or industry, "total": 0, "results": [],
"hint": "No MapsProvider configured. Set GOOGLE_MAPS_API_KEY (Places API enabled).",
},
)
def get_maps_chain() -> list[MapsProvider]:
return [
GooglePlacesProvider(), SerpApiMapsProvider(),
ApifyMapsProvider(), StaticMapsProvider(),
]
async def discover_with_chain(
*, industry: str, city: str, max_results: int = 20,
page_token: str | None = None, hydrate_details: bool = True,
custom_query: str | None = None,
) -> ProviderResult:
last: ProviderResult | None = None
for p in get_maps_chain():
if not p.is_available():
continue
result = await p.discover(
industry=industry, city=city, max_results=max_results,
page_token=page_token, hydrate_details=hydrate_details,
custom_query=custom_query,
)
if result.status == "ok":
return result
last = result
log.info("maps_chain_fallback_from=%s status=%s", p.name, result.status)
return last or ProviderResult(provider="none", status="empty")