254 lines
7.2 KiB
Python
254 lines
7.2 KiB
Python
"""
|
|
AI Insights Service HTTP Client
|
|
Posts insights from forecasting service to AI Insights Service
|
|
"""
|
|
|
|
import httpx
|
|
from typing import Dict, List, Any, Optional
|
|
from uuid import UUID
|
|
import structlog
|
|
from datetime import datetime
|
|
|
|
logger = structlog.get_logger()
|
|
|
|
|
|
class AIInsightsClient:
|
|
"""
|
|
HTTP client for AI Insights Service.
|
|
Allows forecasting service to post detected patterns and insights.
|
|
"""
|
|
|
|
def __init__(self, base_url: str, timeout: int = 30):
|
|
"""
|
|
Initialize AI Insights client.
|
|
|
|
Args:
|
|
base_url: Base URL of AI Insights Service (e.g., http://ai-insights-service:8000)
|
|
timeout: Request timeout in seconds
|
|
"""
|
|
self.base_url = base_url.rstrip('/')
|
|
self.timeout = timeout
|
|
self.client = httpx.AsyncClient(timeout=self.timeout)
|
|
|
|
async def close(self):
|
|
"""Close the HTTP client."""
|
|
await self.client.aclose()
|
|
|
|
async def create_insight(
|
|
self,
|
|
tenant_id: UUID,
|
|
insight_data: Dict[str, Any]
|
|
) -> Optional[Dict[str, Any]]:
|
|
"""
|
|
Create a new insight in AI Insights Service.
|
|
|
|
Args:
|
|
tenant_id: Tenant UUID
|
|
insight_data: Insight data dictionary
|
|
|
|
Returns:
|
|
Created insight dict or None if failed
|
|
"""
|
|
url = f"{self.base_url}/api/v1/ai-insights/tenants/{tenant_id}/insights"
|
|
|
|
try:
|
|
# Ensure tenant_id is in the data
|
|
insight_data['tenant_id'] = str(tenant_id)
|
|
|
|
response = await self.client.post(url, json=insight_data)
|
|
|
|
if response.status_code == 201:
|
|
logger.info(
|
|
"Insight created successfully",
|
|
tenant_id=str(tenant_id),
|
|
insight_title=insight_data.get('title')
|
|
)
|
|
return response.json()
|
|
else:
|
|
logger.error(
|
|
"Failed to create insight",
|
|
status_code=response.status_code,
|
|
response=response.text,
|
|
insight_title=insight_data.get('title')
|
|
)
|
|
return None
|
|
|
|
except Exception as e:
|
|
logger.error(
|
|
"Error creating insight",
|
|
error=str(e),
|
|
tenant_id=str(tenant_id)
|
|
)
|
|
return None
|
|
|
|
async def create_insights_bulk(
|
|
self,
|
|
tenant_id: UUID,
|
|
insights: List[Dict[str, Any]]
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Create multiple insights in bulk.
|
|
|
|
Args:
|
|
tenant_id: Tenant UUID
|
|
insights: List of insight data dictionaries
|
|
|
|
Returns:
|
|
Dictionary with success/failure counts
|
|
"""
|
|
results = {
|
|
'total': len(insights),
|
|
'successful': 0,
|
|
'failed': 0,
|
|
'created_insights': []
|
|
}
|
|
|
|
for insight_data in insights:
|
|
result = await self.create_insight(tenant_id, insight_data)
|
|
if result:
|
|
results['successful'] += 1
|
|
results['created_insights'].append(result)
|
|
else:
|
|
results['failed'] += 1
|
|
|
|
logger.info(
|
|
"Bulk insight creation complete",
|
|
total=results['total'],
|
|
successful=results['successful'],
|
|
failed=results['failed']
|
|
)
|
|
|
|
return results
|
|
|
|
async def get_insights(
|
|
self,
|
|
tenant_id: UUID,
|
|
filters: Optional[Dict[str, Any]] = None
|
|
) -> Optional[Dict[str, Any]]:
|
|
"""
|
|
Get insights for a tenant.
|
|
|
|
Args:
|
|
tenant_id: Tenant UUID
|
|
filters: Optional filters (category, priority, etc.)
|
|
|
|
Returns:
|
|
Paginated insights response or None if failed
|
|
"""
|
|
url = f"{self.base_url}/api/v1/ai-insights/tenants/{tenant_id}/insights"
|
|
|
|
try:
|
|
response = await self.client.get(url, params=filters or {})
|
|
|
|
if response.status_code == 200:
|
|
return response.json()
|
|
else:
|
|
logger.error(
|
|
"Failed to get insights",
|
|
status_code=response.status_code
|
|
)
|
|
return None
|
|
|
|
except Exception as e:
|
|
logger.error("Error getting insights", error=str(e))
|
|
return None
|
|
|
|
async def get_orchestration_ready_insights(
|
|
self,
|
|
tenant_id: UUID,
|
|
target_date: datetime,
|
|
min_confidence: int = 70
|
|
) -> Optional[Dict[str, List[Dict[str, Any]]]]:
|
|
"""
|
|
Get insights ready for orchestration workflow.
|
|
|
|
Args:
|
|
tenant_id: Tenant UUID
|
|
target_date: Target date for orchestration
|
|
min_confidence: Minimum confidence threshold
|
|
|
|
Returns:
|
|
Categorized insights or None if failed
|
|
"""
|
|
url = f"{self.base_url}/api/v1/ai-insights/tenants/{tenant_id}/insights/orchestration-ready"
|
|
|
|
params = {
|
|
'target_date': target_date.isoformat(),
|
|
'min_confidence': min_confidence
|
|
}
|
|
|
|
try:
|
|
response = await self.client.get(url, params=params)
|
|
|
|
if response.status_code == 200:
|
|
return response.json()
|
|
else:
|
|
logger.error(
|
|
"Failed to get orchestration insights",
|
|
status_code=response.status_code
|
|
)
|
|
return None
|
|
|
|
except Exception as e:
|
|
logger.error("Error getting orchestration insights", error=str(e))
|
|
return None
|
|
|
|
async def record_feedback(
|
|
self,
|
|
tenant_id: UUID,
|
|
insight_id: UUID,
|
|
feedback_data: Dict[str, Any]
|
|
) -> Optional[Dict[str, Any]]:
|
|
"""
|
|
Record feedback for an applied insight.
|
|
|
|
Args:
|
|
tenant_id: Tenant UUID
|
|
insight_id: Insight UUID
|
|
feedback_data: Feedback data
|
|
|
|
Returns:
|
|
Feedback response or None if failed
|
|
"""
|
|
url = f"{self.base_url}/api/v1/ai-insights/tenants/{tenant_id}/insights/{insight_id}/feedback"
|
|
|
|
try:
|
|
feedback_data['insight_id'] = str(insight_id)
|
|
|
|
response = await self.client.post(url, json=feedback_data)
|
|
|
|
if response.status_code in [200, 201]:
|
|
logger.info(
|
|
"Feedback recorded",
|
|
insight_id=str(insight_id),
|
|
success=feedback_data.get('success')
|
|
)
|
|
return response.json()
|
|
else:
|
|
logger.error(
|
|
"Failed to record feedback",
|
|
status_code=response.status_code
|
|
)
|
|
return None
|
|
|
|
except Exception as e:
|
|
logger.error("Error recording feedback", error=str(e))
|
|
return None
|
|
|
|
async def health_check(self) -> bool:
|
|
"""
|
|
Check if AI Insights Service is healthy.
|
|
|
|
Returns:
|
|
True if healthy, False otherwise
|
|
"""
|
|
url = f"{self.base_url}/health"
|
|
|
|
try:
|
|
response = await self.client.get(url)
|
|
return response.status_code == 200
|
|
|
|
except Exception as e:
|
|
logger.error("AI Insights Service health check failed", error=str(e))
|
|
return False
|