# /app/app/workers/vehicle/vehicle_robot_3_alchemist.py import asyncio import logging from sqlalchemy import select, update, func, and_, case from app.db.session import AsyncSessionLocal from app.models.vehicle_definitions import VehicleModelDefinition from app.services.ai_service import AIService # MB 2.0 Naplózás logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(name)s: %(message)s') logger = logging.getLogger("Vehicle-Robot-3-Alchemist") class VehicleAlchemist: """ Vehicle Robot 3: AI Synthesizer (Alchemist) Feladata: A kutatási kontextusból strukturált "Gold Data" kinyerése AI segítségével. """ def __init__(self): self.batch_size = 5 self.delay_between_records = 12 # P4000 GPU kímélő késleltetés async def synthesize_vehicle(self, vehicle_id: int): """ AI dúsítás végrehajtása az Ollama/AI segítségével. """ async with AsyncSessionLocal() as db: # Szigorú sémakezelés és zárolás res = await db.execute( select(VehicleModelDefinition) .where(VehicleModelDefinition.id == vehicle_id) .with_for_update(skip_locked=True) ) v = res.scalar_one_or_none() if not v or not v.raw_search_context: logger.warning(f"⚠️ Nincs feldolgozható kontextus ID:{vehicle_id}") return make, model = v.make, v.marketing_name logger.info(f"🧪 Transzmutáció indul: {make} {model}") # Státusz váltás a feldolgozás idejére v.status = 'ai_synthesis_in_progress' await db.commit() # AI hívás a háttérben (Ollama konténer felé) # Itt történik a "mágia": a nyers szövegből JSON lesz gold_data = await AIService.get_gold_data_from_research(make, model, v.raw_search_context) async with AsyncSessionLocal() as db: if gold_data: # Strukturált adatok rögzítése a 'data' sémába await db.execute( update(VehicleModelDefinition) .where(VehicleModelDefinition.id == vehicle_id) .values( marketing_name=gold_data.get("marketing_name", model)[:50], technical_code=gold_data.get("technical_code") or v.technical_code, engine_capacity=gold_data.get("ccm"), power_kw=gold_data.get("kw"), specifications=gold_data, # JSONB mező a teljes technikai laphoz status='gold_enriched', # MB 2.0: Ez a legmagasabb adatszint updated_at=func.now() ) ) logger.info(f"✨ ARANY ADAT GENERÁLVA: {make} {model}") else: # Ha az AI elbukott, visszatesszük várakozóba await db.execute( update(VehicleModelDefinition) .where(VehicleModelDefinition.id == vehicle_id) .values(status='awaiting_ai_synthesis', attempts=v.attempts + 1) ) logger.warning(f"⚠️ AI hiba, visszatéve a sorba: {make} {model}") await db.commit() async def run(self): logger.info("🚀 Vehicle Alchemist ONLINE - Adatpárolás indul...") while True: async with AsyncSessionLocal() as db: # MB 2.0 Prioritás: Legnépszerűbb márkák az élen top_makes = ['SUZUKI', 'TOYOTA', 'SKODA', 'VOLKSWAGEN', 'OPEL'] priorities = case( (and_(VehicleModelDefinition.vehicle_type == 'car', VehicleModelDefinition.make.in_(top_makes)), 1), (VehicleModelDefinition.vehicle_type == 'car', 2), (VehicleModelDefinition.vehicle_type == 'motorcycle', 3), else_=4 ) stmt = select(VehicleModelDefinition.id).where( VehicleModelDefinition.status == 'awaiting_ai_synthesis' ).order_by(priorities, VehicleModelDefinition.updated_at.asc()).limit(self.batch_size) res = await db.execute(stmt) ids = [r[0] for r in res.fetchall()] if not ids: await asyncio.sleep(20) continue for vid in ids: await self.synthesize_vehicle(vid) await asyncio.sleep(self.delay_between_records) if __name__ == "__main__": asyncio.run(VehicleAlchemist().run())