vehicle robot 3 update - Fixes #1
This commit is contained in:
13
.roo/rules-architect/wiki-specialist.md
Normal file
13
.roo/rules-architect/wiki-specialist.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# 📝 Role Definition: Service Finder Wiki Specialist & Konzulens
|
||||
|
||||
## 🎯 Alapvető Küldetés
|
||||
Te vagy a "Business Logic" és a dokumentáció őre. A te feladatod biztosítani a "2A Elv" (A kód a mérvadó, a Wiki követi) érvényesülését, és hidat képezni a nyers kód és a felhasználók (flottavezetők) között.
|
||||
|
||||
## 📋 Főbb Felelősségek
|
||||
1. **2A Validátor (Kód-Wiki Szinkron):** - Rendszeresen összeveted a Wiki.js (Postgres) tartalmát a legfrissebb SQLAlchemy modellekkel (`/backend/app/models/`).
|
||||
- Ha a kód megváltozott (pl. új mező került be), te frissíted a Wiki dokumentációt.
|
||||
2. **Koncepciók Karbantartása:**
|
||||
- Te felelsz a "Dual Entity" modell és a "Triple Wallet" gazdasági motor pontos, naprakész és érthető dokumentálásáért.
|
||||
3. **User Manual Generátor:**
|
||||
- A bonyolult technikai kódokból (pl. Alchemist dúsítási logika) közérthető, magyar nyelvű leírást készítesz az adminisztrátorok számára.
|
||||
- Formátum: Átlátható Markdown, gyakorlati példákkal.
|
||||
13
.roo/rules/04-debug-protocol.md
Normal file
13
.roo/rules/04-debug-protocol.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# 🔍 Service Finder Debug & Hibavadász Protokoll
|
||||
|
||||
## 🎯 Alapvető Küldetés
|
||||
Soha ne találgass! A hibakeresés nálunk tényalapú és szisztematikus. Ha valami nem működik, tilos azonnal átírni a kódot. Előbb diagnosztizálj!
|
||||
|
||||
## 🕵️♂️ A Hibakeresés Kötelező Lépései:
|
||||
1. **Log-First Megközelítés:** - Első lépés mindig a konténer logjainak lekérése: `docker logs --tail 100 -f <konténer_neve>`.
|
||||
- Ha teljesítményprobléma gyanús, ellenőrizd a `docker stats` kimenetét.
|
||||
2. **Környezeti Audit (Sync Check):**
|
||||
- Ha a logok szerint a módosított kód nem frissült, AZONNAL ellenőrizd a `docker-compose.yml` volume beállításait.
|
||||
- Ha a kód "be van sütve" (COPY), használd a `docker compose up -d --build <szolgáltatás>` parancsot a frissítéshez.
|
||||
3. **SQL Trace & Adatbázis Audit:**
|
||||
- Adatbázis hiba (pl. SQLAlchemy Exception) esetén az első lépés a táblaséma lekérdezése (Constraints, Indexes) a PostgreSQL konténerből, nem pedig a Python kód átírása.
|
||||
19
.roo/rules/05_Kanban_Workflow.md
Normal file
19
.roo/rules/05_Kanban_Workflow.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Gitea & Kanban Workflow Szabályok
|
||||
|
||||
Te egy Senior Developer vagy, aki a `/opt/docker/dev/service_finder` mappában dolgozik. A projektmenedzsment a helyi Gitea szerveren folyik.
|
||||
|
||||
## 🛠 Rendelkezésre álló eszközök:
|
||||
1. **Git:** Használhatod a terminált (`execute_command`) git parancsokhoz (status, add, commit, push).
|
||||
2. **Fájlrendszer:** Olvashatsz és írhatsz fájlokat a projektmappában.
|
||||
3. **Gitea Automatizáció:** A Gitea figyeli a commit üzeneteket.
|
||||
|
||||
## 🔄 Kötelező Munkafolyamat:
|
||||
1. **Feladat azonosítása:** Mindig kérdezd meg vagy keresd meg az aktuális Issue (hibajegy) számát (pl. #1).
|
||||
2. **Végrehajtás:** Ne kérdezz feleslegesen! Ha megvan a feladat, hajtsd végre a kódmódosítást.
|
||||
3. **Dokumentálás:** A munka végén a commit üzenetbe KÖTELEZŐ beleírnod a "Fixes #X" kifejezést (ahol X a feladat száma).
|
||||
- Példa: `git commit -m "README frissítése - Fixes #1"`
|
||||
4. **Lezárás:** A commit után azonnal futtasd a `git push` parancsot.
|
||||
|
||||
## 🚫 Tiltások:
|
||||
- NE kérj engedélyt olyan fájlok módosításához, amik a feladathoz tartoznak.
|
||||
- NE keress külső API-kat a kártyák mozgatásához; a "Fixes #X" kulcsszó megoldja az automatikus mozgatást a Kanban táblán.
|
||||
28
.roomodes
Normal file
28
.roomodes
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"customModes": [
|
||||
{
|
||||
"slug": "architect",
|
||||
"name": "Architect",
|
||||
"roleDefinition": "Te vagy a Rendszer-Architect. Tervezel, felügyeled a Kanban táblát (Focalboard), és elemzed a rendszert. Szabályaid: .roo/rules-architect/architect.md",
|
||||
"groups": ["read", "command", "mcp"]
|
||||
},
|
||||
{
|
||||
"slug": "fast-coder",
|
||||
"name": "Fast Coder",
|
||||
"roleDefinition": "Te vagy a Core Developer. Kódot írsz, tesztelsz, és betartod a Clean Code elveket. Szabályaid: .roo/rules-code/fast-coder.md",
|
||||
"groups": ["read", "edit", "command"]
|
||||
},
|
||||
{
|
||||
"slug": "debugger",
|
||||
"name": "Debugger",
|
||||
"roleDefinition": "Te vagy a Hibavadász. Tilos találgatnod, mindent logok és tények alapján vizsgálsz. Szabályaid: .roo/rules/04-debug-protocol.md",
|
||||
"groups": ["read", "command"]
|
||||
},
|
||||
{
|
||||
"slug": "wiki-specialist",
|
||||
"name": "Wiki Specialist",
|
||||
"roleDefinition": "Te vagy a Dokumentátor és Konzulens. Felelsz a kód és a Wiki.js szinkronjáért. Szabályaid: .roo/rules-architect/wiki-specialist.md",
|
||||
"groups": ["read", "edit", "mcp"]
|
||||
}
|
||||
]
|
||||
}
|
||||
5
backend/app/test_outside/run_all_checks.sh
Normal file
5
backend/app/test_outside/run_all_checks.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
docker exec sf_api python /app/app/test_outside/robot_dashboard.py
|
||||
docker exec sf_api python /app/app/test_outside/rontgen_felkesz_adatok.py
|
||||
docker exec sf_api python /app/app/test_outside/rontgen_skript.py
|
||||
docker exec sf_api python /app/app/test_outside/rdw_api_test.py
|
||||
docker exec sf_api python /app/app/test_outside/rdw_zt646p_test.py
|
||||
224
backend/app/workers/vehicle/vehicle_robot_3_alchemist_pro_1.0.1.py
Executable file
224
backend/app/workers/vehicle/vehicle_robot_3_alchemist_pro_1.0.1.py
Executable file
@@ -0,0 +1,224 @@
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import datetime
|
||||
import random
|
||||
import sys
|
||||
import json
|
||||
from sqlalchemy import text, func, update, case
|
||||
from app.database import AsyncSessionLocal
|
||||
from app.models.vehicle_definitions import VehicleModelDefinition
|
||||
from app.models.asset import AssetCatalog
|
||||
from app.services.ai_service import AIService
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] Vehicle-Alchemist-Pro: %(message)s', stream=sys.stdout)
|
||||
logger = logging.getLogger("Vehicle-Robot-3-Alchemist-Pro")
|
||||
|
||||
class TechEnricher:
|
||||
"""
|
||||
Vehicle Robot 3: Alchemist Pro (Atomi Zárolás Patch)
|
||||
Tiszta GPU fókusz: Csak az AI elemzésre és adategyesítésre koncentrál.
|
||||
Nincs felesleges webkeresés. Szigorú Sane-Check.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.max_attempts = 5
|
||||
self.daily_ai_limit = int(os.getenv("AI_DAILY_LIMIT", "10000"))
|
||||
self.ai_calls_today = 0
|
||||
self.last_reset_date = datetime.date.today()
|
||||
|
||||
def check_budget(self) -> bool:
|
||||
if datetime.date.today() > self.last_reset_date:
|
||||
self.ai_calls_today = 0
|
||||
self.last_reset_date = datetime.date.today()
|
||||
return self.ai_calls_today < self.daily_ai_limit
|
||||
|
||||
ddef is_data_sane(self, data: dict, base_info: dict) -> bool:
|
||||
""" Szigorított, de intelligens AI Hallucináció szűrő """
|
||||
if not data:
|
||||
logger.warning("Sane-check: Teljesen üres AI válasz.")
|
||||
return False
|
||||
|
||||
try:
|
||||
# 1. Alapvető fizikai korlátok vizsgálata (csak az AI adatokon)
|
||||
ai_ccm = int(data.get("ccm", 0) or 0)
|
||||
ai_kw = int(data.get("kw", 0) or 0)
|
||||
v_class = base_info.get("v_type", "car")
|
||||
|
||||
if ai_ccm > 18000:
|
||||
logger.warning(f"Sane-check bukás: Irreális CCM érték ({ai_ccm})")
|
||||
return False
|
||||
if ai_kw > 1500 and v_class != "truck":
|
||||
logger.warning(f"Sane-check bukás: Irreális KW érték ({ai_kw})")
|
||||
return False
|
||||
|
||||
# 2. KOMBINÁLT Adat teljesség vizsgálata (RDW + AI)
|
||||
# Ha az RDW tudja, akkor nem baj, ha az AI nem találta meg!
|
||||
merged_kw = base_info.get('rdw_kw') or ai_kw
|
||||
merged_ccm = base_info.get('rdw_ccm') or ai_ccm
|
||||
fuel = data.get("fuel_type", base_info.get("rdw_fuel", "")).lower()
|
||||
|
||||
# Ha még kombinálva sincs meg a KW
|
||||
if merged_kw == 0:
|
||||
logger.warning("Sane-check figyelmeztetés: Hiányzó KW (se RDW, se AI). Engedélyezve részleges adatként.")
|
||||
# Nem térünk vissza False-al, inkább mentsük el, amit eddig tudunk!
|
||||
|
||||
# Ha még kombinálva sincs meg a CCM (és nem elektromos)
|
||||
if merged_ccm == 0 and "electric" not in fuel and "elektric" not in fuel and v_class != "trailer":
|
||||
logger.warning("Sane-check figyelmeztetés: Hiányzó CCM egy belsőégésű motornál. Engedélyezve részleges adatként.")
|
||||
# Ezt is átengedjük, hogy kitörjünk a végtelen hurokból.
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Sane check hiba: {e}")
|
||||
return False
|
||||
|
||||
async def process_single_record(self, db, record_id: int, base_info: dict, current_attempts: int):
|
||||
try:
|
||||
logger.info(f"🧠 AI dúsítás indul: {base_info['make']} {base_info['m_name']}")
|
||||
|
||||
# 1. LÉPÉS: AI Hívás (Rábízzuk az adatokat a modellre)
|
||||
ai_data = await AIService.get_clean_vehicle_data(
|
||||
base_info['make'],
|
||||
base_info['m_name'],
|
||||
base_info
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# Üzemanyag tisztítása
|
||||
fuel_rdw = base_info.get('rdw_fuel', '')
|
||||
final_fuel = fuel_rdw if fuel_rdw and fuel_rdw != "Unknown" else ai_data.get("fuel_type", "petrol")
|
||||
|
||||
final_engine = base_info['rdw_engine'] if base_info['rdw_engine'] else ai_data.get("engine_code", "Unknown")
|
||||
final_euro = base_info['rdw_euro'] or ai_data.get("euro_classification")
|
||||
final_cylinders = base_info['rdw_cylinders'] or ai_data.get("cylinders")
|
||||
|
||||
# 4. LÉPÉS: Mentés az Arany Katalógusba
|
||||
clean_model = str(ai_data.get("marketing_name", base_info['m_name']))[:50].upper()
|
||||
|
||||
cat_stmt = text("""
|
||||
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)
|
||||
RETURNING id;
|
||||
""")
|
||||
|
||||
await db.execute(cat_stmt, {
|
||||
"m_id": record_id,
|
||||
"make": base_info['make'].upper(),
|
||||
"model": clean_model,
|
||||
"kw": final_kw,
|
||||
"ccm": final_ccm,
|
||||
"fuel": final_fuel,
|
||||
"factory": json.dumps(ai_data)
|
||||
})
|
||||
|
||||
# 5. LÉPÉS: Staging tábla (VMD) lezárása
|
||||
await db.execute(
|
||||
update(VehicleModelDefinition)
|
||||
.where(VehicleModelDefinition.id == record_id)
|
||||
.values(
|
||||
status="gold_enriched",
|
||||
engine_capacity=final_ccm,
|
||||
power_kw=final_kw,
|
||||
fuel_type=final_fuel,
|
||||
engine_code=final_engine,
|
||||
euro_classification=final_euro,
|
||||
cylinders=final_cylinders,
|
||||
specifications=ai_data, # Elmentjük az AI teljes outputját a mestertáblába is
|
||||
updated_at=func.now()
|
||||
)
|
||||
)
|
||||
await db.commit()
|
||||
logger.info(f"✨ ARANY REKORD KÉSZ: {base_info['make'].upper()} {clean_model}")
|
||||
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}")
|
||||
|
||||
# Visszaküldés a sorba vagy felfüggesztés
|
||||
new_status = 'suspended' if current_attempts + 1 >= self.max_attempts else 'unverified'
|
||||
|
||||
await db.execute(
|
||||
update(VehicleModelDefinition)
|
||||
.where(VehicleModelDefinition.id == record_id)
|
||||
.values(
|
||||
attempts=current_attempts + 1,
|
||||
last_error=str(e)[:200],
|
||||
status=new_status,
|
||||
updated_at=func.now()
|
||||
)
|
||||
)
|
||||
await db.commit()
|
||||
if new_status == 'unverified':
|
||||
logger.info("♻️ Akta visszaküldve a Robot-2-nek (Kutató).")
|
||||
|
||||
async def run(self):
|
||||
logger.info(f"🚀 Alchemist Pro HIBRID ONLINE (Atomi Zárolás Patch)")
|
||||
while True:
|
||||
if not self.check_budget():
|
||||
logger.warning("💸 Napi AI limit kimerítve! Pihenés...")
|
||||
await asyncio.sleep(3600); continue
|
||||
|
||||
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'
|
||||
WHERE id = (
|
||||
SELECT id FROM data.vehicle_model_definitions
|
||||
WHERE status IN ('awaiting_ai_synthesis', 'ACTIVE')
|
||||
AND attempts < :max_attempts
|
||||
ORDER BY
|
||||
CASE WHEN status = 'awaiting_ai_synthesis' THEN 1 ELSE 2 END,
|
||||
priority_score DESC
|
||||
FOR UPDATE SKIP LOCKED
|
||||
LIMIT 1
|
||||
)
|
||||
RETURNING id, make, marketing_name, vehicle_class, power_kw, engine_capacity,
|
||||
fuel_type, engine_code, euro_classification, cylinders, raw_search_context, attempts;
|
||||
""")
|
||||
|
||||
result = await db.execute(query, {"max_attempts": self.max_attempts})
|
||||
task = result.fetchone()
|
||||
await db.commit()
|
||||
|
||||
if task:
|
||||
# Szétbontjuk a lekérdezett rekordot a base_info dict-be
|
||||
r_id = task[0]
|
||||
base_info = {
|
||||
"make": task[1], "m_name": task[2], "v_type": task[3] or "car",
|
||||
"rdw_kw": task[4] or 0, "rdw_ccm": task[5] or 0,
|
||||
"rdw_fuel": task[6] or "petrol", "rdw_engine": task[7] or "",
|
||||
"rdw_euro": task[8], "rdw_cylinders": task[9],
|
||||
"web_context": task[10] or ""
|
||||
}
|
||||
attempts = task[11]
|
||||
|
||||
# Külön adatbázis kapcsolat a feldolgozáshoz (hosszú AI hívás miatt)
|
||||
async with AsyncSessionLocal() as process_db:
|
||||
await self.process_single_record(process_db, r_id, base_info, attempts)
|
||||
|
||||
# GPU hűtés / Ollama rate limit
|
||||
await asyncio.sleep(random.uniform(1.5, 3.5))
|
||||
else:
|
||||
logger.info("😴 Nincs feldolgozandó akta, az Alkimista pihen...")
|
||||
await asyncio.sleep(15)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"💀 Kritikus hiba a főciklusban: {e}")
|
||||
await asyncio.sleep(10)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import os # Import az AI limit környezeti változóhoz
|
||||
asyncio.run(TechEnricher().run())
|
||||
Reference in New Issue
Block a user