Files
service-finder/backend/app/services/ai_service.py

95 lines
3.4 KiB
Python

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
from app.db.session import SessionLocal
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:
async with SessionLocal() 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)