Private/Invoke-GeminiAIApi.ps1
|
function Invoke-GeminiAIApi { <# .SYNOPSIS Calls the Gemini AI Proxy API with automatic API key management. .DESCRIPTION Invokes the Gemini AI API through the Azure Function proxy. Automatically generates and caches API keys using New-PSUApiKey. Supports automatic retry on failures and API key expiration. .PARAMETER Prompt The prompt to send to Gemini AI. .PARAMETER ReturnJsonResponse Request JSON-formatted response from Gemini. .PARAMETER TimeoutSeconds HTTP request timeout in seconds. Default is 90. .PARAMETER RetryCount Number of retry attempts on failure. Default is 3. .PARAMETER RetryDelaySeconds Delay between retries in seconds. Default is 2. .PARAMETER ApiUrl The Azure Function endpoint URL. .PARAMETER ForceNewApiKey Force generation of a new API key even if cached one exists. .EXAMPLE Invoke-GeminiAIApi -Prompt "What is PowerShell?" Makes a request using cached or newly generated API key .EXAMPLE Invoke-GeminiAIApi -Prompt "List 3 colors" -ReturnJsonResponse Requests JSON response format .EXAMPLE Invoke-GeminiAIApi -Prompt "Explain REST" -ForceNewApiKey Forces generation of new API key before making request .OUTPUTS System.String .NOTES Author: Lakshmanachari Panuganti Date: 10th December 2025 #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory = $true, Position = 0)] [ValidateNotNullOrEmpty()] [string]$Prompt, [Parameter()] [switch]$ReturnJsonResponse, [Parameter()] [ValidateRange(10, 300)] [int]$TimeoutSeconds = 90, [Parameter()] [ValidateRange(1, 10)] [int]$RetryCount = 3, [Parameter()] [ValidateRange(1, 30)] [int]$RetryDelaySeconds = 2, [Parameter()] [ValidateNotNullOrEmpty()] [string]$ApiUrl = "https://omg-geminiai-proxy-func.azurewebsites.net/api/ProxyGeminiAI", [Parameter()] [switch]$ForceNewApiKey ) begin { Write-Verbose "=== Starting Gemini AI API Call ===" Write-Verbose "Prompt length: $($Prompt.Length) characters" Write-Verbose "JSON response: $($ReturnJsonResponse.IsPresent)" Write-Verbose "API URL: $ApiUrl" } process { # ============================================ # 1. Ensure API Key is Available # ============================================ try { # Check if New-PSUApiKey function exists if (-not (Get-Command -Name New-PSUApiKey -ErrorAction SilentlyContinue)) { throw "Required function 'New-PSUApiKey' not found. Please ensure it is loaded in the current session." } # Check if we need a new API key $needNewKey = $false if ($ForceNewApiKey) { Write-Verbose "Force new API key requested" $needNewKey = $true } elseif (-not $script:PSU_API_KEY) { Write-Verbose "No cached API key found" $needNewKey = $true } elseif ($script:PSU_API_KEY_EXPIRY -and ([DateTime]::UtcNow -gt $script:PSU_API_KEY_EXPIRY)) { Write-Verbose "Cached API key has expired" $needNewKey = $true } # Generate new API key if needed if ($needNewKey) { Write-Host "Generating API key..." -ForegroundColor Cyan try { $apiKey = New-PSUApiKey -ErrorAction Stop Write-Verbose "API key generated and cached successfully" } catch { throw "Failed to generate API key: $($_.Exception.Message)" } } else { Write-Verbose "Using cached API key" $apiKey = $script:PSU_API_KEY # Log time remaining if ($script:PSU_API_KEY_EXPIRY) { $timeLeft = $script:PSU_API_KEY_EXPIRY - [DateTime]::UtcNow Write-Verbose "API key expires in $($timeLeft.TotalHours.ToString('F1')) hours" } } } catch { Write-Error "API key preparation failed: $($_.Exception.Message)" throw } # ============================================ # 2. Prepare Request # ============================================ $body = @{ Prompt = $Prompt ReturnJsonResponse = [bool]$ReturnJsonResponse } | ConvertTo-Json -Depth 20 $headers = @{ "Authorization" = "Bearer $apiKey" "Content-Type" = "application/json" } Write-Verbose "Request prepared with Authorization header" # ============================================ # 3. Retry Logic with API Key Refresh # ============================================ $maxAttempts = $RetryCount $attempt = 0 while ($attempt -lt $maxAttempts) { $attempt++ try { Write-Verbose "Attempt $attempt of $maxAttempts..." $invokeParams = @{ Method = 'Post' Uri = $ApiUrl Body = $body Headers = $headers TimeoutSec = $TimeoutSeconds ErrorAction = 'Stop' } Write-Host "Calling Gemini AI API (attempt $attempt)..." -ForegroundColor Cyan $response = Invoke-RestMethod @invokeParams Write-Verbose "Response received successfully" return $response } catch { $errorMessage = $_.Exception.Message # Try to parse error as JSON for specific error handling try { $errorMessageObj = $_ | ConvertFrom-Json -ErrorAction Stop if ($errorMessageObj.Error -like "*Bad Request*") { Write-Error "Invalid request: $errorMessage" return } if ($errorMessageObj.Error -like "*Rate Limit Exceeded*") { Write-Error "Rate limit exceeded: $errorMessage" return } } catch { Write-Verbose "Error response was not JSON format" } # Last attempt - throw error if ($attempt -ge $maxAttempts) { $finalError = "All $maxAttempts retry attempts failed. Last error: $errorMessage" Write-Error $finalError throw $finalError } # Retry with delay Write-Warning "Attempt $attempt failed: $errorMessage" Start-Sleep -Seconds $RetryDelaySeconds } } # Should never reach here if retry logic works correctly Write-Warning "Retry loop completed without success or failure" } end { Write-Verbose "=== Gemini AI API Call Complete ===" } } |