Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -90,30 +90,37 @@ def get_campaign_match(text, rules):
|
|
| 90 |
|
| 91 |
def apply_business_logic(df):
|
| 92 |
if df is None or df.empty: return df
|
| 93 |
-
|
| 94 |
# 1. Quality Group
|
| 95 |
if "lead_quality_score" in df.columns:
|
| 96 |
df["Quality_Group"] = df["lead_quality_score"].apply(categorize_quality)
|
| 97 |
-
|
| 98 |
# 2. Campaign Logic (Smart Fallback)
|
| 99 |
rules = load_campaign_rules()
|
| 100 |
-
|
| 101 |
def resolve_campaign(row):
|
| 102 |
# Priority 1: Landing Page
|
| 103 |
if row.get("landing_page_path"):
|
| 104 |
match = get_campaign_match(row["landing_page_path"], rules)
|
| 105 |
if match: return match
|
| 106 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
if row.get("website_url"):
|
| 108 |
match = get_campaign_match(row["website_url"], rules)
|
| 109 |
if match: return match
|
| 110 |
-
|
|
|
|
| 111 |
if row.get("primary_industry"):
|
| 112 |
match = get_campaign_match(row["primary_industry"], rules)
|
| 113 |
if match: return match
|
| 114 |
-
|
| 115 |
return "Uncategorized"
|
| 116 |
-
|
| 117 |
df["Campaign"] = df.apply(resolve_campaign, axis=1)
|
| 118 |
return df
|
| 119 |
|
|
@@ -274,7 +281,7 @@ def enrich_leads_with_visits(df, start_date, end_date, max_rows=None, progress=g
|
|
| 274 |
if not landing:
|
| 275 |
first_step = visit_route[0]
|
| 276 |
landing = first_step.get("page_path") or first_step.get("page_url")
|
| 277 |
-
|
| 278 |
if not landing or not exit_p:
|
| 279 |
pv_map = {p["id"]: p["attributes"] for p in included if p["type"] == "page_views"}
|
| 280 |
pv_ids = [r["id"] for r in visit.get("relationships", {}).get("page_views", {}).get("data", [])]
|
|
@@ -350,10 +357,12 @@ def build_dashboard(df, preset, top_n):
|
|
| 350 |
target = ["MS Tech", "Fintech", "Adtech"]
|
| 351 |
filtered = df[df["Campaign"].isin(target)].copy()
|
| 352 |
if filtered.empty: return px.bar(title="No Data for Key Campaigns")
|
|
|
|
| 353 |
agg = filtered.groupby("Campaign").agg(
|
| 354 |
Leads_Count=("company_name", "count"),
|
| 355 |
Total_Visits=("total_visits", "sum")
|
| 356 |
).reset_index()
|
|
|
|
| 357 |
fig = go.Figure()
|
| 358 |
fig.add_trace(go.Bar(x=agg["Campaign"], y=agg["Leads_Count"], name="No. of Leads", marker_color="#00C49F"))
|
| 359 |
fig.add_trace(go.Bar(x=agg["Campaign"], y=agg["Total_Visits"], name="Total Visits", marker_color="#FFBB28"))
|
|
@@ -365,6 +374,7 @@ def build_dashboard(df, preset, top_n):
|
|
| 365 |
Leads_Count=("company_name", "count"),
|
| 366 |
Total_Visits=("total_visits", "sum")
|
| 367 |
).reset_index().sort_values("Leads_Count", ascending=False)
|
|
|
|
| 368 |
fig = make_subplots(specs=[[{"secondary_y": True}]])
|
| 369 |
fig.add_trace(go.Bar(x=agg["Campaign"], y=agg["Leads_Count"], name="Leads", marker_color="indigo"), secondary_y=False)
|
| 370 |
fig.add_trace(go.Scatter(x=agg["Campaign"], y=agg["Total_Visits"], name="Visits", mode="lines+markers", line=dict(color="orange", width=3)), secondary_y=True)
|
|
@@ -376,11 +386,13 @@ def build_dashboard(df, preset, top_n):
|
|
| 376 |
grouped = df.groupby(dim, dropna=False).size().reset_index(name="value")
|
| 377 |
else:
|
| 378 |
grouped = df.groupby(dim, dropna=False)[metric].agg(agg).reset_index(name="value")
|
|
|
|
| 379 |
return px.bar(grouped.sort_values("value", ascending=False).head(top_n), x=dim, y="value", title=preset, color=dim)
|
| 380 |
|
| 381 |
def build_trend(df, preset, grain, filter_values):
|
| 382 |
if df is None or df.empty: return px.line(title="No Data")
|
| 383 |
metric, agg, segment = TREND_PRESETS[preset]
|
|
|
|
| 384 |
df_t = df.dropna(subset=["last_visit_date"]).copy()
|
| 385 |
|
| 386 |
if segment and segment not in df_t.columns:
|
|
@@ -472,6 +484,7 @@ with gr.Blocks(title="Leadfeeder Campaign Pro") as demo:
|
|
| 472 |
grain = gr.Radio(["Daily", "Weekly", "Monthly"], value="Daily", label="Granularity")
|
| 473 |
filter_dropdown = gr.Dropdown(multiselect=True, visible=False, label="Filter Segments")
|
| 474 |
plot = gr.Plot()
|
|
|
|
| 475 |
trend_view.change(get_trend_filter_options, [df_state, trend_view], filter_dropdown)
|
| 476 |
gr.Button("Show Trend", variant="primary").click(build_trend, [df_state, trend_view, grain, filter_dropdown], plot)
|
| 477 |
|
|
@@ -512,7 +525,7 @@ with gr.Blocks(title="Leadfeeder Campaign Pro") as demo:
|
|
| 512 |
|
| 513 |
if not target_camp:
|
| 514 |
return "❌ Error: Campaign name cannot be empty.", gr.update()
|
| 515 |
-
|
| 516 |
# 1. Update the dictionary
|
| 517 |
rules[target_camp] = clean_kws
|
| 518 |
|
|
@@ -537,10 +550,10 @@ with gr.Blocks(title="Leadfeeder Campaign Pro") as demo:
|
|
| 537 |
status_message = f"⚠️ Saved locally, but failed to push to Hugging Face (Check HF_TOKEN). Error: {e}"
|
| 538 |
elif not HF_TOKEN:
|
| 539 |
status_message = f"⚠️ Saved locally. To make this permanent on Hugging Face, add an HF_TOKEN secret in your Space settings."
|
| 540 |
-
|
| 541 |
updated_choices = list(rules.keys()) + ["+ Create New Campaign"]
|
| 542 |
return status_message, gr.update(choices=updated_choices, value=target_camp)
|
| 543 |
-
|
| 544 |
save_config_btn.click(save_easy_config, inputs=[camp_dropdown, new_camp_name, kw_input], outputs=[config_status, camp_dropdown])
|
| 545 |
|
| 546 |
# --- TAB 5: DEBUGGER ---
|
|
|
|
| 90 |
|
| 91 |
def apply_business_logic(df):
|
| 92 |
if df is None or df.empty: return df
|
| 93 |
+
|
| 94 |
# 1. Quality Group
|
| 95 |
if "lead_quality_score" in df.columns:
|
| 96 |
df["Quality_Group"] = df["lead_quality_score"].apply(categorize_quality)
|
| 97 |
+
|
| 98 |
# 2. Campaign Logic (Smart Fallback)
|
| 99 |
rules = load_campaign_rules()
|
| 100 |
+
|
| 101 |
def resolve_campaign(row):
|
| 102 |
# Priority 1: Landing Page
|
| 103 |
if row.get("landing_page_path"):
|
| 104 |
match = get_campaign_match(row["landing_page_path"], rules)
|
| 105 |
if match: return match
|
| 106 |
+
|
| 107 |
+
# Priority 2: Exit Page (NEW LOGIC)
|
| 108 |
+
if row.get("exit_page_path"):
|
| 109 |
+
match = get_campaign_match(row["exit_page_path"], rules)
|
| 110 |
+
if match: return match
|
| 111 |
+
|
| 112 |
+
# Priority 3: Website URL
|
| 113 |
if row.get("website_url"):
|
| 114 |
match = get_campaign_match(row["website_url"], rules)
|
| 115 |
if match: return match
|
| 116 |
+
|
| 117 |
+
# Priority 4: Industry
|
| 118 |
if row.get("primary_industry"):
|
| 119 |
match = get_campaign_match(row["primary_industry"], rules)
|
| 120 |
if match: return match
|
| 121 |
+
|
| 122 |
return "Uncategorized"
|
| 123 |
+
|
| 124 |
df["Campaign"] = df.apply(resolve_campaign, axis=1)
|
| 125 |
return df
|
| 126 |
|
|
|
|
| 281 |
if not landing:
|
| 282 |
first_step = visit_route[0]
|
| 283 |
landing = first_step.get("page_path") or first_step.get("page_url")
|
| 284 |
+
|
| 285 |
if not landing or not exit_p:
|
| 286 |
pv_map = {p["id"]: p["attributes"] for p in included if p["type"] == "page_views"}
|
| 287 |
pv_ids = [r["id"] for r in visit.get("relationships", {}).get("page_views", {}).get("data", [])]
|
|
|
|
| 357 |
target = ["MS Tech", "Fintech", "Adtech"]
|
| 358 |
filtered = df[df["Campaign"].isin(target)].copy()
|
| 359 |
if filtered.empty: return px.bar(title="No Data for Key Campaigns")
|
| 360 |
+
|
| 361 |
agg = filtered.groupby("Campaign").agg(
|
| 362 |
Leads_Count=("company_name", "count"),
|
| 363 |
Total_Visits=("total_visits", "sum")
|
| 364 |
).reset_index()
|
| 365 |
+
|
| 366 |
fig = go.Figure()
|
| 367 |
fig.add_trace(go.Bar(x=agg["Campaign"], y=agg["Leads_Count"], name="No. of Leads", marker_color="#00C49F"))
|
| 368 |
fig.add_trace(go.Bar(x=agg["Campaign"], y=agg["Total_Visits"], name="Total Visits", marker_color="#FFBB28"))
|
|
|
|
| 374 |
Leads_Count=("company_name", "count"),
|
| 375 |
Total_Visits=("total_visits", "sum")
|
| 376 |
).reset_index().sort_values("Leads_Count", ascending=False)
|
| 377 |
+
|
| 378 |
fig = make_subplots(specs=[[{"secondary_y": True}]])
|
| 379 |
fig.add_trace(go.Bar(x=agg["Campaign"], y=agg["Leads_Count"], name="Leads", marker_color="indigo"), secondary_y=False)
|
| 380 |
fig.add_trace(go.Scatter(x=agg["Campaign"], y=agg["Total_Visits"], name="Visits", mode="lines+markers", line=dict(color="orange", width=3)), secondary_y=True)
|
|
|
|
| 386 |
grouped = df.groupby(dim, dropna=False).size().reset_index(name="value")
|
| 387 |
else:
|
| 388 |
grouped = df.groupby(dim, dropna=False)[metric].agg(agg).reset_index(name="value")
|
| 389 |
+
|
| 390 |
return px.bar(grouped.sort_values("value", ascending=False).head(top_n), x=dim, y="value", title=preset, color=dim)
|
| 391 |
|
| 392 |
def build_trend(df, preset, grain, filter_values):
|
| 393 |
if df is None or df.empty: return px.line(title="No Data")
|
| 394 |
metric, agg, segment = TREND_PRESETS[preset]
|
| 395 |
+
|
| 396 |
df_t = df.dropna(subset=["last_visit_date"]).copy()
|
| 397 |
|
| 398 |
if segment and segment not in df_t.columns:
|
|
|
|
| 484 |
grain = gr.Radio(["Daily", "Weekly", "Monthly"], value="Daily", label="Granularity")
|
| 485 |
filter_dropdown = gr.Dropdown(multiselect=True, visible=False, label="Filter Segments")
|
| 486 |
plot = gr.Plot()
|
| 487 |
+
|
| 488 |
trend_view.change(get_trend_filter_options, [df_state, trend_view], filter_dropdown)
|
| 489 |
gr.Button("Show Trend", variant="primary").click(build_trend, [df_state, trend_view, grain, filter_dropdown], plot)
|
| 490 |
|
|
|
|
| 525 |
|
| 526 |
if not target_camp:
|
| 527 |
return "❌ Error: Campaign name cannot be empty.", gr.update()
|
| 528 |
+
|
| 529 |
# 1. Update the dictionary
|
| 530 |
rules[target_camp] = clean_kws
|
| 531 |
|
|
|
|
| 550 |
status_message = f"⚠️ Saved locally, but failed to push to Hugging Face (Check HF_TOKEN). Error: {e}"
|
| 551 |
elif not HF_TOKEN:
|
| 552 |
status_message = f"⚠️ Saved locally. To make this permanent on Hugging Face, add an HF_TOKEN secret in your Space settings."
|
| 553 |
+
|
| 554 |
updated_choices = list(rules.keys()) + ["+ Create New Campaign"]
|
| 555 |
return status_message, gr.update(choices=updated_choices, value=target_camp)
|
| 556 |
+
|
| 557 |
save_config_btn.click(save_easy_config, inputs=[camp_dropdown, new_camp_name, kw_input], outputs=[config_status, camp_dropdown])
|
| 558 |
|
| 559 |
# --- TAB 5: DEBUGGER ---
|