""" Decision Support Engine Transforms observations → decisions → actions → outcomes Not selling data. Selling better decisions. """ from typing import Dict, List, Optional, Tuple from dataclasses import dataclass from datetime import datetime from enum import Enum class DecisionType(str, Enum): """Types of decisions supported""" INVESTMENT = "investment" # Where to invest MAINTENANCE = "maintenance" # What to maintain first RISK_MITIGATION = "risk_mitigation" # How to reduce risk ESTABLISHMENT = "establishment" # Where to establish business RESOURCE_ALLOCATION = "resource_allocation" # How to allocate budget SAFETY_IMPROVEMENT = "safety_improvement" # How to improve safety class Stakeholder(str, Enum): """Target stakeholders""" MUNICIPALITY = "municipality" PROPERTY_OWNER = "property_owner" INFRASTRUCTURE_OWNER = "infrastructure_owner" INSURANCE = "insurance" BANK = "bank" RETAIL = "retail" LOGISTICS = "logistics" CITIZEN = "citizen" @dataclass class DecisionRecommendation: """A decision recommendation""" decision_type: DecisionType stakeholder: Stakeholder recommendation: str expected_impact: float confidence: float cost_estimate_usd: Optional[float] timeline_months: Optional[int] supporting_data: List[Dict] risks: List[str] def to_dict(self) -> Dict: return { "decision_type": self.decision_type.value, "stakeholder": self.stakeholder.value, "recommendation": self.recommendation, "expected_impact": round(self.expected_impact, 2), "confidence": round(self.confidence, 2), "cost_estimate_usd": self.cost_estimate_usd, "timeline_months": self.timeline_months, "supporting_data": self.supporting_data, "risks": self.risks } class DecisionEngine: """Generates decision recommendations from reality signals""" def __init__(self): self.decision_models = self._load_decision_models() self.visual_geo_enabled = True # NEW def _load_decision_models(self) -> Dict: """Load decision models for each stakeholder""" return { Stakeholder.MUNICIPALITY: { "priorities": ["safety", "maintenance_backlog", "citizen_satisfaction", "budget_efficiency"], "decision_types": [DecisionType.MAINTENANCE, DecisionType.SAFETY_IMPROVEMENT, DecisionType.RESOURCE_ALLOCATION], "budget_range": [100000, 10000000] }, Stakeholder.PROPERTY_OWNER: { "priorities": ["property_value", "tenant_satisfaction", "maintenance_cost", "market_position"], "decision_types": [DecisionType.INVESTMENT, DecisionType.MAINTENANCE, DecisionType.ESTABLISHMENT], "budget_range": [50000, 5000000] }, Stakeholder.INFRASTRUCTURE_OWNER: { "priorities": ["asset_condition", "failure_risk", "compliance", "lifecycle_cost"], "decision_types": [DecisionType.MAINTENANCE, DecisionType.RISK_MITIGATION, DecisionType.INVESTMENT], "budget_range": [500000, 50000000] }, Stakeholder.INSURANCE: { "priorities": ["risk_assessment", "claim_prevention", "portfolio_optimization"], "decision_types": [DecisionType.RISK_MITIGATION, DecisionType.RESOURCE_ALLOCATION], "budget_range": [0, 0] # Risk-based pricing }, Stakeholder.RETAIL: { "priorities": ["foot_traffic", "demographics", "competition", "accessibility"], "decision_types": [DecisionType.ESTABLISHMENT, DecisionType.INVESTMENT], "budget_range": [100000, 2000000] } } def recommend( self, stakeholder: Stakeholder, location_signals: Dict[str, float], constraints: Optional[Dict] = None, visual_evidence: Optional[Dict] = None # NEW ) -> List[DecisionRecommendation]: """ Generate decision recommendations for a stakeholder Args: stakeholder: Who is making the decision location_signals: Reality signals for the location constraints: Budget, timeline, etc. Returns: Prioritized recommendations """ model = self.decision_models.get(stakeholder, {}) recommendations = [] for decision_type in model.get("decision_types", []): rec = self._generate_recommendation( stakeholder, decision_type, location_signals, constraints, visual_evidence ) if rec: recommendations.append(rec) # Sort by expected impact recommendations.sort(key=lambda x: x.expected_impact, reverse=True) return recommendations def _generate_recommendation( self, stakeholder: Stakeholder, decision_type: DecisionType, signals: Dict[str, float], constraints: Optional[Dict], visual_evidence: Optional[Dict] = None ) -> Optional[DecisionRecommendation]: """Generate a specific recommendation""" if decision_type == DecisionType.MAINTENANCE: return self._maintenance_recommendation(stakeholder, signals, constraints, visual_evidence) elif decision_type == DecisionType.SAFETY_IMPROVEMENT: return self._safety_recommendation(stakeholder, signals, constraints, visual_evidence) elif decision_type == DecisionType.INVESTMENT: return self._investment_recommendation(stakeholder, signals, constraints, visual_evidence) elif decision_type == DecisionType.ESTABLISHMENT: return self._establishment_recommendation(stakeholder, signals, constraints, visual_evidence) elif decision_type == DecisionType.RISK_MITIGATION: return self._risk_recommendation(stakeholder, signals, constraints, visual_evidence) return None def _maintenance_recommendation( self, stakeholder: Stakeholder, signals: Dict[str, float], constraints: Optional[Dict], visual_evidence: Optional[Dict] = None ) -> DecisionRecommendation: """Generate maintenance recommendation""" condition = signals.get("maintenance_quality", 50) backlog = signals.get("maintenance_backlog", 0) if condition < 40: urgency = "critical" expected_impact = 80 elif condition < 60: urgency = "high" expected_impact = 60 else: urgency = "medium" expected_impact = 40 return DecisionRecommendation( decision_type=DecisionType.MAINTENANCE, stakeholder=stakeholder, recommendation=f"Prioritize {urgency} maintenance. Current quality: {condition}/100.", expected_impact=expected_impact, confidence=0.75, cost_estimate_usd=constraints.get("budget_usd", 100000) if constraints else 100000, timeline_months=6, supporting_data=[ {"signal": "maintenance_quality", "value": condition}, {"signal": "maintenance_backlog", "value": backlog} ], risks=["Budget overrun", "Disruption during work"] ) def _safety_recommendation( self, stakeholder: Stakeholder, signals: Dict[str, float], constraints: Optional[Dict], visual_evidence: Optional[Dict] = None ) -> DecisionRecommendation: """Generate safety improvement recommendation""" safety = signals.get("safety_index", 50) lighting = signals.get("lighting", 50) interventions = [] if lighting < 50: interventions.append("improve lighting") if safety < 50: interventions.append("increase surveillance") return DecisionRecommendation( decision_type=DecisionType.SAFETY_IMPROVEMENT, stakeholder=stakeholder, recommendation=f"Improve safety: {', '.join(interventions)}. Current safety: {safety}/100.", expected_impact=(100 - safety) * 0.8, confidence=0.7, cost_estimate_usd=120000, timeline_months=4, supporting_data=[ {"signal": "safety_index", "value": safety}, {"signal": "lighting", "value": lighting} ], risks=["Limited effectiveness if not combined with other measures"] ) def _investment_recommendation( self, stakeholder: Stakeholder, signals: Dict[str, float], constraints: Optional[Dict], visual_evidence: Optional[Dict] = None ) -> DecisionRecommendation: """Generate investment recommendation""" property_value = signals.get("property_value", 50) growth_potential = signals.get("growth_potential", 50) return DecisionRecommendation( decision_type=DecisionType.INVESTMENT, stakeholder=stakeholder, recommendation=f"Investment opportunity. Current value: {property_value}/100. Growth potential: {growth_potential}/100.", expected_impact=growth_potential * 0.9, confidence=0.65, cost_estimate_usd=constraints.get("budget_usd", 500000) if constraints else 500000, timeline_months=12, supporting_data=[ {"signal": "property_value", "value": property_value}, {"signal": "growth_potential", "value": growth_potential} ], risks=["Market downturn", "Construction delays"] ) def _establishment_recommendation( self, stakeholder: Stakeholder, signals: Dict[str, float], constraints: Optional[Dict], visual_evidence: Optional[Dict] = None ) -> DecisionRecommendation: """Generate establishment recommendation""" foot_traffic = signals.get("pedestrian_flow", 50) competition = signals.get("retail_density", 50) demographics = signals.get("family_friendly", 50) # Calculate opportunity score opportunity = (foot_traffic * 0.4 + demographics * 0.3 + (100 - competition) * 0.3) return DecisionRecommendation( decision_type=DecisionType.ESTABLISHMENT, stakeholder=stakeholder, recommendation=f"Establishment opportunity score: {opportunity:.0f}/100. Foot traffic: {foot_traffic}, Competition: {competition}.", expected_impact=opportunity * 0.85, confidence=0.6, cost_estimate_usd=300000, timeline_months=8, supporting_data=[ {"signal": "pedestrian_flow", "value": foot_traffic}, {"signal": "retail_density", "value": competition}, {"signal": "family_friendly", "value": demographics} ], risks=["Competition increase", "Changing demographics"] ) def _risk_recommendation( self, stakeholder: Stakeholder, signals: Dict[str, float], constraints: Optional[Dict], visual_evidence: Optional[Dict] = None ) -> DecisionRecommendation: """Generate risk mitigation recommendation""" risk_score = signals.get("infrastructure_reliability", 50) failure_probability = 100 - risk_score return DecisionRecommendation( decision_type=DecisionType.RISK_MITIGATION, stakeholder=stakeholder, recommendation=f"Risk mitigation needed. Failure probability: {failure_probability:.0f}%. Current reliability: {risk_score}/100.", expected_impact=failure_probability * 0.9, confidence=0.8, cost_estimate_usd=200000, timeline_months=6, supporting_data=[ {"signal": "infrastructure_reliability", "value": risk_score}, {"signal": "failure_probability", "value": failure_probability} ], risks=["Unexpected failures", "Cost escalation"] ) def prioritize_investments( self, stakeholder: Stakeholder, locations: List[Dict], budget_usd: float ) -> Dict: """ Prioritize investments across multiple locations Returns: Prioritized list with ROI estimates """ opportunities = [] for location in locations: signals = location.get("signals", {}) # Calculate investment attractiveness attractiveness = ( signals.get("property_value", 50) * 0.3 + signals.get("growth_potential", 50) * 0.3 + signals.get("safety_index", 50) * 0.2 + signals.get("connectivity", 50) * 0.2 ) # Estimate ROI estimated_roi = attractiveness * 0.5 # Simplified opportunities.append({ "location_id": location.get("id"), "location_name": location.get("name"), "attractiveness": round(attractiveness, 1), "estimated_roi": round(estimated_roi, 1), "recommended_investment": min(budget_usd * 0.2, 1000000), "priority": "high" if attractiveness > 75 else "medium" if attractiveness > 50 else "low" }) # Sort by attractiveness opportunities.sort(key=lambda x: x["attractiveness"], reverse=True) # Allocate budget allocated = 0 for opp in opportunities: if allocated + opp["recommended_investment"] <= budget_usd: opp["allocated"] = opp["recommended_investment"] allocated += opp["allocated"] else: remaining = budget_usd - allocated if remaining > 0: opp["allocated"] = remaining allocated += remaining else: opp["allocated"] = 0 return { "stakeholder": stakeholder.value, "total_budget": budget_usd, "allocated": allocated, "opportunities": opportunities } # Example usage def example_decisions(): """Example: Generate decision recommendations""" engine = DecisionEngine() # Signals for a location signals = { "safety_index": 45, "lighting": 35, "maintenance_quality": 40, "property_value": 60, "growth_potential": 70, "pedestrian_flow": 80, "retail_density": 65, "family_friendly": 55, "infrastructure_reliability": 50 } # Municipality recommendations print("=== Municipality Decisions ===") recs = engine.recommend(Stakeholder.MUNICIPALITY, signals, {"budget_usd": 500000}) for rec in recs: print(f"\n{rec.decision_type.value.upper()}") print(f" Recommendation: {rec.recommendation}") print(f" Expected impact: {rec.expected_impact}") print(f" Cost: ${rec.cost_estimate_usd:,}") print(f" Timeline: {rec.timeline_months} months") # Property owner recommendations print("\n=== Property Owner Decisions ===") recs = engine.recommend(Stakeholder.PROPERTY_OWNER, signals, {"budget_usd": 1000000}) for rec in recs: print(f"\n{rec.decision_type.value.upper()}") print(f" Recommendation: {rec.recommendation}") print(f" Expected impact: {rec.expected_impact}") # Prioritize investments print("\n=== Investment Prioritization ===") locations = [ {"id": "LOC-001", "name": "Downtown", "signals": {"property_value": 80, "growth_potential": 75, "safety_index": 70}}, {"id": "LOC-002", "name": "Suburb A", "signals": {"property_value": 60, "growth_potential": 85, "safety_index": 80}}, {"id": "LOC-003", "name": "Industrial", "signals": {"property_value": 40, "growth_potential": 50, "safety_index": 45}} ] result = engine.prioritize_investments(Stakeholder.PROPERTY_OWNER, locations, 2000000) print(f"Budget: ${result['total_budget']:,}") print(f"Allocated: ${result['allocated']:,}") print("\nPriorities:") for opp in result["opportunities"]: print(f" {opp['location_name']}: {opp['priority']} (ROI: {opp['estimated_roi']}, Allocated: ${opp.get('allocated', 0):,})") return engine if __name__ == '__main__': example_decisions()