AIDA / scripts /fix_listing_6a0b82_geocode.py
destinyebuka's picture
admin
306b89c
Raw
History Blame Contribute Delete
4.18 kB
"""
fix_listing_6a0b82_geocode.py
=============================
One-off data repair for listing 6a0b82f081458f7caa129dd8.
Background: a vague neighborhood ("AGLA", a district of Cotonou, Benin) was
geocoded — before the geocoder was hardened — to Општина Тител, Србија
(lat=45.19, lon=20.09), and the currency was derived as RSD instead of XOF.
This script re-runs the *fixed* geocoder for that listing's location and
corrects latitude/longitude + currency. Idempotent — safe to run twice.
Run from the AIDA/ directory:
python scripts/fix_listing_6a0b82_geocode.py --dry-run # preview only
python scripts/fix_listing_6a0b82_geocode.py # apply
"""
import asyncio
import logging
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from bson import ObjectId
from app.database import connect_db, get_db, disconnect_db
from app.ai.tools.listing_tool import geocode_address, get_currency_for_location
logging.basicConfig(level=logging.INFO, format="%(levelname)s %(message)s")
logger = logging.getLogger(__name__)
DRY_RUN = "--dry-run" in sys.argv
LISTING_ID = "6a0b82f081458f7caa129dd8"
# The bug report identifies this listing as being in Cotonou, Benin.
# The stored `location` field is just "AGLA" (a Cotonou neighborhood) with
# no city context, so the geocoder cannot infer the country on its own
# (it would re-anchor on the AGLA literal, which resolves to Serbia and
# to Bangladesh in the currency manager — that's how this script's first
# run made things worse). For this one-off repair we override:
KNOWN_CITY = "Cotonou, Benin"
FALLBACK_CURRENCY = "XOF"
# Last-resort coordinates if Nominatim is unreachable: Cotonou city center.
FALLBACK_LAT = 6.3654
FALLBACK_LON = 2.4183
async def run():
await connect_db()
try:
db = await get_db()
doc = await db.listings.find_one({"_id": ObjectId(LISTING_ID)})
if not doc:
logger.error(f"Listing {LISTING_ID} not found — nothing to do.")
return
location = doc.get("location") or ""
address = doc.get("address") or ""
logger.info(
f"Current → location={location!r} address={address!r} "
f"lat={doc.get('latitude')} lon={doc.get('longitude')} "
f"currency={doc.get('currency')}"
)
# Re-geocode with the KNOWN city ("Cotonou, Benin"). Passing the
# listing's own "location" field (just "AGLA") as the anchor is
# what produced the Serbia/Bangladesh garbage on the first run.
geo = await geocode_address(address or location, KNOWN_CITY)
new_lat = geo.get("latitude") if geo.get("success") else None
new_lon = geo.get("longitude") if geo.get("success") else None
if new_lat is None or new_lon is None:
logger.warning(
"Re-geocode unsuccessful, falling back to Cotonou city center "
f"({FALLBACK_LAT}, {FALLBACK_LON})."
)
new_lat = FALLBACK_LAT
new_lon = FALLBACK_LON
# Currency: this listing is known to be Benin → XOF. We deliberately
# skip get_currency_for_location() here because feeding it bare
# "AGLA" returns BDT (Bangladesh) with high confidence — exactly
# the bug we are trying to repair.
new_currency = FALLBACK_CURRENCY
logger.info(
f"Proposed → lat={new_lat} lon={new_lon} currency={new_currency} "
f"(approx={geo.get('approximate', False)})"
)
if DRY_RUN:
logger.info("DRY RUN — no changes written.")
return
result = await db.listings.update_one(
{"_id": ObjectId(LISTING_ID)},
{"$set": {
"latitude": new_lat,
"longitude": new_lon,
"currency": new_currency,
}},
)
logger.info(
f"✅ Updated listing {LISTING_ID} "
f"(matched={result.matched_count}, modified={result.modified_count})"
)
finally:
await disconnect_db()
if __name__ == "__main__":
asyncio.run(run())