Spaces:
Runtime error
Runtime error
Download eugene/validation/engine.py from Rex165/eugene-intelligence: direct link, hf CLI and curl.
- Browser
- Download file 11.8 kB
-
https://huggingface.co/spaces/Rex165/eugene-intelligence/resolve/main/eugene/validation/engine.py
- Command line
-
hf download hf://spaces/Rex165/eugene-intelligence/eugene/validation/engine.py
-
curl -L -o engine.py https://huggingface.co/spaces/Rex165/eugene-intelligence/resolve/main/eugene/validation/engine.py
11.8 kB
| """ | |
| Eugene Intelligence - Validation Engine | |
| The trust layer. Michelle Leder said it best: trust is everything. | |
| This module validates every extraction before it reaches a user. | |
| Every data point gets a confidence score and validation check. | |
| """ | |
| import re | |
| import logging | |
| from typing import List, Optional, Dict, Any, Callable | |
| from dataclasses import dataclass, field | |
| from datetime import datetime | |
| logger = logging.getLogger(__name__) | |
| class ValidationResult: | |
| """Result of validating an extraction""" | |
| is_valid: bool | |
| confidence_score: float # 0.0 - 1.0 | |
| errors: List[str] = field(default_factory=list) | |
| warnings: List[str] = field(default_factory=list) | |
| checks_passed: int = 0 | |
| checks_failed: int = 0 | |
| checks_total: int = 0 | |
| def pass_rate(self) -> float: | |
| if self.checks_total == 0: | |
| return 0.0 | |
| return self.checks_passed / self.checks_total | |
| def to_dict(self) -> dict: | |
| return { | |
| "is_valid": self.is_valid, | |
| "confidence_score": round(self.confidence_score, 3), | |
| "pass_rate": round(self.pass_rate, 3), | |
| "checks_passed": self.checks_passed, | |
| "checks_failed": self.checks_failed, | |
| "checks_total": self.checks_total, | |
| "errors": self.errors, | |
| "warnings": self.warnings | |
| } | |
| class Check: | |
| """Single validation check""" | |
| name: str | |
| passed: bool | |
| message: str = "" | |
| severity: str = "error" # error, warning | |
| class Validator: | |
| """ | |
| Base validator. Runs checks against extraction data. | |
| Usage: | |
| validator = Validator() | |
| validator.add_check("positive_debt", lambda d: d.get("total_debt", 0) >= 0, | |
| "Total debt cannot be negative") | |
| result = validator.validate(data) | |
| """ | |
| def __init__(self): | |
| self._checks: List[Dict] = [] | |
| def add_check( | |
| self, | |
| name: str, | |
| check_fn: Callable[[Dict], bool], | |
| error_message: str, | |
| severity: str = "error" | |
| ): | |
| """Add a validation check""" | |
| self._checks.append({ | |
| "name": name, | |
| "fn": check_fn, | |
| "message": error_message, | |
| "severity": severity | |
| }) | |
| def validate(self, data: Dict[str, Any]) -> ValidationResult: | |
| """Run all checks against data""" | |
| errors = [] | |
| warnings = [] | |
| passed = 0 | |
| failed = 0 | |
| for check in self._checks: | |
| try: | |
| if check["fn"](data): | |
| passed += 1 | |
| else: | |
| failed += 1 | |
| if check["severity"] == "error": | |
| errors.append(f"{check['name']}: {check['message']}") | |
| else: | |
| warnings.append(f"{check['name']}: {check['message']}") | |
| except Exception as e: | |
| failed += 1 | |
| errors.append(f"{check['name']}: Check failed with exception: {e}") | |
| total = passed + failed | |
| confidence = passed / total if total > 0 else 0.0 | |
| is_valid = len(errors) == 0 | |
| return ValidationResult( | |
| is_valid=is_valid, | |
| confidence_score=confidence, | |
| errors=errors, | |
| warnings=warnings, | |
| checks_passed=passed, | |
| checks_failed=failed, | |
| checks_total=total | |
| ) | |
| class DebtValidator(Validator): | |
| """Validator for debt extractions""" | |
| def __init__(self): | |
| super().__init__() | |
| self._add_debt_checks() | |
| def _add_debt_checks(self): | |
| # Total debt must be non-negative | |
| self.add_check( | |
| "positive_total_debt", | |
| lambda d: d.get("total_debt") is None or d.get("total_debt", 0) >= 0, | |
| "Total debt cannot be negative" | |
| ) | |
| # Must have at least one instrument | |
| self.add_check( | |
| "has_instruments", | |
| lambda d: len(d.get("instruments", [])) > 0, | |
| "No debt instruments found" | |
| ) | |
| # All instrument principals must be positive | |
| self.add_check( | |
| "positive_principals", | |
| lambda d: all( | |
| i.get("principal", 0) > 0 | |
| for i in d.get("instruments", [{}]) | |
| ), | |
| "All instrument principals must be positive" | |
| ) | |
| # Interest rates should be between 0 and 0.50 (0% to 50%) | |
| self.add_check( | |
| "reasonable_rates", | |
| lambda d: all( | |
| i.get("interest_rate") is None or 0 <= i.get("interest_rate", 0) <= 0.50 | |
| for i in d.get("instruments", []) | |
| ), | |
| "Interest rates should be between 0% and 50%", | |
| severity="warning" | |
| ) | |
| # Maturity dates should be in the future or recent past | |
| self.add_check( | |
| "valid_maturity_dates", | |
| lambda d: all( | |
| i.get("maturity_date") is None or self._is_valid_date(i.get("maturity_date")) | |
| for i in d.get("instruments", []) | |
| ), | |
| "Maturity dates should be valid", | |
| severity="warning" | |
| ) | |
| # Sum of instruments should roughly match total | |
| self.add_check( | |
| "instruments_sum_matches_total", | |
| lambda d: self._check_sum(d), | |
| "Sum of instruments doesn't match total debt (>20% difference)", | |
| severity="warning" | |
| ) | |
| # Each instrument should have a name | |
| self.add_check( | |
| "instruments_have_names", | |
| lambda d: all( | |
| bool(i.get("name", "").strip()) | |
| for i in d.get("instruments", [{}]) | |
| ), | |
| "All instruments should have names" | |
| ) | |
| # Confidence scores should be valid | |
| self.add_check( | |
| "valid_confidence_scores", | |
| lambda d: all( | |
| 0 <= i.get("confidence", 0) <= 1 | |
| for i in d.get("instruments", [{}]) | |
| ), | |
| "Confidence scores must be between 0 and 1" | |
| ) | |
| def _is_valid_date(date_str: str) -> bool: | |
| """Check if date string is valid""" | |
| if not date_str: | |
| return True | |
| try: | |
| datetime.strptime(date_str, "%Y-%m-%d") | |
| return True | |
| except ValueError: | |
| return False | |
| def _check_sum(data: dict) -> bool: | |
| """Check if instrument sum roughly matches total""" | |
| total = data.get("total_debt") | |
| instruments = data.get("instruments", []) | |
| if total is None or not instruments: | |
| return True # Can't check, pass | |
| instrument_sum = sum(i.get("principal", 0) for i in instruments) | |
| if total == 0: | |
| return instrument_sum == 0 | |
| # Allow 20% tolerance | |
| ratio = abs(instrument_sum - total) / total | |
| return ratio <= 0.20 | |
| class EmployeeValidator(Validator): | |
| """Validator for employee/layoff extractions""" | |
| def __init__(self): | |
| super().__init__() | |
| self._add_employee_checks() | |
| def _add_employee_checks(self): | |
| # Must have employee count | |
| self.add_check( | |
| "has_employee_count", | |
| lambda d: d.get("current_employees") is not None or d.get("employee_count") is not None, | |
| "No employee count found" | |
| ) | |
| # Employee count must be positive | |
| self.add_check( | |
| "positive_employee_count", | |
| lambda d: (d.get("current_employees") or d.get("employee_count") or 1) > 0, | |
| "Employee count must be positive" | |
| ) | |
| # If layoff mentioned, must have number or percentage | |
| self.add_check( | |
| "layoff_has_details", | |
| lambda d: ( | |
| not d.get("has_layoffs", False) or | |
| d.get("layoff_count") is not None or | |
| d.get("layoff_percentage") is not None | |
| ), | |
| "Layoff mentioned but no count or percentage provided", | |
| severity="warning" | |
| ) | |
| # Layoff count should be less than total employees | |
| self.add_check( | |
| "layoff_less_than_total", | |
| lambda d: ( | |
| d.get("layoff_count") is None or | |
| d.get("current_employees") is None or | |
| d.get("layoff_count", 0) <= d.get("current_employees", float("inf")) | |
| ), | |
| "Layoff count exceeds total employee count" | |
| ) | |
| class EventValidator(Validator): | |
| """Validator for 8-K material events""" | |
| def __init__(self): | |
| super().__init__() | |
| self._add_event_checks() | |
| def _add_event_checks(self): | |
| # Must have at least one event | |
| self.add_check( | |
| "has_events", | |
| lambda d: len(d.get("events", [])) > 0, | |
| "No events found in 8-K" | |
| ) | |
| # Events must have item numbers | |
| self.add_check( | |
| "events_have_item_numbers", | |
| lambda d: all( | |
| bool(e.get("item_number", "").strip()) | |
| for e in d.get("events", [{}]) | |
| ), | |
| "All events must have item numbers" | |
| ) | |
| # Item numbers should match known patterns | |
| self.add_check( | |
| "valid_item_numbers", | |
| lambda d: all( | |
| re.match(r'^\d+\.\d+$', e.get("item_number", "0.0")) | |
| for e in d.get("events", [{"item_number": "1.01"}]) | |
| ), | |
| "Item numbers should be in format X.XX", | |
| severity="warning" | |
| ) | |
| def validate_debt(data: Dict[str, Any]) -> ValidationResult: | |
| """Convenience function to validate debt extraction""" | |
| return DebtValidator().validate(data) | |
| def validate_employees(data: Dict[str, Any]) -> ValidationResult: | |
| """Convenience function to validate employee extraction""" | |
| return EmployeeValidator().validate(data) | |
| def validate_events(data: Dict[str, Any]) -> ValidationResult: | |
| """Convenience function to validate 8-K events""" | |
| return EventValidator().validate(data) | |
| if __name__ == "__main__": | |
| print("Testing Validation Engine...\n") | |
| # Test good debt data | |
| good_debt = { | |
| "total_debt": 3700, | |
| "instruments": [ | |
| {"name": "Senior Notes", "principal": 1500, "interest_rate": 0.0525, "confidence": 0.9}, | |
| {"name": "Term Loan", "principal": 2000, "confidence": 0.85}, | |
| {"name": "Revolver", "principal": 200, "confidence": 0.8} | |
| ] | |
| } | |
| result = validate_debt(good_debt) | |
| print(f"Good debt data: valid={result.is_valid}, confidence={result.confidence_score:.2f}") | |
| print(f" Passed: {result.checks_passed}/{result.checks_total}") | |
| assert result.is_valid | |
| print(" ✓ Passed\n") | |
| # Test bad debt data | |
| bad_debt = { | |
| "total_debt": -500, | |
| "instruments": [] | |
| } | |
| result = validate_debt(bad_debt) | |
| print(f"Bad debt data: valid={result.is_valid}, confidence={result.confidence_score:.2f}") | |
| print(f" Errors: {result.errors}") | |
| assert not result.is_valid | |
| print(" ✓ Correctly rejected\n") | |
| # Test employee data | |
| good_employees = { | |
| "current_employees": 150000, | |
| "has_layoffs": True, | |
| "layoff_count": 2400, | |
| "layoff_percentage": 1.6 | |
| } | |
| result = validate_employees(good_employees) | |
| print(f"Employee data: valid={result.is_valid}, confidence={result.confidence_score:.2f}") | |
| assert result.is_valid | |
| print(" ✓ Passed\n") | |
| print("✅ All validation tests passed!") | |