Files
matchmaking-v2/research/poc/browser-apply/browser_config.py
raulgupta 89ca9ad647 Initial commit: matchmaking-v2 on-demand multi-board job-search agent
On-demand Scout service (replaces the nightly aggregator):
- FastAPI agent-mesh service; card name "matchmaking-service" (HTTP /a2a/tasks
  + Redis-stream worker matching the sibling-service pattern)
- run_search: parallel multi-board sweep (Naukri/blackfalcondata + Foundit +
  LinkedIn), city-filtered at the board, cheapest-per-result first
- per-board adapters + normalizers -> ScoutJob with rich read-only details and
  offsite apply links; recall mode + MVQ guard
- result cache for dev replay ($0); per-board cost knobs; retry-on-5xx
- research/: engine design, board cost economics, India-actor shortlist, POC
2026-06-18 19:22:03 +05:30

41 lines
1.9 KiB
Python

"""
Shared browser configuration for login_once.py and apply.py.
Both MUST use the identical BrowserProfile so the LinkedIn session you create during login
is reused at apply time. The session lives in ./chrome-profile (git-ignored).
Why a dedicated profile instead of your real Chrome: Chrome 149 blocks remote-debugging on the
default profile (a 2025 anti-infostealer change), and there's no default Chrome profile on this
machine anyway. A dedicated profile gives the same thing — a real, logged-in, persistent
session you control — without sharing any password with our code.
"""
import os
from browser_use import BrowserProfile
HERE = os.path.dirname(os.path.abspath(__file__))
CHROME_PATH = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
PROFILE_DIR = os.path.join(HERE, "chrome-profile")
RESUME_PATH = os.path.join(HERE, "Resume.pdf")
def make_profile(headless: bool = False, persist: bool = True) -> BrowserProfile:
# persist=False -> fresh browser (no user_data_dir): right for public ATS forms that need no
# login, and for unattended sweeps where many runs shouldn't share one profile lock.
kwargs = dict(
executable_path=CHROME_PATH,
headless=headless, # False = you watch it; True = unattended sweep
keep_alive=True, # don't tear the browser down between steps
# --- Hardened pacing (defaults are 0.1 / 0.25 / 0.5) ---
# Slower, human-like timing. Critically, wait_for_network_idle lets Ashby's ASYNC résumé
# upload finish before the next action fires — the flaky step that got us spam-flagged.
# Slower pacing also reduces the bot fingerprint that feeds the spam heuristic.
wait_between_actions=1.2,
minimum_wait_page_load_time=1.0,
wait_for_network_idle_page_load_time=2.5,
)
if persist:
kwargs["user_data_dir"] = PROFILE_DIR # persists cookies/login across runs
return BrowserProfile(**kwargs)