2025-11-27 15:52:40 +01:00
#!/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 ) )
2025-12-05 20:07:01 +01:00
from shared . messaging import RabbitMQClient
2025-11-27 15:52:40 +01:00
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é ' ,
2025-12-05 20:07:01 +01:00
' last_order_date ' : ( datetime . utcnow ( ) - timedelta ( days = 7 ) ) . isoformat ( ) ,
' i18n ' : {
' title_key ' : ' alerts.low_stock_warning.title ' ,
' message_key ' : ' alerts.low_stock_warning.message_generic ' ,
' title_params ' : { ' ingredient_name ' : ' Harina Tipo 55 ' } ,
' message_params ' : {
' ingredient_name ' : ' Harina Tipo 55 ' ,
' current_stock ' : 45 ,
' minimum_stock ' : 200
}
}
2025-11-27 15:52:40 +01:00
} ,
' 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 ,
2025-12-05 20:07:01 +01:00
' unit ' : ' kg ' ,
' i18n ' : {
' title_key ' : ' alerts.supplier_delay.title ' ,
' message_key ' : ' alerts.supplier_delay.message ' ,
' title_params ' : { ' supplier_name ' : ' Levadura Fresh ' } ,
' message_params ' : {
' supplier_name ' : ' Levadura Fresh ' ,
' ingredient_name ' : ' Levadura Fresca ' ,
' po_id ' : ' PO-DEMO-123 ' ,
' new_delivery_date ' : ( datetime . utcnow ( ) + timedelta ( hours = 24 ) ) . strftime ( ' % Y- % m- %d ' ) ,
' original_delivery_date ' : ( datetime . utcnow ( ) - timedelta ( hours = 24 ) ) . strftime ( ' % Y- % m- %d ' )
}
}
2025-11-27 15:52:40 +01:00
} ,
' 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 % e n 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 }
2025-12-05 20:07:01 +01:00
] ,
' i18n ' : {
' title_key ' : ' alerts.waste_trend.title ' ,
' message_key ' : ' alerts.waste_trend.message ' ,
' title_params ' : { ' product_name ' : ' Croissant Mantequilla ' } ,
' message_params ' : {
' product_name ' : ' Croissant Mantequilla ' ,
' spike_percent ' : 15 ,
' trend_days ' : 3 ,
' pattern ' : ' wednesday_overproduction '
}
}
2025-11-27 15:52:40 +01:00
} ,
' 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 ,
2025-12-05 20:07:01 +01:00
' recommended_action ' : ' Aumentar producción croissants y pan rústico 15 % ' ,
' i18n ' : {
' title_key ' : ' alerts.demand_surge_weekend.title ' ,
' message_key ' : ' alerts.demand_surge_weekend.message ' ,
' title_params ' : { ' weekend_date ' : ( datetime . utcnow ( ) + timedelta ( days = 1 ) ) . strftime ( ' % Y- % m- %d ' ) } ,
' message_params ' : {
' surge_percent ' : 15 ,
' date ' : ( datetime . utcnow ( ) + timedelta ( days = 1 ) ) . strftime ( ' % Y- % m- %d ' ) ,
' products ' : [ ' croissants ' , ' pan rustico ' ]
}
}
2025-11-27 15:52:40 +01:00
} ,
' 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 ' ,
2025-12-05 20:07:01 +01:00
' supplier_phone ' : ' +34-555-6789 ' ,
' i18n ' : {
' title_key ' : ' alerts.maintenance_required.title ' ,
' message_key ' : ' alerts.maintenance_required.message_with_hours ' ,
' title_params ' : { ' equipment_name ' : ' Horno Industrial Principal ' } ,
' message_params ' : {
' equipment_name ' : ' Horno Industrial Principal ' ,
' hours_until ' : 48 ,
' maintenance_date ' : ( datetime . utcnow ( ) + timedelta ( hours = 48 ) ) . strftime ( ' % Y- % m- %d ' )
}
}
2025-11-27 15:52:40 +01:00
} ,
' 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 % e n 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 % d emanda 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 ( " \n Troubleshooting: " )
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 ( ) )