diff --git a/lead-engine/app.py b/lead-engine/app.py index e0aa6b7c..b8f80ea5 100644 --- a/lead-engine/app.py +++ b/lead-engine/app.py @@ -2,9 +2,29 @@ import streamlit as st import pandas as pd from db import get_leads, init_db import json +import re +import os from enrich import run_sync, refresh_ce_data from generate_reply import generate_email_draft +def clean_html_to_text(html_content): + """Simple helper to convert HTML email body to readable plain text.""" + if not html_content: + return "" + # Remove head and style tags entirely + clean = re.sub(r'.*?', '', html_content, flags=re.DOTALL | re.IGNORECASE) + clean = re.sub(r'.*?', '', clean, flags=re.DOTALL | re.IGNORECASE) + # Replace
and

with newlines + clean = re.sub(r'', '\n', clean, flags=re.IGNORECASE) + clean = re.sub(r'

', '\n', clean, flags=re.IGNORECASE) + # Remove all other tags + clean = re.sub(r'<.*?>', '', clean) + # Decode some common entities + clean = clean.replace(' ', ' ').replace('&', '&').replace('"', '"') + # Cleanup multiple newlines + clean = re.sub(r'\n\s*\n+', '\n\n', clean).strip() + return clean + st.set_page_config(page_title="TradingTwins Lead Engine", layout="wide") st.title("🚀 Lead Engine: TradingTwins") @@ -51,6 +71,42 @@ if st.sidebar.button("3. Sync to Company Explorer"): except Exception as e: st.error(f"Sync Failed: {e}") +if st.sidebar.checkbox("Show System Debug"): + st.sidebar.subheader("System Diagnostics") + + # 1. API Key Check + from lookup_role import get_gemini_key + key = get_gemini_key() + if key: + st.sidebar.success(f"Gemini Key found ({key[:5]}...)") + else: + st.sidebar.error("Gemini Key NOT found!") + + # 2. SerpAPI Check + serp_key = os.getenv("SERP_API") + if serp_key: + st.sidebar.success(f"SerpAPI Key found ({serp_key[:5]}...)") + else: + st.sidebar.error("SerpAPI Key NOT found in Env!") + + # 3. Network Check + try: + import requests + res = requests.get("https://generativelanguage.googleapis.com", timeout=2) + st.sidebar.success(f"Gemini API Reachable ({res.status_code})") + except Exception as e: + st.sidebar.error(f"Network Error: {e}") + + # 4. Live Lookup Test + if st.sidebar.button("Test Role Lookup (Georg Stahl)"): + from lookup_role import lookup_person_role + with st.sidebar.status("Running Lookup..."): + res = lookup_person_role("Georg Stahl", "Klemm Bohrtechnik GmbH") + if res: + st.sidebar.success(f"Result: {res}") + else: + st.sidebar.error("Result: None") + # Main View leads = get_leads() df = pd.DataFrame(leads) @@ -64,7 +120,16 @@ if not df.empty: st.subheader("Lead Pipeline") for index, row in df.iterrows(): - with st.expander(f"{row['company_name']} ({row['status']})"): + # Format date for title + date_str = "" + if row.get('received_at'): + try: + dt = pd.to_datetime(row['received_at']) + date_str = dt.strftime("%d.%m. %H:%M") + except: + pass + + with st.expander(f"{date_str} | {row['company_name']} ({row['status']})"): c1, c2 = st.columns(2) # --- Left Column: Lead Data --- @@ -79,14 +144,30 @@ if not df.empty: except: pass + role = meta.get('role') + if role: + c1.info(f"**Role:** {role}") + else: + if c1.button("🔍 Find Role (SerpAPI)", key=f"role_{row['id']}"): + from enrich import enrich_contact_role + with st.spinner("Searching LinkedIn via Google..."): + found_role = enrich_contact_role(row) + if found_role: + st.success(f"Found: {found_role}") + st.rerun() + else: + st.error("No role found.") + if meta: c1.write("---") c1.write(f"**Area:** {meta.get('area', '-')}") c1.write(f"**Purpose:** {meta.get('purpose', '-')}") c1.write(f"**Location:** {meta.get('zip', '')} {meta.get('city', '')}") - with c1.expander("Show Original Email Body"): - st.code(row['raw_body'], language="html") + with c1.expander("Show Original Email Content"): + st.text(clean_html_to_text(row['raw_body'])) + if st.checkbox("Show Raw HTML", key=f"raw_{row['id']}"): + st.code(row['raw_body'], language="html") # --- Right Column: Enrichment & Response --- enrichment = json.loads(row['enrichment_data']) if row['enrichment_data'] else {} diff --git a/lead-engine/lookup_role.py b/lead-engine/lookup_role.py index 28548325..49c36d3e 100644 --- a/lead-engine/lookup_role.py +++ b/lead-engine/lookup_role.py @@ -3,23 +3,15 @@ import requests import re from dotenv import load_dotenv -# Load env from root +# Try loading .env only if file exists (Local Dev), otherwise rely on Docker Env env_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '.env')) -load_dotenv(dotenv_path=env_path, override=True) +if os.path.exists(env_path): + load_dotenv(dotenv_path=env_path, override=True) SERP_API_KEY = os.getenv("SERP_API") if not SERP_API_KEY: - print(f"DEBUG: Failed to load SERP_API from {env_path}") - # Fallback: try reading directly if file exists - try: - with open(env_path, 'r') as f: - for line in f: - if line.startswith('SERP_API='): - SERP_API_KEY = line.split('=')[1].strip().strip('"') - print("DEBUG: Loaded key via manual parsing.") - except: - pass + print(f"DEBUG: SERP_API not found in environment.") import json @@ -75,8 +67,10 @@ def extract_role_with_llm(name, company, search_results): # Cleanup: remove punctuation at the end role = role.rstrip('.') return None if "Unbekannt" in role else role - except: - pass + else: + print(f"DEBUG: Gemini API Error {response.status_code}: {response.text}") + except Exception as e: + print(f"DEBUG: Gemini API Exception: {e}") return None def lookup_person_role(name, company):