Skip to content

Commit

Permalink
Use openai compatible environment variables for configuration and all…
Browse files Browse the repository at this point in the history
…ow configuration using more specific variables that do not interfere with the openai defaults

Signed-off-by: Mathias Burger <[email protected]>
  • Loading branch information
mathiasburger committed May 7, 2024
1 parent a233ac6 commit ccf2c18
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 5 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.idea/
16 changes: 16 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,19 @@ Resolves #7
```

Furthermore, commits must be signed off according to the [DCO](DCO).


### Testing

Install and set up [Pester](https://pester.dev/docs/quick-start).

```pwsh
Install-Module Pester -Force
Import-Module Pester -PassThru
```

Run the tests with Pester:

```pwsh
Invoke-Pester -Path .\Tests
```
52 changes: 47 additions & 5 deletions PleasePwsh/PleasePwsh.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,48 @@ Set-PSDebug -Strict
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"

function Get-OpenAIApiKey {
if ($env:PLEASE_OPENAI_API_KEY) {
return $env:PLEASE_OPENAI_API_KEY
}
if ($env:OPENAI_API_KEY) {
return $env:OPENAI_API_KEY
}
return $null
}

function Get-OpenAIModel {
if ($env:PLEASE_OPENAI_CHAT_MODEL) {
return $env:PLEASE_OPENAI_CHAT_MODEL
}
# There is no openai compatible environment variable to set a default model
return "gpt-3.5-turbo"
}

function Get-OpenAIBaseUrl {
if ($env:PLEASE_OPENAI_API_BASE) {
return $env:PLEASE_OPENAI_API_BASE
}
if ($env:OPENAI_API_BASE) {
return $env:OPENAI_API_BASE
}
return "https://api.openai.com"
}

function Get-OpenAIApiVersion {
if ($env:PLEASE_OPENAI_API_VERSION) {
return $env:PLEASE_OPENAI_API_VERSION
}
if ($env:OPENAI_API_VERSION) {
return $env:OPENAI_API_VERSION
}
return "v1"
}

function Get-OpenAIBaseUrlWithVersion {
return "$(Get-OpenAIBaseUrl)/$(Get-OpenAIApiVersion)"
}

<#
.SYNOPSIS
Translates a prompt into a PowerShell command using OpenAI GPT.
Expand Down Expand Up @@ -53,7 +95,7 @@ function Please {
}

function Test-ApiKey {
if ($null -eq $env:OPENAI_API_KEY) {
if ($null -eq $(Get-OpenAIApiKey)) {
Write-Output "`u{1F50E} Api key missing. See https://help.openai.com/en/articles/4936850-where-do-i-find-my-secret-api-key"
$Key = Read-Host "Please provide the api key"

Expand All @@ -68,7 +110,7 @@ function Get-PwshCommand([string]$Prompt) {
$Role = "You translate the input given into PowerShell command. You may not use natural language, but only a PowerShell commands as answer. Do not use markdown. Do not quote the whole output. If you do not know the answer, answer only with 'I do not know'"

$Payload = @{
'model' = "gpt-3.5-turbo"
'model' = Get-OpenAIModel
'messages' = @(
@{ 'role' = 'system'; 'content' = $Role },
@{ 'role' = 'user'; 'content' = $Prompt }
Expand Down Expand Up @@ -115,7 +157,7 @@ function Get-CommandExplanation([string]$Command) {

$Payload = @{
'max_tokens' = 100
'model' = "gpt-3.5-turbo"
'model' = Get-OpenAIModel
'messages' = @(
@{ 'role' = 'user'; 'content' = $Prompt }
)
Expand All @@ -125,11 +167,11 @@ function Get-CommandExplanation([string]$Command) {
}

function Invoke-OpenAIRequest($Payload) {
$Uri = "https://api.openai.com/v1/chat/completions"
$Uri = "$(Get-OpenAIBaseUrlWithVersion)/chat/completions"

$Headers = @{
'Content-Type' = 'application/json'
'Authorization' = "Bearer $env:OPENAI_API_KEY"
'Authorization' = "Bearer $(Get-OpenAIApiKey)"
}

try {
Expand Down
14 changes: 14 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,17 @@ Install-Module -Name PleasePwsh
Set the OpenAI API key as environment variable.
- Open PowerShell profile: `Code $PROFILE`
- Add a line with your API key: `$ENV:OPENAI_API_KEY = <YOUR_API_KEY>`


## Configuration

You can use the following OpenAI compatible environment variables:
* `OPENAI_API_KEY` - Your OpenAI API key
* `OPENAI_API_BASE` - The base URL for the OpenAI API
* `OPENAI_API_VERSION` - The version of the OpenAI API

You can use the more specific environment variables if you do not want to change OpenAI settings globally:
* `PLEASE_OPENAI_API_KEY` - Your OpenAI API key
* `PLEASE_OPENAI_API_BASE` - The base URL for the OpenAI API
* `PLEASE_OPENAI_API_VERSION` - The version of the OpenAI API
* `PLEASE_OPENAI_CHAT_MODEL` - The chat model to use
77 changes: 77 additions & 0 deletions Tests/Configuration.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
BeforeAll {
Remove-Module -Name PleasePwsh -ErrorAction SilentlyContinue
Import-Module $PSScriptRoot/../PleasePwsh/PleasePwsh.psm1

$env:OPENAI_API_KEY = "not-set"

InModuleScope PleasePwsh {
Mock Invoke-RestMethod { return @{ choices = @(@{ message = @{ content = "Hello, World!" } }) } }
Mock Show-Menu { }
Mock Invoke-Action { }
}
}

AfterAll {
$env:OPENAI_API_KEY = $null
$env:OPENAI_API_BASE = $null
$env:OPENAI_API_VERSION = $null
$env:PLEASE_OPENAI_API_BASE = $null
$env:PLEASE_OPENAI_API_VERSION = $null
$env:PLEASE_OPENAI_CHAT_MODEL = $null
}

Describe 'OpenAI Configuration' {
It 'Given no configuration, defaults are used' {
InModuleScope PleasePwsh {
Please "say hello"

Assert-MockCalled Invoke-RestMethod -Times 1 -ParameterFilter {
return ($Body | ConvertFrom-Json).model -eq 'gpt-3.5-turbo' -and
$Uri -eq 'https://api.openai.com/v1/chat/completions' -and
$Method -eq 'Post' -and
$Headers["Content-Type"] -eq 'application/json'
}
}
}

It 'Given configuration from openai compatible environment variables are used' {
InModuleScope PleasePwsh {
$env:OPENAI_API_BASE = "openai-api-base"
$env:OPENAI_API_VERSION = "openai-api-version"

Please "say hello"

Assert-MockCalled Invoke-RestMethod -Times 1 -ParameterFilter {
return ($Body | ConvertFrom-Json).model -eq 'gpt-3.5-turbo' -and
$Uri -eq 'openai-api-base/openai-api-version/chat/completions' -and
$Method -eq 'Post' -and
$Headers["Content-Type"] -eq 'application/json'
}
}
}

It 'Given configuration from please specific environment variables are preferred' {
InModuleScope PleasePwsh {
$env:OPENAI_API_BASE = "openai-api-base"
$env:OPENAI_API_VERSION = "openai-api-version"

$env:PLEASE_OPENAI_API_BASE = "please-api-base"
$env:PLEASE_OPENAI_API_VERSION = "please-api-version"

$env:PLEASE_OPENAI_CHAT_MODEL = "please-chat-model"

Mock Invoke-RestMethod { return @{ choices = @(@{ message = @{ content = "Hello, World!" } }) } }
Mock Show-Menu { }
Mock Invoke-Action { }

Please "say hello"

Assert-MockCalled Invoke-RestMethod -Times 1 -ParameterFilter {
return ($Body | ConvertFrom-Json).model -eq 'please-chat-model' -and
$Uri -eq 'please-api-base/please-api-version/chat/completions' -and
$Method -eq 'Post' -and
$Headers["Content-Type"] -eq 'application/json'
}
}
}
}

0 comments on commit ccf2c18

Please sign in to comment.