Classes/OpenAiChat.psm1
using module "..\Private\OutHelper.psm1" class OpenAiChatMessage { [string]$Role [string]$Content OpenAiChatMessage([string]$role, [string]$content) { $this.Role = $role $this.Content = $content } static [OpenAiChatMessage] ToAssistant([string]$message) { return [OpenAiChatMessage]::new("user", $message) } static [OpenAiChatMessage] FromAssistant([string]$message) { return [OpenAiChatMessage]::new("assistant", $message) } } class OpenAiChat { [string]$AuthToken [string]$Model = "gpt-3.5-turbo" [decimal]$Temperature [decimal]$Top_p [int]$N OpenAiChat([string]$authToken) { $this.AuthToken = $authToken if(!$this.AuthToken) { throw "OpenAiChat requires an auth token (authToken argument on constructor)" } } # messages is an array of objects with 'role' and 'content' properties # 'content' is url encoded before sending to the API [object] Invoke([object]$messages) { $encoded = @() $messages | ForEach-Object { $encoded += @{ "role" = $_.role; "content" = [System.Web.HttpUtility]::UrlEncode($_.content); } } # construct body $body = @{ "model" = $this.Model "messages" = $encoded } # set optional parameters for the request if($this.Temperature) { $body.temperature = $this.Temperature } if($this.Top_p) { $body.top_p = $this.Top_p } if($this.N) { $body.n = $this.N } return $this.InvokeRequestObject($body) } # requestObject is a object/hashtable with the full request body [object] InvokeRequestObject([object]$requestObject) { $url = "https://api.openai.com/v1/chat/completions" $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" $headers.Add("Content-Type", "application/json") $headers.Add("Authorization", "Bearer $($this.AuthToken)") $body = $requestObject | ConvertTo-Json -Depth 10 $response = $null try { Write-Debug "Request:`n$body" $response = Invoke-RestMethod -Method 'POST' -Uri $url -Headers $headers -Body $body Write-Debug "`n`nResponse:`n$($response | ConvertTo-Json -Depth 10)" return $response } catch { [OutHelper]::NonCriticalError("An error occurred: $($_.Exception.Message)") [OutHelper]::NonCriticalError("Request:`n$body") [OutHelper]::NonCriticalError("Response:`n$($response | ConvertTo-Json -Depth 10)") return $null } } [string] Ask([string]$message) { return $this.GetAnswer(@([OpenAiChatMessage]::ToAssistant($message))) } [object] GetAnswer([object]$messages) { $response = $this.Invoke($messages) if($null -ne $response) { # if multiple choices are requested, return an array of strings if($this.N -gt 1) { Write-Debug "N=$($this.N), returning array of $($response.choices.length) strings" return $response.choices | ForEach-Object { [System.Web.HttpUtility]::UrlDecode($_.message.content.Trim()) } } return [System.Web.HttpUtility]::UrlDecode($response.choices.message.content.Trim()) } else { return $null } } } |