Private/Invoke-AICompletion.ps1
|
function Invoke-AICompletion { <# .SYNOPSIS Sends a prompt to an AI provider and returns the completion. .DESCRIPTION Provider-agnostic AI completion function supporting Anthropic, OpenAI, Ollama, and Custom endpoints. Used internally for runbook generation from ticket history and intelligent decision support. #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$Prompt, [Parameter()] [ValidateSet('Anthropic', 'OpenAI', 'Ollama', 'Custom')] [string]$Provider = 'OpenAI', [Parameter()] [string]$ApiKey, [Parameter()] [string]$Model, [Parameter()] [string]$SystemPrompt = 'You are an infrastructure automation expert. Generate precise, actionable content.', [Parameter()] [string]$CustomEndpoint, [Parameter()] [int]$MaxTokens = 4096, [Parameter()] [double]$Temperature = 0.3 ) # Set default models per provider if (-not $Model) { $Model = switch ($Provider) { 'Anthropic' { 'claude-sonnet-4-20250514' } 'OpenAI' { 'gpt-4o' } 'Ollama' { 'llama3' } 'Custom' { 'default' } } } $result = $null switch ($Provider) { 'Anthropic' { if (-not $ApiKey) { throw 'ApiKey is required for Anthropic provider.' } $headers = @{ 'x-api-key' = $ApiKey 'anthropic-version' = '2023-06-01' 'Content-Type' = 'application/json' } $body = @{ model = $Model max_tokens = $MaxTokens system = $SystemPrompt messages = @( @{ role = 'user'; content = $Prompt } ) } | ConvertTo-Json -Depth 10 try { $response = Invoke-RestMethod -Uri 'https://api.anthropic.com/v1/messages' ` -Method Post -Headers $headers -Body $body -ErrorAction Stop $result = $response.content[0].text } catch { Write-Warning "Anthropic API call failed: $_" throw } } 'OpenAI' { if (-not $ApiKey) { throw 'ApiKey is required for OpenAI provider.' } $headers = @{ 'Authorization' = "Bearer $ApiKey" 'Content-Type' = 'application/json' } $body = @{ model = $Model max_tokens = $MaxTokens temperature = $Temperature messages = @( @{ role = 'system'; content = $SystemPrompt } @{ role = 'user'; content = $Prompt } ) } | ConvertTo-Json -Depth 10 try { $response = Invoke-RestMethod -Uri 'https://api.openai.com/v1/chat/completions' ` -Method Post -Headers $headers -Body $body -ErrorAction Stop $result = $response.choices[0].message.content } catch { Write-Warning "OpenAI API call failed: $_" throw } } 'Ollama' { $ollamaUrl = if ($CustomEndpoint) { $CustomEndpoint } else { 'http://localhost:11434' } $body = @{ model = $Model prompt = "${SystemPrompt}`n`n${Prompt}" stream = $false options = @{ num_predict = $MaxTokens temperature = $Temperature } } | ConvertTo-Json -Depth 10 try { $response = Invoke-RestMethod -Uri "$ollamaUrl/api/generate" ` -Method Post -Body $body -ContentType 'application/json' -ErrorAction Stop $result = $response.response } catch { Write-Warning "Ollama API call failed: $_" throw } } 'Custom' { if (-not $CustomEndpoint) { throw 'CustomEndpoint is required for Custom provider.' } $headers = @{ 'Content-Type' = 'application/json' } if ($ApiKey) { $headers['Authorization'] = "Bearer $ApiKey" } $body = @{ model = $Model max_tokens = $MaxTokens temperature = $Temperature messages = @( @{ role = 'system'; content = $SystemPrompt } @{ role = 'user'; content = $Prompt } ) } | ConvertTo-Json -Depth 10 try { $response = Invoke-RestMethod -Uri $CustomEndpoint ` -Method Post -Headers $headers -Body $body -ErrorAction Stop # Try common response formats if ($response.choices) { $result = $response.choices[0].message.content } elseif ($response.content) { $result = if ($response.content -is [array]) { $response.content[0].text } else { $response.content } } elseif ($response.response) { $result = $response.response } elseif ($response.text) { $result = $response.text } else { $result = $response | ConvertTo-Json -Depth 5 } } catch { Write-Warning "Custom API call failed: $_" throw } } } return $result } |