true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ 'content-type: application/json', 'x-api-key: ' . $this->apiKey, 'anthropic-version: 2023-06-01', ], CURLOPT_POSTFIELDS => json_encode([ 'model' => $this->model, 'max_tokens' => $maxTokens, 'system' => [ ['type' => 'text', 'text' => $systemPrompt, 'cache_control' => ['type' => 'ephemeral']], ], 'messages' => [['role' => 'user', 'content' => $userContent]], ]), CURLOPT_TIMEOUT => 90, ]); $raw = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curlError = curl_error($ch); curl_close($ch); if ($raw === false) { throw new RuntimeException("Anthropic-Anfrage fehlgeschlagen: $curlError"); } if ($httpCode >= 400) { throw new RuntimeException("Anthropic-API-Fehler (HTTP $httpCode): " . substr((string) $raw, 0, 500)); } $data = json_decode((string) $raw, true); if (!is_array($data)) { throw new RuntimeException('Anthropic-Antwort konnte nicht als JSON gelesen werden.'); } if (($data['stop_reason'] ?? null) === 'refusal') { throw new RuntimeException('Die KI hat die Anfrage abgelehnt.'); } $text = ''; foreach (($data['content'] ?? []) as $block) { if (($block['type'] ?? null) === 'text') { $text .= $block['text']; } } return [ 'content' => $text, 'inputTokens' => (int) ($data['usage']['input_tokens'] ?? 0), 'outputTokens' => (int) ($data['usage']['output_tokens'] ?? 0), 'cacheCreationInputTokens' => (int) ($data['usage']['cache_creation_input_tokens'] ?? 0), 'cacheReadInputTokens' => (int) ($data['usage']['cache_read_input_tokens'] ?? 0), ]; } }