Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
38.24% covered (danger)
38.24%
13 / 34
25.00% covered (danger)
25.00%
1 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
AiInstructor
38.24% covered (danger)
38.24%
13 / 34
25.00% covered (danger)
25.00%
1 / 4
10.89
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 instruct
66.67% covered (warning)
66.67%
12 / 18
0.00% covered (danger)
0.00%
0 / 1
2.15
 createForCustomConfig
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 createForOllama
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2namespace Apie\AiInstructor;
3
4use Apie\Core\Context\ApieContext;
5use Apie\Core\ValueObjects\NonEmptyString;
6use Apie\SchemaGenerator\ComponentsBuilderFactory;
7use Apie\SchemaGenerator\SchemaGenerator;
8use Apie\Serializer\Serializer;
9use ReflectionNamedType;
10use ReflectionUnionType;
11use Symfony\Component\HttpClient\HttpClient;
12
13final class AiInstructor
14{
15    public function __construct(
16        private readonly SchemaGenerator $schemaGenerator,
17        private readonly Serializer $serializer,
18        private readonly AiClient $aiClient
19    ) {
20    }
21
22    public function instruct(
23        ReflectionNamedType|ReflectionUnionType $type,
24        NonEmptyString $model,
25        string $systemMessage,
26        string $prompt
27    ) {
28        $schema = $this->schemaGenerator->createSchema((string) $type);
29        $response = $this->aiClient->ask(
30            $systemMessage,
31            $prompt,
32            $schema,
33            $model
34        );
35        try {
36            return $this->serializer->denormalizeNewObject(
37                json_decode($response, true),
38                (string) $type,
39                new ApieContext()
40            );
41        } catch (\Exception $exception) {
42            throw new \LogicException(
43                "I could not map the AI response '" . $response . "' to '" . ((string) $type) . "', error: '" . $exception->getMessage() . '"',
44                0,
45                $exception
46            );
47        }
48    }
49
50    public static function createForCustomConfig(string $apiKey, string $baseUrl): self
51    {
52        return new self(
53            new SchemaGenerator(ComponentsBuilderFactory::createComponentsBuilderFactory()),
54            Serializer::create(),
55            new AiClient(
56                HttpClient::create([
57                    'max_redirects' => 7,
58                ]),
59                $apiKey,
60                $baseUrl
61            )
62        );
63    }
64
65    public static function createForOllama()
66    {
67        return self::createForCustomConfig(
68            'IGNORED',
69            'http://localhost:11434/',
70        );
71    }
72}