Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -101,79 +101,48 @@ def apply_business_logic(df):
|
|
| 101 |
if "lead_quality_score" in df.columns:
|
| 102 |
df["Quality_Group"] = df["lead_quality_score"].apply(categorize_quality)
|
| 103 |
|
| 104 |
-
# 2. Campaign Logic (
|
| 105 |
rules = load_campaign_rules()
|
| 106 |
|
| 107 |
def resolve_campaign(row):
|
| 108 |
-
|
| 109 |
-
path
|
| 110 |
-
|
| 111 |
-
# SCENARIO 1: We HAVE a specific landing page path (e.g., /blog/..., /services/...)
|
| 112 |
-
# We strictly enforce keyword matching here to avoid generic pages getting grouped.
|
| 113 |
-
if path and path not in ["", "/", "/home", "nan", "none"]:
|
| 114 |
match = get_campaign_match(path, rules)
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
# SCENARIO 2: The path is missing (unenriched preview) OR it's a generic Homepage
|
| 118 |
-
# Here we fallback to website and industry so your dashboard actually populates!
|
| 119 |
-
website = str(row.get("website_url", "")).strip().lower()
|
| 120 |
-
industry = str(row.get("primary_industry", "")).strip().lower()
|
| 121 |
-
|
| 122 |
-
match = get_campaign_match(website, rules)
|
| 123 |
-
if match: return match
|
| 124 |
-
|
| 125 |
-
match = get_campaign_match(industry, rules)
|
| 126 |
-
if match: return match
|
| 127 |
-
|
| 128 |
return "Uncategorized"
|
| 129 |
-
|
| 130 |
df["Campaign"] = df.apply(resolve_campaign, axis=1)
|
| 131 |
return df
|
| 132 |
|
| 133 |
# =====================================================
|
| 134 |
-
# 2. PRESETS
|
| 135 |
# =====================================================
|
| 136 |
DASHBOARD_PRESETS = {
|
| 137 |
-
# -- SPECIAL VIEWS --
|
| 138 |
"Key Campaigns Bifurcation (MS Tech, Fintech, Adtech)": ("SPECIAL_KEY_BIFURCATION", None, None),
|
| 139 |
"All Campaigns Performance": ("SPECIAL_ALL_PERFORMANCE", None, None),
|
| 140 |
-
|
| 141 |
-
# -- CAMPAIGN & QUALITY --
|
| 142 |
"Visits by Campaign": ("Campaign", "total_visits", "sum"),
|
| 143 |
"Leads by Campaign": ("Campaign", "company_name", "count"),
|
| 144 |
"Leads by Quality Group": ("Quality_Group", "company_name", "count"),
|
| 145 |
-
|
| 146 |
-
# -- GEOGRAPHY (NEW) --
|
| 147 |
"Visits by Country": ("country", "total_visits", "sum"),
|
| 148 |
"Leads by Country": ("country", "company_name", "count"),
|
| 149 |
"Visits by City": ("city", "total_visits", "sum"),
|
| 150 |
"Leads by City": ("city", "company_name", "count"),
|
| 151 |
-
|
| 152 |
-
# -- INDUSTRY (NEW) --
|
| 153 |
"Visits by Industry": ("primary_industry", "total_visits", "sum"),
|
| 154 |
"Leads by Industry": ("primary_industry", "company_name", "count"),
|
| 155 |
-
|
| 156 |
-
# -- OTHERS --
|
| 157 |
"Top Accounts by Visits": ("company_name", "total_visits", "sum"),
|
| 158 |
}
|
| 159 |
|
| 160 |
TREND_PRESETS = {
|
| 161 |
-
# -- CAMPAIGN & QUALITY --
|
| 162 |
"Visits Trend by Campaign": ("total_visits", "sum", "Campaign"),
|
| 163 |
"Leads Trend by Campaign": ("company_name", "count", "Campaign"),
|
| 164 |
"Visits Trend by Quality": ("total_visits", "sum", "Quality_Group"),
|
| 165 |
-
|
| 166 |
-
# -- GEOGRAPHY (NEW) --
|
| 167 |
"Visits Trend by Country": ("total_visits", "sum", "country"),
|
| 168 |
"Leads Trend by Country": ("company_name", "count", "country"),
|
| 169 |
"Visits Trend by City": ("total_visits", "sum", "city"),
|
| 170 |
"Leads Trend by City": ("company_name", "count", "city"),
|
| 171 |
-
|
| 172 |
-
# -- INDUSTRY (NEW) --
|
| 173 |
"Visits Trend by Industry": ("total_visits", "sum", "primary_industry"),
|
| 174 |
"Leads Trend by Industry": ("company_name", "count", "primary_industry"),
|
| 175 |
-
|
| 176 |
-
# -- GENERAL --
|
| 177 |
"Total Visits Trend": ("total_visits", "sum", None),
|
| 178 |
"Active Accounts Trend": ("company_name", "count", None),
|
| 179 |
}
|
|
@@ -389,6 +358,26 @@ def build_dashboard(df, preset, top_n):
|
|
| 389 |
grouped = df.groupby(dim, dropna=False).size().reset_index(name="value")
|
| 390 |
else:
|
| 391 |
grouped = df.groupby(dim, dropna=False)[metric].agg(agg).reset_index(name="value")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 392 |
return px.bar(grouped.sort_values("value", ascending=False).head(top_n), x=dim, y="value", title=preset, color=dim)
|
| 393 |
|
| 394 |
def build_trend(df, preset, grain, filter_values):
|
|
@@ -474,7 +463,7 @@ with gr.Blocks(title="Leadfeeder Campaign Pro") as demo:
|
|
| 474 |
gr.Markdown("### 📊 Charts")
|
| 475 |
with gr.Row():
|
| 476 |
preset = gr.Dropdown(choices=list(DASHBOARD_PRESETS.keys()), label="Chart View", value="Key Campaigns Bifurcation (MS Tech, Fintech, Adtech)")
|
| 477 |
-
top_n = gr.Slider(5, 50, value=10, label="Top N Items")
|
| 478 |
chart = gr.Plot()
|
| 479 |
gr.Button("Build View").click(build_dashboard, [df_state, preset, top_n], chart)
|
| 480 |
|
|
@@ -491,7 +480,7 @@ with gr.Blocks(title="Leadfeeder Campaign Pro") as demo:
|
|
| 491 |
# --- TAB 4: SETTINGS ---
|
| 492 |
with gr.Tab("⚙️ Campaign Settings"):
|
| 493 |
gr.Markdown("### Manage Campaign Groups")
|
| 494 |
-
gr.Markdown("Select a campaign below and paste your keywords separated by commas.")
|
| 495 |
|
| 496 |
init_rules = load_campaign_rules()
|
| 497 |
camp_choices = list(init_rules.keys()) + ["+ Create New Campaign"]
|
|
|
|
| 101 |
if "lead_quality_score" in df.columns:
|
| 102 |
df["Quality_Group"] = df["lead_quality_score"].apply(categorize_quality)
|
| 103 |
|
| 104 |
+
# 2. Campaign Logic (Strict Landing Page Only)
|
| 105 |
rules = load_campaign_rules()
|
| 106 |
|
| 107 |
def resolve_campaign(row):
|
| 108 |
+
path = row.get("landing_page_path")
|
| 109 |
+
if path and path not in ["", "/", "/home"]:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
match = get_campaign_match(path, rules)
|
| 111 |
+
if match:
|
| 112 |
+
return match
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
return "Uncategorized"
|
| 114 |
+
|
| 115 |
df["Campaign"] = df.apply(resolve_campaign, axis=1)
|
| 116 |
return df
|
| 117 |
|
| 118 |
# =====================================================
|
| 119 |
+
# 2. PRESETS
|
| 120 |
# =====================================================
|
| 121 |
DASHBOARD_PRESETS = {
|
|
|
|
| 122 |
"Key Campaigns Bifurcation (MS Tech, Fintech, Adtech)": ("SPECIAL_KEY_BIFURCATION", None, None),
|
| 123 |
"All Campaigns Performance": ("SPECIAL_ALL_PERFORMANCE", None, None),
|
|
|
|
|
|
|
| 124 |
"Visits by Campaign": ("Campaign", "total_visits", "sum"),
|
| 125 |
"Leads by Campaign": ("Campaign", "company_name", "count"),
|
| 126 |
"Leads by Quality Group": ("Quality_Group", "company_name", "count"),
|
|
|
|
|
|
|
| 127 |
"Visits by Country": ("country", "total_visits", "sum"),
|
| 128 |
"Leads by Country": ("country", "company_name", "count"),
|
| 129 |
"Visits by City": ("city", "total_visits", "sum"),
|
| 130 |
"Leads by City": ("city", "company_name", "count"),
|
|
|
|
|
|
|
| 131 |
"Visits by Industry": ("primary_industry", "total_visits", "sum"),
|
| 132 |
"Leads by Industry": ("primary_industry", "company_name", "count"),
|
|
|
|
|
|
|
| 133 |
"Top Accounts by Visits": ("company_name", "total_visits", "sum"),
|
| 134 |
}
|
| 135 |
|
| 136 |
TREND_PRESETS = {
|
|
|
|
| 137 |
"Visits Trend by Campaign": ("total_visits", "sum", "Campaign"),
|
| 138 |
"Leads Trend by Campaign": ("company_name", "count", "Campaign"),
|
| 139 |
"Visits Trend by Quality": ("total_visits", "sum", "Quality_Group"),
|
|
|
|
|
|
|
| 140 |
"Visits Trend by Country": ("total_visits", "sum", "country"),
|
| 141 |
"Leads Trend by Country": ("company_name", "count", "country"),
|
| 142 |
"Visits Trend by City": ("total_visits", "sum", "city"),
|
| 143 |
"Leads Trend by City": ("company_name", "count", "city"),
|
|
|
|
|
|
|
| 144 |
"Visits Trend by Industry": ("total_visits", "sum", "primary_industry"),
|
| 145 |
"Leads Trend by Industry": ("company_name", "count", "primary_industry"),
|
|
|
|
|
|
|
| 146 |
"Total Visits Trend": ("total_visits", "sum", None),
|
| 147 |
"Active Accounts Trend": ("company_name", "count", None),
|
| 148 |
}
|
|
|
|
| 358 |
grouped = df.groupby(dim, dropna=False).size().reset_index(name="value")
|
| 359 |
else:
|
| 360 |
grouped = df.groupby(dim, dropna=False)[metric].agg(agg).reset_index(name="value")
|
| 361 |
+
|
| 362 |
+
# --- NEW: Automatically render a Choropleth Map for country data ---
|
| 363 |
+
if dim == "country":
|
| 364 |
+
# Sort to put the highest values on top
|
| 365 |
+
grouped = grouped.sort_values("value", ascending=False)
|
| 366 |
+
|
| 367 |
+
fig = px.choropleth(
|
| 368 |
+
grouped,
|
| 369 |
+
locations=dim, # Maps directly to the "country" column
|
| 370 |
+
locationmode="country names", # Plotly automatically identifies country names
|
| 371 |
+
color="value", # The heat map scale
|
| 372 |
+
hover_name=dim,
|
| 373 |
+
title=preset,
|
| 374 |
+
color_continuous_scale="Blues" # A clean blue heat map gradient
|
| 375 |
+
)
|
| 376 |
+
# Update layout to remove margins and make the map look crisp
|
| 377 |
+
fig.update_layout(margin={"r":0,"t":40,"l":0,"b":0})
|
| 378 |
+
return fig
|
| 379 |
+
# -------------------------------------------------------------------
|
| 380 |
+
|
| 381 |
return px.bar(grouped.sort_values("value", ascending=False).head(top_n), x=dim, y="value", title=preset, color=dim)
|
| 382 |
|
| 383 |
def build_trend(df, preset, grain, filter_values):
|
|
|
|
| 463 |
gr.Markdown("### 📊 Charts")
|
| 464 |
with gr.Row():
|
| 465 |
preset = gr.Dropdown(choices=list(DASHBOARD_PRESETS.keys()), label="Chart View", value="Key Campaigns Bifurcation (MS Tech, Fintech, Adtech)")
|
| 466 |
+
top_n = gr.Slider(5, 50, value=10, label="Top N Items (Not applicable to Maps)")
|
| 467 |
chart = gr.Plot()
|
| 468 |
gr.Button("Build View").click(build_dashboard, [df_state, preset, top_n], chart)
|
| 469 |
|
|
|
|
| 480 |
# --- TAB 4: SETTINGS ---
|
| 481 |
with gr.Tab("⚙️ Campaign Settings"):
|
| 482 |
gr.Markdown("### Manage Campaign Groups")
|
| 483 |
+
gr.Markdown("Select a campaign below and paste your keywords separated by commas. Changes take effect on the next data load.")
|
| 484 |
|
| 485 |
init_rules = load_campaign_rules()
|
| 486 |
camp_choices = list(init_rules.keys()) + ["+ Create New Campaign"]
|