bcs / app.py
XRachel's picture
Upload 4 files
6ab0f04 verified
import os
import math
from pathlib import Path
import gradio as gr
import pandas as pd
REQUIRED_COLUMNS = [
"CreditScore",
"Age",
"Balance",
"NumOfProducts",
"IsActiveMember",
"EstimatedSalary",
]
def clamp(x, low=0.0, high=1.0):
return max(low, min(high, x))
def churn_probability(
credit_score,
age,
balance,
num_products,
is_active_member,
estimated_salary,
):
score = -1.2
score += max(age - 40, 0) * 0.04
score += max(650 - credit_score, 0) * 0.003
score += min(balance / 100000.0, 2.0) * 0.45
score += 0.35 if int(num_products) <= 1 else -0.15
score += -0.55 if int(is_active_member) == 1 else 0.35
score += min(estimated_salary / 200000.0, 1.0) * 0.08
prob = 1 / (1 + math.exp(-score))
return clamp(prob)
def risk_label(prob):
if prob < 0.30:
return "Low"
if prob < 0.60:
return "Medium"
return "High"
def predict_single(
credit_score,
age,
balance,
num_products,
is_active_member,
estimated_salary,
):
p = churn_probability(
float(credit_score),
float(age),
float(balance),
float(num_products),
int(is_active_member),
float(estimated_salary),
)
label = 1 if p >= 0.5 else 0
summary = (
f"### Prediction Result\n\n"
f"- Churn probability: **{p:.1%}**\n"
f"- Predicted class: **{label}**\n"
f"- Risk level: **{risk_label(p)}**"
)
table = pd.DataFrame(
{
"metric": ["churn_probability", "predicted_class", "risk_level"],
"value": [round(p, 4), label, risk_label(p)],
}
)
return summary, table
def predict_batch(file):
if file is None:
return None, "Please upload a CSV file."
try:
df = pd.read_csv(file.name)
except Exception as e:
return None, f"Could not read CSV: {e}"
missing = [c for c in REQUIRED_COLUMNS if c not in df.columns]
if missing:
return None, f"Missing required columns: {missing}"
probs = []
preds = []
for _, row in df.iterrows():
p = churn_probability(
row["CreditScore"],
row["Age"],
row["Balance"],
row["NumOfProducts"],
row["IsActiveMember"],
row["EstimatedSalary"],
)
probs.append(round(p, 4))
preds.append(1 if p >= 0.5 else 0)
out = df.copy()
out["churn_probability"] = probs
out["churn_prediction"] = preds
output_path = Path("/tmp/bank_churn_predictions.csv")
out.to_csv(output_path, index=False)
return str(output_path), f"Done. Processed {len(out)} rows."
def sample_csv():
df = pd.DataFrame(
[
[600, 45, 50000, 1, 0, 70000],
[720, 31, 12000, 2, 1, 85000],
],
columns=REQUIRED_COLUMNS,
)
path = Path("/tmp/sample_bank_churn_input.csv")
df.to_csv(path, index=False)
return str(path)
def build_ui():
with gr.Blocks() as demo:
gr.Markdown("# 🏦 Bank Churn Simple App")
gr.Markdown(
"This is a lightweight version built to reduce Hugging Face startup issues."
)
with gr.Tab("Single Prediction"):
credit_score = gr.Slider(300, 900, value=650, step=1, label="CreditScore")
age = gr.Slider(18, 100, value=40, step=1, label="Age")
balance = gr.Number(value=50000, label="Balance")
num_products = gr.Slider(1, 4, value=2, step=1, label="NumOfProducts")
is_active_member = gr.Dropdown(
choices=[0, 1], value=1, label="IsActiveMember"
)
estimated_salary = gr.Number(value=80000, label="EstimatedSalary")
predict_btn = gr.Button("Predict")
summary_out = gr.Markdown()
table_out = gr.Dataframe()
predict_btn.click(
fn=predict_single,
inputs=[
credit_score,
age,
balance,
num_products,
is_active_member,
estimated_salary,
],
outputs=[summary_out, table_out],
)
with gr.Tab("CSV Batch Prediction"):
gr.Markdown("Required columns: " + ", ".join(REQUIRED_COLUMNS))
input_file = gr.File(label="Upload CSV", file_types=[".csv"])
batch_btn = gr.Button("Run Batch Prediction")
output_file = gr.File(label="Download Results")
batch_msg = gr.Markdown()
sample_btn = gr.Button("Download Sample CSV")
batch_btn.click(
fn=predict_batch,
inputs=[input_file],
outputs=[output_file, batch_msg],
)
sample_btn.click(fn=sample_csv, outputs=[output_file])
return demo
if __name__ == "__main__":
demo = build_ui()
port = int(os.environ.get("PORT", "7860"))
demo.launch(server_name="0.0.0.0", server_port=port)