115 lines
5.3 KiB
Python
Executable File
115 lines
5.3 KiB
Python
Executable File
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 marketplace.service_staging
|
|
SET status = 'enriching'
|
|
WHERE id = (
|
|
SELECT id FROM marketplace.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 marketplace.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 marketplace.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 marketplace.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()) |