# /opt/docker/dev/service_finder/backend/app/workers/robot0_priority_setter.py import asyncio import httpx import logging import os from sqlalchemy import text from app.db.session import AsyncSessionLocal # Logolás beállítása a Sentinel rendszerhez logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s]: %(message)s') logger = logging.getLogger("Robot-0-Strategist") class Robot0Strategist: """ Robot 0: A Stratéga. Meghatározza a feldolgozási prioritásokat a valós piaci darabszámok alapján. """ RDW_API = "https://opendata.rdw.nl/resource/m9d7-ebf2.json" RDW_TOKEN = os.getenv("RDW_APP_TOKEN") HEADERS = {"X-App-Token": RDW_TOKEN} if RDW_TOKEN else {} # Holland típusok leképezése belső kategóriákra (MB 2.0 prioritás) CATEGORIES = [ {"name": "car", "rdw_types": ["'Personenauto'"]}, {"name": "motorcycle", "rdw_types": ["'Motorfiets'"]}, # JAVÍTVA: Bedrijfsauto hozzáadva, Bedrijfswagen törölve {"name": "truck", "rdw_types": ["'Bedrijfsauto'", "'Vrachtwagen'", "'Opleggertrekker'"]}, {"name": "other", "rdw_types": ["NOT IN ('Personenauto', 'Motorfiets', 'Bedrijfsauto', 'Vrachtwagen', 'Opleggertrekker')"]} ] async def get_popular_makes(self, vehicle_class: str, rdw_types: list): """ Lekéri az adott kategória 500 legnépszerűbb márkáját. """ # SoQL filter összeállítása if "NOT IN" in rdw_types[0]: type_filter = f"voertuigsoort {rdw_types[0]}" else: type_filter = " OR ".join([f"voertuigsoort = {t}" for t in rdw_types]) params = { "$select": "merk, count(*) AS darabszam", # Itt adjuk meg az aliast "$where": type_filter, "$group": "merk", "$order": "darabszam DESC", # Itt hivatkozunk rá "$limit": 500 } async with httpx.AsyncClient(timeout=45.0) as client: try: resp = await client.get(self.RDW_API, params=params, headers=self.HEADERS) if resp.status_code == 200: return resp.json() logger.error(f"⚠️ API Hiba ({vehicle_class}): {resp.status_code}") return [] except Exception as e: logger.error(f"❌ Kapcsolati hiba ({vehicle_class}): {e}") return [] async def run(self): """ A stratégiai prioritás-beállítás futtatása. """ logger.info("🚀 Robot 0 (Strategist) INDUL - Piaci prioritások elemzése...") # --- ÖNGYÓGYÍTÓ ADATBÁZIS JAVÍTÁS --- # Garantáljuk, hogy a priority_score oszlop létezik a táblában async with AsyncSessionLocal() as db: try: await db.execute(text("ALTER TABLE data.catalog_discovery ADD COLUMN IF NOT EXISTS priority_score INTEGER DEFAULT 0;")) await db.commit() logger.info("✅ Adatbázis séma ellenőrizve: priority_score oszlop aktív.") except Exception as e: await db.rollback() logger.error(f"⚠️ Nem sikerült ellenőrizni az oszlopot: {e}") # ------------------------------------ # Nem nyitunk itt globális db-t, hanem a cikluson belül kezeljük for category in self.CATEGORIES: v_class = category["name"] logger.info(f"📊 {v_class.upper()} elemzés és sorbarendezés...") makes = await self.get_popular_makes(v_class, category["rdw_types"]) if not makes: logger.warning(f"⚠️ {v_class.upper()}: Nincs visszaadott adat az RDW-től!") continue added_count = 0 for item in makes: make_name = str(item.get("merk", "")).upper().strip() if not make_name: continue count = int(item.get("darabszam", 0)) # DEBUG: ellenőrizzük az 'item'-et if added_count == 0: logger.info(f"🧬 Elem felépítése: {item} -> Kinyert márka: {make_name}, Prioritás: {count}") # Minden egyes márkához saját session-t nyitunk async with AsyncSessionLocal() as db: try: # JAVÍTÁS: beletettük az attempts (0) és a priority_score (:score) oszlopokat! query = text(""" INSERT INTO data.catalog_discovery (make, model, vehicle_class, status, source, attempts, priority_score) VALUES (:make, 'ALL_VARIANTS', :class, 'pending', 'STRATEGIST-POPULARITY-V2', 0, :score) ON CONFLICT (make, model, vehicle_class) DO UPDATE SET status = 'pending', priority_score = :score WHERE catalog_discovery.status NOT IN ('processed', 'in_progress'); """) # Átadjuk a query-nek a 'score' paramétert is await db.execute(query, {"make": make_name, "class": v_class, "score": count}) await db.commit() added_count += 1 except Exception as e: await db.rollback() logger.warning(f"❌ Sikertelen rögzítés ({make_name}): {e}") logger.info(f"✅ {v_class.upper()} kész: {added_count} márka prioritizálva.") logger.info("🏁 Robot 0 végzett. A terep előkészítve a Hunterek számára.") if __name__ == "__main__": asyncio.run(Robot0Strategist().run())