'https://api.x.ai/v1/responses', 'model' => 'grok-4.7'] : ['url' => 'https://api.openai.com/v1/responses', 'model' => 'gpt-4.1-mini']; if (trim($apiKey) === '') { throw new \RuntimeException('AI_NOT_CONFIGURED'); } if (!in_array($provider, ['openai', 'grok'], true)) { throw new \RuntimeException('Nieprawidłowy dostawca AI: ' . $provider); } $input = "Oceń odpowiedź ucznia na pytanie otwarte.\n\n" . "Pytanie:\n" . $question . "\n\n" . "Wzorzec odpowiedzi:\n" . $pattern . "\n\n" . "Odpowiedź ucznia:\n" . ($answer !== '' ? $answer : 'Brak odpowiedzi') . "\n\n" . "Napisz po polsku krótką ocenę: czy odpowiedź może zostać uznana za poprawną, jakie elementy są poprawne lub błędne oraz czy warto przyznać punkty. Nie zmieniaj wzorca odpowiedzi."; $payload = json_encode([ 'model' => $config['model'], 'input' => $input, 'temperature' => 0.1, ], JSON_UNESCAPED_UNICODE); $response = HttpFactory::getHttp()->post( $config['url'], $payload, [ 'Authorization' => 'Bearer ' . trim($apiKey), 'Content-Type' => 'application/json', ], 60 ); $body = json_decode((string) $response->body, true); if ((int) $response->code < 200 || (int) $response->code >= 300) { throw new \RuntimeException((string) ($body['error']['message'] ?? ('HTTP ' . (int) $response->code))); } $text = $this->extractText($body); if ($text === '') { throw new \RuntimeException('Brak treści odpowiedzi AI.'); } return $text; } private function extractText(array $body): string { if (!empty($body['output_text']) && is_string($body['output_text'])) { return trim($body['output_text']); } $parts = []; foreach ((array) ($body['output'] ?? []) as $output) { foreach ((array) ($output['content'] ?? []) as $content) { if (!empty($content['text']) && is_string($content['text'])) { $parts[] = $content['text']; } } } return trim(implode("\n", $parts)); } }