PluginProbe
Auto Alt Text / 3.0.3
Auto Alt Text v3.0.3
3.0.3 2.8.2 1.3.1 1.3.2 2.0.0 2.1.0 2.1.1 2.2.0 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.5.0 2.5.1 2.5.2 2.5.3 2.6.0 2.6.1 2.7.0 2.8.0 2.8.1 All 28 releases
auto-alt-text / src / App / AIProviders / Anthropic / AnthropicResponse.php

AnthropicResponse.php in Auto Alt Text 3.0.3, at src/App/AIProviders/Anthropic/AnthropicResponse.php

176 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace AATXT\App\AIProviders\Anthropic;
4
5 use AATXT\App\AIProviders\AIProviderInterface;
6 use AATXT\App\AIProviders\Contracts\RequiresAuthentication;
7 use AATXT\App\AIProviders\Contracts\SupportsImageValidation;
8 use AATXT\App\Configuration\AIProviderConfig;
9 use AATXT\App\Exceptions\Anthropic\AnthropicException;
10 use AATXT\App\Infrastructure\Http\HttpClientInterface;
11 use AATXT\Config\Constants;
12
13 /**
14 * Anthropic Claude provider for generating alt text using Claude models.
15 *
16 * Implements SupportsImageValidation and RequiresAuthentication interfaces
17 * following the Interface Segregation Principle.
18 */
19 class AnthropicResponse implements AIProviderInterface, SupportsImageValidation, RequiresAuthentication
20 {
21 /**
22 * @var HttpClientInterface
23 */
24 private $httpClient;
25
26 /**
27 * @var AIProviderConfig
28 */
29 private $config;
30
31 /**
32 * @var AnthropicModelsRegistry|null
33 */
34 private $modelsRegistry;
35
36 /**
37 * Constructor.
38 *
39 * @param HttpClientInterface $httpClient HTTP client for API calls
40 * @param AIProviderConfig $config Configuration with API key, prompt, and model
41 * @param AnthropicModelsRegistry|null $modelsRegistry Optional registry used to fall back
42 * to a currently-available model when the configured one has been retired
43 */
44 public function __construct(
45 HttpClientInterface $httpClient,
46 AIProviderConfig $config,
47 ?AnthropicModelsRegistry $modelsRegistry = null
48 ) {
49 $this->httpClient = $httpClient;
50 $this->config = $config;
51 $this->modelsRegistry = $modelsRegistry;
52 }
53
54 /**
55 * Get the list of supported MIME types for Anthropic Claude.
56 *
57 * @return array<string> List of supported MIME types
58 */
59 public function getSupportedMimeTypes(): array
60 {
61 return Constants::AATXT_ANTHROPIC_ALLOWED_MIME_TYPES;
62 }
63
64 /**
65 * Check if a specific MIME type is supported.
66 *
67 * @param string $mimeType The MIME type to check
68 * @return bool True if supported, false otherwise
69 */
70 public function supportsImage(string $mimeType): bool
71 {
72 return in_array($mimeType, $this->getSupportedMimeTypes(), true);
73 }
74
75 /**
76 * Validate that valid credentials are configured.
77 *
78 * @return bool True if credentials are valid
79 */
80 public function validateCredentials(): bool
81 {
82 $apiKey = $this->config->getApiKey();
83 return !empty($apiKey) && strlen($apiKey) > 10;
84 }
85
86 /**
87 * Check if an API key is configured.
88 *
89 * @return bool True if API key is set
90 */
91 public function hasApiKey(): bool
92 {
93 return !empty($this->config->getApiKey());
94 }
95
96 /**
97 * Make a request to Anthropic Claude API to retrieve a description for the image passed
98 *
99 * @param string $imageUrl
100 * @return string
101 * @throws AnthropicException
102 */
103 public function response(string $imageUrl): string
104 {
105 $apiKey = $this->config->getApiKey();
106
107 if (empty($apiKey)) {
108 throw new AnthropicException('Anthropic API key is missing in plugin settings');
109 }
110
111 $payload = [
112 "model" => $this->resolveModel(),
113 "max_tokens" => 1024,
114 "messages" => [
115 [
116 "role" => "user",
117 "content" => [
118 [
119 "type" => "image",
120 "source" => [
121 "type" => "url",
122 "url" => $imageUrl,
123 ],
124 ],
125 [
126 "type" => "text",
127 "text" => $this->config->getPrompt(),
128 ],
129 ],
130 ],
131 ],
132 ];
133
134 $headers = [
135 'Content-Type' => 'application/json',
136 'x-api-key' => $apiKey,
137 'anthropic-version' => Constants::AATXT_API_VERSION,
138 ];
139
140 try {
141 $data = $this->httpClient->post(Constants::AATXT_ANTHROPIC_ENDPOINT, $headers, $payload);
142 } catch (\Exception $e) {
143 throw new AnthropicException('HTTP request failed: ' . $e->getMessage());
144 }
145
146 $answer = $data['content'][0]['text'] ?? null;
147
148 if (!$answer) {
149 $bodyJson = json_encode($data);
150 throw new AnthropicException('Response format unexpected: ' . $bodyJson);
151 }
152
153 return $answer;
154 }
155
156 /**
157 * Return the model id to send to the API, transparently falling back to the
158 * most recent available model when the configured one is no longer listed
159 * by the registry.
160 */
161 private function resolveModel(): string
162 {
163 $configured = $this->config->getModel();
164
165 if ($this->modelsRegistry === null || $configured === '') {
166 return $configured;
167 }
168
169 if ($this->modelsRegistry->isAvailable($configured)) {
170 return $configured;
171 }
172
173 return $this->modelsRegistry->getDefaultModel();
174 }
175 }
176