Immo-Ka — agrégateur des propriétés à vendre au Québec (73 connecteurs, ~40 000 annonces, React+FastAPI)
Python 47.5%
HTML 27.9%
TypeScript 15.5%
CSS 7.2%
JavaScript 2%
1#!/usr/bin/env python32# -----------------------------------------------------------------------------3# Groupe KA — Annuaire des inspecteurs en bâtiment du Québec (Immo-Ka)4# inspecteurs.py : sert data/inspecteurs.json — entreprises d'inspection de5# bâtiment couvrant les 17 régions administratives (Google Places via Serper).6# Régénération du dataset : scripts/build_inspecteurs.py puis remplacer le JSON.7# NB : le JSON garde la clé générique « movers » (pipeline partagé avec8# l'annuaire des déménageurs) — ce sont les entrées de l'annuaire.9# -----------------------------------------------------------------------------10from __future__ import annotations1112import json13import threading14from pathlib import Path1516from fastapi import APIRouter1718ROOT = Path(__file__).resolve().parent.parent19DATA = ROOT / "data" / "inspecteurs.json"2021router = APIRouter()22_cache: dict = {"mtime": None, "doc": None}23_lock = threading.Lock()242526def load() -> dict:27 """Charge (avec cache par mtime) l'annuaire canonique des inspecteurs."""28 try:29 mtime = DATA.stat().st_mtime30 except FileNotFoundError:31 return {"generated": None, "count": 0, "movers": [], "regions": []}32 with _lock:33 if _cache["doc"] is None or mtime != _cache["mtime"]:34 doc = json.loads(DATA.read_text(encoding="utf-8"))35 regs: dict[str, int] = {}36 for m in doc.get("movers", []):37 regs[m["region"]] = regs.get(m["region"], 0) + 138 doc["regions"] = [{"region": r, "n": n}39 for r, n in sorted(regs.items(),40 key=lambda x: (-x[1], x[0]))]41 _cache["doc"], _cache["mtime"] = doc, mtime42 return _cache["doc"]434445@router.get("/api/inspecteurs")46def api_inspecteurs(region: str | None = None, q: str | None = None):47 """Annuaire des inspecteurs en bâtiment du Québec (filtres : région, texte)."""48 doc = load()49 movers = doc.get("movers", [])50 if region:51 movers = [m for m in movers if m["region"] == region]52 if q:53 needle = q.strip().lower()54 movers = [m for m in movers55 if needle in (m["name"] + " " + m["city"]).lower()]56 return {"generated": doc.get("generated"),57 "total": doc.get("count", 0),58 "count": len(movers),59 "regions": doc.get("regions", []),60 "movers": movers}61