405 lines
17 KiB
Python
405 lines
17 KiB
Python
"""
|
|
Analytics & Predictive Insights serializers for Enterprise Incident Management API
|
|
Provides comprehensive serialization for KPIs, metrics, predictive models, and insights
|
|
"""
|
|
from rest_framework import serializers
|
|
from django.contrib.auth import get_user_model
|
|
from ..models import (
|
|
KPIMetric, KPIMeasurement, IncidentRecurrenceAnalysis, PredictiveModel,
|
|
AnomalyDetection, CostImpactAnalysis, DashboardConfiguration,
|
|
HeatmapData, PredictiveInsight
|
|
)
|
|
|
|
User = get_user_model()
|
|
|
|
|
|
class KPIMetricSerializer(serializers.ModelSerializer):
|
|
"""Serializer for KPI metrics"""
|
|
|
|
created_by_username = serializers.CharField(source='created_by.username', read_only=True)
|
|
measurement_count = serializers.SerializerMethodField()
|
|
latest_measurement = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = KPIMetric
|
|
fields = [
|
|
'id', 'name', 'description', 'metric_type', 'aggregation_type',
|
|
'incident_categories', 'incident_severities', 'incident_priorities',
|
|
'calculation_formula', 'time_window_hours', 'is_active',
|
|
'is_system_metric', 'created_by_username', 'created_at', 'updated_at',
|
|
'measurement_count', 'latest_measurement'
|
|
]
|
|
read_only_fields = ['id', 'created_at', 'updated_at']
|
|
|
|
def get_measurement_count(self, obj):
|
|
"""Get the number of measurements for this metric"""
|
|
return obj.measurements.count()
|
|
|
|
def get_latest_measurement(self, obj):
|
|
"""Get the latest measurement for this metric"""
|
|
latest = obj.measurements.first()
|
|
if latest:
|
|
return {
|
|
'value': str(latest.value),
|
|
'unit': latest.unit,
|
|
'calculated_at': latest.calculated_at,
|
|
'incident_count': latest.incident_count
|
|
}
|
|
return None
|
|
|
|
|
|
class KPIMeasurementSerializer(serializers.ModelSerializer):
|
|
"""Serializer for KPI measurements"""
|
|
|
|
metric_name = serializers.CharField(source='metric.name', read_only=True)
|
|
metric_type = serializers.CharField(source='metric.metric_type', read_only=True)
|
|
|
|
class Meta:
|
|
model = KPIMeasurement
|
|
fields = [
|
|
'id', 'metric', 'metric_name', 'metric_type', 'value', 'unit',
|
|
'measurement_period_start', 'measurement_period_end',
|
|
'incident_count', 'sample_size', 'metadata', 'calculated_at'
|
|
]
|
|
read_only_fields = ['id', 'calculated_at']
|
|
|
|
|
|
class IncidentRecurrenceAnalysisSerializer(serializers.ModelSerializer):
|
|
"""Serializer for incident recurrence analysis"""
|
|
|
|
primary_incident_title = serializers.CharField(source='primary_incident.title', read_only=True)
|
|
primary_incident_severity = serializers.CharField(source='primary_incident.severity', read_only=True)
|
|
recurring_incident_count = serializers.SerializerMethodField()
|
|
recurring_incident_titles = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = IncidentRecurrenceAnalysis
|
|
fields = [
|
|
'id', 'primary_incident', 'primary_incident_title', 'primary_incident_severity',
|
|
'recurring_incidents', 'recurring_incident_count', 'recurring_incident_titles',
|
|
'recurrence_type', 'confidence_score', 'recurrence_rate',
|
|
'common_keywords', 'common_categories', 'time_pattern',
|
|
'total_affected_users', 'total_downtime_hours', 'estimated_cost_impact',
|
|
'prevention_recommendations', 'automation_opportunities',
|
|
'is_resolved', 'resolution_actions', 'created_at', 'updated_at', 'model_version'
|
|
]
|
|
read_only_fields = ['id', 'created_at', 'updated_at']
|
|
|
|
def get_recurring_incident_count(self, obj):
|
|
"""Get the number of recurring incidents"""
|
|
return obj.recurring_incidents.count()
|
|
|
|
def get_recurring_incident_titles(self, obj):
|
|
"""Get titles of recurring incidents"""
|
|
return [incident.title for incident in obj.recurring_incidents.all()]
|
|
|
|
|
|
class PredictiveModelSerializer(serializers.ModelSerializer):
|
|
"""Serializer for predictive models"""
|
|
|
|
created_by_username = serializers.CharField(source='created_by.username', read_only=True)
|
|
insight_count = serializers.SerializerMethodField()
|
|
anomaly_detection_count = serializers.SerializerMethodField()
|
|
performance_summary = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = PredictiveModel
|
|
fields = [
|
|
'id', 'name', 'description', 'model_type', 'algorithm_type',
|
|
'model_config', 'feature_columns', 'target_column',
|
|
'training_data_period_days', 'min_training_samples',
|
|
'accuracy_score', 'precision_score', 'recall_score', 'f1_score',
|
|
'status', 'version', 'model_file_path',
|
|
'last_trained_at', 'training_duration_seconds', 'training_samples_count',
|
|
'auto_retrain_enabled', 'retrain_frequency_days', 'performance_threshold',
|
|
'created_by_username', 'created_at', 'updated_at',
|
|
'insight_count', 'anomaly_detection_count', 'performance_summary'
|
|
]
|
|
read_only_fields = ['id', 'created_at', 'updated_at']
|
|
|
|
def get_insight_count(self, obj):
|
|
"""Get the number of insights generated by this model"""
|
|
return obj.insights.count()
|
|
|
|
def get_anomaly_detection_count(self, obj):
|
|
"""Get the number of anomaly detections by this model"""
|
|
return obj.anomaly_detections.count()
|
|
|
|
def get_performance_summary(self, obj):
|
|
"""Get a summary of model performance metrics"""
|
|
return {
|
|
'accuracy': obj.accuracy_score,
|
|
'precision': obj.precision_score,
|
|
'recall': obj.recall_score,
|
|
'f1_score': obj.f1_score,
|
|
'overall_health': self._calculate_overall_health(obj)
|
|
}
|
|
|
|
def _calculate_overall_health(self, obj):
|
|
"""Calculate overall model health score"""
|
|
if not all([obj.accuracy_score, obj.precision_score, obj.recall_score, obj.f1_score]):
|
|
return 'Unknown'
|
|
|
|
avg_score = (obj.accuracy_score + obj.precision_score + obj.recall_score + obj.f1_score) / 4
|
|
|
|
if avg_score >= 0.9:
|
|
return 'Excellent'
|
|
elif avg_score >= 0.8:
|
|
return 'Good'
|
|
elif avg_score >= 0.7:
|
|
return 'Fair'
|
|
else:
|
|
return 'Poor'
|
|
|
|
|
|
class AnomalyDetectionSerializer(serializers.ModelSerializer):
|
|
"""Serializer for anomaly detection results"""
|
|
|
|
model_name = serializers.CharField(source='model.name', read_only=True)
|
|
model_type = serializers.CharField(source='model.model_type', read_only=True)
|
|
resolved_by_username = serializers.CharField(source='resolved_by.username', read_only=True)
|
|
related_incident_count = serializers.SerializerMethodField()
|
|
related_incident_titles = serializers.SerializerMethodField()
|
|
time_since_detection = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = AnomalyDetection
|
|
fields = [
|
|
'id', 'model', 'model_name', 'model_type',
|
|
'anomaly_type', 'severity', 'status',
|
|
'confidence_score', 'anomaly_score', 'threshold_used',
|
|
'detected_at', 'time_window_start', 'time_window_end',
|
|
'related_incidents', 'related_incident_count', 'related_incident_titles',
|
|
'affected_services', 'affected_metrics',
|
|
'description', 'root_cause_analysis', 'impact_assessment',
|
|
'actions_taken', 'resolved_at', 'resolved_by', 'resolved_by_username',
|
|
'metadata', 'time_since_detection'
|
|
]
|
|
read_only_fields = ['id', 'detected_at']
|
|
|
|
def get_related_incident_count(self, obj):
|
|
"""Get the number of related incidents"""
|
|
return obj.related_incidents.count()
|
|
|
|
def get_related_incident_titles(self, obj):
|
|
"""Get titles of related incidents"""
|
|
return [incident.title for incident in obj.related_incidents.all()]
|
|
|
|
def get_time_since_detection(self, obj):
|
|
"""Get time elapsed since anomaly detection"""
|
|
from django.utils import timezone
|
|
return timezone.now() - obj.detected_at
|
|
|
|
|
|
class CostImpactAnalysisSerializer(serializers.ModelSerializer):
|
|
"""Serializer for cost impact analysis"""
|
|
|
|
incident_title = serializers.CharField(source='incident.title', read_only=True)
|
|
incident_severity = serializers.CharField(source='incident.severity', read_only=True)
|
|
validated_by_username = serializers.CharField(source='validated_by.username', read_only=True)
|
|
cost_per_hour = serializers.SerializerMethodField()
|
|
cost_per_user = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = CostImpactAnalysis
|
|
fields = [
|
|
'id', 'incident', 'incident_title', 'incident_severity',
|
|
'cost_type', 'cost_amount', 'currency',
|
|
'calculation_method', 'calculation_details',
|
|
'downtime_hours', 'affected_users', 'revenue_impact',
|
|
'business_unit', 'service_tier',
|
|
'is_validated', 'validated_by', 'validated_by_username',
|
|
'validated_at', 'validation_notes',
|
|
'created_at', 'updated_at',
|
|
'cost_per_hour', 'cost_per_user'
|
|
]
|
|
read_only_fields = ['id', 'created_at', 'updated_at']
|
|
|
|
def get_cost_per_hour(self, obj):
|
|
"""Calculate cost per hour of downtime"""
|
|
if obj.downtime_hours and obj.downtime_hours > 0:
|
|
return float(obj.cost_amount / obj.downtime_hours)
|
|
return None
|
|
|
|
def get_cost_per_user(self, obj):
|
|
"""Calculate cost per affected user"""
|
|
if obj.affected_users and obj.affected_users > 0:
|
|
return float(obj.cost_amount / obj.affected_users)
|
|
return None
|
|
|
|
|
|
class DashboardConfigurationSerializer(serializers.ModelSerializer):
|
|
"""Serializer for dashboard configurations"""
|
|
|
|
created_by_username = serializers.CharField(source='created_by.username', read_only=True)
|
|
allowed_user_count = serializers.SerializerMethodField()
|
|
allowed_usernames = serializers.SerializerMethodField()
|
|
widget_count = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = DashboardConfiguration
|
|
fields = [
|
|
'id', 'name', 'description', 'dashboard_type',
|
|
'layout_config', 'widget_configs', 'widget_count',
|
|
'is_public', 'allowed_users', 'allowed_user_count', 'allowed_usernames',
|
|
'allowed_roles', 'auto_refresh_enabled', 'refresh_interval_seconds',
|
|
'is_active', 'created_by_username', 'created_at', 'updated_at'
|
|
]
|
|
read_only_fields = ['id', 'created_at', 'updated_at']
|
|
|
|
def get_allowed_user_count(self, obj):
|
|
"""Get the number of allowed users"""
|
|
return obj.allowed_users.count()
|
|
|
|
def get_allowed_usernames(self, obj):
|
|
"""Get usernames of allowed users"""
|
|
return [user.username for user in obj.allowed_users.all()]
|
|
|
|
def get_widget_count(self, obj):
|
|
"""Get the number of widgets in this dashboard"""
|
|
return len(obj.widget_configs) if obj.widget_configs else 0
|
|
|
|
|
|
class HeatmapDataSerializer(serializers.ModelSerializer):
|
|
"""Serializer for heatmap data"""
|
|
|
|
data_point_count = serializers.SerializerMethodField()
|
|
time_span_hours = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = HeatmapData
|
|
fields = [
|
|
'id', 'name', 'heatmap_type', 'time_period_start', 'time_period_end',
|
|
'time_granularity', 'data_points', 'data_point_count',
|
|
'color_scheme', 'aggregation_method', 'time_span_hours',
|
|
'created_at', 'updated_at'
|
|
]
|
|
read_only_fields = ['id', 'created_at', 'updated_at']
|
|
|
|
def get_data_point_count(self, obj):
|
|
"""Get the number of data points"""
|
|
return len(obj.data_points) if obj.data_points else 0
|
|
|
|
def get_time_span_hours(self, obj):
|
|
"""Get the time span in hours"""
|
|
from django.utils import timezone
|
|
delta = obj.time_period_end - obj.time_period_start
|
|
return delta.total_seconds() / 3600
|
|
|
|
|
|
class PredictiveInsightSerializer(serializers.ModelSerializer):
|
|
"""Serializer for predictive insights"""
|
|
|
|
model_name = serializers.CharField(source='model.name', read_only=True)
|
|
model_type = serializers.CharField(source='model.model_type', read_only=True)
|
|
acknowledged_by_username = serializers.CharField(source='acknowledged_by.username', read_only=True)
|
|
related_incident_count = serializers.SerializerMethodField()
|
|
related_incident_titles = serializers.SerializerMethodField()
|
|
time_until_expiry = serializers.SerializerMethodField()
|
|
is_expired = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = PredictiveInsight
|
|
fields = [
|
|
'id', 'model', 'model_name', 'model_type',
|
|
'insight_type', 'title', 'description',
|
|
'confidence_level', 'confidence_score',
|
|
'predicted_value', 'prediction_horizon', 'prediction_date',
|
|
'input_features', 'supporting_evidence',
|
|
'related_incidents', 'related_incident_count', 'related_incident_titles',
|
|
'affected_services', 'recommendations', 'risk_assessment',
|
|
'is_acknowledged', 'acknowledged_by', 'acknowledged_by_username',
|
|
'acknowledged_at', 'is_validated', 'actual_value', 'validation_accuracy',
|
|
'generated_at', 'expires_at', 'time_until_expiry', 'is_expired'
|
|
]
|
|
read_only_fields = ['id', 'generated_at']
|
|
|
|
def get_related_incident_count(self, obj):
|
|
"""Get the number of related incidents"""
|
|
return obj.related_incidents.count()
|
|
|
|
def get_related_incident_titles(self, obj):
|
|
"""Get titles of related incidents"""
|
|
return [incident.title for incident in obj.related_incidents.all()]
|
|
|
|
def get_time_until_expiry(self, obj):
|
|
"""Get time until insight expires"""
|
|
from django.utils import timezone
|
|
return obj.expires_at - timezone.now()
|
|
|
|
def get_is_expired(self, obj):
|
|
"""Check if insight has expired"""
|
|
return obj.is_expired
|
|
|
|
|
|
# Summary and aggregation serializers
|
|
class KPISummarySerializer(serializers.Serializer):
|
|
"""Serializer for KPI summary data"""
|
|
|
|
metric_type = serializers.CharField()
|
|
metric_name = serializers.CharField()
|
|
current_value = serializers.DecimalField(max_digits=15, decimal_places=4)
|
|
unit = serializers.CharField()
|
|
trend = serializers.CharField() # 'up', 'down', 'stable'
|
|
trend_percentage = serializers.DecimalField(max_digits=5, decimal_places=2)
|
|
period_start = serializers.DateTimeField()
|
|
period_end = serializers.DateTimeField()
|
|
incident_count = serializers.IntegerField()
|
|
target_value = serializers.DecimalField(max_digits=15, decimal_places=4, allow_null=True)
|
|
target_met = serializers.BooleanField()
|
|
|
|
|
|
class AnomalySummarySerializer(serializers.Serializer):
|
|
"""Serializer for anomaly summary data"""
|
|
|
|
total_anomalies = serializers.IntegerField()
|
|
critical_anomalies = serializers.IntegerField()
|
|
high_anomalies = serializers.IntegerField()
|
|
medium_anomalies = serializers.IntegerField()
|
|
low_anomalies = serializers.IntegerField()
|
|
unresolved_anomalies = serializers.IntegerField()
|
|
false_positive_rate = serializers.DecimalField(max_digits=5, decimal_places=2)
|
|
average_resolution_time = serializers.DurationField()
|
|
|
|
|
|
class CostSummarySerializer(serializers.Serializer):
|
|
"""Serializer for cost summary data"""
|
|
|
|
total_cost = serializers.DecimalField(max_digits=15, decimal_places=2)
|
|
currency = serializers.CharField()
|
|
downtime_cost = serializers.DecimalField(max_digits=15, decimal_places=2)
|
|
lost_revenue = serializers.DecimalField(max_digits=15, decimal_places=2)
|
|
penalty_cost = serializers.DecimalField(max_digits=15, decimal_places=2)
|
|
resource_cost = serializers.DecimalField(max_digits=15, decimal_places=2)
|
|
total_downtime_hours = serializers.DecimalField(max_digits=10, decimal_places=2)
|
|
total_affected_users = serializers.IntegerField()
|
|
cost_per_hour = serializers.DecimalField(max_digits=10, decimal_places=2)
|
|
cost_per_user = serializers.DecimalField(max_digits=10, decimal_places=2)
|
|
|
|
|
|
class PredictiveInsightSummarySerializer(serializers.Serializer):
|
|
"""Serializer for predictive insight summary data"""
|
|
|
|
total_insights = serializers.IntegerField()
|
|
high_confidence_insights = serializers.IntegerField()
|
|
medium_confidence_insights = serializers.IntegerField()
|
|
low_confidence_insights = serializers.IntegerField()
|
|
acknowledged_insights = serializers.IntegerField()
|
|
validated_insights = serializers.IntegerField()
|
|
expired_insights = serializers.IntegerField()
|
|
average_accuracy = serializers.DecimalField(max_digits=5, decimal_places=2)
|
|
active_models = serializers.IntegerField()
|
|
|
|
|
|
class DashboardDataSerializer(serializers.Serializer):
|
|
"""Serializer for complete dashboard data"""
|
|
|
|
kpi_summary = KPISummarySerializer(many=True)
|
|
anomaly_summary = AnomalySummarySerializer()
|
|
cost_summary = CostSummarySerializer()
|
|
insight_summary = PredictiveInsightSummarySerializer()
|
|
recent_anomalies = AnomalyDetectionSerializer(many=True)
|
|
recent_insights = PredictiveInsightSerializer(many=True)
|
|
heatmap_data = HeatmapDataSerializer(many=True)
|
|
last_updated = serializers.DateTimeField()
|