Spaces:
Sleeping
Sleeping
| """ | |
| What-If Simulation Engine for LexAI | |
| =================================== | |
| Hackathon MVP - Interactive case outcome simulation | |
| Shows how changes in case facts affect predictions | |
| """ | |
| from typing import Dict, Any, List, Optional | |
| import re | |
| from bias_prediction_engine import get_model | |
| class SimulationEngine: | |
| """ | |
| Simulate legal case outcomes with modified facts | |
| """ | |
| def __init__(self): | |
| self.ml_model = get_model() | |
| # Modifiable factors and their impacts | |
| self.factor_impacts = { | |
| 'prior_conviction': { | |
| 'weight': 0.25, | |
| 'direction': 'negative', | |
| 'description': 'Previous criminal record' | |
| }, | |
| 'witness_credibility': { | |
| 'weight': 0.20, | |
| 'direction': 'positive', | |
| 'description': 'Reliability of witnesses' | |
| }, | |
| 'evidence_quality': { | |
| 'weight': 0.30, | |
| 'direction': 'positive', | |
| 'description': 'Strength of evidence' | |
| }, | |
| 'mitigating_factors': { | |
| 'weight': 0.15, | |
| 'direction': 'positive', | |
| 'description': 'Circumstances favoring accused' | |
| }, | |
| 'flight_risk': { | |
| 'weight': 0.10, | |
| 'direction': 'negative', | |
| 'description': 'Risk of absconding' | |
| } | |
| } | |
| def simulate_outcome(self, | |
| base_case: Dict[str, Any], | |
| modifications: Dict[str, Any]) -> Dict[str, Any]: | |
| """ | |
| Simulate how case outcome changes with modifications | |
| Args: | |
| base_case: Original case facts | |
| modifications: Changes to apply | |
| Returns: | |
| Comparison of outcomes | |
| """ | |
| # Get base prediction | |
| base_text = base_case.get('facts', '') | |
| base_prediction = self.ml_model.predict_outcome( | |
| base_text, | |
| base_case.get('metadata', {}) | |
| ) | |
| # Apply modifications | |
| modified_text = self._apply_modifications(base_text, modifications) | |
| modified_prediction = self.ml_model.predict_outcome( | |
| modified_text, | |
| base_case.get('metadata', {}) | |
| ) | |
| # Calculate impact | |
| impact_analysis = self._analyze_impact( | |
| base_prediction, | |
| modified_prediction, | |
| modifications | |
| ) | |
| return { | |
| 'base_case': { | |
| 'facts': base_text, | |
| 'prediction': base_prediction | |
| }, | |
| 'modified_case': { | |
| 'facts': modified_text, | |
| 'prediction': modified_prediction, | |
| 'changes_applied': list(modifications.keys()) | |
| }, | |
| 'impact_analysis': impact_analysis, | |
| 'visualization_data': self._generate_viz_data( | |
| base_prediction, | |
| modified_prediction | |
| ) | |
| } | |
| def _apply_modifications(self, base_text: str, modifications: Dict[str, Any]) -> str: | |
| """Apply modifications to case facts""" | |
| modified = base_text | |
| # Remove prior conviction if specified | |
| if modifications.get('remove_prior_conviction'): | |
| modified = re.sub( | |
| r'(prior conviction|criminal record|previous offense).*?\.', | |
| 'has no prior criminal record.', | |
| modified, | |
| flags=re.IGNORECASE | |
| ) | |
| # Add strong alibi | |
| if modifications.get('add_strong_alibi'): | |
| modified += " The accused has a strong alibi with multiple credible witnesses confirming their presence elsewhere during the incident." | |
| # Improve witness credibility | |
| if modifications.get('improve_witness_credibility'): | |
| modified = re.sub( | |
| r'(witness.*?)(contradictory|unreliable|questionable)', | |
| r'\1credible and consistent', | |
| modified, | |
| flags=re.IGNORECASE | |
| ) | |
| # Add mitigating factors | |
| if modifications.get('add_mitigating_factors'): | |
| mitigating = modifications['add_mitigating_factors'] | |
| modified += f" {mitigating}" | |
| # Reduce flight risk | |
| if modifications.get('reduce_flight_risk'): | |
| modified += " The accused has deep roots in the community, stable employment, and family responsibilities, eliminating any flight risk." | |
| # Enhance evidence quality | |
| if modifications.get('enhance_evidence'): | |
| modified = re.sub( | |
| r'(evidence.*?)(weak|insufficient|circumstantial)', | |
| r'\1strong and conclusive', | |
| modified, | |
| flags=re.IGNORECASE | |
| ) | |
| return modified | |
| def _analyze_impact(self, | |
| base_pred: Dict, | |
| modified_pred: Dict, | |
| modifications: Dict) -> Dict[str, Any]: | |
| """Analyze impact of modifications""" | |
| confidence_change = modified_pred['confidenceScore'] - base_pred['confidenceScore'] | |
| outcome_changed = base_pred['predictedOutcome'] != modified_pred['predictedOutcome'] | |
| # Calculate factor contributions | |
| factor_impacts = [] | |
| for mod_key, mod_value in modifications.items(): | |
| if mod_value: # If modification was applied | |
| factor_name = mod_key.replace('_', ' ').title() | |
| estimated_impact = self._estimate_factor_impact(mod_key) | |
| factor_impacts.append({ | |
| 'factor': factor_name, | |
| 'estimated_impact': estimated_impact, | |
| 'direction': 'positive' if estimated_impact > 0 else 'negative' | |
| }) | |
| return { | |
| 'outcome_changed': outcome_changed, | |
| 'confidence_change': round(confidence_change, 3), | |
| 'confidence_change_percent': round(confidence_change * 100, 1), | |
| 'factor_contributions': factor_impacts, | |
| 'key_factors': self._identify_key_factors(modifications), | |
| 'recommendation': self._generate_recommendation( | |
| base_pred, | |
| modified_pred, | |
| outcome_changed | |
| ) | |
| } | |
| def _estimate_factor_impact(self, factor_key: str) -> float: | |
| """Estimate impact of a specific factor""" | |
| impact_map = { | |
| 'remove_prior_conviction': 0.25, | |
| 'add_strong_alibi': 0.30, | |
| 'improve_witness_credibility': 0.20, | |
| 'add_mitigating_factors': 0.15, | |
| 'reduce_flight_risk': 0.10, | |
| 'enhance_evidence': 0.35, | |
| } | |
| return impact_map.get(factor_key, 0.10) | |
| def _identify_key_factors(self, modifications: Dict) -> List[str]: | |
| """Identify most impactful factors""" | |
| applied_mods = [k for k, v in modifications.items() if v] | |
| impacts = [(mod, self._estimate_factor_impact(mod)) for mod in applied_mods] | |
| impacts.sort(key=lambda x: x[1], reverse=True) | |
| return [mod.replace('_', ' ').title() for mod, _ in impacts[:3]] | |
| def _generate_recommendation(self, | |
| base_pred: Dict, | |
| modified_pred: Dict, | |
| outcome_changed: bool) -> str: | |
| """Generate recommendation based on simulation""" | |
| if outcome_changed: | |
| return f"Modifying the specified factors could change the outcome from {base_pred['predictedOutcome']} to {modified_pred['predictedOutcome']}. These factors should be given priority in case preparation." | |
| else: | |
| conf_diff = abs(modified_pred['confidenceScore'] - base_pred['confidenceScore']) | |
| if conf_diff > 0.15: | |
| return f"While the outcome remains {base_pred['predictedOutcome']}, the confidence has changed by {round(conf_diff * 100, 1)}%. These factors significantly influence case strength." | |
| else: | |
| return "The modifications have minimal impact on the outcome. Other factors may be more critical to case success." | |
| def _generate_viz_data(self, base_pred: Dict, modified_pred: Dict) -> Dict: | |
| """Generate data for visualization""" | |
| return { | |
| 'confidence_comparison': { | |
| 'base': round(base_pred['confidenceScore'] * 100, 1), | |
| 'modified': round(modified_pred['confidenceScore'] * 100, 1), | |
| 'change': round((modified_pred['confidenceScore'] - base_pred['confidenceScore']) * 100, 1) | |
| }, | |
| 'outcome_labels': { | |
| 'base': base_pred['predictedOutcome'], | |
| 'modified': modified_pred['predictedOutcome'] | |
| }, | |
| 'chart_type': 'bar_comparison', | |
| 'color_scheme': { | |
| 'base': '#6366f1', # Indigo | |
| 'modified': '#10b981' # Green | |
| } | |
| } | |
| def sensitivity_analysis(self, case_facts: str) -> Dict[str, Any]: | |
| """ | |
| Analyze sensitivity to different factors | |
| Tests each factor independently to see impact | |
| """ | |
| base_prediction = self.ml_model.predict_outcome(case_facts, {}) | |
| sensitivity_results = [] | |
| # Test each modification independently | |
| test_modifications = [ | |
| {'remove_prior_conviction': True}, | |
| {'add_strong_alibi': True}, | |
| {'improve_witness_credibility': True}, | |
| {'add_mitigating_factors': 'First-time offender with family responsibilities'}, | |
| {'reduce_flight_risk': True}, | |
| ] | |
| for mod in test_modifications: | |
| result = self.simulate_outcome( | |
| {'facts': case_facts}, | |
| mod | |
| ) | |
| mod_name = list(mod.keys())[0].replace('_', ' ').title() | |
| sensitivity_results.append({ | |
| 'factor': mod_name, | |
| 'confidence_impact': result['impact_analysis']['confidence_change'], | |
| 'outcome_change': result['impact_analysis']['outcome_changed'], | |
| 'new_outcome': result['modified_case']['prediction']['predictedOutcome'] | |
| }) | |
| # Sort by impact | |
| sensitivity_results.sort( | |
| key=lambda x: abs(x['confidence_impact']), | |
| reverse=True | |
| ) | |
| return { | |
| 'base_outcome': base_prediction['predictedOutcome'], | |
| 'base_confidence': base_prediction['confidenceScore'], | |
| 'sensitivity_analysis': sensitivity_results, | |
| 'most_influential_factor': sensitivity_results[0]['factor'] if sensitivity_results else None, | |
| 'visualization_ready': True | |
| } | |
| # Global instance | |
| _simulation_engine = None | |
| def get_simulation_engine() -> SimulationEngine: | |
| """Get or create simulation engine instance""" | |
| global _simulation_engine | |
| if _simulation_engine is None: | |
| _simulation_engine = SimulationEngine() | |
| return _simulation_engine | |
| # Test | |
| if __name__ == "__main__": | |
| engine = SimulationEngine() | |
| # Test case | |
| base_case = { | |
| 'facts': """ | |
| The accused has prior conviction for theft. Witnesses gave contradictory statements. | |
| Evidence is largely circumstantial. The accused attempted to flee when arrested. | |
| """, | |
| 'metadata': {'case_type': 'criminal'} | |
| } | |
| # Test modifications | |
| modifications = { | |
| 'remove_prior_conviction': True, | |
| 'add_strong_alibi': True, | |
| 'improve_witness_credibility': True, | |
| } | |
| print("Running simulation...") | |
| result = engine.simulate_outcome(base_case, modifications) | |
| print(f"\nBase Outcome: {result['base_case']['prediction']['predictedOutcome']}") | |
| print(f"Base Confidence: {result['base_case']['prediction']['confidenceScore']}") | |
| print(f"\nModified Outcome: {result['modified_case']['prediction']['predictedOutcome']}") | |
| print(f"Modified Confidence: {result['modified_case']['prediction']['confidenceScore']}") | |
| print(f"\nOutcome Changed: {result['impact_analysis']['outcome_changed']}") | |
| print(f"Confidence Change: {result['impact_analysis']['confidence_change_percent']}%") | |
| print(f"Key Factors: {', '.join(result['impact_analysis']['key_factors'])}") | |
| print(f"\nRecommendation: {result['impact_analysis']['recommendation']}") | |