diff options
Diffstat (limited to 'bin/gpt')
| -rwxr-xr-x | bin/gpt/gpt | 120 |
1 files changed, 84 insertions, 36 deletions
diff --git a/bin/gpt/gpt b/bin/gpt/gpt index cd312d6..4d0f651 100755 --- a/bin/gpt/gpt +++ b/bin/gpt/gpt | |||
| @@ -3,11 +3,13 @@ | |||
| 3 | # TODO | 3 | # TODO |
| 4 | # - Use suggested block to wrap data: | 4 | # - Use suggested block to wrap data: |
| 5 | # https://help.openai.com/en/articles/6654000-best-practices-for-prompt-engineering-with-openai-api | 5 | # https://help.openai.com/en/articles/6654000-best-practices-for-prompt-engineering-with-openai-api |
| 6 | # - Add signal trap for API parameters (like stop) | 6 | # - Print token usage when exit |
| 7 | |||
| 8 | # User can dynamically change these options for API call | ||
| 9 | configurable_options=( behavior temperature max_tokens ) | ||
| 7 | 10 | ||
| 8 | # If script is interupt by SIGINT, simply print leave message | 11 | # If script is interupt by SIGINT, simply print leave message |
| 9 | trap 'echo -e "\nChat Finished, cached file: $cache"; exit 0' INT | 12 | trap _print_leave_message INT |
| 10 | trap '_configure_completion' TSTP | ||
| 11 | 13 | ||
| 12 | # Function for printing helper message | 14 | # Function for printing helper message |
| 13 | _print_helper_message() { | 15 | _print_helper_message() { |
| @@ -40,22 +42,72 @@ Options: | |||
| 40 | -s|--skip Skip message, STDIN would be treated as your message | 42 | -s|--skip Skip message, STDIN would be treated as your message |
| 41 | 43 | ||
| 42 | * The other arguments would be treated as message content. | 44 | * The other arguments would be treated as message content. |
| 43 | If no message is specified, user should type it by hands. | 45 | If no message is specified, user should input content by hands. |
| 44 | If STDIN is given, it would be append to the end of message. | 46 | If STDIN is given, it would be append to the end of message. |
| 45 | 47 | ||
| 48 | Special prompt: | ||
| 49 | Options If input starts with '.', then a prompt of options shows up. | ||
| 50 | User can modify option value for API calls. | ||
| 51 | |||
| 46 | Reference: https://platform.openai.com/docs/api-reference/completions | 52 | Reference: https://platform.openai.com/docs/api-reference/completions |
| 47 | EOF | 53 | EOF |
| 48 | } | 54 | } |
| 49 | 55 | ||
| 50 | _configure_completion() { | 56 | _print_leave_message(){ |
| 51 | field="$( | 57 | echo -e "\nChat Finished, cached file: $cache" |
| 52 | dialog --form "Configure Completion" 10 50 3 \ | 58 | exit 0 |
| 53 | --stdout \ | 59 | } |
| 54 | 'model:' 1 1 "$(eval 'echo $model')" 1 15 25 0 \ | 60 | |
| 55 | 'temperature:' 2 1 "$(eval 'echo $temperature')" 2 15 25 0 \ | 61 | # A prompt for option configuration |
| 56 | 'max_tokens:' 3 1 "$(eval 'echo $max_tokens')" 3 15 25 0 | 62 | _configure_options() { |
| 57 | )" | 63 | # Apply original trap action, and exit this prompt |
| 58 | 64 | trap 'trap _print_leave_message SIGINT; echo; return' INT | |
| 65 | # Hint message | ||
| 66 | echo 'List of options: (Use Ctrl-C to exit)' | ||
| 67 | |||
| 68 | # Print all available options | ||
| 69 | index=0 | ||
| 70 | for option in "${configurable_options[@]}"; do | ||
| 71 | echo -e "$index." "$option:\t" "$(eval "echo \$$option")" | ||
| 72 | (( index+=1 )) | ||
| 73 | done | ||
| 74 | |||
| 75 | # Prompt for user input | ||
| 76 | while true; do | ||
| 77 | echo | ||
| 78 | read -e -r -p "Modify which option? (0~$((index-1))) " selection | ||
| 79 | local field=${configurable_options[$selection]} | ||
| 80 | eval "read -e -r -p '$field: ' $field" | ||
| 81 | done | ||
| 82 | } | ||
| 83 | |||
| 84 | # Get latest content for completion | ||
| 85 | _get_content() { | ||
| 86 | |||
| 87 | # Read data from STDIN | ||
| 88 | [ ! -t 0 ] && data="$(cat)" | ||
| 89 | |||
| 90 | if [ ! "$SKIP_INPUT" = true ] ; then | ||
| 91 | # Read content it from terminal | ||
| 92 | while true; do | ||
| 93 | read -e -r -p "Let's Chat: " content </dev/tty | ||
| 94 | [[ "$content" =~ ^\. ]] && echo && _configure_options && echo -e '\n------\n' && continue | ||
| 95 | [ -n "$content" ] && break | ||
| 96 | done | ||
| 97 | elif [[ "$count" -eq 0 && -z "$data" ]]; then | ||
| 98 | echo -e "No data from STDIN\n" | ||
| 99 | exit 1; | ||
| 100 | fi | ||
| 101 | |||
| 102 | # If it is the first round, append STDIN (If it exists) at the end | ||
| 103 | if [[ ! "$SKIP_INPUT" = true && -n "$data" ]] ; then | ||
| 104 | content="$(printf "%s\\n\\n%s" "$content" "$data")" | ||
| 105 | echo -e "\n$data" | ||
| 106 | # Or only use STDIN as content | ||
| 107 | elif [ -n "$data" ]; then | ||
| 108 | content="$data" | ||
| 109 | echo "$content" | ||
| 110 | fi | ||
| 59 | } | 111 | } |
| 60 | 112 | ||
| 61 | # Check OPENAI API KEY"Department:" 3 1 "" 3 15 25 0 | 113 | # Check OPENAI API KEY"Department:" 3 1 "" 3 15 25 0 |
| @@ -82,15 +134,20 @@ while [ "$#" -gt 0 ]; do | |||
| 82 | temperature="$2" | 134 | temperature="$2" |
| 83 | shift 2 | 135 | shift 2 |
| 84 | ;; | 136 | ;; |
| 85 | -m|--max_tokens) | 137 | -M|--max_tokens) |
| 86 | max_tokens="$2" | 138 | max_tokens="$2" |
| 87 | shift 2 | 139 | shift 2 |
| 88 | ;; | 140 | ;; |
| 141 | -s|--skip) | ||
| 142 | SKIP_INPUT=true | ||
| 143 | shift 1 | ||
| 144 | ;; | ||
| 89 | -h|--help) | 145 | -h|--help) |
| 90 | _print_helper_message | 146 | _print_helper_message |
| 91 | exit 0 | 147 | exit 0 |
| 92 | ;; | 148 | ;; |
| 93 | *) | 149 | *) |
| 150 | SKIP_INPUT=true | ||
| 94 | content="$1" | 151 | content="$1" |
| 95 | shift 1 | 152 | shift 1 |
| 96 | ;; | 153 | ;; |
| @@ -105,30 +162,21 @@ temperature=${temperature:-0.7} | |||
| 105 | max_tokens=${max_tokens:-2048} | 162 | max_tokens=${max_tokens:-2048} |
| 106 | 163 | ||
| 107 | # Prepare for chat session | 164 | # Prepare for chat session |
| 108 | cache=`mktemp` && touch $cache # && trap "rm $cache" EXIT | 165 | cache=$(mktemp) && touch "$cache" |
| 166 | #trap "rm $cache" EXIT | ||
| 109 | session=() | 167 | session=() |
| 110 | count=0 | 168 | count=0 |
| 111 | 169 | ||
| 112 | # Use while to keep chat session | 170 | # Use while to keep chat session |
| 113 | while true; do | 171 | while true; do |
| 114 | # Read prompt from terminal | 172 | _get_content |
| 115 | # If content is not specified by argumment, read it from terminal | 173 | |
| 116 | [[ -z "$content" || $count >=1 ]] && read -e -r -p "Let's Chat: " content </dev/tty | 174 | # User must input by hands in the following rounds |
| 117 | # If no user input, simple print helper message and exit with code 1 | 175 | SKIP_INPUT=false |
| 118 | [ -z "$content" ] && { echo -e "No message is given\n"; _print_helper_message; exit 1; } | ||
| 119 | # Read data from STDIN | ||
| 120 | [ ! -t 0 ] && data="$(cat)" | ||
| 121 | # Append data to the end of content | ||
| 122 | # And print it out | ||
| 123 | if [ -n "$data" ]; then | ||
| 124 | content="$(printf "%s\\n\\n%s" "$content" "$data")" | ||
| 125 | echo | ||
| 126 | echo "$data" | ||
| 127 | fi | ||
| 128 | 176 | ||
| 129 | # Put user message into session | 177 | # Put user message into session |
| 130 | user_message="$(cat <<EOF | 178 | user_message="$(cat <<EOF |
| 131 | {"role": "user", "content": $(<<<"$content" jq -sR .)} | 179 | {"role": "user", "content": $(printf '%s' "$content" | jq -sR .)} |
| 132 | EOF | 180 | EOF |
| 133 | )" | 181 | )" |
| 134 | session+=("$user_message") | 182 | session+=("$user_message") |
| @@ -139,8 +187,8 @@ EOF | |||
| 139 | { | 187 | { |
| 140 | "model": "$model", | 188 | "model": "$model", |
| 141 | "messages": [ | 189 | "messages": [ |
| 142 | {"role": "system", "content": $(echo $behavior | jq -sR .)}, | 190 | {"role": "system", "content": $(echo "$behavior" | jq -sR .)}, |
| 143 | `IFS=',\n'; echo "${session[*]}"` | 191 | $(IFS=','; echo "${session[*]}") |
| 144 | ], | 192 | ], |
| 145 | "temperature": $temperature, | 193 | "temperature": $temperature, |
| 146 | "max_tokens": $max_tokens | 194 | "max_tokens": $max_tokens |
| @@ -148,7 +196,7 @@ EOF | |||
| 148 | EOF | 196 | EOF |
| 149 | )" | 197 | )" |
| 150 | # Append request body into cache | 198 | # Append request body into cache |
| 151 | echo "$body" >>$cache | 199 | echo "$body" >>"$cache" |
| 152 | 200 | ||
| 153 | # Add an empty line between prompt and response | 201 | # Add an empty line between prompt and response |
| 154 | echo -e '\n------\n' | 202 | echo -e '\n------\n' |
| @@ -156,15 +204,15 @@ EOF | |||
| 156 | # API call | 204 | # API call |
| 157 | # Save original response into cache file | 205 | # Save original response into cache file |
| 158 | # And only print content of message | 206 | # And only print content of message |
| 159 | response="` | 207 | response="$( |
| 160 | curl https://api.openai.com/$ROUTE \ | 208 | curl https://api.openai.com/$ROUTE \ |
| 161 | --silent \ | 209 | --silent \ |
| 162 | -H "Content-Type: application/json" \ | 210 | -H "Content-Type: application/json" \ |
| 163 | -H "Authorization: Bearer $OPENAI_API_KEY" \ | 211 | -H "Authorization: Bearer $OPENAI_API_KEY" \ |
| 164 | -d "$body" | \ | 212 | -d "$body" | \ |
| 165 | jq . | tee -a $cache | \ | 213 | jq . | tee -a "$cache" | \ |
| 166 | jq -r .choices[0].message.content | 214 | jq -r .choices[0].message.content |
| 167 | `" | 215 | )" |
| 168 | echo -e "${response}\n\n------\n" | 216 | echo -e "${response}\n\n------\n" |
| 169 | 217 | ||
| 170 | # Append newest message into session | 218 | # Append newest message into session |