SPB Git

spb/lou-ka

Public

Lou·Ka — tous les logements à louer du Québec, un seul endroit.

5.6 KB · 133 lines python
1#!/usr/bin/env python32# -----------------------------------------------------------------------------3# Lou-Ka — Agrégateur de logements à louer (province de Québec)4# Auteur : Simon-Pierre Boucher — contact@spboucher.ai5# run.py : point d'entrée — `sync`, `watch`, `serve`6# -----------------------------------------------------------------------------7"""Utilisation :8    python run.py sync [source ...]     # synchronise les annonces9    python run.py watch [minutes]       # synchronise en boucle (défaut 60 min)10    python run.py sync-ct [source ...]  # synchronise la section court terme11    python run.py watch-ct [minutes]    # boucle court terme (défaut 360 min)12    python run.py serve [port]          # démarre l'API + le frontend (défaut 8080)13    python run.py record <source ...>   # enregistre les fixtures de test d'une source14    python run.py geocode [n]           # géocode les annonces sans coordonnées (max n requêtes)15    python run.py poi [n]               # commodités de proximité par immeuble (max n requêtes)16    python run.py env [n]               # environnement OSM par tuile (socle des KA Scores)17    python run.py kascores [all]        # calcule les KA Scores du parc (all = tout recalculer)18"""19from __future__ import annotations2021import os22import sys23from pathlib import Path2425# Charger .env (FIRECRAWL_API_KEY, etc.) sans dépendance externe26_env = Path(__file__).parent / ".env"27if _env.exists():28    for line in _env.read_text().splitlines():29        line = line.strip()30        if line and not line.startswith("#") and "=" in line:31            k, _, v = line.partition("=")32            os.environ.setdefault(k.strip(), v.strip())333435def main() -> None:36    cmd = sys.argv[1] if len(sys.argv) > 1 else "serve"37    if cmd == "sync":38        from louka import ingest39        ingest.run(sys.argv[2:] or None)40    elif cmd == "watch":41        from louka import ingest42        minutes = int(sys.argv[2]) if len(sys.argv) > 2 else 6043        ingest.watch(minutes * 60)44    elif cmd == "sync-ct":45        from louka.shortterm import ingest as ct_ingest46        ct_ingest.run(sys.argv[2:] or None)47    elif cmd == "watch-ct":48        from louka.shortterm import ingest as ct_ingest49        minutes = int(sys.argv[2]) if len(sys.argv) > 2 else 36050        ct_ingest.watch(minutes * 60)51    elif cmd == "geocode1":52        from louka import geocode53        limit = int(sys.argv[2]) if len(sys.argv) > 2 else None54        geocode.run(limit)55    elif cmd == "geocode":56        # lot Adresses Québec (rapide) ; « geocode1 » = ancien mode 1-par-157        from louka import geocode58        limit = int(sys.argv[2]) if len(sys.argv) > 2 else None59        geocode.run_batch(limit)60    elif cmd == "quality":61        # (re)calcule le score de complétude + publication/quarantaine62        from louka import quality63        limit = int(sys.argv[2]) if len(sys.argv) > 2 else None64        quality.backfill(limit)65    elif cmd == "imgaudit":66        # contrôle qualité des images (liens morts, minuscules, placeholders,67        # doublons) — incrémental : python run.py imgaudit [n_annonces] [source]68        from louka import imgcheck69        limit = int(sys.argv[2]) if len(sys.argv) > 2 else 150070        src = sys.argv[3] if len(sys.argv) > 3 else None71        imgcheck.run(limit, source=src)72    elif cmd == "fairvalue":73        # (re)calcule la juste valeur locative de toutes les annonces publiées74        from louka import fairvalue75        fairvalue.compute_all()76    elif cmd == "poi":77        from louka import poi78        limit = int(sys.argv[2]) if len(sys.argv) > 2 else None79        poi.run(limit)80    elif cmd == "quartier":81        from louka import quartier82        limit = int(sys.argv[2]) if len(sys.argv) > 2 else None83        quartier.enrich(limit)84    elif cmd == "env":85        # données d'environnement OSM par tuile (routes, rails, cyclable,86        # bars, POI complets) — cache ~3 mois, socle des KA Scores87        from louka import environment88        limit = int(sys.argv[2]) if len(sys.argv) > 2 else None89        print(environment.run(limit))90    elif cmd == "kascores":91        # (re)calcule les KA Scores (Walk/Transit/Bike/Calme/Services + global)92        # incrémental ; « python run.py kascores all » force tout le parc93        from louka import kascores94        force = len(sys.argv) > 2 and sys.argv[2] == "all"95        print(kascores.run(recompute_all=force))96    elif cmd == "inondation-build":97        from louka import inondation98        inondation.build()99    elif cmd == "air-refresh":100        from louka import air101        air.refresh()102    elif cmd == "gaz-refresh":103        from louka import gaz104        print(f"[gaz] {gaz.refresh()} stations")105    elif cmd == "hydro-precompute":106        from louka import hydro107        n = int(sys.argv[2]) if len(sys.argv) > 2 else 100108        b = int(sys.argv[3]) if len(sys.argv) > 3 else 40109        hydro.precompute(limit=n, budget=b)110    elif cmd == "rdl":111        from louka import rdl112        rdl.refresh()113    elif cmd == "record":114        from louka import fixtures115        from louka.connectors import CONNECTORS116        targets = sys.argv[2:] or sorted(CONNECTORS)117        for sid in targets:118            try:119                print(f"[lou-ka] record {sid} ... {fixtures.record(sid)}")120            except Exception as exc:121                print(f"[lou-ka] record {sid} ÉCHEC : {exc}", file=sys.stderr)122    elif cmd == "serve":123        import uvicorn124        port = int(sys.argv[2]) if len(sys.argv) > 2 else 8080125        uvicorn.run("louka.web:app", host="0.0.0.0", port=port)126    else:127        print(__doc__)128        sys.exit(1)129130131if __name__ == "__main__":132    main()133
Files · 2d725b81ad9ff64d201e21d11f86a1b3577ffb02
Menu

Theme