Skip to content

Commit

Permalink
Merge pull request #2 from mathiasburger/feature/configuration
Browse files Browse the repository at this point in the history
Use openai compatible environment variables for configuration and all…
  • Loading branch information
kaspertng authored May 7, 2024
2 parents a233ac6 + ccf2c18 commit fa73dcf
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 fa73dcf

Please sign in to comment.