New alert system and panel de control page
This commit is contained in:
373
services/demo_session/scripts/seed_enriched_alert_demo.py
Normal file
373
services/demo_session/scripts/seed_enriched_alert_demo.py
Normal file
@@ -0,0 +1,373 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Seed demo data for Unified Alert Service
|
||||
|
||||
This script creates demo alerts that showcase the enrichment capabilities:
|
||||
- Low stock (AI already handled - prevented issue)
|
||||
- Supplier delay (action needed - critical)
|
||||
- Waste trend (trend warning - standard)
|
||||
- Orchestrator actions (for context enrichment)
|
||||
|
||||
The unified alert-processor service automatically enriches all alerts with:
|
||||
- Multi-factor priority scoring
|
||||
- Orchestrator context (AI actions)
|
||||
- Business impact analysis
|
||||
- Smart actions with deep links
|
||||
- Timing intelligence
|
||||
|
||||
Usage:
|
||||
python services/demo_session/scripts/seed_enriched_alert_demo.py
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
import uuid
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
|
||||
# Add project root to path
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
||||
|
||||
from shared.messaging.rabbitmq import RabbitMQClient
|
||||
import structlog
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
# Demo tenant ID (should match existing demo tenant)
|
||||
DEMO_TENANT_ID = "demo-tenant-bakery-ia"
|
||||
|
||||
# Demo entity IDs (should match existing demo data)
|
||||
FLOUR_INGREDIENT_ID = "flour-tipo-55"
|
||||
YEAST_INGREDIENT_ID = "yeast-fresh"
|
||||
CROISSANT_PRODUCT_ID = "croissant-mantequilla"
|
||||
CROISSANT_BATCH_ID = "batch-croissants-001"
|
||||
YEAST_SUPPLIER_ID = "supplier-levadura-fresh"
|
||||
FLOUR_PO_ID = "po-flour-demo-001"
|
||||
|
||||
# Demo alerts for unified alert-processor (automatically enriched)
|
||||
DEMO_ALERTS = [
|
||||
# Alert 1: Low Stock - AI Already Handled (Prevented Issue)
|
||||
{
|
||||
'id': str(uuid.uuid4()),
|
||||
'tenant_id': DEMO_TENANT_ID,
|
||||
'item_type': 'alert',
|
||||
'service': 'inventory',
|
||||
'type': 'low_stock',
|
||||
'severity': 'warning', # Will be enriched with priority score ~71
|
||||
'title': 'Bajo Stock: Harina Tipo 55',
|
||||
'message': 'Stock: 45kg, Mínimo: 200kg',
|
||||
'actions': [], # Will be enhanced with smart actions
|
||||
'metadata': {
|
||||
'ingredient_id': FLOUR_INGREDIENT_ID,
|
||||
'ingredient_name': 'Harina Tipo 55',
|
||||
'current_stock': 45,
|
||||
'minimum_stock': 200,
|
||||
'unit': 'kg',
|
||||
'supplier_name': 'Harinera San José',
|
||||
'last_order_date': (datetime.utcnow() - timedelta(days=7)).isoformat()
|
||||
},
|
||||
'timestamp': datetime.utcnow().isoformat()
|
||||
},
|
||||
|
||||
# Alert 2: Supplier Delay - Action Needed (Critical)
|
||||
{
|
||||
'id': str(uuid.uuid4()),
|
||||
'tenant_id': DEMO_TENANT_ID,
|
||||
'item_type': 'alert',
|
||||
'service': 'procurement',
|
||||
'type': 'supplier_delay',
|
||||
'severity': 'critical', # Will be enriched with priority score ~92
|
||||
'actions': [], # Will be enhanced with smart actions
|
||||
'title': 'Retraso de Proveedor: Levadura Fresh',
|
||||
'message': 'Entrega retrasada 24 horas. Levadura necesaria para producción de mañana.',
|
||||
'metadata': {
|
||||
'supplier_id': YEAST_SUPPLIER_ID,
|
||||
'supplier_name': 'Levadura Fresh',
|
||||
'supplier_phone': '+34-555-1234',
|
||||
'supplier_email': 'pedidos@levadura-fresh.es',
|
||||
'ingredient_id': YEAST_INGREDIENT_ID,
|
||||
'ingredient_name': 'Levadura Fresca',
|
||||
'batch_id': CROISSANT_BATCH_ID,
|
||||
'batch_name': 'Croissants Mantequilla Mañana',
|
||||
'orders_affected': 3,
|
||||
'financial_impact_eur': 450,
|
||||
'deadline': (datetime.utcnow() + timedelta(hours=6)).isoformat(),
|
||||
'quantity_needed': 15,
|
||||
'unit': 'kg'
|
||||
},
|
||||
'timestamp': datetime.utcnow().isoformat()
|
||||
},
|
||||
|
||||
# Alert 3: Waste Trend - Trend Warning (Standard)
|
||||
{
|
||||
'id': str(uuid.uuid4()),
|
||||
'tenant_id': DEMO_TENANT_ID,
|
||||
'item_type': 'alert',
|
||||
'service': 'production',
|
||||
'type': 'waste_trend',
|
||||
'severity': 'medium', # Will be enriched with priority score ~58
|
||||
'actions': [], # Will be enhanced with smart actions
|
||||
'title': 'Tendencia de Desperdicio: Croissants',
|
||||
'message': 'Desperdicio aumentó 15% en 3 días. Patrón detectado: sobreproducción miércoles.',
|
||||
'metadata': {
|
||||
'product_id': CROISSANT_PRODUCT_ID,
|
||||
'product_name': 'Croissant Mantequilla',
|
||||
'waste_percentage': 23,
|
||||
'baseline_percentage': 8,
|
||||
'trend_days': 3,
|
||||
'pattern': 'wednesday_overproduction',
|
||||
'pattern_description': 'Desperdicio consistentemente alto los miércoles (18%, 21%, 23%)',
|
||||
'financial_impact_eur': 180,
|
||||
'recommendation': 'Reducir producción miércoles en 25 unidades',
|
||||
'confidence': 0.85,
|
||||
'historical_data': [
|
||||
{'day': 'Mon', 'waste_pct': 7},
|
||||
{'day': 'Tue', 'waste_pct': 9},
|
||||
{'day': 'Wed', 'waste_pct': 23},
|
||||
{'day': 'Thu', 'waste_pct': 8},
|
||||
{'day': 'Fri', 'waste_pct': 6}
|
||||
]
|
||||
},
|
||||
'timestamp': datetime.utcnow().isoformat()
|
||||
},
|
||||
|
||||
# Alert 4: Forecast Anomaly - Information (Low Priority)
|
||||
{
|
||||
'id': str(uuid.uuid4()),
|
||||
'tenant_id': DEMO_TENANT_ID,
|
||||
'item_type': 'alert',
|
||||
'service': 'forecasting',
|
||||
'type': 'forecast_updated',
|
||||
'severity': 'low', # Will be enriched with priority score ~35
|
||||
'actions': [], # Will be enhanced with smart actions
|
||||
'title': 'Previsión Actualizada: Fin de Semana Soleado',
|
||||
'message': 'Pronóstico meteorológico actualizado: soleado sábado y domingo. Aumento de demanda esperado.',
|
||||
'metadata': {
|
||||
'forecast_type': 'weather_based',
|
||||
'weather_condition': 'sunny',
|
||||
'days_affected': ['2024-11-23', '2024-11-24'],
|
||||
'expected_demand_increase_pct': 15,
|
||||
'confidence': 0.78,
|
||||
'recommended_action': 'Aumentar producción croissants y pan rústico 15%'
|
||||
},
|
||||
'timestamp': datetime.utcnow().isoformat()
|
||||
},
|
||||
|
||||
# Alert 5: Equipment Maintenance - Action Needed (Medium)
|
||||
{
|
||||
'id': str(uuid.uuid4()),
|
||||
'tenant_id': DEMO_TENANT_ID,
|
||||
'item_type': 'alert',
|
||||
'service': 'production',
|
||||
'type': 'equipment_maintenance',
|
||||
'severity': 'medium', # Will be enriched with priority score ~65
|
||||
'actions': [], # Will be enhanced with smart actions
|
||||
'title': 'Mantenimiento Programado: Horno Industrial',
|
||||
'message': 'Horno principal requiere mantenimiento en 48 horas según calendario.',
|
||||
'metadata': {
|
||||
'equipment_id': 'oven-001',
|
||||
'equipment_name': 'Horno Industrial Principal',
|
||||
'equipment_type': 'oven',
|
||||
'maintenance_type': 'preventive',
|
||||
'scheduled_date': (datetime.utcnow() + timedelta(hours=48)).isoformat(),
|
||||
'estimated_duration_hours': 3,
|
||||
'last_maintenance': (datetime.utcnow() - timedelta(days=90)).isoformat(),
|
||||
'maintenance_interval_days': 90,
|
||||
'supplier_contact': 'TecnoHornos Madrid',
|
||||
'supplier_phone': '+34-555-6789'
|
||||
},
|
||||
'timestamp': datetime.utcnow().isoformat()
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
# Demo orchestrator actions (for context enrichment)
|
||||
DEMO_ORCHESTRATOR_ACTIONS = [
|
||||
# Action 1: PO Created for Flour (provides context for Alert 1)
|
||||
{
|
||||
'id': str(uuid.uuid4()),
|
||||
'tenant_id': DEMO_TENANT_ID,
|
||||
'action_type': 'purchase_order_created',
|
||||
'reasoning_type': 'preventive',
|
||||
'entity_type': 'purchase_order',
|
||||
'entity_id': FLOUR_PO_ID,
|
||||
'summary': 'Pedido de compra #12345 creado para 500kg harina',
|
||||
'reasoning_summary': 'Detecté que el stock se agotará en 2.3 días basándome en patrones históricos de demanda. Creé pedido de compra para llegar el viernes.',
|
||||
'metadata': {
|
||||
'ingredient_id': FLOUR_INGREDIENT_ID,
|
||||
'ingredient_name': 'Harina Tipo 55',
|
||||
'quantity': 500,
|
||||
'unit': 'kg',
|
||||
'supplier_name': 'Harinera San José',
|
||||
'po_number': 'PO-12345',
|
||||
'estimated_delivery': (datetime.utcnow() + timedelta(days=2, hours=10)).isoformat(),
|
||||
'estimated_savings_eur': 200,
|
||||
'prevented_issue': 'stockout',
|
||||
'confidence': 0.92,
|
||||
'demand_forecast_method': 'historical_patterns',
|
||||
'stock_runout_days': 2.3
|
||||
},
|
||||
'created_at': (datetime.utcnow() - timedelta(hours=2)).isoformat()
|
||||
},
|
||||
|
||||
# Action 2: Batch Scheduled for Weekend (weather-based)
|
||||
{
|
||||
'id': str(uuid.uuid4()),
|
||||
'tenant_id': DEMO_TENANT_ID,
|
||||
'action_type': 'batch_scheduled',
|
||||
'reasoning_type': 'weather_based',
|
||||
'entity_type': 'production_batch',
|
||||
'entity_id': CROISSANT_BATCH_ID,
|
||||
'summary': 'Aumentada producción croissants 20% para sábado',
|
||||
'reasoning_summary': 'Pronóstico meteorológico muestra fin de semana soleado. Datos históricos muestran aumento de demanda 15% en sábados soleados.',
|
||||
'metadata': {
|
||||
'product_id': CROISSANT_PRODUCT_ID,
|
||||
'product_name': 'Croissant Mantequilla',
|
||||
'quantity_increase': 25,
|
||||
'quantity_increase_pct': 20,
|
||||
'date': (datetime.utcnow() + timedelta(days=2)).date().isoformat(),
|
||||
'weather_condition': 'sunny',
|
||||
'confidence': 0.85,
|
||||
'historical_sunny_saturday_demand_increase': 15,
|
||||
'estimated_additional_revenue_eur': 180
|
||||
},
|
||||
'created_at': (datetime.utcnow() - timedelta(hours=4)).isoformat()
|
||||
},
|
||||
|
||||
# Action 3: Waste Reduction Adjustment (for trend context)
|
||||
{
|
||||
'id': str(uuid.uuid4()),
|
||||
'tenant_id': DEMO_TENANT_ID,
|
||||
'action_type': 'production_adjusted',
|
||||
'reasoning_type': 'waste_reduction',
|
||||
'entity_type': 'production_plan',
|
||||
'entity_id': str(uuid.uuid4()),
|
||||
'summary': 'Reducida producción lunes 10% basado en patrón post-fin de semana',
|
||||
'reasoning_summary': 'Detecté patrón de baja demanda post-fin de semana. Histórico muestra reducción 12% demanda lunes. Ajusté producción para prevenir desperdicio.',
|
||||
'metadata': {
|
||||
'day_of_week': 'monday',
|
||||
'reduction_pct': 10,
|
||||
'historical_demand_drop_pct': 12,
|
||||
'products_affected': ['Croissant Mantequilla', 'Pan Rústico'],
|
||||
'estimated_waste_prevented_eur': 85,
|
||||
'confidence': 0.78
|
||||
},
|
||||
'created_at': (datetime.utcnow() - timedelta(hours=20)).isoformat()
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
async def seed_enriched_alert_demo():
|
||||
"""
|
||||
Seed demo data for unified alert service
|
||||
|
||||
This creates alerts that will be automatically enriched by alert-processor with:
|
||||
- Multi-factor priority scoring
|
||||
- Orchestrator context (AI actions)
|
||||
- Business impact analysis
|
||||
- Smart actions
|
||||
- Timing intelligence
|
||||
"""
|
||||
|
||||
print("\n" + "="*70)
|
||||
print("🚀 SEEDING DEMO DATA FOR UNIFIED ALERT SERVICE")
|
||||
print("="*70 + "\n")
|
||||
|
||||
rabbitmq_url = os.getenv('RABBITMQ_URL', 'amqp://guest:guest@localhost:5672/')
|
||||
|
||||
try:
|
||||
# Initialize RabbitMQ client
|
||||
logger.info("Connecting to RabbitMQ", url=rabbitmq_url)
|
||||
rabbitmq_client = RabbitMQClient(rabbitmq_url, 'demo-seeder')
|
||||
await rabbitmq_client.connect()
|
||||
|
||||
# Publish demo alerts (will be automatically enriched)
|
||||
print("\n📤 Publishing Alerts (Automatic Enrichment):")
|
||||
print("-" * 70)
|
||||
|
||||
for i, alert in enumerate(DEMO_ALERTS, 1):
|
||||
routing_key = f"{alert['item_type']}.{alert['service']}.{alert['type']}"
|
||||
|
||||
# Use publish_event method (correct API)
|
||||
success = await rabbitmq_client.publish_event(
|
||||
exchange_name='alerts.exchange',
|
||||
routing_key=routing_key,
|
||||
event_data=alert,
|
||||
persistent=True
|
||||
)
|
||||
|
||||
if not success:
|
||||
logger.warning("Failed to publish alert", alert_id=alert['id'])
|
||||
continue
|
||||
|
||||
print(f" {i}. ✅ {alert['title']}")
|
||||
print(f" Service: {alert['service']}")
|
||||
print(f" Severity: {alert['severity']} (will be enriched)")
|
||||
print(f" Routing Key: {routing_key}")
|
||||
print()
|
||||
|
||||
# Note about orchestrator actions
|
||||
print("\n📊 Orchestrator Actions (for Context Enrichment):")
|
||||
print("-" * 70)
|
||||
print("NOTE: Orchestrator actions should be seeded via orchestrator service.")
|
||||
print("These provide context for 'AI already handled' enrichment.\n")
|
||||
|
||||
for i, action in enumerate(DEMO_ORCHESTRATOR_ACTIONS, 1):
|
||||
print(f" {i}. {action['summary']}")
|
||||
print(f" Type: {action['reasoning_type']}")
|
||||
print(f" Created: {action['created_at']}")
|
||||
print()
|
||||
|
||||
print("💡 TIP: To seed orchestrator actions, run:")
|
||||
print(" python services/orchestrator/scripts/seed_demo_actions.py")
|
||||
print()
|
||||
|
||||
await rabbitmq_client.disconnect()
|
||||
|
||||
print("="*70)
|
||||
print("✅ DEMO ALERTS SEEDED SUCCESSFULLY!")
|
||||
print("="*70)
|
||||
print()
|
||||
print("Next steps:")
|
||||
print(" 1. Verify alert-processor service is running:")
|
||||
print(" kubectl get pods -l app.kubernetes.io/name=alert-processor-service")
|
||||
print()
|
||||
print(" 2. Check logs for automatic enrichment:")
|
||||
print(" kubectl logs -f deployment/alert-processor-service")
|
||||
print()
|
||||
print(" 3. View enriched alerts in dashboard:")
|
||||
print(" http://localhost:3000/dashboard")
|
||||
print()
|
||||
print("Expected automatic enrichment:")
|
||||
print(" • Low Stock Alert → Important (71) - Prevented Issue + Smart Actions")
|
||||
print(" • Supplier Delay → Critical (92) - Action Needed + Deep Links")
|
||||
print(" • Waste Trend → Standard (58) - Trend Warning + AI Reasoning")
|
||||
print(" • Forecast Update → Info (35) - Information")
|
||||
print(" • Equipment Maint → Standard (65) - Action Needed + Timing")
|
||||
print()
|
||||
print("All alerts enriched with:")
|
||||
print(" ✓ Multi-factor priority scores")
|
||||
print(" ✓ Orchestrator context (AI actions)")
|
||||
print(" ✓ Business impact analysis")
|
||||
print(" ✓ Smart actions with deep links")
|
||||
print(" ✓ Timing intelligence")
|
||||
print()
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Failed to seed demo data", error=str(e))
|
||||
print(f"\n❌ ERROR: {str(e)}")
|
||||
print("\nTroubleshooting:")
|
||||
print(" • Verify RabbitMQ is running: kubectl get pods | grep rabbitmq")
|
||||
print(" • Check RABBITMQ_URL environment variable")
|
||||
print(" • Ensure raw_alerts exchange can be created")
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Load environment variables
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
# Run seeder
|
||||
asyncio.run(seed_enriched_alert_demo())
|
||||
Reference in New Issue
Block a user