New alert service
This commit is contained in:
138
services/alert_processor/app/enrichment/urgency_analyzer.py
Normal file
138
services/alert_processor/app/enrichment/urgency_analyzer.py
Normal file
@@ -0,0 +1,138 @@
|
||||
"""
|
||||
Urgency analyzer for alerts.
|
||||
|
||||
Assesses time sensitivity, deadlines, and determines if action can wait.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
from datetime import datetime, timedelta, timezone
|
||||
import structlog
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
|
||||
class UrgencyAnalyzer:
|
||||
"""Analyze urgency from event metadata"""
|
||||
|
||||
def analyze(self, event_type: str, metadata: Dict[str, Any]) -> dict:
|
||||
"""
|
||||
Analyze urgency for an event.
|
||||
|
||||
Returns dict with:
|
||||
- hours_until_consequence: Time until impact occurs
|
||||
- can_wait_until_tomorrow: Boolean
|
||||
- deadline_utc: ISO datetime if deadline exists
|
||||
- peak_hour_relevant: Boolean
|
||||
- hours_pending: Age of alert
|
||||
"""
|
||||
|
||||
urgency = {
|
||||
"hours_until_consequence": 24, # Default: 24 hours
|
||||
"can_wait_until_tomorrow": True,
|
||||
"deadline_utc": None,
|
||||
"peak_hour_relevant": False,
|
||||
"hours_pending": 0
|
||||
}
|
||||
|
||||
# Calculate based on event type
|
||||
if "critical" in event_type or "urgent" in event_type:
|
||||
urgency["hours_until_consequence"] = 2
|
||||
urgency["can_wait_until_tomorrow"] = False
|
||||
|
||||
elif "production" in event_type:
|
||||
urgency.update(self._analyze_production_urgency(metadata))
|
||||
|
||||
elif "stock" in event_type or "shortage" in event_type:
|
||||
urgency.update(self._analyze_stock_urgency(metadata))
|
||||
|
||||
elif "delivery" in event_type or "overdue" in event_type:
|
||||
urgency.update(self._analyze_delivery_urgency(metadata))
|
||||
|
||||
# Check for explicit deadlines
|
||||
if "required_delivery_date" in metadata:
|
||||
urgency.update(self._calculate_deadline_urgency(metadata["required_delivery_date"]))
|
||||
|
||||
if "production_date" in metadata:
|
||||
urgency.update(self._calculate_deadline_urgency(metadata["production_date"]))
|
||||
|
||||
if "expected_date" in metadata:
|
||||
urgency.update(self._calculate_deadline_urgency(metadata["expected_date"]))
|
||||
|
||||
return urgency
|
||||
|
||||
def _analyze_production_urgency(self, metadata: Dict[str, Any]) -> dict:
|
||||
"""Analyze urgency for production alerts"""
|
||||
urgency = {}
|
||||
|
||||
delay_minutes = metadata.get("delay_minutes", 0)
|
||||
|
||||
if delay_minutes > 120:
|
||||
urgency["hours_until_consequence"] = 1
|
||||
urgency["can_wait_until_tomorrow"] = False
|
||||
elif delay_minutes > 60:
|
||||
urgency["hours_until_consequence"] = 4
|
||||
urgency["can_wait_until_tomorrow"] = False
|
||||
else:
|
||||
urgency["hours_until_consequence"] = 8
|
||||
|
||||
# Production is peak-hour sensitive
|
||||
urgency["peak_hour_relevant"] = True
|
||||
|
||||
return urgency
|
||||
|
||||
def _analyze_stock_urgency(self, metadata: Dict[str, Any]) -> dict:
|
||||
"""Analyze urgency for stock alerts"""
|
||||
urgency = {}
|
||||
|
||||
# Hours until needed
|
||||
if "hours_until" in metadata:
|
||||
urgency["hours_until_consequence"] = metadata["hours_until"]
|
||||
urgency["can_wait_until_tomorrow"] = urgency["hours_until_consequence"] > 24
|
||||
|
||||
# Days until expiry
|
||||
elif "days_until_expiry" in metadata:
|
||||
days = metadata["days_until_expiry"]
|
||||
if days <= 1:
|
||||
urgency["hours_until_consequence"] = days * 24
|
||||
urgency["can_wait_until_tomorrow"] = False
|
||||
else:
|
||||
urgency["hours_until_consequence"] = days * 24
|
||||
|
||||
return urgency
|
||||
|
||||
def _analyze_delivery_urgency(self, metadata: Dict[str, Any]) -> dict:
|
||||
"""Analyze urgency for delivery alerts"""
|
||||
urgency = {}
|
||||
|
||||
days_overdue = metadata.get("days_overdue", 0)
|
||||
|
||||
if days_overdue > 3:
|
||||
urgency["hours_until_consequence"] = 2
|
||||
urgency["can_wait_until_tomorrow"] = False
|
||||
elif days_overdue > 1:
|
||||
urgency["hours_until_consequence"] = 8
|
||||
urgency["can_wait_until_tomorrow"] = False
|
||||
|
||||
return urgency
|
||||
|
||||
def _calculate_deadline_urgency(self, deadline_str: str) -> dict:
|
||||
"""Calculate urgency based on deadline"""
|
||||
try:
|
||||
if isinstance(deadline_str, str):
|
||||
deadline = datetime.fromisoformat(deadline_str.replace('Z', '+00:00'))
|
||||
else:
|
||||
deadline = deadline_str
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
time_until = deadline - now
|
||||
|
||||
hours_until = time_until.total_seconds() / 3600
|
||||
|
||||
return {
|
||||
"deadline_utc": deadline.isoformat(),
|
||||
"hours_until_consequence": max(0, round(hours_until, 1)),
|
||||
"can_wait_until_tomorrow": hours_until > 24
|
||||
}
|
||||
except Exception as e:
|
||||
logger.warning("deadline_parse_failed", deadline=deadline_str, error=str(e))
|
||||
return {}
|
||||
Reference in New Issue
Block a user