SPB Git forge

spb/home-ka

Public
10commits 1branches 0releases
793.0 KBsize
maindefault branch
20 days agolast push
Python 49.6% TypeScript 25.5% CSS 24.1%
2.8 KB · 74 lines python
Raw Blame History
1# -----------------------------------------------------------------------------2# Home-Ka — US real-estate aggregator (Groupe KA)3# Author: Simon-Pierre Boucher — contact@spboucher.ai4# quality.py : data-quality gate — completeness score and publication5# threshold (quarantine), same principle as immo-ka/quality.py.6# A listing without a plausible price, location, type or usable content stays7# out of the grid/map/stats until later cycles complete it; its detail page8# by uid remains reachable.9# -----------------------------------------------------------------------------10from __future__ import annotations1112import sqlite31314PRICE_MIN, PRICE_MAX = 5_000, 200_000_00015PUBLISH_THRESHOLD = 0.551617_WEIGHTS = {18    "price": 0.30,       # plausible list price19    "location": 0.25,    # city+state or zip20    "address": 0.15,21    "type": 0.10,22    "content": 0.10,     # description or features23    "images": 0.10,24}252627def score_row(r) -> float:28    s = 0.029    price = r["list_price"]30    if price is not None and PRICE_MIN <= price <= PRICE_MAX:31        s += _WEIGHTS["price"]32    if (r["city"] and r["state"]) or r["zip_code"]:33        s += _WEIGHTS["location"]34    if r["street_address"]:35        s += _WEIGHTS["address"]36    if r["property_type"]:37        s += _WEIGHTS["type"]38    if (r["description"] and len(r["description"]) > 40) or \39            (r["features"] and r["features"] != "[]"):40        s += _WEIGHTS["content"]41    if r["images"] and r["images"] != "[]":42        s += _WEIGHTS["images"]43    return round(s, 3)444546def refresh(con: sqlite3.Connection) -> dict:47    published = quarantined = 048    for r in con.execute(49            "SELECT uid, list_price, city, state, zip_code, street_address,"50            " property_type, description, features, images"51            " FROM listings WHERE active=1"):52        q = score_row(r)53        # a plausible asking price is a HARD requirement for publication —54        # crawled sold/off-market shells must never reach the grid55        price_ok = (r["list_price"] is not None56                    and PRICE_MIN <= r["list_price"] <= PRICE_MAX)57        pub = 1 if (q >= PUBLISH_THRESHOLD and price_ok) else 058        published += pub59        quarantined += 1 - pub60        con.execute("UPDATE listings SET quality=?, published=? WHERE uid=?",61                    (q, pub, r["uid"]))62    con.commit()63    return {"published": published, "quarantined": quarantined}646566def summary(con: sqlite3.Connection) -> dict:67    rows = [dict(r) for r in con.execute(68        "SELECT source, COUNT(*) n, SUM(published) published,"69        " ROUND(AVG(quality), 3) avg_quality,"70        " SUM(CASE WHEN list_price IS NULL THEN 1 ELSE 0 END) no_price,"71        " SUM(CASE WHEN lat IS NULL THEN 1 ELSE 0 END) no_geo"72        " FROM listings WHERE active=1 GROUP BY source ORDER BY n DESC")]73    return {"by_source": rows}74