$role, 'parts' => [ ['text' => $message['content']] ] ]; } $request = [ 'contents' => $contents, ]; // Add generation config if options provided $generationConfig = array_filter([ 'temperature' => $options['temperature'] ?? null, 'maxOutputTokens' => $options['max_tokens'] ?? null, 'topP' => $options['top_p'] ?? null, 'stopSequences' => $options['stop'] ?? null, ], fn($value) => $value !== null); if (!empty($generationConfig)) { $request['generationConfig'] = $generationConfig; } return $request; } protected function getAuthHeaders(): array { return [ 'Content-Type' => 'application/json', ]; } public function chatCompletion(array $messages, array $options = []): array { $model = $options['model'] ?? 'gemini-pro'; $data = $this->buildRequest($messages, $options); // Gemini uses API key as query parameter $endpoint = "/models/{$model}:generateContent?key={$this->apiKey}"; return $this->makeRequest($endpoint, $data); } public function normalizeResponse(array $response): array { $candidate = $response['candidates'][0] ?? []; $content = $candidate['content'] ?? []; $parts = $content['parts'] ?? []; $textContent = ''; foreach ($parts as $part) { $textContent .= $part['text'] ?? ''; } $usageMetadata = $response['usageMetadata'] ?? []; return [ 'id' => null, // Gemini doesn't provide an ID 'model' => $response['modelVersion'] ?? null, 'content' => $textContent, 'role' => 'assistant', 'finish_reason' => $candidate['finishReason'] ?? null, 'usage' => [ 'prompt_tokens' => $usageMetadata['promptTokenCount'] ?? 0, 'completion_tokens' => $usageMetadata['candidatesTokenCount'] ?? 0, 'total_tokens' => $usageMetadata['totalTokenCount'] ?? 0, ], 'raw_response' => $response, ]; } public function calculateCost(int $promptTokens, int $completionTokens, string $model): float { $cacheKey = "pricing:gemini:{$model}"; $pricing = Cache::remember($cacheKey, 3600, function () use ($model) { return ModelPricing::where('provider', 'gemini') ->where('model', $model) ->where('is_active', true) ->first(); }); if (!$pricing) { return 0.0; } $promptCost = ($promptTokens / 1_000_000) * $pricing->input_price_per_million; $completionCost = ($completionTokens / 1_000_000) * $pricing->output_price_per_million; return round($promptCost + $completionCost, 6); } public function getSupportedModels(): array { return [ 'gemini-pro', 'gemini-pro-vision', 'gemini-1.5-pro', 'gemini-1.5-flash', 'gemini-ultra', ]; } }