diff --git a/browser-use-service/main.py b/browser-use-service/main.py index 78367a2..deb303b 100644 --- a/browser-use-service/main.py +++ b/browser-use-service/main.py @@ -372,6 +372,7 @@ OFFER_PATTERNS = [ r"\bmy\s+portfolio\b", r"\breasonable\s+(price|pricing|rate)\b", r"\bwhatsapp\s+(me|us|at)\b", + r"\bwhatsapp\b", r"\blooking\s+for\s+(a\s+)?(business|client|customer)\b", r"\bhelp\s+your\s+business\b", r"\bi\s+am\s+a\s+(web|freelance|designer|developer)\b", @@ -407,6 +408,46 @@ OFFER_PATTERNS = [ r"\bselling\s+(my|a|the|this)\b", r"\bpremium\b", r"\bi'm\s+selling\b", + r"\bgroup\b", + r"\bi\s+can\s+help\b", + r"\binbox\s+me\b", + r"\bpm\s+me\b", + r"\bdm\s+me\b", + r"\bmessage\s+me\s+for\b", + r"\bquote\b", + r"\bdiscount\b", + r"\bbest\s+(deal|price|offer|service)\b", + r"\bprice\s+(start|begin|include|range)\b", + r"\breach\s+out\b", + r"\bclick\s+(the\s+)?link\b", + r"\bcheck\s+(out|this|my)\b", + r"\bwebsite\s+for\s+your\b", + r"\bprobono\b", + r"\bfreelance\s+opportunit", + r"\bfull.?stack\b", + r"\bresponsive\s+(web)?sites?\b", + r"\blooking\s+for\s+(new\s+)?(projects?|work)\b", + r"\bmern\s+stack\b", + r"\bexpress\s+js\b", + r"\breact\s+js\b", + r"\bnode\s+js\b", + r"\bwebsite\s+for\s+\$\b", + r"\bi\s+build\s+(websites?|shopify|wordpress)\b", + r"\bwe\s+build\s+(websites?|shopify|wordpress)\b", + r"\bi\s+create\s+(websites?|shopify|wordpress)\b", + r"\bwe\s+create\s+(websites?|shopify|wordpress)\b", + r"\bfull.?time\s+(position|job|role|work)\b", + r"\bremote\s+(position|job|role|work)\b", + r"\bhelp\s+wanted\b", + r"\bjob\s+(opening|vacancy|opportunity)\b", + r"\bnow\s+hiring\b", + r"\bpart.?time\s+(position|job|role|work)\b", + r"\byears?\s+of\s+(teaching|experience)\b", + r"\bsend\s+(you|me)\s+(the\s+)?link\b", + r"\bcomment\s+.*\bsend\b", + r"\bfor\s+free\b", + r"\bmake\s+money\b", + r"\bno\s+coding\b", ] REQUEST_PATTERNS = [ @@ -748,7 +789,7 @@ def _clean_fb_text(text: str) -> str: return '\n'.join(cleaned_lines) # Words that should never be treated as person names -_NON_NAMES = {"online","tutor","tutoring","school","academy","learning","urgently","looking","south","africa","philippines","australia","creative","professional","digital","services","solutions","statistics","actuarial","homeschooling","homeschool","reading","math","english","science","grade","group","page","website","design","development","agency","company","studio","graphic","technical","support","customer","guest","post","fashion","wordpress","shopify","ecommerce","business","marketing","social","media","content","strategy","seo","free","domain","hosting","sponsored","promoted","advertisement","need","want","help","please","contact","send","message","whatsapp","hire","freelance","writer","blogger","expert","specialist","consultant","freelancer","software","creators","village","town","city","university","college","institute","evolve","aesthetics","sale","selling","premium","builder","pro","people","ecommerce"} +_NON_NAMES = {"online","tutor","tutoring","school","academy","learning","urgently","looking","south","africa","philippines","australia","creative","professional","digital","services","solutions","statistics","actuarial","homeschooling","homeschool","reading","math","english","science","grade","group","page","website","design","development","agency","company","studio","graphic","technical","support","customer","guest","post","fashion","wordpress","shopify","ecommerce","business","marketing","social","media","content","strategy","seo","free","domain","hosting","sponsored","promoted","advertisement","need","want","help","please","contact","send","message","whatsapp","hire","freelance","writer","blogger","expert","specialist","consultant","freelancer","software","creators","village","town","city","university","college","institute","evolve","aesthetics","sale","selling","premium","builder","pro","people","ecommerce","press","anonymous","tuition","parents","tutors","advanced","custom","fields","speed","optimization","elementor","woocommerce","acf","availability","january","february","march","april","may","june","july","august","september","october","november","december","mums","dads","uae","sharjah","dubai","abu","dhabi","hong","kong","canada","usa","united","kingdom","aunty","piano","plus","recommendations","needed"} # ── Post Extraction ────────────────────────────────────────────────── # Two strategies for extracting posts from page content: @@ -756,10 +797,22 @@ _NON_NAMES = {"online","tutor","tutoring","school","academy","learning","urgentl # 2. _extract_posts_from_text — fallback that parses raw page text line by line # Both apply dedup (seen_texts), offer filtering, and request scoring. +_GROUP_SUFFIXES = [" - South Africa", " - Australia", " - Philippines", " PH", "Group", "help group", "info group", "public group", "private group", "group for", "community", "creators", "marketplace"] + def _extract_posts_from_elements(elements: list[dict], base_url: str) -> list[dict]: posts = [] seen_texts = set() + now = datetime.utcnow() for el in elements: + # Reject group posts immediately + if el.get('isGroup'): + continue + # Reject posts older than 2 days + ts = el.get('ts', 0) + if ts: + age_seconds = (now.timestamp() * 1000 - ts) / 1000 + if age_seconds > 172800: # 2 days + continue raw_text = el.get('text', '') if len(raw_text) < 40: continue @@ -773,13 +826,23 @@ def _extract_posts_from_elements(elements: list[dict], base_url: str) -> list[di if dekey in seen_texts: continue seen_texts.add(dekey) + # Reject if text contains group-like patterns + lower = text.lower() + if ' / ' in lower: + continue + skip = False + for suff in _GROUP_SUFFIXES: + if suff.lower() in lower: + skip = True + break + if skip: + continue request_score = 2 if is_request(text) else 0 post_url = el.get('url') or base_url # Prefer JS-extracted date, fall back to text parsing js_date = (el.get('date') or '').strip() if js_date: - # Try ISO datetime from