GradioApp / app.py
CarloAlberto1's picture
Create app.py
12b7a88 verified
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import gradio as gr
import re
custom_theme = gr.themes.Base().set(
body_background_fill="linear-gradient(120deg, #f9fcff 0%, #fef6ff 100%)",
block_background_fill="white",
block_shadow="0px 5px 15px rgba(0,0,0,0.06)",
block_border_width="1px",
block_border_color="#e6e6e6",
)
# Run predictions
results_df = run_batch_predictions(df, pipe)
# Create a new DataFrame without 'Clusters' and 'Recommendation'
export_df = results_df.drop(columns=[col for col in ['Clusters', 'Recommendation'] if col in results_df.columns])
# Save to CSV
export_df.to_csv('results_summary.csv', index=False)
# Add the constant column
results_df["RecordCount"] = 1
# Extract actions
''''
def extract_actions(html_text):
if not isinstance(html_text, str):
return ["No action"]
text = html_text.replace("<br>", "\n")
actions = re.findall(r"• (.+)", text)
return actions if actions else ["No action"]
'''
# Drilldown DataFrame
drilldown_data = []
for _, row in results_df.iterrows():
churn_pred = row["Churn Prediction"]
prob= row["Probability"]
clusters = row["Clusters"]
if isinstance(clusters, dict):
for cluster_name, rec_list in clusters.items():
for rec in rec_list:
drilldown_data.append({
"Churn Prediction": churn_pred,
"Cluster": cluster_name,
"Recommendation": rec,
"Probability": prob
})
drilldown_df = pd.DataFrame(drilldown_data)
# Chart defaults
px.defaults.template = "plotly_white"
px.defaults.color_discrete_sequence = px.colors.qualitative.Set2
# Helper for numeric KPI cards
def make_numeric_card(title, value, suffix=""):
fig = go.Figure(go.Indicator(
mode="number",
value=value,
number={'font': {'size': 36}, 'suffix': suffix},
title={'text': title, 'font': {'size': 16}}
))
fig.update_layout(
height=140, width=220,
margin=dict(l=10, r=10, t=25, b=10),
paper_bgcolor="white"
)
return fig
# Build Analytics Figures
def generate_analytics_figs(df):
figs = {}
figs["avg_tenure"] = make_numeric_card("Avg Tenure (Months)", df["Tenure in Months"].mean())
figs["avg_charge"] = make_numeric_card("Avg Monthly Charge ($)", df["Monthly Charge"].mean(), suffix="$")
figs["avg_data"] = make_numeric_card("Avg Monthly GB Download", df["Avg Monthly GB Download"].mean())
figs["tenure_hist"] = px.histogram(df, x="Tenure in Months", nbins=20, title="Tenure Distribution")
figs["age_hist"] = px.histogram(df, x="Age", nbins=20, title="Age Distribution")
figs["contract_pie"] = px.pie(df, names="Contract", hole=0.4, title="Contract Types")
figs["dependents_donut"] = px.pie(df, names="Number of Dependents", hole=0.4, title="Dependents Distribution")
figs["senior_pie"] = px.pie(df, names="Senior Citizen", hole=0.4, title="Senior Citizen Ratio")
figs["streaming_pie"] = px.pie(df, names="Streaming Movies", hole=0.4, title="Streaming Movies Adoption")
figs["security_pie"] = px.pie(df, names="Online Security", hole=0.4, title="Online Security Subscription")
figs["unlimited_pie"] = px.pie(df, names="Unlimited Data", hole=0.4, title="Unlimited Data Adoption")
referrals_df = df["Number of Referrals"].value_counts().reset_index()
referrals_df.columns = ["Number of Referrals", "count"]
figs["referrals_bar"] = px.bar(
referrals_df,
x="Number of Referrals",
y="count",
title="Referrals Count Distribution",
labels={"Number of Referrals": "Number of Referrals", "count": "Count"}
)
for f in figs.values():
f.update_layout(margin=dict(l=20, r=20, t=40, b=20))
return figs
analytics_figs = generate_analytics_figs(results_df)
# Drilldown Chart
def generate_drilldown_chart():
if drilldown_df.empty:
fig = px.treemap(names=["No data"], parents=[""], values=[1], title="No recommendations yet")
return fig
fig = px.treemap(
drilldown_df,
path=['Churn Prediction', 'Cluster', 'Recommendation'],
values=None,
title="Recommendations by Churn Prediction & Cluster",
)
fig.update_traces(
textinfo='label+percent parent',
hovertemplate="<b>%{label}</b><br>Customers: %{value}<br>Percentage of parent: %{percentParent:.1%}<extra></extra>"
)
fig.update_layout(
margin=dict(l=20, r=20, t=50, b=20),
title_font=dict(size=18)
)
return fig
# Customer Details
def get_customer_details(customer_id):
row = results_df[results_df["Customer ID"] == customer_id].iloc[0]
prediction = row["Churn Prediction"]
clusters = row["Clusters"]
prob= row["Probability"]
# Convert decimal probability → percentage
pct_value = float(prob) * 100 # numeric percentage, e.g. 82.3
pct = f"{pct_value:.0f}%" # string percentage, e.g. "82%"
# Categorize risk
if pct_value < 30:
risk_level = "Low"
elif pct_value < 60:
risk_level = "Medium"
else:
risk_level = "High"
# Corrected line
churn_risk = f"{risk_level} ({pct})"
# Build recommendations with cluster names
if isinstance(clusters, dict):
rec_lines = []
for cluster_name, rec_list in clusters.items():
for rec in rec_list:
rec_lines.append(f"<b>{cluster_name}:</b> {rec}")
recommendations_html = "<br>• ".join(rec_lines) if rec_lines else "No recommendations"
else:
recommendations_html = "No recommendations"
selected_features = [
'Contract', 'Tenure in Months', 'Age', 'Number of Referrals',
'Monthly Charge', 'Number of Dependents', 'Senior Citizen',
'Streaming Movies', 'Online Security', 'Avg Monthly GB Download',
'Unlimited Data'
]
# Table with customer features
table_html = "<table style='width:100%; border-collapse: collapse;'>"
table_html += "<tbody>"
for col in selected_features:
table_html += f"<tr><td style='padding:8px; border:1px solid #ddd; font-weight:600;'>{col}</td>"
table_html += f"<td style='padding:8px; border:1px solid #ddd;'>{row[col]}</td></tr>"
table_html += "</tbody></table>"
# Build full HTML with recommendations **outside** the table
full_html = (
f"<b>Churn Risk:</b> {churn_risk}<br><br>"
f"<b>Recommendations:</b><br>• {recommendations_html}<br><br>"
f"<b>Customer Details:</b><br>{table_html}"
)
return full_html
# Gradio App
with gr.Blocks(
theme=custom_theme,
title="CRM Churn Dashboard",
css="""
/* FORCE LIGHT MODE */
:root {
--color-background: #ffffff !important;
--color-border: #e6e6e6 !important;
--color-text: #000000 !important;
--body-background-fill: linear-gradient(120deg, #f9fcff 0%, #fef6ff 100%) !important;
/* Override dark mode variables */
--dark-mode: 0 !important;
--neutral-900: #000000 !important;
--neutral-800: #1a1a1a !important;
--neutral-700: #2a2a2a !important;
--neutral-600: #3a3a3a !important;
--neutral-500: #777 !important;
--neutral-400: #aaa !important;
--neutral-300: #ccc !important;
--neutral-200: #eee !important;
--neutral-100: #fafafa !important;
}
body {
background: linear-gradient(120deg, #f9fcff 0%, #fef6ff 100%) !important;
}
/* Force blocks to be light */
.gr-block, .gr-panel, .gr-box, .gr-container {
background: white !important;
color: black !important;
}
/* Dropdowns, inputs, etc. */
input, select, textarea {
background: white !important;
color: black !important;
border: 1px solid #ddd !important;
}
"""
) as demo:
gr.Markdown("## 📊 CRM Analytics Dashboard")
with gr.Tabs():
# Actions Insights tab
with gr.TabItem("Actions Overview"):
gr.Markdown("### Drilldown of Recommendations by Cluster")
drilldown_plot = gr.Plot(value=generate_drilldown_chart())
# Analytics Dashboard tab (donut style, original font)
with gr.TabItem("Analytics Dashboard"):
gr.Markdown("### Customer Base Analytics Overview")
with gr.Row():
gr.Plot(value=analytics_figs["avg_tenure"])
gr.Plot(value=analytics_figs["avg_charge"])
gr.Plot(value=analytics_figs["avg_data"])
with gr.Row():
gr.Plot(value=analytics_figs["tenure_hist"])
gr.Plot(value=analytics_figs["age_hist"])
with gr.Row():
gr.Plot(value=analytics_figs["contract_pie"])
gr.Plot(value=analytics_figs["dependents_donut"])
with gr.Row():
gr.Plot(value=analytics_figs["senior_pie"])
gr.Plot(value=analytics_figs["streaming_pie"])
with gr.Row():
gr.Plot(value=analytics_figs["security_pie"])
gr.Plot(value=analytics_figs["unlimited_pie"])
gr.Plot(value=analytics_figs["referrals_bar"])
# Customer Insights tab
with gr.TabItem("CRM Details"):
gr.Markdown("### Customer-Level Predictions & Recommendations")
customer_dropdown = gr.Dropdown(
choices=results_df["Customer ID"].tolist(),
value=results_df["Customer ID"].iloc[0],
label="Select Customer"
)
customer_output = gr.HTML()
customer_dropdown.change(
fn=get_customer_details,
inputs=customer_dropdown,
outputs=customer_output
)
demo.launch(share=True)