From d04fb92c2773b9c8544911f42bf36082c83e18e8 Mon Sep 17 00:00:00 2001 From: Mathias Burger Date: Tue, 7 May 2024 15:20:28 +0200 Subject: [PATCH] Use openai compatible environment variables for configuration and allow configuration using more specific variables that do not interfere with the openai defaults Signed-off-by: Mathias Burger --- CONTRIBUTING.md | 9 ++++++ README.md | 13 +++++++++ please.sh | 70 +++++++++++++++++++++++++++-------------------- test/join_by.bats | 49 +++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 30 deletions(-) create mode 100644 test/join_by.bats diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 94e9c97..9f86562 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -42,3 +42,12 @@ Resolves #7 ``` Furthermore, commits must be signed off according to the [DCO](DCO). + +### Testing + +Install [bats](https://bats-core.readthedocs.io/en/stable/installation.html). + +Run tests: +``` +bats --formatter pretty test +``` \ No newline at end of file diff --git a/README.md b/README.md index b4fd116..b136dba 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,19 @@ To store your API key using macOS keychain, run security add-generic-password -a "${USER}" -s OPENAI_API_KEY -w "${apiKey}" ``` +## 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 + ## Troubleshooting If you receive the following error message: diff --git a/please.sh b/please.sh index a1137a4..c76b84e 100755 --- a/please.sh +++ b/please.sh @@ -2,7 +2,7 @@ set -uo pipefail -model='gpt-4' +model=${PLEASE_OPENAI_CHAT_MODEL:-'gpt-4-turbo'} options=("[I] Invoke" "[C] Copy to clipboard" "[Q] Ask a question" "[A] Abort" ) number_of_options=${#options[@]} keyName="OPENAI_API_KEY" @@ -22,7 +22,10 @@ exclamation="\xE2\x9D\x97" questionMark="\x1B[31m?\x1B[0m" checkMark="\x1B[31m\xE2\x9C\x93\x1B[0m" -openai_invocation_url=${OPENAI_URL:-"https://api.openai.com/v1"} +openai_api_base=${PLEASE_OPENAI_API_BASE:-${OPENAI_API_BASE:-${OPENAI_URL:-"https://api.openai.com"}}} +openai_api_version=${PLEASE_OPENAI_API_VERSION:-${OPENAI_API_VERSION:-"v1"}} +openai_invocation_url=${openai_api_base}/${openai_api_version} + fail_msg="echo 'I do not know. Please rephrase your question.'" declare -a qaMessages=() @@ -98,10 +101,10 @@ function store_api_key() { else if [[ "$OSTYPE" == "darwin"* ]]; then security add-generic-password -a "${USER}" -s "${keyName}" -w "${apiKey}" -U - OPENAI_API_KEY=$(security find-generic-password -a "${USER}" -s "${keyName}" -w) + PLEASE_OPENAI_API_KEY=$(security find-generic-password -a "${USER}" -s "${keyName}" -w) else echo -e "${apiKey}" | secret-tool store --label="${keyName}" username "${USER}" key_name "${keyName}" - OPENAI_API_KEY=$(secret-tool lookup username "${USER}" key_name "${keyName}") + PLEASE_OPENAI_API_KEY=$(secret-tool lookup username "${USER}" key_name "${keyName}") fi echo "API key stored successfully and set as a global variable." break @@ -130,7 +133,7 @@ display_help() { echo " The remaining arguments are used as input to be turned into a CLI command." echo echo "OpenAI API Key:" - echo " The API key needs to be set as OPENAI_API_KEY environment variable or keychain entry. " + echo " The API key needs to be set as PLEASE_OPENAI_API_KEY or OPENAI_API_KEY environment variable or keychain entry. " } @@ -141,8 +144,8 @@ debug() { } check_key() { - if [ -z "${OPENAI_API_KEY+x}" ]; then - debug "OPENAI_API_KEY environment variable not set, trying to find it in keychain" + if [ -z "${PLEASE_OPENAI_API_KEY:-${OPENAI_API_KEY:-}}" ]; then + debug "PLEASE_OPENAI_API_KEY or OPENAI_API_KEY environment variable not set, trying to find it in keychain" get_key_from_keychain fi } @@ -156,7 +159,7 @@ get_key_from_keychain() { ;; Linux*) if ! command -v secret-tool &> /dev/null; then - debug "OPENAI_API_KEY not set and secret-tool not installed. Install it with 'sudo apt install libsecret-tools'." + debug "PLEASE_OPENAI_API_KEY or OPENAI_API_KEY not set and secret-tool not installed. Install it with 'sudo apt install libsecret-tools'." exitStatus=1 else key=$(secret-tool lookup username "${USER}" key_name "${keyName}") @@ -164,13 +167,13 @@ get_key_from_keychain() { fi ;; *) - debug "OPENAI_API_KEY not set and no supported keychain available." + debug "PLEASE_OPENAI_API_KEY or OPENAI_API_KEY not set and no supported keychain available." exitStatus=1 ;; esac if [ "${exitStatus}" -ne 0 ]; then - echo "OPENAI_API_KEY not set and unable to find it in keychain. See the README on how to persist your key." + echo "PLEASE_OPENAI_API_KEY or OPENAI_API_KEY not set and unable to find it in keychain. See the README on how to persist your key." echo "You can get an API at https://beta.openai.com/" echo "Please enter your OpenAI API key now to use it this time only, or rerun 'please -a' to store it in the keychain." echo "Your API Key:" @@ -181,7 +184,7 @@ get_key_from_keychain() { echo "No API key provided. Exiting." exit 1 fi - OPENAI_API_KEY="${key}" + PLEASE_OPENAI_API_KEY="${key}" } get_command() { @@ -221,7 +224,7 @@ perform_openai_request() { -s -w "\n%{http_code}" \ -H "Content-Type: application/json" \ -H "Accept-Encoding: identity" \ - -H "Authorization: Bearer ${OPENAI_API_KEY}" \ + -H "Authorization: Bearer ${PLEASE_OPENAI_API_KEY:-$OPENAI_API_KEY}" \ -d "${payload}" \ --silent) debug "Response:\n${result[*]}" @@ -460,26 +463,33 @@ function join_by { fi } -if [ $# -eq 0 ]; then - input=("-h") -else - input=("$@") -fi +function main() { + if [ $# -eq 0 ]; then + input=("-h") + else + input=("$@") + fi -check_args "${input[@]}" -check_key + check_args "${input[@]}" + check_key -get_command -if [ "${explain}" -eq 1 ]; then - explain_command -fi + get_command + if [ "${explain}" -eq 1 ]; then + explain_command + fi -print_option + print_option -if test "${command}" = "${fail_msg}"; then - exit 1 -fi + if test "${command}" = "${fail_msg}"; then + exit 1 + fi + + init_questions + choose_action + act_on_action +} -init_questions -choose_action -act_on_action +# Only call main if the script is not being sourced +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main +fi \ No newline at end of file diff --git a/test/join_by.bats b/test/join_by.bats new file mode 100644 index 0000000..0beb224 --- /dev/null +++ b/test/join_by.bats @@ -0,0 +1,49 @@ +#!/usr/bin/env bats + +load $BATS_TEST_DIRNAME/../please.sh + +@test "join elements with a comma" { + result=$(join_by ',' 'a' 'b' 'c') + [ "$result" == "a,b,c" ] +} + +@test "join elements with a semicolon" { + result=$(join_by ';' '1' '2' '3') + [ "$result" == "1;2;3" ] +} + +@test "join with a space as delimiter" { + result=$(join_by ' ' 'x' 'y' 'z') + [ "$result" == "x y z" ] +} + +@test "join with an empty delimiter" { + result=$(join_by '' '1' '2' '3') + [ "$result" == "123" ] +} + +@test "no delimiter provided should return the first element" { + result=$(join_by '' 'single') + [ "$result" == "single" ] +} + +@test "join using array with no elements" { + qaMessages=() + + result=$(join_by , "${qaMessages[@]}") + [ "$result" == "" ] +} + +@test "join using array with one element" { + qaMessages=("a") + + result=$(join_by , "${qaMessages[@]}") + [ "$result" == "a" ] +} + +@test "join using array with two elements" { + qaMessages=("a" "b") + + result=$(join_by , "${qaMessages[@]}") + [ "$result" == "a,b" ] +} \ No newline at end of file