| """ |
| Module 8: Generate Architecture Diagram |
| System architecture visualization. |
| """ |
| import os, sys |
| sys.path.insert(0, '/app/fraud_detection') |
| import matplotlib |
| matplotlib.use('Agg') |
| import matplotlib.pyplot as plt |
| import matplotlib.patches as mpatches |
| from matplotlib.patches import FancyBboxPatch, FancyArrowPatch |
| import numpy as np |
|
|
| from config import FIGURES_DIR, FIG_DPI, FIG_BG |
|
|
|
|
| def draw_architecture(): |
| """Draw the system architecture diagram.""" |
| fig, ax = plt.subplots(1, 1, figsize=(16, 10), facecolor=FIG_BG) |
| ax.set_xlim(0, 16) |
| ax.set_ylim(0, 10) |
| ax.axis('off') |
| |
| |
| c_input = '#3498db' |
| c_process = '#2ecc71' |
| c_model = '#e74c3c' |
| c_output = '#f39c12' |
| c_storage = '#9b59b6' |
| |
| def box(x, y, w, h, text, color, fontsize=9): |
| rect = FancyBboxPatch((x, y), w, h, boxstyle="round,pad=0.1", |
| facecolor=color, edgecolor='black', linewidth=1.5, alpha=0.85) |
| ax.add_patch(rect) |
| ax.text(x + w/2, y + h/2, text, ha='center', va='center', |
| fontsize=fontsize, fontweight='bold', color='white', |
| multialignment='center') |
| |
| def arrow(x1, y1, x2, y2): |
| ax.annotate('', xy=(x2, y2), xytext=(x1, y1), |
| arrowprops=dict(arrowstyle='->', color='black', lw=2)) |
| |
| |
| ax.text(8, 9.5, 'Fraud Detection System Architecture', ha='center', |
| fontsize=16, fontweight='bold', color='#2c3e50') |
| |
| |
| box(0.5, 7.5, 3, 1, 'Transaction\nStream', c_input, 10) |
| box(4, 7.5, 3, 1, 'Feature\nEngineering\n(12 features)', c_process, 9) |
| box(7.5, 7.5, 3, 1, 'RobustScaler\n(Fit on Train)', c_process, 9) |
| |
| arrow(3.5, 8, 4, 8) |
| arrow(7, 8, 7.5, 8) |
| |
| |
| box(0.5, 5, 2.2, 1.2, 'Logistic\nRegression', c_model, 8) |
| box(3, 5, 2.2, 1.2, 'Random\nForest', c_model, 8) |
| box(5.5, 5, 2.2, 1.2, 'XGBoost\n(Best)', c_model, 8) |
| box(8, 5, 2.2, 1.2, 'LightGBM', c_model, 8) |
| box(10.5, 5, 2.2, 1.2, 'MLP\nNeural Net', c_model, 8) |
| box(13, 5, 2.5, 1.2, 'Autoencoder\n(Anomaly)', c_model, 8) |
| |
| |
| for x in [1.6, 4.1, 6.6, 9.1, 11.6, 14.25]: |
| arrow(9, 7.5, x, 6.2) |
| |
| |
| box(3, 2.8, 4, 1.2, 'Voting Ensemble\n(XGB + LGBM + RF)', c_output, 10) |
| box(8, 2.8, 4, 1.2, 'Optuna Tuning\n(Hyperparameter Opt)', c_storage, 9) |
| |
| arrow(5, 5, 5, 4) |
| arrow(10, 5, 10, 4) |
| arrow(8, 3.4, 7, 3.4) |
| |
| |
| box(3, 0.5, 4, 1.5, 'FastAPI\nPOST /predict\n< 10ms latency', c_input, 9) |
| box(8, 0.5, 4, 1.5, 'Decision\nFraud Prob + Risk Level\n+ Top Risk Factors', c_output, 9) |
| |
| arrow(5, 2.8, 5, 2) |
| arrow(7, 1.25, 8, 1.25) |
| |
| |
| box(12.5, 7.5, 3, 1, 'Monitoring\nDrift Detection\nRetraining', c_storage, 9) |
| arrow(10.5, 8, 12.5, 8) |
| |
| |
| box(12.5, 2.8, 3, 1.2, 'Explainability\nSHAP + LIME', c_process, 9) |
| arrow(12, 5, 14, 4) |
| |
| plt.tight_layout() |
| plt.savefig(os.path.join(FIGURES_DIR, "architecture_diagram.png"), dpi=FIG_DPI, bbox_inches='tight', facecolor=FIG_BG) |
| plt.savefig(os.path.join(FIGURES_DIR, "architecture_diagram.pdf"), bbox_inches='tight', facecolor=FIG_BG) |
| plt.close() |
| print("Saved: architecture_diagram.png/pdf") |
|
|
|
|
| if __name__ == "__main__": |
| draw_architecture() |
|
|