import asyncio import logging import json from sqlalchemy import select, text, update, func from app.database import AsyncSessionLocal # JAVÍTVA from app.models.service import ServiceProfile, ExpertiseTag, ServiceExpertise, ServiceStaging # Logolás MB 2.0 szabvány logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(name)s: %(message)s') logger = logging.getLogger("Service-Robot-3-Enricher") class ServiceEnricher: """ Service Robot 3: Professional Classifier (Atomi Zárolással) """ @staticmethod async def match_expertise_to_service(db, service_profile_id: int, scraped_text: str): """ Kulcsszó-alapú elemző motor az ExpertiseTag tábla alapján. """ if not scraped_text: return tags_query = await db.execute(select(ExpertiseTag).where(ExpertiseTag.is_official == True)) all_tags = tags_query.scalars().all() found_any = False for tag in all_tags: match_count = 0 for kw in (tag.search_keywords or []): if kw.lower() in scraped_text.lower(): match_count += 1 if match_count > 0: existing_check = await db.execute( select(ServiceExpertise).where( ServiceExpertise.service_id == service_profile_id, ServiceExpertise.expertise_id == tag.id ) ) if not existing_check.scalar(): new_link = ServiceExpertise( service_id=service_profile_id, expertise_id=tag.id, confidence_level=min(match_count, 2) ) db.add(new_link) found_any = True logger.info(f"✅ {tag.key} szakma azonosítva a szerviznél.") if found_any: await db.commit() @classmethod async def run_worker(cls): logger.info("🧠 Service Enricher ONLINE - Szakmai elemzés indítása (Atomi Zárolás)") while True: try: async with AsyncSessionLocal() as db: # 1. Zárolunk egy "enrich_ready" szervizt a Staging táblából query = text(""" UPDATE data.service_staging SET status = 'enriching' WHERE id = ( SELECT id FROM data.service_staging WHERE status = 'enrich_ready' FOR UPDATE SKIP LOCKED LIMIT 1 ) RETURNING id, name, city, full_address, fingerprint, raw_data; """) result = await db.execute(query) task = result.fetchone() await db.commit() if task: s_id, name, city, address, fprint, raw_data = task web_context = raw_data.get('web_context', '') if isinstance(raw_data, dict) else '' async with AsyncSessionLocal() as process_db: try: # 2. Áttesszük a végleges ServiceProfile táblába (mert már van elég adatunk a webről) profile_stmt = text(""" INSERT INTO data.service_profiles (fingerprint, status, trust_score, location, is_verified, bio) VALUES (:fp, 'active', 40, ST_SetSRID(ST_MakePoint(19.04, 47.49), 4326), false, :bio) ON CONFLICT (fingerprint) DO UPDATE SET bio = EXCLUDED.bio RETURNING id; """) # Megjegyzés: A GPS koordinátát (19.04, 47.49) majd a Validator (Robot-4) pontosítja! p_result = await process_db.execute(profile_stmt, {"fp": fprint, "bio": name + " - " + city}) profile_id = p_result.scalar() await process_db.commit() # 3. Futtatjuk a kulcsszó-elemzést await cls.match_expertise_to_service(process_db, profile_id, web_context) # 4. Lezárjuk a Staging feladatot await process_db.execute(text("UPDATE data.service_staging SET status = 'processed' WHERE id = :id"), {"id": s_id}) await process_db.commit() except Exception as e: await process_db.rollback() logger.error(f"Hiba a dúsítás során ({s_id}): {e}") await process_db.execute(text("UPDATE data.service_staging SET status = 'error' WHERE id = :id"), {"id": s_id}) await process_db.commit() else: await asyncio.sleep(15) except Exception as e: logger.error(f"💀 Kritikus hiba a főciklusban: {e}") await asyncio.sleep(10) if __name__ == "__main__": asyncio.run(ServiceEnricher.run_worker())