import os import json import logging import asyncio import re import base64 import httpx from typing import Dict, Any, Optional, List from sqlalchemy import select # JAVÍTVA: AsyncSessionLocal használata from app.db.session import AsyncSessionLocal from app.models.system import SystemParameter logger = logging.getLogger("AI-Service") class AIService: OLLAMA_BASE_URL = "http://ollama:11434/api/generate" TEXT_MODEL = "qwen2.5-coder:32b" VISION_MODEL = "llava:7b" DVLA_API_KEY = os.getenv("DVLA_API_KEY") @classmethod async def get_config_delay(cls) -> float: try: # JAVÍTVA: Aszinkron session kezelés async with AsyncSessionLocal() as db: stmt = select(SystemParameter).where(SystemParameter.key == "AI_REQUEST_DELAY") res = await db.execute(stmt) param = res.scalar_one_or_none() return float(param.value) if param else 0.1 except Exception: return 0.1 @classmethod async def get_gold_data_from_research(cls, make: str, model: str, raw_context: str) -> Optional[Dict[str, Any]]: await asyncio.sleep(await cls.get_config_delay()) prompt = f""" FELADAT: A mellékelt kutatási adatokból állíts össze egy hiteles technikai adatlapot. JÁRMŰ: {make} {model} KUTATÁSI ADATOK (Szemetesláda tartalom): {raw_context} SZIGORÚ SZABÁLYOK: 1. Csak a megerősített adatokat töltsd ki. 2. Ha lóerőt (hp/bhp) találsz, váltsd át kW-ra (hp * 0.745). 3. A 'marketing_name' maradjon 50 karakter alatt. VÁLASZ FORMÁTUM (Tiszta JSON): {{ "marketing_name": "string", "technical_code": "string", "ccm": int, "kw": int, "maintenance": {{ "oil_type": "string", "oil_qty_liters": float, "spark_plug": "string", "final_drive": "string" }}, "tires": {{ "front": "string", "rear": "string" }}, "is_duplicate_potential": bool }} """ return await cls._execute_ai_call(prompt, make, model) @classmethod async def _execute_ai_call(cls, prompt: str, make: str, model: str) -> Optional[Dict[str, Any]]: payload = { "model": cls.TEXT_MODEL, "prompt": prompt, "stream": False, "format": "json", "options": {"temperature": 0.1} } try: async with httpx.AsyncClient(timeout=120.0) as client: response = await client.post(cls.OLLAMA_BASE_URL, json=payload) response.raise_for_status() res_json = response.json() return json.loads(res_json.get("response", "{}")) except Exception as e: logger.error(f"❌ AI hiba ({make} {model}): {e}") return None @classmethod async def get_clean_vehicle_data(cls, make: str, raw_model: str, v_type: str, sources: Dict[str, Any]) -> Optional[Dict[str, Any]]: await asyncio.sleep(await cls.get_config_delay()) prompt = f""" FELADAT: Normalizáld a jármű adatait. GYÁRTÓ: {make} | MODELL: {raw_model} ADATOK: {json.dumps(sources)} (JSON válasz marketing_name, synonyms, technical_code, ccm, kw, year_from, year_to) """ return await cls._execute_ai_call(prompt, make, raw_model)