pylord/API-BFSI
0
1"""2Fraud explanation generator using rule-based templates3Falls back to simple explanations if HuggingFace models are not available4"""5 6def generate_explanation(transaction_data: dict, derived_features: dict, 7 risk_score: float, rule_score: float, 8 rules_triggered: list) -> str:9 """10 Generate a clear, professional explanation for the fraud prediction.11 Uses template-based approach for reliability and speed.12 """13 14 # Determine fraud status15 is_fraud = risk_score >= 0.616 fraud_status = "FRAUDULENT" if is_fraud else "LEGITIMATE"17 18 # Build explanation parts19 explanation_parts = []20 21 # 1. Overall assessment22 if is_fraud:23 explanation_parts.append(24 f"⚠️ This transaction has been flagged as {fraud_status} with a combined risk score of {risk_score:.2%}."25 )26 else:27 explanation_parts.append(28 f"✓ This transaction appears {fraud_status} with a combined risk score of {risk_score:.2%}."29 )30 31 # 2. Model contribution32 model_risk = risk_score - rule_score33 if model_risk > 0.5:34 explanation_parts.append(35 f"The ML model detected a high fraud probability ({model_risk:.2%})."36 )37 elif model_risk > 0.3:38 explanation_parts.append(39 f"The ML model indicated moderate risk ({model_risk:.2%})."40 )41 else:42 explanation_parts.append(43 f"The ML model indicated low risk ({model_risk:.2%})."44 )45 46 # 3. Rule-based contribution47 if rules_triggered:48 explanation_parts.append(49 f"Additionally, {len(rules_triggered)} risk rule(s) were triggered:"50 )51 for rule in rules_triggered:52 explanation_parts.append(f" • {rule}")53 else:54 explanation_parts.append("No specific risk rules were triggered.")55 56 # 4. Key risk factors57 risk_factors = []58 59 amount = derived_features.get("transaction_amount", 0)60 if amount > 100000:61 risk_factors.append(f"Very high transaction amount (₹{amount:,.2f})")62 elif amount > 50000:63 risk_factors.append(f"High transaction amount (₹{amount:,.2f})")64 65 if derived_features.get("kyc_verified", 1) == 0:66 risk_factors.append("Account not KYC verified")67 68 account_age = derived_features.get("account_age_days", 999)69 if account_age < 10:70 risk_factors.append(f"Very new account ({account_age} days old)")71 elif account_age < 30:72 risk_factors.append(f"New account ({account_age} days old)")73 74 if derived_features.get("is_night_txn", 0) == 1:75 risk_factors.append("Transaction during night hours (10 PM - 6 AM)")76 77 if derived_features.get("is_weekend_txn", 0) == 1:78 risk_factors.append("Weekend transaction")79 80 if derived_features.get("is_holiday_txn", 0) == 1:81 risk_factors.append("Transaction on a public holiday")82 83 if risk_factors:84 explanation_parts.append("\nKey risk factors identified:")85 for factor in risk_factors[:5]: # Limit to top 586 explanation_parts.append(f" • {factor}")87 88 # 5. Recommendation89 if is_fraud:90 if risk_score > 0.8:91 explanation_parts.append(92 "\n🚨 RECOMMENDATION: Block this transaction and contact the customer immediately."93 )94 elif risk_score > 0.6:95 explanation_parts.append(96 "\n⚠️ RECOMMENDATION: Review this transaction and consider additional verification."97 )98 else:99 explanation_parts.append(100 "\n✓ RECOMMENDATION: Transaction can proceed with standard monitoring."101 )102 103 return "\n".join(explanation_parts)104 105 106def generate_explanation_simple(risk_score: float, is_fraud: int, 107 rules_triggered: list) -> str:108 """109 Simple fallback explanation generator110 """111 status = "fraudulent" if is_fraud else "legitimate"112 113 explanation = f"This transaction is classified as {status} with a risk score of {risk_score:.2%}."114 115 if rules_triggered:116 explanation += f" The following risk indicators were detected: {', '.join(rules_triggered)}."117 else:118 explanation += " No specific risk indicators were detected."119 120 return explanation121 122 123# Optional: Advanced HuggingFace model integration124# Uncomment and modify if you want to use actual LLM generation125 126"""127from transformers import pipeline128import logging129 130try:131 # Load a small generative model132 generator = pipeline(133 "text-generation",134 model="distilgpt2",135 max_new_tokens=150,136 temperature=0.7137 )138 HF_MODEL_AVAILABLE = True139 logging.info("✅ HuggingFace model loaded successfully")140except Exception as e:141 HF_MODEL_AVAILABLE = False142 logging.warning(f"⚠️ HuggingFace model not available: {e}")143 generator = None144 145 146def generate_explanation_with_llm(transaction_data: dict, derived_features: dict,147 risk_score: float, rule_score: float,148 rules_triggered: list) -> str:149 '''150 Generate explanation using LLM (if available)151 '''152 if not HF_MODEL_AVAILABLE or generator is None:153 return generate_explanation(transaction_data, derived_features, 154 risk_score, rule_score, rules_triggered)155 156 try:157 prompt = f'''158 Fraud Detection Analysis:159 - Risk Score: {risk_score:.2%}160 - Amount: ₹{derived_features.get("transaction_amount", 0):,.2f}161 - KYC Verified: {"Yes" if derived_features.get("kyc_verified") == 1 else "No"}162 - Account Age: {derived_features.get("account_age_days", 0)} days163 - Rules Triggered: {", ".join(rules_triggered) if rules_triggered else "None"}164 165 Explain why this transaction is {"fraudulent" if risk_score >= 0.6 else "legitimate"}:166 '''167 168 result = generator(prompt, max_new_tokens=150, do_sample=True)[0]["generated_text"]169 170 # Extract only the generated part (after the prompt)171 if prompt in result:172 explanation = result.split(prompt)[-1].strip()173 else:174 explanation = result.strip()175 176 return explanation177 178 except Exception as e:179 logging.error(f"LLM generation failed: {e}")180 return generate_explanation(transaction_data, derived_features,181 risk_score, rule_score, rules_triggered)182"""