mirror of
https://github.com/0xacx/chatGPT-shell-cli.git
synced 2024-11-24 11:25:31 +00:00
autoformatting
This commit is contained in:
parent
364b15bf78
commit
c6efe1ce38
412
chatgpt.sh
412
chatgpt.sh
@ -9,23 +9,23 @@ CHATGPT_CYAN_LABEL="\n\033[36mchatgpt \033[0m"
|
||||
# error handling function
|
||||
# $1 should be the response body
|
||||
handle_error() {
|
||||
if echo "$1" | jq -e '.error' >/dev/null; then
|
||||
echo -e "Your request to Open AI API failed: \033[0;31m$(echo $1 | jq -r '.error.type')\033[0m"
|
||||
echo $1 | jq -r '.error.message'
|
||||
exit 1
|
||||
fi
|
||||
if echo "$1" | jq -e '.error' >/dev/null; then
|
||||
echo -e "Your request to Open AI API failed: \033[0;31m$(echo $1 | jq -r '.error.type')\033[0m"
|
||||
echo $1 | jq -r '.error.message'
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# request to OpenAI API completions endpoint function
|
||||
# $1 should be the request prompt
|
||||
request_to_completions() {
|
||||
request_prompt=$1
|
||||
request_prompt=$1
|
||||
|
||||
response=$(curl https://api.openai.com/v1/completions \
|
||||
-sS \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H "Authorization: Bearer $OPENAI_KEY" \
|
||||
-d '{
|
||||
response=$(curl https://api.openai.com/v1/completions \
|
||||
-sS \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H "Authorization: Bearer $OPENAI_KEY" \
|
||||
-d '{
|
||||
"model": "'"$MODEL"'",
|
||||
"prompt": "'"${request_prompt}"'",
|
||||
"max_tokens": '$MAX_TOKENS',
|
||||
@ -36,12 +36,12 @@ request_to_completions() {
|
||||
# request to OpenAI API image generations endpoint function
|
||||
# $1 should be the prompt
|
||||
request_to_image() {
|
||||
prompt=$1
|
||||
image_response=$(curl https://api.openai.com/v1/images/generations \
|
||||
-sS \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H "Authorization: Bearer $OPENAI_KEY" \
|
||||
-d '{
|
||||
prompt=$1
|
||||
image_response=$(curl https://api.openai.com/v1/images/generations \
|
||||
-sS \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H "Authorization: Bearer $OPENAI_KEY" \
|
||||
-d '{
|
||||
"prompt": "'"${prompt#*image:}"'",
|
||||
"n": 1,
|
||||
"size": "'"$SIZE"'"
|
||||
@ -51,12 +51,12 @@ request_to_image() {
|
||||
# request to OpenAPI API chat completion endpoint function
|
||||
# $1 should be the message(s) formatted with role and content
|
||||
request_to_chat() {
|
||||
message=$1
|
||||
response=$(curl https://api.openai.com/v1/chat/completions \
|
||||
-sS \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H "Authorization: Bearer $OPENAI_KEY" \
|
||||
-d '{
|
||||
message=$1
|
||||
response=$(curl https://api.openai.com/v1/chat/completions \
|
||||
-sS \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H "Authorization: Bearer $OPENAI_KEY" \
|
||||
-d '{
|
||||
"model": "'"$MODEL"'",
|
||||
"messages": [
|
||||
{"role": "system", "content": "'"$SYSTEM_PROMPT"'"},
|
||||
@ -67,19 +67,19 @@ request_to_chat() {
|
||||
}')
|
||||
}
|
||||
|
||||
# build chat context before each request for /completions (all models except
|
||||
# build chat context before each request for /completions (all models except
|
||||
# gpt turbo)
|
||||
# $1 should be the chat context
|
||||
# $2 should be the escaped prompt
|
||||
build_chat_context() {
|
||||
chat_context=$1
|
||||
escaped_prompt=$2
|
||||
if [ -z "$chat_context" ]; then
|
||||
chat_context="$CHAT_INIT_PROMPT\nQ: $escaped_prompt"
|
||||
else
|
||||
chat_context="$chat_context\nQ: $escaped_prompt"
|
||||
fi
|
||||
request_prompt="${chat_context//$'\n'/\\n}"
|
||||
chat_context=$1
|
||||
escaped_prompt=$2
|
||||
if [ -z "$chat_context" ]; then
|
||||
chat_context="$CHAT_INIT_PROMPT\nQ: $escaped_prompt"
|
||||
else
|
||||
chat_context="$chat_context\nQ: $escaped_prompt"
|
||||
fi
|
||||
request_prompt="${chat_context//$'\n'/\\n}"
|
||||
}
|
||||
|
||||
# maintain chat context function for /completions (all models except gpt turbo)
|
||||
@ -88,18 +88,18 @@ build_chat_context() {
|
||||
# $1 should be the chat context
|
||||
# $2 should be the response data (only the text)
|
||||
maintain_chat_context() {
|
||||
chat_context=$1
|
||||
response_data=$2
|
||||
# add response to chat context as answer
|
||||
chat_context="$chat_context${chat_context:+\n}\nA: ${response_data//$'\n'/\\n}"
|
||||
# check prompt length, 1 word =~ 1.3 tokens
|
||||
# reserving 100 tokens for next user prompt
|
||||
while (($(echo "$chat_context" | wc -c) * 1, 3 > (MAX_TOKENS - 100))); do
|
||||
# remove first/oldest QnA from prompt
|
||||
chat_context=$(echo "$chat_context" | sed -n '/Q:/,$p' | tail -n +2)
|
||||
# add init prompt so it is always on top
|
||||
chat_context="$CHAT_INIT_PROMPT $chat_context"
|
||||
done
|
||||
chat_context=$1
|
||||
response_data=$2
|
||||
# add response to chat context as answer
|
||||
chat_context="$chat_context${chat_context:+\n}\nA: ${response_data//$'\n'/\\n}"
|
||||
# check prompt length, 1 word =~ 1.3 tokens
|
||||
# reserving 100 tokens for next user prompt
|
||||
while (($(echo "$chat_context" | wc -c) * 1, 3 > (MAX_TOKENS - 100))); do
|
||||
# remove first/oldest QnA from prompt
|
||||
chat_context=$(echo "$chat_context" | sed -n '/Q:/,$p' | tail -n +2)
|
||||
# add init prompt so it is always on top
|
||||
chat_context="$CHAT_INIT_PROMPT $chat_context"
|
||||
done
|
||||
}
|
||||
|
||||
# build user chat message function for /chat/completions (gpt turbo model)
|
||||
@ -107,15 +107,15 @@ maintain_chat_context() {
|
||||
# $1 should be the chat message
|
||||
# $2 should be the escaped prompt
|
||||
build_user_chat_message() {
|
||||
chat_message=$1
|
||||
escaped_prompt=$2
|
||||
if [ -z "$chat_message" ]; then
|
||||
chat_message="{\"role\": \"user\", \"content\": \"$escaped_prompt\"}"
|
||||
else
|
||||
chat_message="$chat_message, {\"role\": \"user\", \"content\": \"$escaped_prompt\"}"
|
||||
fi
|
||||
chat_message=$1
|
||||
escaped_prompt=$2
|
||||
if [ -z "$chat_message" ]; then
|
||||
chat_message="{\"role\": \"user\", \"content\": \"$escaped_prompt\"}"
|
||||
else
|
||||
chat_message="$chat_message, {\"role\": \"user\", \"content\": \"$escaped_prompt\"}"
|
||||
fi
|
||||
|
||||
request_prompt=$chat_message
|
||||
request_prompt=$chat_message
|
||||
}
|
||||
|
||||
# adds the assistant response to the message in (chatml) format
|
||||
@ -124,85 +124,85 @@ build_user_chat_message() {
|
||||
# $1 should be the chat message
|
||||
# $2 should be the response data (only the text)
|
||||
add_assistant_response_to_chat_message() {
|
||||
chat_message=$1
|
||||
response_data=$2
|
||||
chat_message=$1
|
||||
response_data=$2
|
||||
|
||||
# replace new line characters from response with space
|
||||
response_data=$(echo "$response_data" | tr '\n' ' ')
|
||||
# add response to chat context as answer
|
||||
chat_message="$chat_message, {\"role\": \"assistant\", \"content\": \"$response_data\"}"
|
||||
# replace new line characters from response with space
|
||||
response_data=$(echo "$response_data" | tr '\n' ' ')
|
||||
# add response to chat context as answer
|
||||
chat_message="$chat_message, {\"role\": \"assistant\", \"content\": \"$response_data\"}"
|
||||
|
||||
# transform to json array to parse with jq
|
||||
chat_message_json="[ $chat_message ]"
|
||||
# check prompt length, 1 word =~ 1.3 tokens
|
||||
# reserving 100 tokens for next user prompt
|
||||
while (($(echo "$chat_message" | wc -c) * 1, 3 > (MAX_TOKENS - 100))); do
|
||||
# remove first/oldest QnA from prompt
|
||||
chat_message=$(echo "$chat_message_json" | jq -c '.[2:] | .[] | {role, content}')
|
||||
done
|
||||
# transform to json array to parse with jq
|
||||
chat_message_json="[ $chat_message ]"
|
||||
# check prompt length, 1 word =~ 1.3 tokens
|
||||
# reserving 100 tokens for next user prompt
|
||||
while (($(echo "$chat_message" | wc -c) * 1, 3 > (MAX_TOKENS - 100))); do
|
||||
# remove first/oldest QnA from prompt
|
||||
chat_message=$(echo "$chat_message_json" | jq -c '.[2:] | .[] | {role, content}')
|
||||
done
|
||||
}
|
||||
|
||||
# parse command line arguments
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case $1 in
|
||||
-i | --init-prompt)
|
||||
CHAT_INIT_PROMPT="$2"
|
||||
CONTEXT=true
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
--init-prompt-from-file)
|
||||
CHAT_INIT_PROMPT=$(cat "$2")
|
||||
CONTEXT=true
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-p | --prompt)
|
||||
prompt="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
--prompt-from-file)
|
||||
prompt=$(cat "$2")
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-t | --temperature)
|
||||
TEMPERATURE="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
--max-tokens)
|
||||
MAX_TOKENS="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-m | --model)
|
||||
MODEL="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-s | --size)
|
||||
SIZE="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-c | --chat-context)
|
||||
CONTEXT=true
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-cc | --chat-completion)
|
||||
MODEL="gpt-3.5-turbo"
|
||||
CHAT_COMPLETION=true
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unknown parameter: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
case $1 in
|
||||
-i | --init-prompt)
|
||||
CHAT_INIT_PROMPT="$2"
|
||||
CONTEXT=true
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
--init-prompt-from-file)
|
||||
CHAT_INIT_PROMPT=$(cat "$2")
|
||||
CONTEXT=true
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-p | --prompt)
|
||||
prompt="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
--prompt-from-file)
|
||||
prompt=$(cat "$2")
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-t | --temperature)
|
||||
TEMPERATURE="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
--max-tokens)
|
||||
MAX_TOKENS="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-m | --model)
|
||||
MODEL="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-s | --size)
|
||||
SIZE="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-c | --chat-context)
|
||||
CONTEXT=true
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-cc | --chat-completion)
|
||||
MODEL="gpt-3.5-turbo"
|
||||
CHAT_COMPLETION=true
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unknown parameter: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# set defaults
|
||||
@ -215,8 +215,8 @@ CHAT_COMPLETION=${CHAT_COMPLETION:-false}
|
||||
|
||||
# create history file
|
||||
if [ ! -f ~/.chatgpt_history ]; then
|
||||
touch ~/.chatgpt_history
|
||||
chmod a+rw ~/.chatgpt_history
|
||||
touch ~/.chatgpt_history
|
||||
chmod a+rw ~/.chatgpt_history
|
||||
fi
|
||||
|
||||
running=true
|
||||
@ -224,100 +224,100 @@ running=true
|
||||
# if prompt already entered, run on pipe mode (run once, no chat)
|
||||
# prompt from pipe
|
||||
if [ -p /dev/stdin ]; then
|
||||
pipe_mode_prompt+=$(cat -)
|
||||
pipe_mode_prompt+=$(cat -)
|
||||
# prompt from argument
|
||||
elif [ -n "$prompt" ]; then
|
||||
pipe_mode_prompt=${prompt}
|
||||
pipe_mode_prompt=${prompt}
|
||||
else
|
||||
echo -e "Welcome to chatgpt. You can quit with '\033[36mexit\033[0m'."
|
||||
echo -e "Welcome to chatgpt. You can quit with '\033[36mexit\033[0m'."
|
||||
fi
|
||||
|
||||
while $running; do
|
||||
|
||||
if [ -z "$pipe_mode_prompt" ]; then
|
||||
echo -e "\nEnter a prompt:"
|
||||
read prompt
|
||||
else
|
||||
# set vars for pipe mode
|
||||
prompt=${pipe_mode_prompt}
|
||||
running=false
|
||||
CHATGPT_CYAN_LABEL=""
|
||||
fi
|
||||
if [ -z "$pipe_mode_prompt" ]; then
|
||||
echo -e "\nEnter a prompt:"
|
||||
read prompt
|
||||
else
|
||||
# set vars for pipe mode
|
||||
prompt=${pipe_mode_prompt}
|
||||
running=false
|
||||
CHATGPT_CYAN_LABEL=""
|
||||
fi
|
||||
|
||||
if [ "$prompt" == "exit" ]; then
|
||||
running=false
|
||||
elif [[ "$prompt" =~ ^image: ]]; then
|
||||
request_to_image "$prompt"
|
||||
handle_error "$image_response"
|
||||
image_url=$(echo $image_response | jq -r '.data[0].url')
|
||||
echo -e "${CHATGPT_CYAN_LABEL}Your image was created. \n\nLink: ${image_url}\n"
|
||||
if [ "$prompt" == "exit" ]; then
|
||||
running=false
|
||||
elif [[ "$prompt" =~ ^image: ]]; then
|
||||
request_to_image "$prompt"
|
||||
handle_error "$image_response"
|
||||
image_url=$(echo $image_response | jq -r '.data[0].url')
|
||||
echo -e "${CHATGPT_CYAN_LABEL}Your image was created. \n\nLink: ${image_url}\n"
|
||||
|
||||
if [[ "$TERM_PROGRAM" == "iTerm.app" ]]; then
|
||||
curl -sS $image_url -o temp_image.png
|
||||
imgcat temp_image.png
|
||||
rm temp_image.png
|
||||
else
|
||||
echo "Would you like to open it? (Yes/No)"
|
||||
read answer
|
||||
if [ "$answer" == "Yes" ] || [ "$answer" == "yes" ] || [ "$answer" == "y" ] || [ "$answer" == "Y" ] || [ "$answer" == "ok" ]; then
|
||||
open "${image_url}"
|
||||
fi
|
||||
fi
|
||||
elif [[ "$prompt" == "history" ]]; then
|
||||
echo -e "\n$(cat ~/.chatgpt_history)"
|
||||
elif [[ "$prompt" == "models" ]]; then
|
||||
models_response=$(curl https://api.openai.com/v1/models \
|
||||
-sS \
|
||||
-H "Authorization: Bearer $OPENAI_KEY")
|
||||
handle_error "$models_response"
|
||||
models_data=$(echo $models_response | jq -r -C '.data[] | {id, owned_by, created}')
|
||||
echo -e "${CHATGPT_CYAN_LABEL}This is a list of models currently available at OpenAI API:\n ${models_data}"
|
||||
elif [[ "$prompt" =~ ^model: ]]; then
|
||||
models_response=$(curl https://api.openai.com/v1/models \
|
||||
-sS \
|
||||
-H "Authorization: Bearer $OPENAI_KEY")
|
||||
handle_error "$models_response"
|
||||
model_data=$(echo $models_response | jq -r -C '.data[] | select(.id=="'"${prompt#*model:}"'")')
|
||||
echo -e "${CHATGPT_CYAN_LABEL}Complete details for model: ${prompt#*model:}\n ${model_data}"
|
||||
elif [[ "$CHAT_COMPLETION" = true ]]; then
|
||||
# escape quotation marks
|
||||
escaped_prompt=$(echo "$prompt" | sed 's/"/\\"/g')
|
||||
# escape new lines
|
||||
request_prompt=${escaped_prompt//$'\n'/' '}
|
||||
if [[ "$TERM_PROGRAM" == "iTerm.app" ]]; then
|
||||
curl -sS $image_url -o temp_image.png
|
||||
imgcat temp_image.png
|
||||
rm temp_image.png
|
||||
else
|
||||
echo "Would you like to open it? (Yes/No)"
|
||||
read answer
|
||||
if [ "$answer" == "Yes" ] || [ "$answer" == "yes" ] || [ "$answer" == "y" ] || [ "$answer" == "Y" ] || [ "$answer" == "ok" ]; then
|
||||
open "${image_url}"
|
||||
fi
|
||||
fi
|
||||
elif [[ "$prompt" == "history" ]]; then
|
||||
echo -e "\n$(cat ~/.chatgpt_history)"
|
||||
elif [[ "$prompt" == "models" ]]; then
|
||||
models_response=$(curl https://api.openai.com/v1/models \
|
||||
-sS \
|
||||
-H "Authorization: Bearer $OPENAI_KEY")
|
||||
handle_error "$models_response"
|
||||
models_data=$(echo $models_response | jq -r -C '.data[] | {id, owned_by, created}')
|
||||
echo -e "${CHATGPT_CYAN_LABEL}This is a list of models currently available at OpenAI API:\n ${models_data}"
|
||||
elif [[ "$prompt" =~ ^model: ]]; then
|
||||
models_response=$(curl https://api.openai.com/v1/models \
|
||||
-sS \
|
||||
-H "Authorization: Bearer $OPENAI_KEY")
|
||||
handle_error "$models_response"
|
||||
model_data=$(echo $models_response | jq -r -C '.data[] | select(.id=="'"${prompt#*model:}"'")')
|
||||
echo -e "${CHATGPT_CYAN_LABEL}Complete details for model: ${prompt#*model:}\n ${model_data}"
|
||||
elif [[ "$CHAT_COMPLETION" = true ]]; then
|
||||
# escape quotation marks
|
||||
escaped_prompt=$(echo "$prompt" | sed 's/"/\\"/g')
|
||||
# escape new lines
|
||||
request_prompt=${escaped_prompt//$'\n'/' '}
|
||||
|
||||
build_user_chat_message "$chat_message" "$request_prompt"
|
||||
request_to_chat "$request_prompt"
|
||||
handle_error "$response"
|
||||
response_data=$(echo $response | jq -r '.choices[].message.content')
|
||||
echo -e "${CHATGPT_CYAN_LABEL}${response_data}"
|
||||
build_user_chat_message "$chat_message" "$request_prompt"
|
||||
request_to_chat "$request_prompt"
|
||||
handle_error "$response"
|
||||
response_data=$(echo $response | jq -r '.choices[].message.content')
|
||||
echo -e "${CHATGPT_CYAN_LABEL}${response_data}"
|
||||
|
||||
response_data=$(echo "$response_data" | sed 's/"/\\"/g')
|
||||
response_data=$(echo "$response_data" | sed 's/"/\\"/g')
|
||||
|
||||
add_assistant_response_to_chat_message "$chat_message" "$response_data"
|
||||
add_assistant_response_to_chat_message "$chat_message" "$response_data"
|
||||
|
||||
timestamp=$(date +"%d/%m/%Y %H:%M")
|
||||
echo -e "$timestamp $prompt \n$response_data \n" >>~/.chatgpt_history
|
||||
else
|
||||
# escape quotation marks
|
||||
escaped_prompt=$(echo "$prompt" | sed 's/"/\\"/g')
|
||||
# escape new lines
|
||||
request_prompt=${escaped_prompt//$'\n'/' '}
|
||||
timestamp=$(date +"%d/%m/%Y %H:%M")
|
||||
echo -e "$timestamp $prompt \n$response_data \n" >>~/.chatgpt_history
|
||||
else
|
||||
# escape quotation marks
|
||||
escaped_prompt=$(echo "$prompt" | sed 's/"/\\"/g')
|
||||
# escape new lines
|
||||
request_prompt=${escaped_prompt//$'\n'/' '}
|
||||
|
||||
if [ "$CONTEXT" = true ]; then
|
||||
build_chat_context "$chat_context" "$escaped_prompt"
|
||||
fi
|
||||
if [ "$CONTEXT" = true ]; then
|
||||
build_chat_context "$chat_context" "$escaped_prompt"
|
||||
fi
|
||||
|
||||
request_to_completions "$request_prompt"
|
||||
handle_error "$response"
|
||||
response_data=$(echo $response | jq -r '.choices[].text' | sed '1,2d; s/^A://g')
|
||||
echo -e "${CHATGPT_CYAN_LABEL}${response_data}"
|
||||
request_to_completions "$request_prompt"
|
||||
handle_error "$response"
|
||||
response_data=$(echo $response | jq -r '.choices[].text' | sed '1,2d; s/^A://g')
|
||||
echo -e "${CHATGPT_CYAN_LABEL}${response_data}"
|
||||
|
||||
if [ "$CONTEXT" = true ]; then
|
||||
escaped_response_data=$(echo "$response_data" | sed 's/"/\\"/g')
|
||||
maintain_chat_context "$chat_context" "$escaped_response_data"
|
||||
fi
|
||||
if [ "$CONTEXT" = true ]; then
|
||||
escaped_response_data=$(echo "$response_data" | sed 's/"/\\"/g')
|
||||
maintain_chat_context "$chat_context" "$escaped_response_data"
|
||||
fi
|
||||
|
||||
timestamp=$(date +"%d/%m/%Y %H:%M")
|
||||
echo -e "$timestamp $prompt \n$escaped_response_data \n" >>~/.chatgpt_history
|
||||
fi
|
||||
timestamp=$(date +"%d/%m/%Y %H:%M")
|
||||
echo -e "$timestamp $prompt \n$escaped_response_data \n" >>~/.chatgpt_history
|
||||
fi
|
||||
done
|
||||
|
Loading…
Reference in New Issue
Block a user