File size: 19,797 Bytes
1801261 abd202e e01bb8b abd202e 1801261 abd202e 1801261 abd202e 1801261 abd202e 1801261 abd202e e01bb8b abd202e 1801261 abd202e 1801261 abd202e 1801261 abd202e 1801261 abd202e fdd2b68 abd202e 1801261 abd202e fdd2b68 abd202e 1801261 fdd2b68 abd202e fdd2b68 1801261 abd202e 1801261 abd202e 1801261 abd202e 1801261 abd202e 1801261 abd202e fdd2b68 e01bb8b fdd2b68 abd202e fdd2b68 1801261 abd202e 1801261 abd202e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 |
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"""
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px; margin: 20px 0;">
<div style="background: linear-gradient(135deg, #007bff, #0056b3); color: white; padding: 20px; border-radius: 15px; text-align: center; box-shadow: 0 4px 15px rgba(0,123,255,0.3);">
<div style="font-size: 2.5rem; font-weight: bold; margin-bottom: 5px;">{accuracy:.1%}</div>
<div style="font-size: 1.1rem;">🎯 Accuracy</div>
</div>
<div style="background: linear-gradient(135deg, #28a745, #20c997); color: white; padding: 20px; border-radius: 15px; text-align: center; box-shadow: 0 4px 15px rgba(40,167,69,0.3);">
<div style="font-size: 2.5rem; font-weight: bold; margin-bottom: 5px;">{precision:.1%}</div>
<div style="font-size: 1.1rem;">🎯 Precision</div>
</div>
<div style="background: linear-gradient(135deg, #ffc107, #fd7e14); color: white; padding: 20px; border-radius: 15px; text-align: center; box-shadow: 0 4px 15px rgba(255,193,7,0.3);">
<div style="font-size: 2.5rem; font-weight: bold; margin-bottom: 5px;">{recall:.1%}</div>
<div style="font-size: 1.1rem;">📊 Recall</div>
</div>
<div style="background: linear-gradient(135deg, #17a2b8, #138496); color: white; padding: 20px; border-radius: 15px; text-align: center; box-shadow: 0 4px 15px rgba(23,162,184,0.3);">
<div style="font-size: 2.5rem; font-weight: bold; margin-bottom: 5px;">{f1:.1%}</div>
<div style="font-size: 1.1rem">⚖️ F1 Score</div>
</div>
</div>
<div style="background: #d4edda; border: 1px solid #c3e6cb; color: #155724; padding: 15px; border-radius: 10px; margin-top: 15px; text-align: center;">
<strong>✅ Model trained successfully on 1,000 synthetic SAP AR records!</strong><br>
<em>The model is now ready to make predictions on unpaid invoices.</em>
</div>
"""
return fig, metrics_html, gr.update(interactive=True, variant="primary")
except Exception as e:
error_html = f"""
<div style="background: #f8d7da; border: 1px solid #f5c6cb; color: #721c24; padding: 15px; border-radius: 10px; text-align: center;">
<strong>❌ Training failed:</strong> {str(e)}
</div>
"""
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 = """
<div style="background: #f8d7da; border: 1px solid #f5c6cb; color: #721c24; padding: 15px; border-radius: 10px; text-align: center;">
<strong>❌ Please train the model first!</strong><br>
<em>Go to the Model Training tab and click "Train ML Model"</em>
</div>
"""
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"""
<div style="background: #d4edda; border: 1px solid #c3e6cb; color: #155724; padding: 20px; border-radius: 10px; margin: 15px 0;">
<div style="text-align: center; margin-bottom: 15px;">
<strong style="font-size: 1.2rem;">🔮 Prediction Results Generated Successfully!</strong>
</div>
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; text-align: center;">
<div style="background: rgba(40, 167, 69, 0.1); padding: 15px; border-radius: 8px; border: 2px solid #28a745;">
<div style="font-size: 2rem; font-weight: bold; color: #28a745;">{will_pay}</div>
<div style="font-weight: bold;">✅ Will Pay</div>
</div>
<div style="background: rgba(220, 53, 69, 0.1); padding: 15px; border-radius: 8px; border: 2px solid #dc3545;">
<div style="font-size: 2rem; font-weight: bold; color: #dc3545;">{risk_default}</div>
<div style="font-weight: bold;">❌ Risk of Default</div>
</div>
<div style="background: rgba(255, 193, 7, 0.1); padding: 15px; border-radius: 8px; border: 2px solid #ffc107;">
<div style="font-size: 2rem; font-weight: bold; color: #856404;">{high_risk}</div>
<div style="font-weight: bold;">🔴 High Risk</div>
</div>
</div>
</div>
"""
return results_df, success_msg, fig
except Exception as e:
error_msg = f"""
<div style="background: #f8d7da; border: 1px solid #f5c6cb; color: #721c24; padding: 15px; border-radius: 10px; text-align: center;">
<strong>❌ Prediction failed:</strong> {str(e)}
</div>
"""
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("""
<div class="main-header">
<h1 style="font-size: 2.5rem; margin-bottom: 15px; text-shadow: 2px 2px 4px rgba(0,0,0,0.5); color: white; font-weight: bold;">
🏢 SAP Account Receivable ML Prediction Demo
</h1>
<p style="font-size: 1.2rem; color: rgba(255,255,255,0.9); margin: 0; text-shadow: 1px 1px 2px rgba(0,0,0,0.3);">
Machine Learning-powered invoice payment prediction system using TensorFlow
</p>
</div>
""")
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) |