Architect és robot szabályok frissítése - Fixes #1

This commit is contained in:
Roo
2026-03-06 14:43:46 +00:00
parent 696db55fd8
commit 75975b2741
3 changed files with 66 additions and 43 deletions

View File

@@ -4,6 +4,7 @@ import datetime
import random
import sys
import json
import os
from sqlalchemy import text, func, update, case
from app.database import AsyncSessionLocal
from app.models.vehicle_definitions import VehicleModelDefinition
@@ -15,9 +16,9 @@ logger = logging.getLogger("Vehicle-Robot-3-Alchemist-Pro")
class TechEnricher:
"""
Vehicle Robot 3: Alchemist Pro (Atomi Zárolás Patch)
Vehicle Robot 3: Alchemist Pro (Atomi Zárolás + Kézi Moderáció Patch)
Tiszta GPU fókusz: Csak az AI elemzésre és adategyesítésre koncentrál.
Nincs felesleges webkeresés. Szigorú Sane-Check.
Nincs felesleges webkeresés. Szigorú, de intelligens Sane-Check.
"""
def __init__(self):
self.max_attempts = 5
@@ -31,34 +32,38 @@ class TechEnricher:
self.last_reset_date = datetime.date.today()
return self.ai_calls_today < self.daily_ai_limit
def is_data_sane(self, data: dict, base_info: dict) -> bool:
""" Szigorított AI Hallucináció szűrő """
if not data: return False
try:
ccm = int(data.get("ccm", 0) or 0)
kw = int(data.get("kw", 0) or 0)
v_class = base_info.get("v_type", "car")
# 1. Alapvető fizikai korlátok
if ccm > 18000 or (kw > 1500 and v_class != "truck"):
return False
# 2. Üres adatok kizárása (Kivéve elektromos autók, ahol ccm = 0)
fuel = data.get("fuel_type", base_info.get("rdw_fuel", "")).lower()
if kw == 0:
return False
if ccm == 0 and "electric" not in fuel and "elektric" not in fuel and v_class != "trailer":
return False
def validate_merged_data(self, merged_kw: int, merged_ccm: int, v_class: str, fuel: str, current_attempts: int) -> tuple[bool, str]:
""" Intelligens validáció a MERGE után. Visszaadja a státuszt és a hiba okát. """
if merged_ccm > 18000:
return False, f"Irreális CCM érték ({merged_ccm})"
if merged_kw > 1500 and v_class != "truck":
return False, f"Irreális KW érték ({merged_kw})"
return True
except Exception as e:
logger.debug(f"Sane check hiba: {e}")
return False
# Ha hiányzik a KW
if merged_kw == 0:
if current_attempts < 3:
return False, "Hiányzó KW adat. Újrakutatás javasolt."
else:
logger.warning("Sane-check: Többszöri próbálkozás után sincs KW, de átengedjük részlegesként.")
# Ha hiányzik a CCM (és belsőégésű)
if merged_ccm == 0 and "electric" not in fuel and "elektric" not in fuel and v_class != "trailer":
if current_attempts < 3:
return False, "Hiányzó CCM (belsőégésű motornál). Újrakutatás javasolt."
else:
logger.warning("Sane-check: Többszöri próbálkozás után sincs CCM, átengedjük részlegesként.")
return True, "OK"
async def process_single_record(self, db, record_id: int, base_info: dict, current_attempts: int):
# Pontos azonosító a logokhoz (Márka, Modell, ID, RDW adatok)
v_ident = f"{base_info['make'].upper()} {base_info['m_name']} (ID: {record_id}, RDW: {base_info['rdw_ccm']}ccm, KW: {base_info['rdw_kw']})"
attempt_str = f"[Próba: {current_attempts + 1}/{self.max_attempts}]"
ai_data = {} # Üres dict, ha az AI hívás elszállna
try:
logger.info(f"🧠 AI dúsítás indul: {base_info['make']} {base_info['m_name']}")
logger.info(f"🧠 AI dúsítás indul: {v_ident} {attempt_str}")
# 1. LÉPÉS: AI Hívás (Rábízzuk az adatokat a modellre)
ai_data = await AIService.get_clean_vehicle_data(
@@ -66,14 +71,14 @@ class TechEnricher:
base_info['m_name'],
base_info
)
if not ai_data:
raise ValueError("Teljesen üres AI válasz (API hiba vagy extrém hallucináció).")
# 2. LÉPÉS: Validáció (Ha az AI rossz adatot ad, NEM megyünk ki a webre, hanem dobjuk az aktát!)
if not ai_data or not self.is_data_sane(ai_data, base_info):
raise ValueError("Az AI hiányos adatot adott vissza vagy hallucinált.")
# 3. LÉPÉS: HIBRID MERGE (Az RDW adatok felülbírálják az AI-t a hatósági paramétereknél)
final_kw = base_info['rdw_kw'] if base_info['rdw_kw'] > 0 else (ai_data.get("kw") or 0)
final_ccm = base_info['rdw_ccm'] if base_info['rdw_ccm'] > 0 else (ai_data.get("ccm") or 0)
# 2. LÉPÉS: HIBRID MERGE (Még a validáció előtt!)
# Az RDW adatok felülbírálják az AI-t a hatósági paramétereknél
final_kw = base_info['rdw_kw'] if base_info['rdw_kw'] > 0 else int(ai_data.get("kw", 0) or 0)
final_ccm = base_info['rdw_ccm'] if base_info['rdw_ccm'] > 0 else int(ai_data.get("ccm", 0) or 0)
# Üzemanyag tisztítása
fuel_rdw = base_info.get('rdw_fuel', '')
@@ -83,6 +88,11 @@ class TechEnricher:
final_euro = base_info['rdw_euro'] or ai_data.get("euro_classification")
final_cylinders = base_info['rdw_cylinders'] or ai_data.get("cylinders")
# 3. LÉPÉS: Intelligens Validáció
is_valid, error_msg = self.validate_merged_data(final_kw, final_ccm, base_info['v_type'], final_fuel.lower(), current_attempts)
if not is_valid:
raise ValueError(f"Validációs hiba: {error_msg}")
# 4. LÉPÉS: Mentés az Arany Katalógusba
clean_model = str(ai_data.get("marketing_name", base_info['m_name']))[:50].upper()
@@ -90,7 +100,7 @@ class TechEnricher:
INSERT INTO data.vehicle_catalog
(master_definition_id, make, model, power_kw, engine_capacity, fuel_type, factory_data)
VALUES (:m_id, :make, :model, :kw, :ccm, :fuel, :factory)
ON CONFLICT (make, model, year_from, fuel_type) DO NOTHING
ON CONFLICT ON CONSTRAINT uix_vehicle_catalog_full DO NOTHING
RETURNING id;
""")
@@ -121,15 +131,18 @@ class TechEnricher:
)
)
await db.commit()
logger.info(f"✨ ARANY REKORD KÉSZ: {base_info['make'].upper()} {clean_model}")
logger.info(f"✨ ARANY REKORD KÉSZ: {v_ident}")
self.ai_calls_today += 1
except Exception as e:
await db.rollback()
logger.warning(f"⚠️ Alkimista hiba ({base_info['make']} {base_info['m_name']}): {e}")
logger.warning(f"⚠️ Alkimista hiba - {v_ident}: {e}")
# Visszaküldés a sorba vagy felfüggesztés
new_status = 'suspended' if current_attempts + 1 >= self.max_attempts else 'unverified'
# Ha elértük a limitet, KÉZI MODERÁCIÓRA küldjük, egyébként vissza a Kutatónak
new_status = 'manual_review_needed' if current_attempts + 1 >= self.max_attempts else 'unverified'
# Elmentjük az AI részleges válaszát (vagy a hibát), hogy az admin lássa, mit rontott el a gép
review_data = ai_data if ai_data else {"error": "Nincs értékelhető JSON adat az AI-tól", "raw_context": base_info['web_context']}
await db.execute(
update(VehicleModelDefinition)
@@ -138,15 +151,19 @@ class TechEnricher:
attempts=current_attempts + 1,
last_error=str(e)[:200],
status=new_status,
specifications=review_data, # Kézi ellenőrzéshez beírjuk a törött adatot!
updated_at=func.now()
)
)
await db.commit()
if new_status == 'unverified':
logger.info("♻️ Akta visszaküldve a Robot-2-nek (Kutató).")
logger.info(f"♻️ Akta visszaküldve a Robot-2-nek (Kutató). {attempt_str}")
else:
logger.error(f"🛑 Max próbálkozás elérve! Kézi moderációra küldve: {v_ident}")
async def run(self):
logger.info(f"🚀 Alchemist Pro HIBRID ONLINE (Atomi Zárolás Patch)")
logger.info(f"🚀 Alchemist Pro HIBRID ONLINE (Atomi Zárolás + Moderáció Patch)")
while True:
if not self.check_budget():
logger.warning("💸 Napi AI limit kimerítve! Pihenés...")
@@ -155,7 +172,6 @@ class TechEnricher:
try:
async with AsyncSessionLocal() as db:
# ATOMI ZÁROLÁS (A "Szent Grál" a race condition ellen)
# A Robot-1 (ACTIVE) és a Robot-2 (awaiting_ai_synthesis) aktáit is felveszi!
query = text("""
UPDATE data.vehicle_model_definitions
SET status = 'ai_synthesis_in_progress'
@@ -204,5 +220,4 @@ class TechEnricher:
await asyncio.sleep(10)
if __name__ == "__main__":
import os # Import az AI limit környezeti változóhoz
asyncio.run(TechEnricher().run())