Improve AI logic
This commit is contained in:
253
services/forecasting/app/clients/ai_insights_client.py
Normal file
253
services/forecasting/app/clients/ai_insights_client.py
Normal file
@@ -0,0 +1,253 @@
|
||||
"""
|
||||
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
|
||||
Reference in New Issue
Block a user