""" Heuristics to flag HTML pages that look like elected-official / board / council / contact directories. Used by the jurisdiction scrape pipeline to drive structured contact extraction and manifest flags. """ from __future__ import annotations import re from typing import Any, Dict, List, Optional, Set from urllib.parse import urlparse _URL_HINTS: List[tuple[str, str, int]] = [ (r"commissioner[-_/]?bio", "officials", 28), (r"county[-_]?commission", "commission", 20), (r"major[-_]?council", "council", 22), (r"mayor[-_]?&?[-_]?council", "council", 20), (r"city\s*council", "council", 22), (r"town\s*council", "council", 22), (r"county[-_]?official", "officials", 24), (r"/official", "officials", 18), (r"board[-_]?of[-_]?education", "board", 24), (r"meet[-_]?the[-_]?board", "board", 26), (r"board[-_]?member", "board", 20), (r"commission(er)?s?", "commission", 18), (r"mayor", "mayor", 16), (r"council", "council", 14), (r"contact[-_]?us", "contacts", 16), (r"/contacts?/", "contacts", 14), (r"directory", "directory", 12), (r"elected", "officials", 14), (r"leadership", "directory", 10), (r"staff", "directory", 8), ] _TITLE_HINTS = ( "board of", "commissioner bio", "mayor and council", "mayor & council", "school board", "city council", "town council", "county commission", "commissioner", "mayor", "council member", "elected official", "county official", "contact us", "meet the", "trustee", "superintendent", ) def classify_contact_directory_page(page_url: str, html: Optional[str]) -> Dict[str, Any]: """ Return a dict with ``is_directory``, ``directory_kind``, ``score``, ``matched_signals``. ``directory_kind`` is a coarse bucket: ``board``, ``council``, ``commission``, ``mayor``, ``officials``, ``contacts``, ``directory``, ``mixed``, or ``unknown``. """ url = (page_url or "").strip() path = "" try: path = (urlparse(url).path or "").lower() except Exception: path = "" path_flat = re.sub(r"[_\s]+", "-", path) blob_l = f"{url.lower()} {path_flat}" signals: List[str] = [] kinds: Set[str] = set() score = 0 for pattern, kind, weight in _URL_HINTS: if re.search(pattern, blob_l, re.I): signals.append(f"url_re:{pattern}") kinds.add(kind) score += weight title_l = "" text_head_l = "" if html: tl = re.search(r"