mktgtech commited on
Commit
0111c4d
·
verified ·
1 Parent(s): e7aa248

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +39 -32
app.py CHANGED
@@ -9,12 +9,15 @@ import plotly.express as px
9
  from plotly.subplots import make_subplots
10
  import plotly.graph_objects as go
11
  from datetime import date, timedelta
 
12
 
13
  # =====================================================
14
  # CONFIG / SECRETS
15
  # =====================================================
16
  API_TOKEN = os.getenv("LEADFEEDER_API_TOKEN")
17
  APP_PASSWORD = os.getenv("APP_PASSWORD")
 
 
18
 
19
  if not API_TOKEN or not APP_PASSWORD:
20
  print("⚠️ WARNING: Secrets missing. App will launch but API calls will fail.")
@@ -64,15 +67,6 @@ def load_campaign_rules():
64
  return DEFAULT_CAMPAIGNS
65
  return DEFAULT_CAMPAIGNS
66
 
67
- def save_campaign_rules(rules_text):
68
- try:
69
- rules = json.loads(rules_text)
70
- with open(CAMPAIGN_CONFIG_FILE, "w") as f:
71
- json.dump(rules, f, indent=4)
72
- return "✅ Configuration Saved!", rules
73
- except json.JSONDecodeError:
74
- return "❌ Error: Invalid JSON.", None
75
-
76
  def categorize_quality(score):
77
  if pd.isna(score): return "Unknown"
78
  try:
@@ -101,30 +95,23 @@ 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 (Hybrid Strict Match)
105
  rules = load_campaign_rules()
106
 
107
  def resolve_campaign(row):
108
- # Clean path to be safe
109
- path = str(row.get("landing_page_path", "")).strip().lower()
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
- return match if match else "Uncategorized"
 
 
 
 
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)
@@ -491,7 +478,6 @@ 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"]
@@ -513,7 +499,7 @@ with gr.Blocks(title="Leadfeeder Campaign Pro") as demo:
513
 
514
  camp_dropdown.change(update_ui_on_select, inputs=[camp_dropdown], outputs=[new_camp_name, kw_input])
515
 
516
- save_config_btn = gr.Button("💾 Save Configuration", variant="primary")
517
  config_status = gr.Markdown()
518
 
519
  def save_easy_config(selected_camp, new_name, kw_string):
@@ -527,12 +513,33 @@ with gr.Blocks(title="Leadfeeder Campaign Pro") as demo:
527
  if not target_camp:
528
  return "❌ Error: Campaign name cannot be empty.", gr.update()
529
 
 
530
  rules[target_camp] = clean_kws
 
 
531
  with open(CAMPAIGN_CONFIG_FILE, "w") as f:
532
  json.dump(rules, f, indent=4)
533
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
534
  updated_choices = list(rules.keys()) + ["+ Create New Campaign"]
535
- return f"✅ Saved successfully! Updated keywords for '{target_camp}'.", gr.update(choices=updated_choices, value=target_camp)
536
 
537
  save_config_btn.click(save_easy_config, inputs=[camp_dropdown, new_camp_name, kw_input], outputs=[config_status, camp_dropdown])
538
 
 
9
  from plotly.subplots import make_subplots
10
  import plotly.graph_objects as go
11
  from datetime import date, timedelta
12
+ from huggingface_hub import HfApi # ADDED: For permanent saving to Hugging Face
13
 
14
  # =====================================================
15
  # CONFIG / SECRETS
16
  # =====================================================
17
  API_TOKEN = os.getenv("LEADFEEDER_API_TOKEN")
18
  APP_PASSWORD = os.getenv("APP_PASSWORD")
19
+ HF_TOKEN = os.getenv("HF_TOKEN") # ADDED: Your Hugging Face write token
20
+ SPACE_ID = os.getenv("SPACE_ID") # ADDED: Automatically provided by HF Spaces
21
 
22
  if not API_TOKEN or not APP_PASSWORD:
23
  print("⚠️ WARNING: Secrets missing. App will launch but API calls will fail.")
 
67
  return DEFAULT_CAMPAIGNS
68
  return DEFAULT_CAMPAIGNS
69
 
 
 
 
 
 
 
 
 
 
70
  def categorize_quality(score):
71
  if pd.isna(score): return "Unknown"
72
  try:
 
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
+ # Priority 2: Website URL
107
+ if row.get("website_url"):
108
+ match = get_campaign_match(row["website_url"], rules)
109
+ if match: return match
110
+ # Priority 3: Industry
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)
 
478
  # --- TAB 4: SETTINGS ---
479
  with gr.Tab("⚙️ Campaign Settings"):
480
  gr.Markdown("### Manage Campaign Groups")
 
481
 
482
  init_rules = load_campaign_rules()
483
  camp_choices = list(init_rules.keys()) + ["+ Create New Campaign"]
 
499
 
500
  camp_dropdown.change(update_ui_on_select, inputs=[camp_dropdown], outputs=[new_camp_name, kw_input])
501
 
502
+ save_config_btn = gr.Button("💾 Save Configuration to Hugging Face", variant="primary")
503
  config_status = gr.Markdown()
504
 
505
  def save_easy_config(selected_camp, new_name, kw_string):
 
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
+
519
+ # 2. Save file locally first
520
  with open(CAMPAIGN_CONFIG_FILE, "w") as f:
521
  json.dump(rules, f, indent=4)
522
 
523
+ status_message = f"✅ Saved locally! Updated keywords for '{target_camp}'."
524
+
525
+ # 3. Push to Hugging Face automatically
526
+ if HF_TOKEN and SPACE_ID:
527
+ try:
528
+ api = HfApi(token=HF_TOKEN)
529
+ api.upload_file(
530
+ path_or_fileobj=CAMPAIGN_CONFIG_FILE,
531
+ path_in_repo=CAMPAIGN_CONFIG_FILE,
532
+ repo_id=SPACE_ID,
533
+ repo_type="space"
534
+ )
535
+ status_message = f"✅ Saved securely to Hugging Face Cloud! Updated keywords for '{target_camp}'."
536
+ except Exception as e:
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