llm_service.py

Code Hygiene Score: 84

Issues 1

Zeile Typ Beschreibung
73 magic_number Magic Number gefunden: 1000

Dependencies 11

Klassen 1

Code

"""LLM-Service für Wissensextraktion."""

import json
import re
import sys
import time

import requests

sys.path.insert(0, "/var/www/scripts/pipeline")

from config import ANTHROPIC_API_KEY, OLLAMA_HOST
from db import db

from .models import DEFAULT_MODELS, ModelConfig


class LLMService:
    """Service für LLM-Aufrufe."""

    def __init__(self, model_config: ModelConfig | None = None):
        """Initialisiere Service mit Modellkonfiguration."""
        self.model = model_config or DEFAULT_MODELS["ollama"]
        self.anthropic_client = None

        if self.model.provider == "anthropic":
            self._init_anthropic()

    def _init_anthropic(self):
        """Initialisiere Anthropic Client."""
        try:
            import anthropic

            if ANTHROPIC_API_KEY:
                self.anthropic_client = anthropic.Anthropic(api_key=ANTHROPIC_API_KEY)
        except ImportError:
            db.log("WARNING", "Anthropic SDK nicht installiert, fallback zu Ollama")
            self.model = DEFAULT_MODELS["ollama"]

    def call_llm(self, prompt: str, json_output: bool = True) -> str:
        """Rufe LLM auf und gib Antwort zurück."""
        start_time = time.time()

        try:
            if self.model.provider == "anthropic" and self.anthropic_client:
                response = self.anthropic_client.messages.create(
                    model=self.model.model_name,
                    max_tokens=self.model.max_tokens,
                    temperature=self.model.temperature,
                    messages=[{"role": "user", "content": prompt}],
                )
                result = response.content[0].text
                tokens_in = response.usage.input_tokens
                tokens_out = response.usage.output_tokens
            else:
                # Ollama
                payload = {
                    "model": self.model.model_name,
                    "prompt": prompt,
                    "stream": False,
                    "options": {"temperature": self.model.temperature},
                }
                if json_output:
                    payload["format"] = "json"

                resp = requests.post(f"{OLLAMA_HOST}/api/generate", json=payload, timeout=600)
                resp.raise_for_status()
                data = resp.json()
                result = data.get("response", "")
                tokens_in = data.get("prompt_eval_count", 0)
                tokens_out = data.get("eval_count", 0)

            duration_ms = int((time.time() - start_time) * 1000)

            # Protokolliere LLM-Aufruf
            db.log_to_protokoll(
                client_name="pipeline-knowledge",
                request=prompt[:500],
                response=result[:500],
                model_name=f"{self.model.provider}:{self.model.model_name}",
                tokens_input=tokens_in,
                tokens_output=tokens_out,
                duration_ms=duration_ms,
                status="completed",
            )

            return result

        except Exception as e:
            db.log("ERROR", f"LLM-Aufruf fehlgeschlagen: {e}")
            return "{}"

    def parse_json(self, text: str) -> dict:
        """Extrahiere JSON aus LLM-Antwort."""
        try:
            # Versuche direkt zu parsen
            return json.loads(text)
        except json.JSONDecodeError:
            # Suche nach JSON-Block
            match = re.search(r"\{[\s\S]*\}", text)
            if match:
                try:
                    return json.loads(match.group())
                except json.JSONDecodeError:
                    pass
        return {}
← Übersicht Graph