Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
OllamaClient
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
2 / 2
3
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 ask
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2namespace Apie\AiInstructor;
3
4use cebe\openapi\spec\Schema;
5use Symfony\Component\HttpClient\Exception\ClientException;
6use Symfony\Component\HttpClient\HttpClient;
7use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
8use Symfony\Contracts\HttpClient\HttpClientInterface;
9
10class OllamaClient extends AiClient
11{
12    private HttpClientInterface $client;
13    private string $baseUrl;
14
15    public function __construct(?HttpClientInterface $client = null, string $baseUrl = 'http://localhost:11434')
16    {
17        $this->client = $client ?? HttpClient::create([]);
18        $this->baseUrl = rtrim($baseUrl, '/');
19    }
20
21    public function ask(string $systemMessage, string $prompt, Schema $schema, ?string $model = null): string
22    {
23        try {
24            $response = $this->client->request('POST', $this->baseUrl . '/api/chat', [
25                'headers' => [
26                    'Content-Type' => 'application/json',
27                ],
28                'json' => [
29                    'model' => $model ?? 'tinyllama',
30                    'stream' => false,
31                    'format' => $schema->getSerializableData(),
32                    'messages' => [
33                        ['role' => 'system', 'content' => $systemMessage],
34                        ['role' => 'user', 'content' => $prompt],
35                    ],
36                ],
37            ]);
38
39            $data = $response->toArray();
40
41            return $data['message']['content'] ?? 'No response';
42        } catch (TransportExceptionInterface|ClientException $e) {
43            throw new \RuntimeException(
44                'Request failed: ' . $e->getMessage() . ' "' . ($response ?? null)?->getContent(false) . '"',
45                0,
46                $e
47            );
48        }
49    }
50}