átlagos kiegészítséek jó sok
This commit is contained in:
@@ -23,7 +23,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.database import AsyncSessionLocal
|
||||
from app.models.identity import User
|
||||
from app.models.audit import FinancialLedger, LedgerEntryType, WalletType
|
||||
from app.models import FinancialLedger, LedgerEntryType, WalletType
|
||||
from app.services.billing_engine import record_ledger_entry
|
||||
from app.services.notification_service import NotificationService
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
# /app/app/workers/system/system_robot_2_service_auditor.py
|
||||
# /opt/docker/dev/service_finder/backend/app/workers/system/system_robot_2_service_auditor.py
|
||||
import asyncio
|
||||
import logging
|
||||
from datetime import datetime, timezone
|
||||
from sqlalchemy import select, and_, update
|
||||
from sqlalchemy import select, and_, update, func
|
||||
from sqlalchemy.dialects.postgresql import insert
|
||||
from app.database import AsyncSessionLocal
|
||||
from app.models.organization import Organization, OrgType
|
||||
from app.models.service import ServiceProfile
|
||||
from app.models.staged_data import ServiceStaging
|
||||
from app.models.marketplace.organization import Organization, OrgType
|
||||
from app.models.marketplace.service import ServiceProfile
|
||||
from app.models.marketplace.staged_data import ServiceStaging
|
||||
|
||||
# MB 2.0 Naplózás
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s]: %(message)s')
|
||||
@@ -14,42 +15,127 @@ logger = logging.getLogger("System-Robot-2-ServiceAuditor")
|
||||
|
||||
class ServiceAuditor:
|
||||
"""
|
||||
System Robot 2: Service Auditor & Judge
|
||||
System Robot 2: Service Auditor & Judge (Gamification 2.0)
|
||||
Feladata:
|
||||
1. Meglévő szervizek auditálása (ne legyenek "halott" adatok).
|
||||
2. Staging adatok automatikus élesítése, ha a bizalmi szint eléri a küszöböt.
|
||||
1. Staging adatok auditálása dinamikus trust_score küszöb alapján.
|
||||
2. Sikeres audit esetén Organization és ServiceProfile létrehozás.
|
||||
3. Bukott audit esetén needs_moderation státusz.
|
||||
"""
|
||||
|
||||
TRUST_THRESHOLD = 80 # Ezen pontszám felett automatikusan élesítünk
|
||||
@classmethod
|
||||
async def get_promotion_threshold(cls, db):
|
||||
""" Dinamikus küszöbérték kiolvasása a system_parameters táblából (SQL text) """
|
||||
from sqlalchemy import text
|
||||
try:
|
||||
result = await db.execute(
|
||||
text("SELECT value FROM system.system_parameters WHERE key = 'service_promotion_threshold' AND scope_level = 'global'")
|
||||
)
|
||||
row = result.fetchone()
|
||||
if row:
|
||||
import json
|
||||
value = json.loads(row[0]) if isinstance(row[0], str) else row[0]
|
||||
threshold = value.get('trust_score', 50) if isinstance(value, dict) else 50
|
||||
else:
|
||||
threshold = 50
|
||||
except Exception as e:
|
||||
logger.warning(f"⚠️ Nem sikerült lekérni a küszöbértéket: {e}, alapértelmezett 50")
|
||||
threshold = 50
|
||||
logger.info(f"📊 Dinamikus trust_score küszöb: {threshold}")
|
||||
return threshold
|
||||
|
||||
@classmethod
|
||||
async def promote_staging_data(cls):
|
||||
"""
|
||||
AZ AUTOMATA BÍRÓ:
|
||||
Megnézi a Staging táblát, és ha valami elérte a ponthatárt,
|
||||
automatikusan átemeli az éles profilok közé.
|
||||
AZ AUTOMATA BÍRÓ (Gamification 2.0):
|
||||
Atomikus tranzakcióban feldolgozza az auditor_ready státuszú rekordokat.
|
||||
"""
|
||||
async with AsyncSessionLocal() as db:
|
||||
stmt = select(ServiceStaging).where(
|
||||
and_(
|
||||
ServiceStaging.status == "researched",
|
||||
ServiceStaging.trust_score >= cls.TRUST_THRESHOLD
|
||||
)
|
||||
)
|
||||
result = await db.execute(stmt)
|
||||
to_promote = result.scalars().all()
|
||||
|
||||
for stage in to_promote:
|
||||
logger.info(f"⚖️ Automatikus élesítés (Admin nélkül): {stage.name} (Bizalom: {stage.trust_score})")
|
||||
|
||||
# Itt jön az átemelő logika:
|
||||
# 1. Organization létrehozása
|
||||
# 2. ServiceProfile létrehozása
|
||||
# 3. ExpertiseTags átmásolása
|
||||
|
||||
stage.status = "promoted"
|
||||
# Dinamikus küszöb lekérdezése
|
||||
threshold = await cls.get_promotion_threshold(db)
|
||||
|
||||
await db.commit()
|
||||
# FOR UPDATE SKIP LOCKED használata
|
||||
stmt = select(ServiceStaging).where(
|
||||
ServiceStaging.status == "auditor_ready"
|
||||
).with_for_update(skip_locked=True).limit(10)
|
||||
|
||||
result = await db.execute(stmt)
|
||||
to_process = result.scalars().all()
|
||||
|
||||
processed = 0
|
||||
for stage in to_process:
|
||||
try:
|
||||
# Audit logika
|
||||
if stage.trust_score >= threshold:
|
||||
# A) SIKERES AUDIT
|
||||
logger.info(f"✅ Sikeres audit: {stage.name} (trust_score={stage.trust_score})")
|
||||
|
||||
# Organization létrehozása vagy meglévő keresése név alapján
|
||||
org_stmt = select(Organization).where(
|
||||
and_(
|
||||
Organization.name == stage.name,
|
||||
Organization.org_type == OrgType.service
|
||||
)
|
||||
)
|
||||
org_result = await db.execute(org_stmt)
|
||||
org = org_result.scalar_one_or_none()
|
||||
|
||||
if not org:
|
||||
org = Organization(
|
||||
name=stage.name,
|
||||
org_type=OrgType.service,
|
||||
is_active=True,
|
||||
created_by=stage.submitted_by if stage.submitted_by else None
|
||||
)
|
||||
db.add(org)
|
||||
await db.flush() # ID generáláshoz
|
||||
|
||||
# ServiceProfile létrehozása
|
||||
profile = ServiceProfile(
|
||||
organization_id=org.id,
|
||||
name=stage.name,
|
||||
description=stage.description,
|
||||
latitude=None, # TODO: később geokódolás
|
||||
longitude=None,
|
||||
address=stage.full_address,
|
||||
contact_phone=stage.contact_phone,
|
||||
website=stage.website,
|
||||
status='pending_validation', # Következő robot/ember dúsíthatja
|
||||
trust_score=stage.trust_score,
|
||||
raw_data=stage.raw_data
|
||||
)
|
||||
db.add(profile)
|
||||
await db.flush()
|
||||
|
||||
# Staging rekord frissítése
|
||||
stage.status = 'pending_validation'
|
||||
stage.organization_id = org.id
|
||||
stage.service_profile_id = profile.id
|
||||
stage.updated_at = func.now() # audited_at helyett updated_at
|
||||
|
||||
logger.info(f" ➡️ Organization #{org.id} és ServiceProfile #{profile.id} létrehozva")
|
||||
|
||||
else:
|
||||
# B) BUKOTT AUDIT
|
||||
logger.warning(f"❌ Bukott audit: {stage.name} (trust_score={stage.trust_score} < {threshold})")
|
||||
stage.status = 'needs_moderation'
|
||||
stage.updated_at = func.now()
|
||||
|
||||
processed += 1
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"💥 Hiba a staging feldolgozás közben (ID {stage.id}): {e}")
|
||||
await db.rollback()
|
||||
# Staging rekord hibás státuszba helyezése
|
||||
stage.status = 'error'
|
||||
stage.updated_at = func.now()
|
||||
# További hibakezelés: lehet naplózni audit_trail-be
|
||||
continue
|
||||
|
||||
if processed > 0:
|
||||
await db.commit()
|
||||
logger.info(f"📦 Feldolgozva {processed} staging rekord")
|
||||
else:
|
||||
logger.debug("ℹ️ Nincs feldolgozható staging rekord")
|
||||
|
||||
@classmethod
|
||||
async def audit_existing_services(cls):
|
||||
@@ -92,7 +178,7 @@ class ServiceAuditor:
|
||||
|
||||
@classmethod
|
||||
async def run(cls):
|
||||
logger.info("⚖️ System Auditor ONLINE - Bírói és Karbantartó üzemmód")
|
||||
logger.info("⚖️ System Auditor ONLINE - Gamification 2.0 Bírói mód")
|
||||
while True:
|
||||
# 1. Először élesítjük az új felfedezéseket
|
||||
await cls.promote_staging_data()
|
||||
@@ -100,8 +186,8 @@ class ServiceAuditor:
|
||||
# 2. Utána karbantartjuk a meglévőket
|
||||
await cls.audit_existing_services()
|
||||
|
||||
# Naponta egyszer fut le a teljes kör
|
||||
await asyncio.sleep(86400)
|
||||
# Rövid várakozás a következő ciklus előtt (teszteléshez 60 másodperc)
|
||||
await asyncio.sleep(60)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(ServiceAuditor.run())
|
||||
Reference in New Issue
Block a user