spb/ora-ka Public
Ora-Ka — cinq agrégateurs Ka, une barre de recherche hybride (exact + sémantique)
Python 80%
TypeScript 12.9%
CSS 6.8%
1# -----------------------------------------------------------------------------2# Immo-Ka — Agrégateur de maisons à vendre (province de Québec)3# Auteur : Simon-Pierre Boucher — contact@spboucher.ai4# connectors/agences_source_immo.py : agences INDÉPENDANTES sur la plateforme5# source.immo (plugin WordPress). Beaucoup de petites/moyennes agences QC6# l'utilisent (liste sur source.immo). Chacune expose sa config publique à7# /wp-content/uploads/_sourceimmo/_configs.json → on lit l'API publique8# api-v1.source.immo (voir SourceImmoConnector). Ce sont des agences9# autonomes : leurs inscriptions (leur propre n° Centris) sont ADDITIVES —10# pas de sous-agence d'une bannière déjà couverte → source_id normal (pas _ag_).11#12# Un connecteur par agence est généré depuis data/source_immo_agencies.json.13# -----------------------------------------------------------------------------14from __future__ import annotations1516import json17from pathlib import Path1819from .sourceimmo import SourceImmoConnector20from ..schema import PropertyListing2122REGISTRY = Path(__file__).resolve().parent.parent.parent / "data" / "source_immo_agencies.json"232425class _AgenceSourceImmo(SourceImmoConnector):26 """Agence indépendante source.immo. Recharge sa config depuis le site27 (résilient aux rotations d'UUID) ; agency_name pour l'affichage Sources."""2829 agency_name = ""3031 def fetch(self) -> list[PropertyListing]:32 base = self.site_url.rstrip("/")33 try:34 cfg = self.get(f"{base}/wp-content/uploads/_sourceimmo/_configs.json").json()35 self.account_id = cfg.get("account_id", self.account_id)36 self.api_key = cfg.get("api_key", self.api_key)37 self.app_id = cfg.get("app_id", self.app_id)38 self.view_id = cfg.get("default_view", self.view_id)39 except Exception:40 pass41 return super().fetch()4243 def _to_listing(self, it: dict) -> PropertyListing | None:44 lst = super()._to_listing(it)45 if lst is not None:46 lst.broker_name = self.agency_name47 lst.agency = self.agency_name48 ref = it.get("ref_number") or it.get("id")49 if ref and self.site_url:50 lst.url = f"{self.site_url.rstrip('/')}/propriete/{ref}"51 return lst525354def _load() -> list[dict]:55 try:56 return json.loads(REGISTRY.read_text(encoding="utf-8"))57 except Exception:58 return []596061# Génère une classe par agence du registre.62for _ag in _load():63 if not all(_ag.get(k) for k in ("id", "domain", "account", "api", "app", "view")):64 continue65 _sid = _ag["id"]66 _dom = _ag["domain"].rstrip("/")67 globals()[f"AGENCE_{_sid.upper()}"] = type(68 "AgenceSI" + "".join(p.title() for p in _sid.split("_")),69 (_AgenceSourceImmo,),70 {71 "source_id": _sid,72 "account_id": _ag["account"], "api_key": _ag["api"],73 "app_id": _ag["app"], "view_id": _ag["view"],74 "site_url": f"https://{_dom}/",75 "agency_name": _ag.get("name", _sid.title()),76 },77 )78