MistralAdapter::chat()   A
last analyzed

Complexity

Conditions 3
Paths 6

Size

Total Lines 53
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 36
nc 6
nop 3
dl 0
loc 53
rs 9.344
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Squareetlabs\LaravelToon\Adapters;
6
7
use Illuminate\Http\Client\PendingRequest;
8
use Illuminate\Support\Facades\Http;
9
10
class MistralAdapter extends BaseLLMAdapter
11
{
12
    private ?PendingRequest $client = null;
13
14
    public function getName(): string
15
    {
16
        return 'Mistral AI';
17
    }
18
19
    public function isEnabled(): bool
20
    {
21
        return config('laravel-toon.adapters.mistral.enabled', false);
22
    }
23
24
    public function sendMessage(
25
        string $message,
26
        ?string $model = null,
27
        ?array $options = null
28
    ): array {
29
        if (!$this->isEnabled()) {
30
            return ['success' => false, 'error' => 'Mistral adapter not enabled'];
31
        }
32
33
        $model ??= $this->getDefaultModel();
34
        $options ??= [];
35
36
        $toonMessage = $this->compressMessage($message);
37
38
        $payload = array_merge([
39
            'model' => $model,
40
            'messages' => [
41
                ['role' => 'user', 'content' => $toonMessage],
42
            ],
43
        ], $options);
44
45
        try {
46
            $response = $this->getClient()
47
                ->post('/chat/completions', $payload)
48
                ->throw()
49
                ->json();
50
51
            return [
52
                'success' => true,
53
                'adapter' => 'mistral',
54
                'model' => $model,
55
                'original_message_tokens' => $this->tokenAnalyzer->estimate($message),
56
                'compressed_message_tokens' => $this->tokenAnalyzer->estimate($toonMessage),
57
                'response' => $response,
58
                'compressed_message' => $toonMessage,
59
            ];
60
        } catch (\Exception $e) {
61
            return [
62
                'success' => false,
63
                'error' => $e->getMessage(),
64
            ];
65
        }
66
    }
67
68
    public function chat(
69
        array $messages,
70
        ?string $model = null,
71
        ?array $options = null
72
    ): array {
73
        if (!$this->isEnabled()) {
74
            return ['success' => false, 'error' => 'Mistral adapter not enabled'];
75
        }
76
77
        $model ??= $this->getDefaultModel();
78
        $options ??= [];
79
80
        // Compress messages
81
        $compressedMessages = array_map(fn ($msg) => [
82
            ...$msg,
83
            'content' => $this->compressMessage($msg['content']),
84
        ], $messages);
85
86
        $payload = array_merge([
87
            'model' => $model,
88
            'messages' => $compressedMessages,
89
        ], $options);
90
91
        try {
92
            $response = $this->getClient()
93
                ->post('/chat/completions', $payload)
94
                ->throw()
95
                ->json();
96
97
            $originalTokens = array_sum(array_map(
98
                fn ($msg) => $this->tokenAnalyzer->estimate($msg['content']),
99
                $messages
100
            ));
101
102
            $compressedTokens = array_sum(array_map(
103
                fn ($msg) => $this->tokenAnalyzer->estimate($msg['content']),
104
                $compressedMessages
105
            ));
106
107
            return [
108
                'success' => true,
109
                'adapter' => 'mistral',
110
                'model' => $model,
111
                'messages_count' => count($messages),
112
                'original_tokens' => $originalTokens,
113
                'compressed_tokens' => $compressedTokens,
114
                'tokens_saved' => $originalTokens - $compressedTokens,
115
                'response' => $response,
116
            ];
117
        } catch (\Exception $e) {
118
            return [
119
                'success' => false,
120
                'error' => $e->getMessage(),
121
            ];
122
        }
123
    }
124
125
    public function getDefaultModel(): string
126
    {
127
        return config('laravel-toon.adapters.mistral.default_model', 'mistral-large-latest');
128
    }
129
130
    public function getAvailableModels(): array
131
    {
132
        return [
133
            'mistral-large-latest',
134
            'mistral-medium-latest',
135
            'mistral-small-latest',
136
            'mistral-tiny',
137
        ];
138
    }
139
140
    private function getClient(): PendingRequest
141
    {
142
        if (null === $this->client) {
143
            $baseUrl = config('laravel-toon.adapters.mistral.base_url', 'https://api.mistral.ai');
144
            $apiKey = config('laravel-toon.adapters.mistral.api_key');
145
            $timeout = config('laravel-toon.adapters.mistral.timeout', 30);
146
147
            $this->client = Http::baseUrl($baseUrl)
148
                ->withHeader('Authorization', 'Bearer '.$apiKey)
149
                ->withHeader('Content-Type', 'application/json')
150
                ->timeout($timeout);
151
        }
152
153
        return $this->client;
154
    }
155
}
156
157