diff --git a/browser-use-service/main.py b/browser-use-service/main.py index 7994527..b24f6b9 100644 --- a/browser-use-service/main.py +++ b/browser-use-service/main.py @@ -534,6 +534,19 @@ FB_SEARCHES = [ "who can design a website for my", "looking for someone to create a website", "recommendations for a web designer", + "I need a website", + "I need a website built", + "need wordpress site", + "need a custom website", + "I need a new website", + "need an online store", + "need an online shop", + "need website help", + "who can help me with my website", + "looking for a website designer", + "need a shopify website", + "looking for website design", + "want to build a website for my", ] VIEWPORTS = [ @@ -1361,6 +1374,8 @@ async def ask_ollama(prompt: str) -> str: async def classify_leads(results: list[dict]) -> list[dict]: if not results: return [] + + # ── 1. AI classification ───────────────────────────────────────── briefs = [r["title"][:200] for r in results] prompt = f"""Classify each post as LEAD or NOT. LEAD = someone REQUESTING/POSTING/WANTING a website built, designed, or created for them. @@ -1376,7 +1391,7 @@ NOT LEAD: For each numbered post, answer ONLY "yes" (LEAD) or "no" (NOT LEAD): {chr(10).join(f'{i+1}. {t}' for i, t in enumerate(briefs))} Return a JSON array like ["yes","no","yes"] matching the order above.""" - ai_succeeded = False + ai_leads: list[dict] = [] try: raw = await ask_ollama(prompt) raw = raw.strip() @@ -1389,55 +1404,87 @@ Return a JSON array like ["yes","no","yes"] matching the order above.""" raw = raw.strip() answers = json.loads(raw) if isinstance(answers, list) and len(answers) == len(results): - ai_succeeded = True - filtered = [] for i, ans in enumerate(answers): if isinstance(ans, str) and ans.lower() == 'yes': - filtered.append(results[i]) - if filtered: - return filtered[:10] - logger.info("AI classified all %d items as NOT LEAD — returning empty", len(results)) - return [] + ai_leads.append(results[i]) + logger.info("AI classified %d/%d as LEAD", len(ai_leads), len(results)) except Exception as e: - logger.warning("AI classification failed, falling back to keyword filter: %s", e) + logger.warning("AI classification failed: %s", e) - if not ai_succeeded: - web_terms = [ - "website", "web design", "web develop", "web dev", - "web designer", "web developer", - "build my website", "build a website", "create a website", - "landing page", "wordpress", "ecommerce", - "my website", "business website", - "site for my", "site for my business", - "new website", "redesign my website", - "help with my website", "update my website", - ] - request_terms = [ - "looking for", "need a", "need an", "looking to", - "need someone", "hire a", "want someone", - "need help with", "would like", "build me", - "design my", "make me a", "create my", - "looking", "need", "want", "help", - "who can", "i need", - "recommend", "anyone know", "anyone recommend", - "know a", "know any", "recommendation", - "suggest", "looking for recommendations", - "can anyone", "does anyone", - ] - filtered = [] + # ── 2. Keyword fallback (always runs) ──────────────────────────── + web_terms = [ + "website", "web design", "web develop", "web dev", + "web designer", "web developer", + "build my website", "build a website", "create a website", + "landing page", "wordpress", "ecommerce", + "my website", "business website", + "site for my", "site for my business", + "new website", "redesign my website", + "help with my website", "update my website", + "make a website", "make my website", + "website for my", + "online store", "online shop", + "build my site", "build a site", + "set up a website", "set up my website", + "custom website", + "shopify", + "my site", + "webpage", "web page", + ] + request_terms = [ + "looking for", "need a", "need an", "looking to", + "need someone", "hire a", "want someone", + "need help with", "would like", "build me", + "design my", "make me a", "create my", + "looking", "need", "want", "help", + "who can", "i need", + "recommend", "anyone know", "anyone recommend", + "know a", "know any", "recommendation", + "suggest", "looking for recommendations", + "can anyone", "does anyone", + "dm me", "pm me", "message me", + "quote for", + "can you help", + "how much", + "price for", + ] + keyword_leads: list[dict] = [] + for r in results: + t = r['title'].lower() + has_web = any(kw in t for kw in web_terms) + has_request = any(kw in t for kw in request_terms) + if not has_web or not has_request: + continue + if any(kw in t for kw in ['i build website', 'i offer web', 'i am a web developer', + 'affordable web design package', 'web hosting', + 'i do web design', 'i develop websites']): + continue + keyword_leads.append(r) + + # ── 3. Merge: prefer AI leads, supplement with keywords to reach 5 ── + seen_titles: set[int] = set() + merged: list[dict] = [] + for r in ai_leads + keyword_leads: + key = hash(r.get('title', '')) + if key not in seen_titles: + seen_titles.add(key) + merged.append(r) + + # Fill to 5 with loose keyword matches (at least web OR request term) + if len(merged) < 5: for r in results: + key = hash(r.get('title', '')) + if key in seen_titles: + continue t = r['title'].lower() - has_web = any(kw in t for kw in web_terms) - has_request = any(kw in t for kw in request_terms) - if not has_web or not has_request: - continue - if any(kw in t for kw in ['i build website', 'i offer web', 'i am a web developer', - 'affordable web design package', 'web hosting', - 'i do web design', 'i develop websites']): - continue - filtered.append(r) - return filtered[:10] - return [] + if any(kw in t for kw in web_terms) or any(kw in t for kw in request_terms): + seen_titles.add(key) + merged.append(r) + if len(merged) >= 5: + break + + logger.info("classify_leads: %d merged (%d AI + %d keyword) from %d raw", len(merged), len(ai_leads), len(keyword_leads), len(results)) + return merged[:10] # ══════════════════════════════════════════════════════════════════════ # FastAPI Endpoints diff --git a/public/uploads/voice/09d5be1e-251b-4ae7-b694-7b0fbbfcefd6.webm b/public/uploads/voice/09d5be1e-251b-4ae7-b694-7b0fbbfcefd6.webm new file mode 100644 index 0000000..0ee5bd3 Binary files /dev/null and b/public/uploads/voice/09d5be1e-251b-4ae7-b694-7b0fbbfcefd6.webm differ diff --git a/public/uploads/voice/9d4622a3-50ec-41fc-b2bf-4ad10c45509f.webm b/public/uploads/voice/9d4622a3-50ec-41fc-b2bf-4ad10c45509f.webm new file mode 100644 index 0000000..0ee5bd3 Binary files /dev/null and b/public/uploads/voice/9d4622a3-50ec-41fc-b2bf-4ad10c45509f.webm differ diff --git a/public/uploads/voice/da8c23db-4d1c-449f-975a-8b17048d50de.webm b/public/uploads/voice/da8c23db-4d1c-449f-975a-8b17048d50de.webm new file mode 100644 index 0000000..51efbba Binary files /dev/null and b/public/uploads/voice/da8c23db-4d1c-449f-975a-8b17048d50de.webm differ diff --git a/public/uploads/voice/fc4ae288-90a2-4f86-8f68-5d5e37472658.webm b/public/uploads/voice/fc4ae288-90a2-4f86-8f68-5d5e37472658.webm new file mode 100644 index 0000000..0ee5bd3 Binary files /dev/null and b/public/uploads/voice/fc4ae288-90a2-4f86-8f68-5d5e37472658.webm differ diff --git a/src/components/layout/sidebar.tsx b/src/components/layout/sidebar.tsx index 2f25b89..2b89968 100644 --- a/src/components/layout/sidebar.tsx +++ b/src/components/layout/sidebar.tsx @@ -95,7 +95,7 @@ export function Sidebar({ collapsed, onToggle, mobileOpen, onMobileClose }: Side "relative flex h-10 w-10 items-center justify-center rounded-lg transition-colors", isActive ? "bg-sidebar-primary text-sidebar-primary-foreground" - : "text-sidebar-foreground/60 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground" + : "text-sidebar-foreground/60 hover:bg-sidebar-accent hover:text-white" )} > @@ -104,7 +104,7 @@ export function Sidebar({ collapsed, onToggle, mobileOpen, onMobileClose }: Side )} - + {item.label} @@ -143,12 +143,12 @@ export function Sidebar({ collapsed, onToggle, mobileOpen, onMobileClose }: Side - + Facebook Accounts diff --git a/src/components/layout/system-monitor.tsx b/src/components/layout/system-monitor.tsx index dacda7f..f1cff80 100644 --- a/src/components/layout/system-monitor.tsx +++ b/src/components/layout/system-monitor.tsx @@ -36,7 +36,7 @@ export function SystemMonitor({ collapsed }: SystemMonitorProps) { if (collapsed) { return ( -
+
{rssMB}