Spaces:
Running
Running
deploy(hf): sync szl-holdings/a11oy@e2c6283676c908aee7cc08925f71a38d1dae1ccf derived COPY set
Browse filesReusable Dockerfile-COPY-derived deploy from szl-holdings/a11oy e2c6283676c908aee7cc08925f71a38d1dae1ccf.
Files: 1357 Pruned: 0
Derived from Dockerfile COPY sources (NO hand-maintained allowlist).
Signed-off-by: SZL Holdings <noreply@szlholdings.ai>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- a11oy_deva_feeds.py +82 -11
- a11oy_vertical_feeds.py +78 -8
a11oy_deva_feeds.py
CHANGED
|
@@ -843,18 +843,89 @@ def feed_hpd_violations(limit: int = 200) -> dict[str, Any]:
|
|
| 843 |
|
| 844 |
|
| 845 |
def feed_dob_violations(limit: int = 60) -> dict[str, Any]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 846 |
limit = _bounded_limit(limit, 60, 1000)
|
| 847 |
-
|
| 848 |
-
|
| 849 |
-
|
| 850 |
-
|
| 851 |
-
|
| 852 |
-
|
| 853 |
-
|
| 854 |
-
|
| 855 |
-
|
| 856 |
-
|
| 857 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 858 |
|
| 859 |
|
| 860 |
def feed_sec_realestate(limit: int = 12) -> dict[str, Any]:
|
|
|
|
| 843 |
|
| 844 |
|
| 845 |
def feed_dob_violations(limit: int = 60) -> dict[str, Any]:
|
| 846 |
+
"""Fetch the newest valid source-reported issue dates, not an unordered sample.
|
| 847 |
+
|
| 848 |
+
The DOB field is text and contains malformed values. Provider-side bounds
|
| 849 |
+
remove non-date prefixes and future-looking values; calendar validation
|
| 850 |
+
remains local. A recent fetch never proves that a violation is still open.
|
| 851 |
+
"""
|
| 852 |
limit = _bounded_limit(limit, 60, 1000)
|
| 853 |
+
as_of = datetime.now(timezone.utc).date()
|
| 854 |
+
upper = as_of.strftime("%Y%m%d")
|
| 855 |
+
order = "issue_date DESC, isn_dob_bis_viol DESC"
|
| 856 |
+
# Bounded oversampling leaves room to reject invalid calendar dates while
|
| 857 |
+
# retaining the established maximum of 1,000 upstream rows.
|
| 858 |
+
fetch_limit = min(1000, limit * 3)
|
| 859 |
+
url = (
|
| 860 |
+
"https://data.cityofnewyork.us/resource/3h2n-5cm9.json?%24limit="
|
| 861 |
+
+ str(fetch_limit)
|
| 862 |
+
+ "&%24select=isn_dob_bis_viol,violation_type,house_number,street,boro,issue_date,violation_category,block,lot,description"
|
| 863 |
+
+ "&%24where=issue_date%20between%20%2700010101%27%20and%20%27"
|
| 864 |
+
+ upper
|
| 865 |
+
+ "%27&%24order=issue_date%20DESC%2C%20isn_dob_bis_viol%20DESC"
|
| 866 |
+
)
|
| 867 |
+
|
| 868 |
+
def parse(data):
|
| 869 |
+
if not isinstance(data, list):
|
| 870 |
+
raise ValueError("DOB source must return a JSON array")
|
| 871 |
+
valid = []
|
| 872 |
+
rejected_dates = 0
|
| 873 |
+
rejected_rows = 0
|
| 874 |
+
for row in data[:fetch_limit]:
|
| 875 |
+
if not isinstance(row, dict):
|
| 876 |
+
rejected_rows += 1
|
| 877 |
+
continue
|
| 878 |
+
issued = row.get("issue_date")
|
| 879 |
+
if not isinstance(issued, str) or re.fullmatch(r"[0-9]{8}", issued) is None:
|
| 880 |
+
rejected_dates += 1
|
| 881 |
+
continue
|
| 882 |
+
try:
|
| 883 |
+
issued_date = datetime.strptime(issued, "%Y%m%d").date()
|
| 884 |
+
except ValueError:
|
| 885 |
+
rejected_dates += 1
|
| 886 |
+
continue
|
| 887 |
+
if issued_date > as_of:
|
| 888 |
+
rejected_dates += 1
|
| 889 |
+
continue
|
| 890 |
+
# Preserve source values; no inference about an open/closed case.
|
| 891 |
+
valid.append({
|
| 892 |
+
"id": row.get("isn_dob_bis_viol"),
|
| 893 |
+
"type": row.get("violation_type"),
|
| 894 |
+
"street": (
|
| 895 |
+
str(row.get("house_number") or "")
|
| 896 |
+
+ " " + str(row.get("street") or "")
|
| 897 |
+
).strip(),
|
| 898 |
+
"boro": row.get("boro"),
|
| 899 |
+
"category": row.get("violation_category"),
|
| 900 |
+
"block": row.get("block"),
|
| 901 |
+
"lot": row.get("lot"),
|
| 902 |
+
"desc": str(row.get("description") or "")[:120],
|
| 903 |
+
"issued": issued,
|
| 904 |
+
})
|
| 905 |
+
# Provider order is requested above; repeat it locally to prevent an
|
| 906 |
+
# unordered/partially cached response from becoming the newest-first UI.
|
| 907 |
+
valid.sort(key=lambda item: (item["issued"], str(item["id"] or "")), reverse=True)
|
| 908 |
+
items = valid[:limit]
|
| 909 |
+
return {
|
| 910 |
+
"items": items,
|
| 911 |
+
"selection": {
|
| 912 |
+
"order": order,
|
| 913 |
+
"as_of_date": as_of.isoformat(),
|
| 914 |
+
"upstream_limit": fetch_limit,
|
| 915 |
+
"rows_observed": min(len(data), fetch_limit),
|
| 916 |
+
"rows_returned": len(items),
|
| 917 |
+
"invalid_dates_rejected": rejected_dates,
|
| 918 |
+
"invalid_rows_rejected": rejected_rows,
|
| 919 |
+
"source_dates_are_not_case_status": True,
|
| 920 |
+
"requested_count_met": len(items) == limit,
|
| 921 |
+
},
|
| 922 |
+
}
|
| 923 |
+
|
| 924 |
+
return _cached_fetch(
|
| 925 |
+
_variant_cache_key("dob_viol", limit=limit, order=order,
|
| 926 |
+
as_of=upper, upstream_limit=fetch_limit),
|
| 927 |
+
url, ttl=1800, parser=parse,
|
| 928 |
+
)
|
| 929 |
|
| 930 |
|
| 931 |
def feed_sec_realestate(limit: int = 12) -> dict[str, Any]:
|
a11oy_vertical_feeds.py
CHANGED
|
@@ -1520,15 +1520,85 @@ def feed_nyc_hpd(limit: int = 40) -> dict[str, Any]:
|
|
| 1520 |
|
| 1521 |
|
| 1522 |
def feed_nyc_dob(limit: int = 30) -> dict[str, Any]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1523 |
limit = _bounded_limit(limit, 30, 1000)
|
| 1524 |
-
|
| 1525 |
-
|
| 1526 |
-
|
| 1527 |
-
|
| 1528 |
-
|
| 1529 |
-
|
| 1530 |
-
|
| 1531 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1532 |
|
| 1533 |
|
| 1534 |
# ===========================================================================
|
|
|
|
| 1520 |
|
| 1521 |
|
| 1522 |
def feed_nyc_dob(limit: int = 30) -> dict[str, Any]:
|
| 1523 |
+
"""Fetch the newest valid source-reported issue dates, not an unordered sample.
|
| 1524 |
+
|
| 1525 |
+
The DOB field is text and contains malformed values. Provider-side bounds
|
| 1526 |
+
remove non-date prefixes and future-looking values; calendar validation
|
| 1527 |
+
remains local. A recent fetch never proves that a violation is still open.
|
| 1528 |
+
"""
|
| 1529 |
limit = _bounded_limit(limit, 30, 1000)
|
| 1530 |
+
as_of = datetime.now(timezone.utc).date()
|
| 1531 |
+
upper = as_of.strftime("%Y%m%d")
|
| 1532 |
+
order = "issue_date DESC, isn_dob_bis_viol DESC"
|
| 1533 |
+
# Bounded oversampling leaves room to reject invalid calendar dates while
|
| 1534 |
+
# retaining the established maximum of 1,000 upstream rows.
|
| 1535 |
+
fetch_limit = min(1000, limit * 3)
|
| 1536 |
+
url = (
|
| 1537 |
+
"https://data.cityofnewyork.us/resource/3h2n-5cm9.json?%24limit="
|
| 1538 |
+
+ str(fetch_limit)
|
| 1539 |
+
+ "&%24select=isn_dob_bis_viol,violation_type,house_number,street,boro,issue_date"
|
| 1540 |
+
+ "&%24where=issue_date%20between%20%2700010101%27%20and%20%27"
|
| 1541 |
+
+ upper
|
| 1542 |
+
+ "%27&%24order=issue_date%20DESC%2C%20isn_dob_bis_viol%20DESC"
|
| 1543 |
+
)
|
| 1544 |
+
|
| 1545 |
+
def parse(data):
|
| 1546 |
+
if not isinstance(data, list):
|
| 1547 |
+
raise ValueError("DOB source must return a JSON array")
|
| 1548 |
+
valid = []
|
| 1549 |
+
rejected_dates = 0
|
| 1550 |
+
rejected_rows = 0
|
| 1551 |
+
for row in data[:fetch_limit]:
|
| 1552 |
+
if not isinstance(row, dict):
|
| 1553 |
+
rejected_rows += 1
|
| 1554 |
+
continue
|
| 1555 |
+
issued = row.get("issue_date")
|
| 1556 |
+
if not isinstance(issued, str) or re.fullmatch(r"[0-9]{8}", issued) is None:
|
| 1557 |
+
rejected_dates += 1
|
| 1558 |
+
continue
|
| 1559 |
+
try:
|
| 1560 |
+
issued_date = datetime.strptime(issued, "%Y%m%d").date()
|
| 1561 |
+
except ValueError:
|
| 1562 |
+
rejected_dates += 1
|
| 1563 |
+
continue
|
| 1564 |
+
if issued_date > as_of:
|
| 1565 |
+
rejected_dates += 1
|
| 1566 |
+
continue
|
| 1567 |
+
# Preserve source values; no inference about an open/closed case.
|
| 1568 |
+
valid.append({
|
| 1569 |
+
"id": row.get("isn_dob_bis_viol"),
|
| 1570 |
+
"type": row.get("violation_type"),
|
| 1571 |
+
"street": (
|
| 1572 |
+
str(row.get("house_number") or "")
|
| 1573 |
+
+ " " + str(row.get("street") or "")
|
| 1574 |
+
).strip(),
|
| 1575 |
+
"boro": row.get("boro"),
|
| 1576 |
+
"issued": issued,
|
| 1577 |
+
})
|
| 1578 |
+
# Provider order is requested above; repeat it locally to prevent an
|
| 1579 |
+
# unordered/partially cached response from becoming the newest-first UI.
|
| 1580 |
+
valid.sort(key=lambda item: (item["issued"], str(item["id"] or "")), reverse=True)
|
| 1581 |
+
items = valid[:limit]
|
| 1582 |
+
return {
|
| 1583 |
+
"items": items,
|
| 1584 |
+
"selection": {
|
| 1585 |
+
"order": order,
|
| 1586 |
+
"as_of_date": as_of.isoformat(),
|
| 1587 |
+
"upstream_limit": fetch_limit,
|
| 1588 |
+
"rows_observed": min(len(data), fetch_limit),
|
| 1589 |
+
"rows_returned": len(items),
|
| 1590 |
+
"invalid_dates_rejected": rejected_dates,
|
| 1591 |
+
"invalid_rows_rejected": rejected_rows,
|
| 1592 |
+
"source_dates_are_not_case_status": True,
|
| 1593 |
+
"requested_count_met": len(items) == limit,
|
| 1594 |
+
},
|
| 1595 |
+
}
|
| 1596 |
+
|
| 1597 |
+
return _cached_fetch(
|
| 1598 |
+
_variant_cache_key("nyc_dob", limit=limit, order=order,
|
| 1599 |
+
as_of=upper, upstream_limit=fetch_limit),
|
| 1600 |
+
url, ttl=1800, parser=parse,
|
| 1601 |
+
)
|
| 1602 |
|
| 1603 |
|
| 1604 |
# ===========================================================================
|