imporve features

This commit is contained in:
Urtzi Alfaro
2025-11-14 07:23:56 +01:00
parent 9bc048d360
commit a8d8828935
32 changed files with 5436 additions and 271 deletions

View File

@@ -245,7 +245,7 @@ class ExternalServiceClient(BaseServiceClient):
result = await self._make_request(
"GET",
f"external/tenants/{tenant_id}/location-context",
"external/location-context",
tenant_id=tenant_id,
timeout=5.0
)
@@ -257,6 +257,128 @@ class ExternalServiceClient(BaseServiceClient):
logger.info("No location context found for tenant", tenant_id=tenant_id)
return None
async def create_tenant_location_context(
self,
tenant_id: str,
city_id: str,
school_calendar_id: Optional[str] = None,
neighborhood: Optional[str] = None,
local_events: Optional[List[Dict[str, Any]]] = None,
notes: Optional[str] = None
) -> Optional[Dict[str, Any]]:
"""
Create or update location context for a tenant.
This establishes the city association for a tenant and optionally assigns
a school calendar. Typically called during tenant registration to set up
location-based context for ML features.
Args:
tenant_id: Tenant UUID
city_id: Normalized city ID (e.g., "madrid", "barcelona")
school_calendar_id: Optional school calendar UUID to assign
neighborhood: Optional neighborhood name
local_events: Optional list of local events with impact data
notes: Optional notes about the location context
Returns:
Dict with created location context including nested calendar details,
or None if creation failed
"""
payload = {"city_id": city_id}
if school_calendar_id:
payload["school_calendar_id"] = school_calendar_id
if neighborhood:
payload["neighborhood"] = neighborhood
if local_events:
payload["local_events"] = local_events
if notes:
payload["notes"] = notes
logger.info(
"Creating tenant location context",
tenant_id=tenant_id,
city_id=city_id,
has_calendar=bool(school_calendar_id)
)
result = await self._make_request(
"POST",
"external/location-context",
tenant_id=tenant_id,
json=payload,
timeout=10.0
)
if result:
logger.info(
"Successfully created tenant location context",
tenant_id=tenant_id,
city_id=city_id
)
return result
else:
logger.warning(
"Failed to create tenant location context",
tenant_id=tenant_id,
city_id=city_id
)
return None
async def suggest_calendar_for_tenant(
self,
tenant_id: str
) -> Optional[Dict[str, Any]]:
"""
Get smart calendar suggestion for a tenant based on POI data and location.
Analyzes tenant's location context, nearby schools from POI detection,
and available calendars to provide an intelligent suggestion with
confidence score and reasoning.
Args:
tenant_id: Tenant UUID
Returns:
Dict with:
- suggested_calendar_id: Suggested calendar UUID
- calendar_name: Name of suggested calendar
- confidence: Float 0.0-1.0
- confidence_percentage: Percentage format
- reasoning: List of reasoning steps
- fallback_calendars: Alternative suggestions
- should_auto_assign: Boolean recommendation
- admin_message: Formatted message for display
- school_analysis: Analysis of nearby schools
Or None if request failed
"""
logger.info("Requesting calendar suggestion", tenant_id=tenant_id)
result = await self._make_request(
"POST",
"external/location-context/suggest-calendar",
tenant_id=tenant_id,
timeout=10.0
)
if result:
confidence = result.get("confidence_percentage", 0)
suggested = result.get("calendar_name", "None")
logger.info(
"Calendar suggestion received",
tenant_id=tenant_id,
suggested_calendar=suggested,
confidence=confidence
)
return result
else:
logger.warning(
"Failed to get calendar suggestion",
tenant_id=tenant_id
)
return None
async def get_school_calendar(
self,
calendar_id: str,
@@ -379,6 +501,11 @@ class ExternalServiceClient(BaseServiceClient):
"""
Get POI context for a tenant including ML features for forecasting.
With the new tenant-based architecture:
- Gateway receives at: /api/v1/tenants/{tenant_id}/external/poi-context
- Gateway proxies to external service at: /api/v1/tenants/{tenant_id}/poi-context
- This client calls: /tenants/{tenant_id}/poi-context
This retrieves stored POI detection results and calculated ML features
that should be included in demand forecasting predictions.
@@ -394,14 +521,11 @@ class ExternalServiceClient(BaseServiceClient):
"""
logger.info("Fetching POI context for forecasting", tenant_id=tenant_id)
# Note: POI context endpoint structure is /external/poi-context/{tenant_id}
# We pass tenant_id to _make_request which will build: /api/v1/tenants/{tenant_id}/external/poi-context/{tenant_id}
# But the actual endpoint in external service is just /poi-context/{tenant_id}
# So we need to use the operations prefix correctly
# Updated endpoint path to follow tenant-based pattern: /tenants/{tenant_id}/poi-context
result = await self._make_request(
"GET",
f"external/operations/poi-context/{tenant_id}",
tenant_id=None, # Don't auto-prefix, we're including tenant_id in the path
f"tenants/{tenant_id}/poi-context", # Updated path: /tenants/{tenant_id}/poi-context
tenant_id=tenant_id, # Pass tenant_id to include in headers for authentication
timeout=5.0
)