WickedFaith's picture
Upload 77 files
3efedb0 verified
raw
history blame contribute delete
13.7 kB
import sys
import os
# Add the project root directory to the path
project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(project_root)
print(f"Project root: {project_root}")
print(f"Python path: {sys.path}")
# Import models
from src.api.loan_model import LoanApprovalModel
from src.api.attrition_model import AttritionModel
from src.api.diabetes_model import DiabetesModel
from src.api.liver_model import LiverDiseaseModel
from fastapi import FastAPI, HTTPException, Depends
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import List, Optional, Dict, Union, Any
from src.data.database import Application, Prediction, get_db, SessionLocal
import json
import os
from datetime import datetime
import logging
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI(
title="Multi-Model Prediction API",
description="API for predicting loan approval, employee attrition, diabetes risk, and liver disease",
version="1.0.0"
)
# Add CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Allows all origins
allow_credentials=True,
allow_methods=["*"], # Allows all methods
allow_headers=["*"], # Allows all headers
)
# Set up model paths
model_dir = os.path.join(project_root, "models")
print(f"Model directory: {model_dir}")
# Load the trained model
loan_model = LoanApprovalModel(model_dir=model_dir)
# Fix the import for liver disease model
try:
from src.api.liver_disease_model import LiverDiseaseModel
except ImportError:
try:
from liver_disease_model import LiverDiseaseModel
except ImportError:
print("Warning: Could not import LiverDiseaseModel")
# Load models
try:
attrition_model = AttritionModel()
diabetes_model = DiabetesModel()
liver_model = LiverDiseaseModel() # Use the correct class name
logger.info("All models loaded successfully")
except Exception as e:
logger.error(f"Error loading models: {str(e)}")
# Continue execution even if model loading fails
# Models will be initialized as needed
# Define response model for predictions
class PredictionResponse(BaseModel):
prediction: bool
probability: float
feature_importance: Optional[List[float]] = None
# Define request model for attrition prediction
class AttritionPredictionRequest(BaseModel):
Age: int
DistanceFromHome: int
EnvironmentSatisfaction: int
JobLevel: int
JobSatisfaction: int
MonthlyIncome: int
OverTime: str
TotalWorkingYears: int
WorkLifeBalance: int
YearsAtCompany: int
class LoanFeatures(BaseModel):
no_of_dependents: int
education: str
self_employed: str
income_annum: float
loan_amount: float
loan_term: int
cibil_score: int
residential_assets_value: float
commercial_assets_value: float
luxury_assets_value: float
bank_asset_value: float
@app.post("/predict")
async def predict(request: Dict[str, Any]):
try:
model_type = request.get("model_type", "").lower()
features = request.get("features", {})
if model_type == "liver":
result = liver_model.predict(features)
return {
"prediction": result["prediction"],
"probability": result["probability"],
"feature_importance": liver_model.get_feature_importance()
}
elif model_type == "diabetes":
result = diabetes_model.predict(features)
return {
"prediction": result["prediction"],
"probability": result["probability"],
"feature_importance": diabetes_model.get_feature_importance()
}
elif model_type == "attrition":
result = attrition_model.predict(features)
return {
"prediction": result["prediction"],
"probability": result["probability"],
"feature_importance": attrition_model.get_feature_importance()
}
elif model_type == "loan":
result = loan_model.predict(features)
return {
"prediction": result["prediction"],
"probability": result["probability"],
"feature_importance": loan_model.get_feature_importance()
}
else:
raise HTTPException(status_code=400, detail=f"Unknown model type: {model_type}")
except Exception as e:
logger.error(f"Error in prediction: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
@app.post("/predict/attrition", response_model=PredictionResponse)
async def predict_attrition(request: AttritionPredictionRequest):
try:
# Convert request to dictionary
features = request.dict()
# Make prediction
result = attrition_model.predict(features)
return result
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# Update the liver disease endpoint to use the correct model variable
@app.post("/predict/liver", response_model=PredictionResponse)
async def predict_liver_disease(request: Dict[str, Any]):
try:
# Make prediction using the liver_model variable
result = liver_model.predict(request)
# Get feature importance if available
feature_importance = None
if hasattr(liver_model, 'get_feature_importance') and callable(getattr(liver_model, 'get_feature_importance')):
feature_importance = liver_model.get_feature_importance()
# Return prediction result
return {
"prediction": result["prediction"],
"probability": result["probability"],
"feature_importance": feature_importance
}
except Exception as e:
logger.error(f"Error in liver disease prediction: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
# Add this endpoint if it doesn't exist
@app.post("/predict/loan", response_model=PredictionResponse)
async def predict_loan(request: Dict[str, Any]):
try:
# Extract features from request
features = request.get("features", request) # Handle both formats
# Make prediction
result = loan_model.predict(features)
# Get feature importance
feature_importance = None
if hasattr(loan_model, 'get_feature_importance') and callable(getattr(loan_model, 'get_feature_importance')):
try:
feature_importance = loan_model.get_feature_importance()
except Exception as e:
logger.warning(f"Error getting feature importance: {str(e)}")
# Provide dummy feature importance values
feature_importance = [0.2, 0.15, 0.15, 0.1, 0.1, 0.08, 0.07, 0.05, 0.05, 0.03, 0.02]
else:
# If method doesn't exist, provide dummy values
logger.warning("get_feature_importance method not found, using dummy values")
feature_importance = [0.2, 0.15, 0.15, 0.1, 0.1, 0.08, 0.07, 0.05, 0.05, 0.03, 0.02]
# Return prediction result
return {
"prediction": result["prediction"],
"probability": result["probability"],
"feature_importance": feature_importance
}
except Exception as e:
logger.error(f"Error in loan prediction: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
@app.post("/predict/loan_approval")
async def predict_loan_approval(features: LoanFeatures):
"""Predict loan approval based on applicant features."""
try:
# Convert Pydantic model to dict
features_dict = features.dict()
# Log input features for debugging
logger.info(f"Input features: {features_dict}")
# Calculate derived metrics
monthly_income = features_dict['income_annum'] / 12
total_assets = (
features_dict['residential_assets_value'] +
features_dict['commercial_assets_value'] +
features_dict['luxury_assets_value'] +
features_dict['bank_asset_value']
)
# Calculate monthly EMI (Equated Monthly Installment)
annual_interest_rate = 0.10 # 10% annual interest rate
monthly_rate = annual_interest_rate / 12
loan_term_months = features_dict['loan_term'] * 12
monthly_payment = (features_dict['loan_amount'] * monthly_rate * (1 + monthly_rate)**loan_term_months) / ((1 + monthly_rate)**loan_term_months - 1)
# Calculate key ratios
debt_to_income = monthly_payment / monthly_income
asset_to_loan = total_assets / features_dict['loan_amount']
# Make prediction
result, probability, feature_importance = loan_model.predict(features_dict)
# Generate personalized explanation
explanation = []
# Credit Score Analysis
if features_dict['cibil_score'] >= 750:
explanation.append("Your excellent CIBIL score of {score} significantly strengthens your application.".format(
score=features_dict['cibil_score']
))
elif features_dict['cibil_score'] >= 650:
explanation.append("Your fair CIBIL score of {score} is acceptable but could be improved.".format(
score=features_dict['cibil_score']
))
else:
explanation.append("Your CIBIL score of {score} is below the preferred threshold.".format(
score=features_dict['cibil_score']
))
# Income and EMI Analysis
if debt_to_income <= 0.3:
explanation.append("Your monthly loan payment (₹{emi:,.2f}) represents {ratio:.1%} of your monthly income (₹{income:,.2f}), which is very manageable.".format(
emi=monthly_payment,
ratio=debt_to_income,
income=monthly_income
))
elif debt_to_income <= 0.5:
explanation.append("Your monthly loan payment (₹{emi:,.2f}) represents {ratio:.1%} of your monthly income (₹{income:,.2f}), which is moderate but acceptable.".format(
emi=monthly_payment,
ratio=debt_to_income,
income=monthly_income
))
else:
explanation.append("Your monthly loan payment (₹{emi:,.2f}) represents {ratio:.1%} of your monthly income (₹{income:,.2f}), which is relatively high.".format(
emi=monthly_payment,
ratio=debt_to_income,
income=monthly_income
))
# Asset Coverage Analysis
if asset_to_loan >= 2:
explanation.append("Your total assets (₹{assets:,.2f}) provide excellent coverage at {ratio:.1f}x the loan amount.".format(
assets=total_assets,
ratio=asset_to_loan
))
elif asset_to_loan >= 1:
explanation.append("Your total assets (₹{assets:,.2f}) adequately cover the loan amount at {ratio:.1f}x.".format(
assets=total_assets,
ratio=asset_to_loan
))
else:
explanation.append("Your total assets (₹{assets:,.2f}) provide limited coverage at {ratio:.1f}x the loan amount.".format(
assets=total_assets,
ratio=asset_to_loan
))
# Employment Status
if features_dict['self_employed'] == "Yes":
explanation.append("As a self-employed individual, income stability is a key consideration.")
else:
explanation.append("Your salaried employment status provides income stability.")
# Education
if features_dict['education'] == "Graduate":
explanation.append("Your graduate education is viewed favorably.")
# Dependents
if features_dict['no_of_dependents'] > 2:
explanation.append("Having {deps} dependents increases your financial responsibilities.".format(
deps=features_dict['no_of_dependents']
))
# Format response
response = {
"prediction": result,
"probability": float(probability),
"feature_importance": {k: float(v) for k, v in feature_importance.items()},
"explanation": explanation,
"financial_metrics": {
"monthly_income": float(monthly_income),
"monthly_payment": float(monthly_payment),
"debt_to_income": float(debt_to_income),
"asset_to_loan": float(asset_to_loan),
"total_assets": float(total_assets)
}
}
logger.info(f"Prediction response: {response}")
return response
except Exception as e:
logger.error(f"Error making prediction: {str(e)}")
logger.exception("Detailed traceback:")
raise HTTPException(status_code=500, detail=str(e))
@app.get("/health")
async def health_check():
return {"status": "healthy"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=8000)