Backup #371

ID371
Dateipfad/var/www/dev.campus.systemische-tools.de/src/Infrastructure/AI/OllamaService.php
Version2
Typ modified
Größe7.3 KB
Hashd7ba59aee06375f89eddb31c1eba1373e27635c65a8535283de253342e6cffbd
Datum2025-12-22 08:25:22
Geändert vonclaude-code-hook
GrundClaude Code Pre-Hook Backup vor Edit-Operation
Datei existiert Ja

Dateiinhalt

<?php

declare(strict_types=1);

namespace Infrastructure\AI;

use RuntimeException;

/**
 * Service for interacting with Ollama API for embeddings and text generation.
 *
 * Provides methods to:
 * - Generate embeddings from text using models like mxbai-embed-large
 * - Generate text responses using LLMs like gemma3:4b-it-qat
 * - Check API availability and health status
 *
 * This service uses cURL for HTTP requests without external dependencies.
 * All methods include proper timeout handling and exception management.
 *
 * @package Infrastructure\AI
 * @author  System Generated
 * @version 1.0.0
 */
final readonly class OllamaService
{
    /**
     * Default timeout for HTTP requests in seconds.
     */
    private const int DEFAULT_TIMEOUT = 60;

    /**
     * Health check timeout in seconds.
     */
    private const int HEALTH_CHECK_TIMEOUT = 5;

    /**
     * Constructs a new OllamaService instance.
     *
     * @param string $host The Ollama API host URL (default: http://localhost:11434)
     */
    public function __construct(
        private string $host = 'http://localhost:11434'
    ) {
    }

    /**
     * Generates an embedding vector for the given text.
     *
     * Uses the specified model to convert text into a numerical vector representation.
     * The default model mxbai-embed-large produces 1024-dimensional embeddings.
     *
     * @param string $text  The text to embed
     * @param string $model The embedding model to use (default: mxbai-embed-large)
     *
     * @return array<int, float> The embedding vector as an array of floats
     *
     * @throws RuntimeException If the API request fails or returns invalid data
     *
     * @example
     * $service = new OllamaService();
     * $embedding = $service->getEmbedding('Hello world');
     * // Returns: [0.123, -0.456, 0.789, ...] (1024 dimensions)
     */
    public function getEmbedding(string $text, string $model = 'mxbai-embed-large'): array
    {
        $url = $this->host . '/api/embeddings';

        $payload = [
            'model' => $model,
            'prompt' => $text,
        ];

        $response = $this->makeRequest($url, $payload, self::DEFAULT_TIMEOUT);

        if (!isset($response['embedding']) || !is_array($response['embedding'])) {
            throw new RuntimeException('Invalid embedding response from Ollama API');
        }

        return array_map(
            static fn (mixed $value): float => (float) $value,
            $response['embedding']
        );
    }

    /**
     * Generates text using the specified LLM model.
     *
     * Sends a prompt to the Ollama API and receives generated text in response.
     * This method does not stream responses - it waits for the complete response.
     *
     * @param string $prompt      The prompt to generate text from
     * @param string $model       The LLM model to use (default: gemma3:4b-it-qat)
     * @param float  $temperature Sampling temperature 0.0-1.0 (default: 0.7)
     *
     * @return string The generated text response
     *
     * @throws RuntimeException If the API request fails or returns invalid data
     *
     * @example
     * $service = new OllamaService();
     * $response = $service->generate('Explain quantum computing in simple terms.', 'gemma3:4b-it-qat', 0.7);
     * // Returns: "Quantum computing is a type of computing that..."
     */
    public function generate(string $prompt, string $model = 'gemma3:4b-it-qat', float $temperature = 0.7): string
    {
        $url = $this->host . '/api/generate';

        $payload = [
            'model' => $model,
            'prompt' => $prompt,
            'stream' => false,
            'options' => [
                'temperature' => max(0.0, min(1.0, $temperature)),
            ],
        ];

        $response = $this->makeRequest($url, $payload, 120);

        if (!isset($response['response'])) {
            throw new RuntimeException('Invalid generate response from Ollama API');
        }

        return (string) $response['response'];
    }

    /**
     * Checks if the Ollama API is available and responding.
     *
     * Attempts to fetch the list of available models as a health check.
     * This is a quick operation with a short timeout.
     *
     * @return bool True if the API is available, false otherwise
     *
     * @example
     * $service = new OllamaService();
     * if ($service->isAvailable()) {
     *     echo "Ollama is running";
     * } else {
     *     echo "Ollama is not available";
     * }
     */
    public function isAvailable(): bool
    {
        $url = $this->host . '/api/tags';

        try {
            $ch = curl_init($url);

            if ($ch === false) {
                return false;
            }

            curl_setopt_array($ch, [
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => self::HEALTH_CHECK_TIMEOUT,
                CURLOPT_CONNECTTIMEOUT => self::HEALTH_CHECK_TIMEOUT,
                CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
            ]);

            $result = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

            curl_close($ch);

            return $result !== false && $httpCode === 200;
        } catch (\Throwable) {
            return false;
        }
    }

    /**
     * Makes an HTTP POST request to the Ollama API.
     *
     * Internal helper method that handles cURL initialization, request execution,
     * error handling, and response parsing.
     *
     * @param string               $url     The API endpoint URL
     * @param array<string, mixed> $payload The JSON payload to send
     * @param int                  $timeout The request timeout in seconds
     *
     * @return array<string, mixed> The decoded JSON response
     *
     * @throws RuntimeException If the request fails or returns an error
     */
    private function makeRequest(string $url, array $payload, int $timeout): array
    {
        $ch = curl_init($url);

        if ($ch === false) {
            throw new RuntimeException('Failed to initialize cURL');
        }

        $jsonPayload = json_encode($payload);

        if ($jsonPayload === false) {
            curl_close($ch);

            throw new RuntimeException('Failed to encode JSON payload');
        }

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $jsonPayload,
            CURLOPT_TIMEOUT => $timeout,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'Content-Length: ' . strlen($jsonPayload),
            ],
        ]);

        $result = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $curlError = curl_error($ch);

        curl_close($ch);

        if ($result === false) {
            throw new RuntimeException(
                sprintf('cURL request failed: %s', $curlError !== '' ? $curlError : 'Unknown error')
            );
        }

        if ($httpCode !== 200) {
            throw new RuntimeException(
                sprintf('Ollama API returned HTTP %d: %s', $httpCode, $result)
            );
        }

        $decoded = json_decode((string) $result, true);

        if (!is_array($decoded)) {
            throw new RuntimeException('Failed to decode JSON response from Ollama API');
        }

        return $decoded;
    }
}

Vollständig herunterladen

Aktionen

Herunterladen

Andere Versionen dieser Datei

ID Version Typ Größe Datum
748 8 modified 7.2 KB 2025-12-23 07:59
744 7 modified 7.4 KB 2025-12-23 07:58
375 6 modified 7.4 KB 2025-12-22 08:25
374 5 modified 7.4 KB 2025-12-22 08:25
373 4 modified 7.4 KB 2025-12-22 08:25
372 3 modified 7.4 KB 2025-12-22 08:25
371 2 modified 7.3 KB 2025-12-22 08:25
51 1 modified 7.1 KB 2025-12-20 18:30

← Zurück zur Übersicht