Add Groq API as an AI provider
This commit is contained in:
@@ -23,6 +23,11 @@ class AiService
|
||||
'grok-4.20' => 'Grok 4.20 Reasoning',
|
||||
'grok-4.20-non-reasoning' => 'Grok 4.20 Non-Reasoning',
|
||||
],
|
||||
'groq' => [
|
||||
'openai/gpt-oss-120b' => 'GPT OSS 120B',
|
||||
'openai/gpt-oss-20b' => 'GPT OSS 20B',
|
||||
'llama-3.3-70b-versatile' => 'Llama 3.3 70B Versatile',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -30,15 +35,17 @@ class AiService
|
||||
{
|
||||
$provider = strtolower(trim($provider));
|
||||
$provider = preg_replace('/[^a-z]/', '', $provider);
|
||||
$config = $provider === 'grok'
|
||||
? ['url' => 'https://api.x.ai/v1/responses']
|
||||
: ['url' => 'https://api.openai.com/v1/responses'];
|
||||
$config = match ($provider) {
|
||||
'grok' => ['url' => 'https://api.x.ai/v1/responses'],
|
||||
'groq' => ['url' => 'https://api.groq.com/openai/v1/chat/completions'],
|
||||
default => ['url' => 'https://api.openai.com/v1/responses'],
|
||||
};
|
||||
|
||||
if (trim($apiKey) === '') {
|
||||
throw new \RuntimeException('AI_NOT_CONFIGURED');
|
||||
}
|
||||
|
||||
if (!in_array($provider, ['openai', 'grok'], true)) {
|
||||
if (!in_array($provider, ['openai', 'grok', 'groq'], true)) {
|
||||
throw new \RuntimeException('Nieprawidłowy dostawca AI: ' . $provider);
|
||||
}
|
||||
|
||||
@@ -54,12 +61,18 @@ class AiService
|
||||
. "Odpowiedź ucznia:\n" . ($answer !== '' ? $answer : 'Brak odpowiedzi') . "\n\n"
|
||||
. "Zwróć wyłącznie poprawny obiekt JSON w formacie {\"awarded_points\": liczba_całkowita, \"feedback\": \"krótka ocena po polsku\"}. W ocenie opisz poprawne i brakujące elementy. Nie zmieniaj wzorca odpowiedzi.";
|
||||
|
||||
$requestData = [
|
||||
'model' => $model,
|
||||
'input' => $input,
|
||||
];
|
||||
$requestData = $provider === 'groq'
|
||||
? [
|
||||
'model' => $model,
|
||||
'messages' => [['role' => 'user', 'content' => $input]],
|
||||
'temperature' => 0.1,
|
||||
]
|
||||
: [
|
||||
'model' => $model,
|
||||
'input' => $input,
|
||||
];
|
||||
// GPT-5.x reasoning models do not accept a custom temperature.
|
||||
if ($provider === 'grok' || $model === 'gpt-4.1-mini') {
|
||||
if ($provider === 'grok' || ($provider === 'openai' && $model === 'gpt-4.1-mini')) {
|
||||
$requestData['temperature'] = 0.1;
|
||||
}
|
||||
$payload = json_encode($requestData, JSON_UNESCAPED_UNICODE);
|
||||
@@ -115,12 +128,16 @@ class AiService
|
||||
private function getUsage(array $body, string $provider, string $model): ?array
|
||||
{
|
||||
$usage = $body['usage'] ?? null;
|
||||
if (!is_array($usage) || !isset($usage['input_tokens'], $usage['output_tokens'])) {
|
||||
if (!is_array($usage)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$inputTokens = max(0, (int) $usage['input_tokens']);
|
||||
$outputTokens = max(0, (int) $usage['output_tokens']);
|
||||
$inputTokens = max(0, (int) ($usage['input_tokens'] ?? $usage['prompt_tokens'] ?? 0));
|
||||
$outputTokens = max(0, (int) ($usage['output_tokens'] ?? $usage['completion_tokens'] ?? 0));
|
||||
if ((!isset($usage['input_tokens']) && !isset($usage['prompt_tokens']))
|
||||
|| (!isset($usage['output_tokens']) && !isset($usage['completion_tokens']))) {
|
||||
return null;
|
||||
}
|
||||
$cachedTokens = min($inputTokens, max(0, (int) ($usage['input_tokens_details']['cached_tokens'] ?? 0)));
|
||||
$cost = null;
|
||||
$costSource = '';
|
||||
@@ -162,6 +179,10 @@ class AiService
|
||||
|
||||
private function extractText(array $body): string
|
||||
{
|
||||
if (isset($body['choices'][0]['message']['content']) && is_string($body['choices'][0]['message']['content'])) {
|
||||
return trim($body['choices'][0]['message']['content']);
|
||||
}
|
||||
|
||||
if (!empty($body['output_text']) && is_string($body['output_text'])) {
|
||||
return trim($body['output_text']);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user