from typing import Any, Dict, List from ai_matcher import AIMatcher from ai_rules import AIRulesEngine from feedback_logger import FeedbackLogger from models import Match, Receipt, Transaction class MatchingEngine: def __init__(self): self.ai_matcher = AIMatcher() self.rules_engine = AIRulesEngine() self.feedback_logger = FeedbackLogger() def process_matching( self, receipts: List[Receipt], transactions: List[Transaction] ) -> List[Match]: # Get AI matches ai_matches = self.ai_matcher.match_receipts_to_transactions( receipts, transactions ) # Apply rules and enhance matches enhanced_matches = [] for match in ai_matches: enhanced_match = self._enhance_match_with_rules(match) enhanced_matches.append(enhanced_match) return enhanced_matches def _enhance_match_with_rules(self, match: Match) -> Match: rule_results = self.rules_engine.apply_rules(match.receipt, match.transaction) # Apply confidence boost from rules if rule_results["confidence_boost"] > 0: match.confidence_score = min( 1.0, match.confidence_score + rule_results["confidence_boost"] ) # Auto-approve if rules say so if rule_results["auto_approve"]: match.confidence_score = 1.0 match.match_reason += " (Auto-approved by rules)" # Add tax analysis to match if rule_results.get("tax_analysis"): match.tax_analysis = rule_results["tax_analysis"] return match def approve_match(self, match: Match, user_id: str): # Log the approval self.feedback_logger.log_override( transaction_id=match.transaction.id, original_match=f"AI Score: {match.confidence_score}", correction="Approved", reason="User approved match", user_id=user_id, ) def reject_match(self, match: Match, reason: str, user_id: str): # Log the rejection self.feedback_logger.log_override( transaction_id=match.transaction.id, original_match=f"AI Score: {match.confidence_score}", correction="Rejected", reason=reason, user_id=user_id, ) def get_matching_stats(self, matches: List[Match]) -> Dict[str, Any]: if not matches: return { "total": 0, "high_confidence": 0, "low_confidence": 0, "avg_score": 0, } high_confidence = len([m for m in matches if m.confidence_score >= 0.8]) low_confidence = len([m for m in matches if m.confidence_score < 0.8]) avg_score = sum(m.confidence_score for m in matches) / len(matches) return { "total": len(matches), "high_confidence": high_confidence, "low_confidence": low_confidence, "avg_score": round(avg_score, 3), }