Python 68.8%
TypeScript 18.6%
CSS 8.7%
JavaScript 3.3%
HTML 0.6%
1#!/usr/bin/env python32# -----------------------------------------------------------------------------3# Rent-Ka — Rental listings aggregator (Canada, outside Québec)4# Author: 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 serve [port] # démarre l'API + le frontend (défaut 8080)11 python run.py record <source ...> # enregistre les fixtures de test d'une source12 python run.py geocode [n] # géocode les annonces sans coordonnées (max n requêtes)13 python run.py poi [n] # commodités de proximité par immeuble (max n requêtes)14 python run.py env [n] # environnement OSM par tuile (socle des KA Scores)15 python run.py kascores [all] # calcule les KA Scores du parc (all = tout recalculer)16"""17from __future__ import annotations1819import os20import sys21from pathlib import Path2223# Charger .env (FIRECRAWL_API_KEY, etc.) sans dépendance externe24_env = Path(__file__).parent / ".env"25if _env.exists():26 for line in _env.read_text().splitlines():27 line = line.strip()28 if line and not line.startswith("#") and "=" in line:29 k, _, v = line.partition("=")30 os.environ.setdefault(k.strip(), v.strip())313233def main() -> None:34 cmd = sys.argv[1] if len(sys.argv) > 1 else "serve"35 if cmd == "sync":36 from rentka import ingest37 ingest.run(sys.argv[2:] or None)38 elif cmd == "watch":39 from rentka import ingest40 minutes = int(sys.argv[2]) if len(sys.argv) > 2 else 6041 ingest.watch(minutes * 60)42 elif cmd == "geocode1":43 from rentka import geocode44 limit = int(sys.argv[2]) if len(sys.argv) > 2 else None45 geocode.run(limit)46 elif cmd == "geocode":47 # lot Adresses Québec (rapide) ; « geocode1 » = ancien mode 1-par-148 from rentka import geocode49 limit = int(sys.argv[2]) if len(sys.argv) > 2 else None50 geocode.run_batch(limit)51 elif cmd == "quality":52 # (re)calcule le score de complétude + publication/quarantaine53 from rentka import quality54 limit = int(sys.argv[2]) if len(sys.argv) > 2 else None55 quality.backfill(limit)56 elif cmd == "imgaudit":57 # contrôle qualité des images (liens morts, minuscules, placeholders,58 # doublons) — incrémental : python run.py imgaudit [n_annonces] [source]59 from rentka import imgcheck60 limit = int(sys.argv[2]) if len(sys.argv) > 2 else 150061 src = sys.argv[3] if len(sys.argv) > 3 else None62 imgcheck.run(limit, source=src)63 elif cmd == "fairvalue":64 # (re)calcule la juste valeur locative de toutes les annonces publiées65 from rentka import fairvalue66 fairvalue.compute_all()67 elif cmd == "poi":68 from rentka import poi69 limit = int(sys.argv[2]) if len(sys.argv) > 2 else None70 poi.run(limit)71 elif cmd == "quartier":72 from rentka import quartier73 limit = int(sys.argv[2]) if len(sys.argv) > 2 else None74 quartier.enrich(limit)75 elif cmd == "env":76 # données d'environnement OSM par tuile (routes, rails, cyclable,77 # bars, POI complets) — cache ~3 mois, socle des KA Scores78 from rentka import environment79 limit = int(sys.argv[2]) if len(sys.argv) > 2 else None80 print(environment.run(limit))81 elif cmd == "kascores":82 # (re)calcule les KA Scores (Walk/Transit/Bike/Calme/Services + global)83 # incrémental ; « python run.py kascores all » force tout le parc84 from rentka import kascores85 force = len(sys.argv) > 2 and sys.argv[2] == "all"86 print(kascores.run(recompute_all=force))87 elif cmd == "record":88 from rentka import fixtures89 from rentka.connectors import CONNECTORS90 targets = sys.argv[2:] or sorted(CONNECTORS)91 for sid in targets:92 try:93 print(f"[rent-ka] record {sid} ... {fixtures.record(sid)}")94 except Exception as exc:95 print(f"[rent-ka] record {sid} ÉCHEC : {exc}", file=sys.stderr)96 elif cmd == "serve":97 import uvicorn98 port = int(sys.argv[2]) if len(sys.argv) > 2 else 808099 uvicorn.run("rentka.web:app", host="0.0.0.0", port=port)100 else:101 print(__doc__)102 sys.exit(1)103104105if __name__ == "__main__":106 main()107