Add AI insights feature

This commit is contained in:
Urtzi Alfaro
2025-12-15 21:14:22 +01:00
parent 5642b5a0c0
commit c566967bea
39 changed files with 17729 additions and 404 deletions

View File

@@ -11,6 +11,7 @@ from uuid import UUID
from app.ml.dynamic_rules_engine import DynamicRulesEngine
from app.clients.ai_insights_client import AIInsightsClient
from shared.messaging import UnifiedEventPublisher
logger = structlog.get_logger()
@@ -29,10 +30,12 @@ class RulesOrchestrator:
def __init__(
self,
ai_insights_base_url: str = "http://ai-insights-service:8000"
ai_insights_base_url: str = "http://ai-insights-service:8000",
event_publisher: Optional[UnifiedEventPublisher] = None
):
self.rules_engine = DynamicRulesEngine()
self.ai_insights_client = AIInsightsClient(ai_insights_base_url)
self.event_publisher = event_publisher
async def learn_and_post_rules(
self,
@@ -100,7 +103,17 @@ class RulesOrchestrator:
post_results = {'total': 0, 'successful': 0, 'failed': 0}
logger.info("No insights to post")
# Step 4: Return comprehensive results
# Step 4: Publish insight events to RabbitMQ
created_insights = post_results.get('created_insights', [])
if created_insights:
product_context = {'inventory_product_id': inventory_product_id}
await self._publish_insight_events(
tenant_id=tenant_id,
insights=created_insights,
product_context=product_context
)
# Step 5: Return comprehensive results
return {
'tenant_id': tenant_id,
'inventory_product_id': inventory_product_id,
@@ -229,6 +242,71 @@ class RulesOrchestrator:
return results
async def _publish_insight_events(self, tenant_id, insights, product_context=None):
"""
Publish insight events to RabbitMQ for alert processing.
Args:
tenant_id: Tenant identifier
insights: List of created insights
product_context: Additional context about the product
"""
if not self.event_publisher:
logger.warning("No event publisher available for business rules insights")
return
for insight in insights:
# Determine severity based on confidence and priority
confidence = insight.get('confidence', 0)
priority = insight.get('priority', 'medium')
# Map priority to severity, with confidence as tiebreaker
if priority == 'critical' or (priority == 'high' and confidence >= 70):
severity = 'high'
elif priority == 'high' or (priority == 'medium' and confidence >= 80):
severity = 'medium'
else:
severity = 'low'
# Prepare the event data
event_data = {
'insight_id': insight.get('id'),
'type': insight.get('type'),
'title': insight.get('title'),
'description': insight.get('description'),
'category': insight.get('category'),
'priority': insight.get('priority'),
'confidence': confidence,
'recommendation': insight.get('recommendation_actions', []),
'impact_type': insight.get('impact_type'),
'impact_value': insight.get('impact_value'),
'inventory_product_id': product_context.get('inventory_product_id') if product_context else None,
'timestamp': insight.get('detected_at', datetime.utcnow().isoformat()),
'source_service': 'forecasting',
'source_model': 'dynamic_rules_engine'
}
try:
await self.event_publisher.publish_recommendation(
event_type='ai_business_rule',
tenant_id=tenant_id,
severity=severity,
data=event_data
)
logger.info(
"Published business rules insight event",
tenant_id=tenant_id,
insight_id=insight.get('id'),
severity=severity
)
except Exception as e:
logger.error(
"Failed to publish business rules insight event",
tenant_id=tenant_id,
insight_id=insight.get('id'),
error=str(e)
)
async def close(self):
"""Close HTTP client connections."""
await self.ai_insights_client.close()