import gradio as gr import numpy as np import pandas as pd import tensorflow as tf from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score from sklearn.model_selection import train_test_split import plotly.graph_objects as go import plotly.express as px from datetime import datetime, timedelta import random import time class SAPARPredictor: def __init__(self): self.model = None self.training_history = None self.is_trained = False def generate_synthetic_data(self, n_samples=1000): """Generate synthetic SAP AR data""" np.random.seed(42) # For reproducibility customers = ['CUST001', 'CUST002', 'CUST003', 'CUST004', 'CUST005', 'CUST006', 'CUST007', 'CUST008'] data = [] for i in range(n_samples): invoice_amount = np.random.uniform(1000, 51000) customer_code = np.random.choice(customers) days_overdue = np.random.randint(0, 120) previous_delays = np.random.randint(0, 5) credit_score = np.random.uniform(0, 100) industry_risk = np.random.uniform(0, 1) seasonality = np.sin((i % 365) * 2 * np.pi / 365) # Create correlation between features and payment probability payment_prob = 0.7 payment_prob -= min(days_overdue / 100, 0.4) payment_prob -= min(previous_delays / 10, 0.3) payment_prob += (credit_score - 50) / 200 payment_prob -= industry_risk * 0.2 payment_prob += seasonality * 0.1 payment_prob = max(0.05, min(0.95, payment_prob)) paid_on_time = 1 if np.random.random() < payment_prob else 0 data.append({ 'invoice_amount': invoice_amount / 50000, # Normalize 'days_overdue': days_overdue / 120, # Normalize 'previous_delays': previous_delays / 5, # Normalize 'credit_score': credit_score / 100, # Already normalized 'industry_risk': industry_risk, 'seasonality': (seasonality + 1) / 2, # Normalize to 0-1 'paid_on_time': paid_on_time }) return pd.DataFrame(data) def train_model(self, progress=gr.Progress()): """Train the ML model with progress tracking""" try: progress(0, desc="🔄 Generating synthetic data...") # Generate training data df = self.generate_synthetic_data(1000) time.sleep(0.5) # Simulate data generation time progress(0.2, desc="📊 Preparing features and labels...") # Prepare features and labels feature_columns = ['invoice_amount', 'days_overdue', 'previous_delays', 'credit_score', 'industry_risk', 'seasonality'] X = df[feature_columns].values y = df['paid_on_time'].values # Split data X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) progress(0.3, desc="🧠 Building neural network...") # Create model self.model = tf.keras.Sequential([ tf.keras.layers.Dense(32, activation='relu', input_shape=(6,)), tf.keras.layers.Dropout(0.2), tf.keras.layers.Dense(16, activation='relu'), tf.keras.layers.Dropout(0.2), tf.keras.layers.Dense(1, activation='sigmoid') ]) self.model.compile( optimizer=tf.keras.optimizers.Adam(0.001), loss='binary_crossentropy', metrics=['accuracy'] ) progress(0.4, desc="🎯 Training model (50 epochs)...") # Train model history = self.model.fit( X_train, y_train, epochs=50, batch_size=32, validation_split=0.2, verbose=0 ) progress(0.8, desc="📈 Evaluating model performance...") # Make predictions on test set y_pred_proba = self.model.predict(X_test, verbose=0) y_pred = (y_pred_proba > 0.5).astype(int) # Calculate metrics accuracy = accuracy_score(y_test, y_pred) precision = precision_score(y_test, y_pred) recall = recall_score(y_test, y_pred) f1 = f1_score(y_test, y_pred) self.training_history = history.history self.is_trained = True progress(1.0, desc="✅ Training completed successfully!") # Create training visualization fig = go.Figure() epochs = list(range(1, len(history.history['accuracy']) + 1)) fig.add_trace(go.Scatter( x=epochs, y=history.history['accuracy'], mode='lines+markers', name='Training Accuracy', line=dict(color='#007bff', width=4), marker=dict(size=8) )) fig.add_trace(go.Scatter( x=epochs, y=history.history['val_accuracy'], mode='lines+markers', name='Validation Accuracy', line=dict(color='#28a745', width=4), marker=dict(size=8) )) fig.update_layout( title={ 'text': '📊 Model Training Progress', 'x': 0.5, 'font': {'size': 20} }, xaxis_title='Epoch', yaxis_title='Accuracy', template='plotly_white', #height=450, hovermode='x unified', legend=dict( yanchor="bottom", y=0.02, xanchor="right", x=0.98 ) ) # Create metrics cards HTML metrics_html = f"""
{accuracy:.1%}
🎯 Accuracy
{precision:.1%}
🎯 Precision
{recall:.1%}
📊 Recall
{f1:.1%}
⚖️ F1 Score
✅ Model trained successfully on 1,000 synthetic SAP AR records!
The model is now ready to make predictions on unpaid invoices.
""" return fig, metrics_html, gr.update(interactive=True, variant="primary") except Exception as e: error_html = f"""
❌ Training failed: {str(e)}
""" return None, error_html, gr.update(interactive=False) def generate_unpaid_invoices(self): """Generate sample unpaid invoices for prediction""" customers = ['SAP-CUST001', 'SAP-CUST002', 'SAP-CUST003', 'SAP-CUST004', 'SAP-CUST005'] invoices = [] for i in range(12): invoice_id = f"INV-{datetime.now().strftime('%Y%m%d')}-{i:03d}" customer = random.choice(customers) amount = random.randint(5000, 50000) days_overdue = random.randint(0, 90) previous_delays = random.randint(0, 4) credit_score = random.randint(40, 100) invoices.append({ 'Invoice ID': invoice_id, 'Customer': customer, 'Amount ($)': amount, 'Days Overdue': days_overdue, 'Previous Delays': previous_delays, 'Credit Score': credit_score, 'Industry Risk': round(random.random(), 3), 'Seasonality': round(random.random(), 3) }) return pd.DataFrame(invoices) def make_predictions(self): """Make predictions on unpaid invoices""" if not self.is_trained: error_msg = """
❌ Please train the model first!
Go to the Model Training tab and click "Train ML Model"
""" return None, error_msg, None try: # Generate unpaid invoices df = self.generate_unpaid_invoices() # Prepare features for prediction features = [] for _, row in df.iterrows(): features.append([ row['Amount ($)'] / 50000, # Normalize row['Days Overdue'] / 120, # Normalize row['Previous Delays'] / 5, # Normalize row['Credit Score'] / 100, # Normalize row['Industry Risk'], row['Seasonality'] ]) # Make predictions predictions = self.model.predict(np.array(features), verbose=0) # Create results dataframe with better formatting results_df = df.copy() prob_values = [p[0] for p in predictions] # Add prediction columns results_df['Payment Probability'] = [f"{p:.1%}" for p in prob_values] results_df['Prediction'] = ['✅ Will Pay' if p > 0.5 else '❌ Risk of Default' for p in prob_values] results_df['Risk Level'] = ['🟢 Low Risk' if p > 0.7 else '🟡 Medium Risk' if p > 0.4 else '🔴 High Risk' for p in prob_values] # Format amount column results_df['Amount ($)'] = results_df['Amount ($)'].apply(lambda x: f"${x:,}") # Reorder columns for better display column_order = ['Invoice ID', 'Customer', 'Amount ($)', 'Days Overdue', 'Credit Score', 'Payment Probability', 'Prediction', 'Risk Level'] results_df = results_df[column_order] # Create probability distribution chart fig = go.Figure() # Create histogram fig.add_trace(go.Histogram( x=prob_values, nbinsx=15, marker_color='rgba(0, 123, 255, 0.7)', marker_line_color='rgba(0, 123, 255, 1)', marker_line_width=2, name='Payment Probability' )) # Add vertical lines for risk thresholds fig.add_vline(x=0.4, line_dash="dash", line_color="orange", annotation_text="Medium Risk Threshold") fig.add_vline(x=0.7, line_dash="dash", line_color="green", annotation_text="Low Risk Threshold") fig.update_layout( title={ 'text': '📊 Distribution of Payment Probabilities', 'x': 0.5, 'font': {'size': 18} }, xaxis_title='Payment Probability', yaxis_title='Number of Invoices', template='plotly_white', #height=400, showlegend=False ) # Count predictions by category will_pay = sum(1 for p in prob_values if p > 0.5) risk_default = len(prob_values) - will_pay high_risk = sum(1 for p in prob_values if p <= 0.4) success_msg = f"""
🔮 Prediction Results Generated Successfully!
{will_pay}
✅ Will Pay
{risk_default}
❌ Risk of Default
{high_risk}
🔴 High Risk
""" return results_df, success_msg, fig except Exception as e: error_msg = f"""
❌ Prediction failed: {str(e)}
""" return None, error_msg, None # Initialize the predictor predictor = SAPARPredictor() # Create Gradio interface with improved layout with gr.Blocks( theme=gr.themes.Soft( primary_hue="blue", secondary_hue="green", neutral_hue="slate" ), title="SAP AR ML Prediction Demo", css=""" .gradio-container { max-width: 1400px !important; margin: 0 auto !important; } .main-header { text-align: center; margin-bottom: 2rem; padding: 2rem; background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%); border-radius: 15px; color: white; margin-bottom: 30px; box-shadow: 0 8px 32px rgba(0,0,0,0.2); } .tab-nav { margin-bottom: 20px; } """ ) as demo: gr.HTML("""

🏢 SAP Account Receivable ML Prediction Demo

Machine Learning-powered invoice payment prediction system using TensorFlow

""") with gr.Tabs() as tabs: with gr.Tab("🎯 Model Training", id=0): with gr.Row(): with gr.Column(scale=2): gr.Markdown(""" ### 🚀 Train Your ML Model This will create a neural network trained on **1,000 synthetic SAP AR records** to predict invoice payment likelihood. The model analyzes multiple factors including invoice amount, days overdue, customer credit score, and payment history. """) train_btn = gr.Button( "🚀 Train ML Model", variant="primary", size="lg", scale=1 ) with gr.Column(scale=1): gr.Markdown(""" ### 📋 Model Features - Invoice Amount - Days Overdue - Previous Delays - Credit Score - Industry Risk - Seasonality """) metrics_display = gr.HTML() with gr.Row(): training_plot = gr.Plot(label="📈 Training Progress") with gr.Row(): predict_btn = gr.Button( "🔮 Generate Predictions", variant="secondary", interactive=False, size="lg" ) with gr.Tab("📊 Invoice Predictions", id=1): gr.Markdown(""" ### 🔮 Real-time Payment Predictions View ML-powered predictions for unpaid invoices with probability scores and risk assessments. """) prediction_status = gr.HTML() # Changed layout to stack vertically instead of side by side with gr.Column(): predictions_df = gr.Dataframe( label="📋 Invoice Predictions", interactive=False, wrap=True, # height=400 ) probability_plot = gr.Plot(label="📊 Probability Distribution") # Event handlers train_btn.click( fn=predictor.train_model, outputs=[training_plot, metrics_display, predict_btn], show_progress=True ) predict_btn.click( fn=predictor.make_predictions, outputs=[predictions_df, prediction_status, probability_plot] ) # Launch the app if __name__ == "__main__": demo.launch(share=True)