Datavision / backend /mcp /insight_engine.py
DataVision CI/CD Bot
release: clean production build for HuggingFace Space
09801ca
Raw
History Blame Contribute Delete
24.7 kB
# Insight Engine MCP Service
"""
Enterprise Automated Insight Generation Engine
Features:
- Trend detection (MoM, YoY)
- Anomaly detection (Z-score)
- Top/bottom performer analysis
- Risk identification
- Opportunity scoring
- Customer segmentation insights
- Automated recommendations
Usage:
from mcp.insight_engine import InsightEngine
engine = InsightEngine()
result = engine.analyze(data)
"""
import numpy as np
from typing import Dict, List, Any, Optional
from dataclasses import dataclass, field
from enum import Enum
from datetime import datetime
class InsightType(Enum):
TREND = "trend"
ANOMALY = "anomaly"
RISK = "risk"
OPPORTUNITY = "opportunity"
PERFORMANCE = "performance"
RECOMMENDATION = "recommendation"
class InsightSeverity(Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
CRITICAL = "critical"
@dataclass
class Insight:
"""A single business insight"""
type: InsightType
message: str
severity: InsightSeverity
metric: str
value: Optional[float] = None
change_pct: Optional[float] = None
recommendation: Optional[str] = None
icon: str = "💡"
@dataclass
class InsightResult:
"""Result from insight engine"""
insights: List[Insight]
summary: str
risk_score: float
opportunity_score: float
health_score: float
top_priority: str
class InsightEngine:
"""
Enterprise Automated Insight Generation Engine.
Analyzes business data and generates:
- Trend insights (growth/decline patterns)
- Anomaly alerts (unusual values)
- Risk warnings
- Opportunity identification
- Actionable recommendations
"""
# Thresholds for analysis
GROWTH_THRESHOLD = 5 # % for significant growth
DECLINE_THRESHOLD = -5 # % for significant decline
ANOMALY_Z_SCORE = 2 # Z-score threshold for anomalies
def __init__(self):
self.insights_generated = 0
def analyze(
self,
revenue: float = 0,
revenue_previous: float = 0,
customers: int = 0,
customers_previous: int = 0,
orders: int = 0,
orders_previous: int = 0,
top_products: Optional[List[Dict]] = None,
top_customers: Optional[List[Dict]] = None,
time_series: Optional[List[Dict]] = None,
churn_rate: float = 0,
profit_margin: float = 0
) -> InsightResult:
"""
Analyze business metrics and generate insights.
Args:
revenue: Current period revenue
revenue_previous: Previous period revenue
customers: Current customer count
customers_previous: Previous customer count
orders: Current order count
orders_previous: Previous order count
top_products: List of top products with revenue
top_customers: List of top customers with revenue
time_series: Time series data for trend analysis
churn_rate: Customer churn rate
profit_margin: Profit margin (0-1)
Returns:
InsightResult with all generated insights
"""
insights = []
# Revenue trends
if revenue and revenue_previous:
insights.extend(self._analyze_revenue_trend(revenue, revenue_previous))
# Customer trends
if customers and customers_previous:
insights.extend(self._analyze_customer_trend(customers, customers_previous))
# Order trends
if orders and orders_previous:
insights.extend(self._analyze_order_trend(orders, orders_previous))
# Product performance
if top_products:
insights.extend(self._analyze_product_performance(top_products))
# Customer concentration
if top_customers and revenue:
insights.extend(self._analyze_customer_concentration(top_customers, revenue))
# Time series anomalies
if time_series:
insights.extend(self._detect_anomalies(time_series))
insights.extend(self._detect_time_trends(time_series))
# Risk analysis
insights.extend(self._analyze_risks(churn_rate, profit_margin, revenue, revenue_previous))
# Opportunity identification
insights.extend(self._identify_opportunities(
revenue, customers, orders, top_products, profit_margin
))
# Calculate scores
risk_score = self._calculate_risk_score(insights)
opp_score = self._calculate_opportunity_score(insights)
health_score = self._calculate_health_score(insights, risk_score, opp_score)
# Generate summary
summary = self._generate_summary(insights, risk_score, opp_score)
# Find top priority
priority = self._find_top_priority(insights)
return InsightResult(
insights=insights,
summary=summary,
risk_score=risk_score,
opportunity_score=opp_score,
health_score=health_score,
top_priority=priority
)
def _analyze_revenue_trend(self, current: float, previous: float) -> List[Insight]:
"""Analyze revenue trend."""
insights = []
change_pct = ((current - previous) / previous * 100) if previous else 0
if change_pct > 20:
insights.append(Insight(
type=InsightType.TREND,
message=f"Revenue grew {change_pct:.1f}% - exceptional performance!",
severity=InsightSeverity.HIGH,
metric="revenue",
value=current,
change_pct=change_pct,
icon="🚀"
))
elif change_pct > self.GROWTH_THRESHOLD:
insights.append(Insight(
type=InsightType.TREND,
message=f"Revenue increased {change_pct:.1f}% period-over-period",
severity=InsightSeverity.MEDIUM,
metric="revenue",
value=current,
change_pct=change_pct,
icon="📈"
))
elif change_pct < -20:
insights.append(Insight(
type=InsightType.RISK,
message=f"Revenue dropped {abs(change_pct):.1f}% - requires immediate attention",
severity=InsightSeverity.CRITICAL,
metric="revenue",
value=current,
change_pct=change_pct,
recommendation="Analyze root causes: pricing, churn, or market conditions",
icon="🚨"
))
elif change_pct < self.DECLINE_THRESHOLD:
insights.append(Insight(
type=InsightType.RISK,
message=f"Revenue decreased {abs(change_pct):.1f}% - monitor closely",
severity=InsightSeverity.HIGH,
metric="revenue",
value=current,
change_pct=change_pct,
recommendation="Review sales pipeline and customer retention",
icon="⚠️"
))
return insights
def _analyze_customer_trend(self, current: int, previous: int) -> List[Insight]:
"""Analyze customer trend."""
insights = []
change_pct = ((current - previous) / previous * 100) if previous else 0
if change_pct > 10:
insights.append(Insight(
type=InsightType.TREND,
message=f"Customer base grew {change_pct:.1f}%",
severity=InsightSeverity.MEDIUM,
metric="customers",
value=current,
change_pct=change_pct,
icon="👥"
))
elif change_pct < -10:
insights.append(Insight(
type=InsightType.RISK,
message=f"Customer base declined {abs(change_pct):.1f}%",
severity=InsightSeverity.HIGH,
metric="customers",
value=current,
change_pct=change_pct,
recommendation="Implement customer retention programs",
icon="⚠️"
))
return insights
def _analyze_order_trend(self, current: int, previous: int) -> List[Insight]:
"""Analyze order volume trend."""
insights = []
change_pct = ((current - previous) / previous * 100) if previous else 0
if change_pct > 15:
insights.append(Insight(
type=InsightType.TREND,
message=f"Order volume up {change_pct:.1f}% - strong demand",
severity=InsightSeverity.MEDIUM,
metric="orders",
value=current,
change_pct=change_pct,
icon="📦"
))
elif change_pct < -15:
insights.append(Insight(
type=InsightType.RISK,
message=f"Order volume down {abs(change_pct):.1f}%",
severity=InsightSeverity.HIGH,
metric="orders",
value=current,
change_pct=change_pct,
recommendation="Review product catalog and pricing strategy",
icon="📉"
))
return insights
def _analyze_product_performance(self, products: List[Dict]) -> List[Insight]:
"""Analyze product performance."""
insights = []
if not products:
return insights
# Top performer
top = products[0] if products else None
if top:
insights.append(Insight(
type=InsightType.PERFORMANCE,
message=f"Top product: {top.get('name', 'Unknown')} - ${top.get('revenue', 0):,.0f}",
severity=InsightSeverity.LOW,
metric="product_revenue",
value=top.get('revenue', 0),
icon="🏆"
))
# Product concentration risk
if len(products) >= 2:
total = sum(p.get('revenue', 0) for p in products)
top_share = (products[0].get('revenue', 0) / total * 100) if total else 0
if top_share > 50:
insights.append(Insight(
type=InsightType.RISK,
message=f"High product concentration: top product = {top_share:.0f}% of revenue",
severity=InsightSeverity.MEDIUM,
metric="product_concentration",
value=top_share,
recommendation="Diversify product portfolio to reduce risk",
icon="⚠️"
))
return insights
def _analyze_customer_concentration(self, customers: List[Dict], total_revenue: float) -> List[Insight]:
"""Analyze customer concentration risk."""
insights = []
if not customers or not total_revenue:
return insights
# Top customer concentration
top_5_revenue = sum(c.get('revenue', 0) for c in customers[:5])
concentration = (top_5_revenue / total_revenue * 100) if total_revenue else 0
if concentration > 60:
insights.append(Insight(
type=InsightType.RISK,
message=f"High customer concentration: top 5 = {concentration:.0f}% of revenue",
severity=InsightSeverity.HIGH,
metric="customer_concentration",
value=concentration,
recommendation="Expand customer base to reduce dependency",
icon="🚨"
))
elif concentration > 40:
insights.append(Insight(
type=InsightType.RISK,
message=f"Moderate customer concentration: top 5 = {concentration:.0f}% of revenue",
severity=InsightSeverity.MEDIUM,
metric="customer_concentration",
value=concentration,
icon="⚠️"
))
return insights
def _detect_anomalies(self, time_series: List[Dict]) -> List[Insight]:
"""Detect anomalies in time series data."""
insights = []
if len(time_series) < 5:
return insights
values = [item.get('value', item.get('revenue', 0)) for item in time_series]
mean = np.mean(values)
std = np.std(values)
if std == 0:
return insights
# Check for anomalies
for i, (item, val) in enumerate(zip(time_series, values)):
z_score = (val - mean) / std
if abs(z_score) > self.ANOMALY_Z_SCORE:
date = item.get('date', f'Period {i+1}')
direction = "spike" if z_score > 0 else "drop"
insights.append(Insight(
type=InsightType.ANOMALY,
message=f"Unusual {direction} detected on {date}",
severity=InsightSeverity.HIGH,
metric="anomaly",
value=val,
recommendation=f"Investigate cause of {direction}",
icon="🔍"
))
return insights
def _detect_time_trends(self, time_series: List[Dict]) -> List[Insight]:
"""Detect trends in time series."""
insights = []
if len(time_series) < 3:
return insights
values = [item.get('value', item.get('revenue', 0)) for item in time_series]
# Simple trend detection
first_half = np.mean(values[:len(values)//2])
second_half = np.mean(values[len(values)//2:])
change = ((second_half - first_half) / first_half * 100) if first_half else 0
if change > 10:
insights.append(Insight(
type=InsightType.TREND,
message=f"Accelerating growth trend detected (+{change:.1f}%)",
severity=InsightSeverity.MEDIUM,
metric="trend",
change_pct=change,
icon="📈"
))
elif change < -10:
insights.append(Insight(
type=InsightType.TREND,
message=f"Declining trend detected ({change:.1f}%)",
severity=InsightSeverity.HIGH,
metric="trend",
change_pct=change,
recommendation="Address root causes of decline",
icon="📉"
))
return insights
def _analyze_risks(
self,
churn_rate: float,
profit_margin: float,
revenue: float,
revenue_previous: float
) -> List[Insight]:
"""Identify business risks."""
insights = []
# Churn risk
if churn_rate > 0.15:
insights.append(Insight(
type=InsightType.RISK,
message=f"High churn rate: {churn_rate*100:.1f}%",
severity=InsightSeverity.CRITICAL,
metric="churn",
value=churn_rate * 100,
recommendation="Implement immediate retention initiatives",
icon="🚨"
))
elif churn_rate > 0.08:
insights.append(Insight(
type=InsightType.RISK,
message=f"Elevated churn rate: {churn_rate*100:.1f}%",
severity=InsightSeverity.HIGH,
metric="churn",
value=churn_rate * 100,
recommendation="Review customer satisfaction and support",
icon="⚠️"
))
# Margin risk
if profit_margin > 0 and profit_margin < 0.1:
insights.append(Insight(
type=InsightType.RISK,
message=f"Low profit margin: {profit_margin*100:.1f}%",
severity=InsightSeverity.HIGH,
metric="margin",
value=profit_margin * 100,
recommendation="Optimize costs or adjust pricing",
icon="⚠️"
))
return insights
def _identify_opportunities(
self,
revenue: float,
customers: int,
orders: int,
products: Optional[List[Dict]],
margin: float
) -> List[Insight]:
"""Identify growth opportunities."""
insights = []
# Cross-sell opportunity
if customers and orders:
orders_per_customer = orders / customers
if orders_per_customer < 2:
insights.append(Insight(
type=InsightType.OPPORTUNITY,
message=f"Cross-sell opportunity: {orders_per_customer:.1f} orders/customer",
severity=InsightSeverity.MEDIUM,
metric="orders_per_customer",
value=orders_per_customer,
recommendation="Implement cross-sell campaigns to increase order frequency",
icon="💡"
))
# Upsell opportunity
if revenue and customers:
avg_value = revenue / customers
insights.append(Insight(
type=InsightType.OPPORTUNITY,
message=f"Current customer value: ${avg_value:,.0f} - potential for upselling",
severity=InsightSeverity.LOW,
metric="customer_value",
value=avg_value,
recommendation="Target high-value customers with premium offerings",
icon="💎"
))
# Margin improvement opportunity
if margin and margin < 0.3:
potential = revenue * 0.05 # 5% margin improvement
insights.append(Insight(
type=InsightType.OPPORTUNITY,
message=f"Margin improvement could add ${potential:,.0f} to profit",
severity=InsightSeverity.MEDIUM,
metric="margin_opportunity",
value=potential,
recommendation="Review cost structure and pricing strategy",
icon="💰"
))
return insights
def _calculate_risk_score(self, insights: List[Insight]) -> float:
"""Calculate overall risk score (0-100)."""
risk_insights = [i for i in insights if i.type == InsightType.RISK]
if not risk_insights:
return 10 # Low baseline risk
score = 0
for insight in risk_insights:
if insight.severity == InsightSeverity.CRITICAL:
score += 30
elif insight.severity == InsightSeverity.HIGH:
score += 20
elif insight.severity == InsightSeverity.MEDIUM:
score += 10
else:
score += 5
return min(100, score)
def _calculate_opportunity_score(self, insights: List[Insight]) -> float:
"""Calculate opportunity score (0-100)."""
opp_insights = [i for i in insights if i.type == InsightType.OPPORTUNITY]
base_score = len(opp_insights) * 15
return min(100, base_score + 20) # Base opportunity exists
def _calculate_health_score(
self,
insights: List[Insight],
risk_score: float,
opp_score: float
) -> float:
"""Calculate overall business health score."""
# Start at 70
health = 70
# Adjust for risks
health -= risk_score * 0.3
# Boost for opportunities
health += opp_score * 0.1
# Boost for positive trends
positive_trends = sum(1 for i in insights
if i.type == InsightType.TREND
and i.change_pct and i.change_pct > 0)
health += positive_trends * 5
return max(0, min(100, health))
def _generate_summary(
self,
insights: List[Insight],
risk_score: float,
opp_score: float
) -> str:
"""Generate executive summary."""
risk_count = sum(1 for i in insights if i.type == InsightType.RISK)
opp_count = sum(1 for i in insights if i.type == InsightType.OPPORTUNITY)
trend_count = sum(1 for i in insights if i.type == InsightType.TREND)
parts = []
if risk_score > 50:
parts.append(f"⚠️ {risk_count} risks need attention")
elif risk_count > 0:
parts.append(f"ℹ️ {risk_count} risk(s) identified")
if opp_count > 0:
parts.append(f"💡 {opp_count} growth opportunities found")
if trend_count > 0:
parts.append(f"📈 {trend_count} trend insights detected")
return " | ".join(parts) if parts else "Analysis complete - no major findings"
def _find_top_priority(self, insights: List[Insight]) -> str:
"""Find the highest priority insight."""
# Critical risks first
critical = [i for i in insights if i.severity == InsightSeverity.CRITICAL]
if critical:
return critical[0].message
# High severity next
high = [i for i in insights if i.severity == InsightSeverity.HIGH]
if high:
return high[0].message
# Opportunities
opps = [i for i in insights if i.type == InsightType.OPPORTUNITY]
if opps:
return opps[0].message
return "No immediate priorities"
def generate_insights(
revenue: float = 0,
revenue_previous: float = 0,
customers: int = 0,
orders: int = 0,
churn_rate: float = 0.05,
profit_margin: float = 0.2,
time_series: Optional[List[Dict]] = None,
top_products: Optional[List[Dict]] = None,
top_customers: Optional[List[Dict]] = None
) -> Dict[str, Any]:
"""
Convenience function to generate insights.
Returns:
Dict with all insights and scores
"""
engine = InsightEngine()
result = engine.analyze(
revenue=revenue,
revenue_previous=revenue_previous,
customers=customers,
customers_previous=int(customers * 0.95), # Assume 5% growth if not provided
orders=orders,
orders_previous=int(orders * 0.9),
top_products=top_products,
top_customers=top_customers,
time_series=time_series,
churn_rate=churn_rate,
profit_margin=profit_margin
)
return {
"success": True,
"insights": [
{
"type": i.type.value,
"message": i.message,
"severity": i.severity.value,
"metric": i.metric,
"value": i.value,
"change_pct": i.change_pct,
"recommendation": i.recommendation,
"icon": i.icon
}
for i in result.insights
],
"summary": result.summary,
"risk_score": result.risk_score,
"opportunity_score": result.opportunity_score,
"health_score": result.health_score,
"top_priority": result.top_priority
}
# Quick test
if __name__ == "__main__":
result = generate_insights(
revenue=500000,
revenue_previous=450000,
customers=250,
orders=1200,
churn_rate=0.12,
profit_margin=0.18,
top_products=[
{"name": "AI Starter Kit", "revenue": 150000},
{"name": "Pro Pack", "revenue": 100000},
{"name": "Enterprise", "revenue": 80000}
],
top_customers=[
{"name": "Acme Corp", "revenue": 120000},
{"name": "TechStart", "revenue": 80000},
{"name": "DataCo", "revenue": 60000}
]
)
print("Insight Analysis:")
print(f"Summary: {result['summary']}")
print(f"Health Score: {result['health_score']:.0f}/100")
print(f"Risk Score: {result['risk_score']:.0f}/100")
print(f"\nTop Priority: {result['top_priority']}")
print(f"\nInsights ({len(result['insights'])}):")
for i in result['insights'][:5]:
print(f" {i['icon']} [{i['type']}] {i['message']}")