diff options
author | Hsieh Chin Fan <pham@topo.tw> | 2023-03-23 12:41:22 +0800 |
---|---|---|
committer | Hsieh Chin Fan <pham@topo.tw> | 2023-03-23 12:41:22 +0800 |
commit | 5615babc802b35e8c287b87fd1a3d1fb2932a4d1 (patch) | |
tree | f7de6ee352e6b73caa06e5afd78beca1a2db100e | |
parent | 943259404bfd39965c42f2a22a2c0beac479062f (diff) | |
parent | 7594d8bbfa51e94a0fbfd5fb0649af3be0181ccc (diff) |
Merge branch 'gpt' into dev
-rwxr-xr-x | bin/gpt/gpt | 102 |
1 files changed, 71 insertions, 31 deletions
diff --git a/bin/gpt/gpt b/bin/gpt/gpt index ab4b64c..63241ac 100755 --- a/bin/gpt/gpt +++ b/bin/gpt/gpt | |||
@@ -1,11 +1,14 @@ | |||
1 | #! /bin/bash | 1 | #! /bin/bash |
2 | 2 | ||
3 | # TODO | 3 | # TODO |
4 | # - Put previous response into tokens | 4 | # - Use suggested block to wrap data: |
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) | ||
5 | 7 | ||
6 | [ -z "$OPENAI_API_KEY" ] && OPENAI_API_KEY=$(token openai) | 8 | # If script is interupt by SIGINT, simply print leave message |
7 | [ -z "$OPENAI_API_KEY" ] && echo API KEY not specified && exit 1 | 9 | trap 'echo -e "\nChat Finished, cached file: $cache"; exit 0' INT |
8 | 10 | ||
11 | # Function for printing helper message | ||
9 | _print_helper_message() { | 12 | _print_helper_message() { |
10 | cat <<EOF | 13 | cat <<EOF |
11 | Usage: gpt [-h] [-m MODEL] [-m4] [-b BEHAVIOR] [-t temperature] | 14 | Usage: gpt [-h] [-m MODEL] [-m4] [-b BEHAVIOR] [-t temperature] |
@@ -41,6 +44,11 @@ Reference: https://platform.openai.com/docs/api-reference/completions | |||
41 | EOF | 44 | EOF |
42 | } | 45 | } |
43 | 46 | ||
47 | # Check OPENAI API KEY | ||
48 | [ -z "$OPENAI_API_KEY" ] && OPENAI_API_KEY=$(token openai) | ||
49 | [ -z "$OPENAI_API_KEY" ] && { echo API KEY not specified; exit 1; } | ||
50 | |||
51 | |||
44 | # Parse arguments | 52 | # Parse arguments |
45 | while [ "$#" -gt 0 ]; do | 53 | while [ "$#" -gt 0 ]; do |
46 | case "$1" in | 54 | case "$1" in |
@@ -75,44 +83,76 @@ while [ "$#" -gt 0 ]; do | |||
75 | esac | 83 | esac |
76 | done | 84 | done |
77 | 85 | ||
78 | # Available: | 86 | # Set variables |
79 | # v1/models | ||
80 | # v1/chat/completions | ||
81 | ROUTE=v1/chat/completions | 87 | ROUTE=v1/chat/completions |
82 | |||
83 | model=${model:-gpt-3.5-turbo} | 88 | model=${model:-gpt-3.5-turbo} |
84 | behavior="${behavior:-You are a helpful programming assistant}" | 89 | behavior="${behavior:-You are a helpful programming assistant}" |
85 | temperature=${temperature:-0.7} | 90 | temperature=${temperature:-0.7} |
86 | n=${n:-1} | 91 | n=${n:-1} |
92 | cache=`mktemp` && touch $cache # && trap "rm $cache" EXIT | ||
93 | session=() | ||
94 | count=0 | ||
95 | |||
96 | # Use while to keep chat session | ||
97 | while true; do | ||
98 | # Read prompt from terminal | ||
99 | # If content is not specified by argumment, read it from terminal | ||
100 | [[ -z "$content" || $count >=1 ]] && read -e -r -p "Let's Chat: " content </dev/tty | ||
101 | # If no user input, simple print helper message and exit with code 1 | ||
102 | [ -z "$content" ] && { echo -e "No message is given\n"; _print_helper_message; exit 1; } | ||
103 | # Read data from STDIN | ||
104 | [ ! -t 0 ] && data="$(cat)" | ||
105 | # Append data to the end of content | ||
106 | [ -n "$data" ] && content="$(printf "%s\\n\\n%s" "$content" "$data")" | ||
107 | |||
108 | # Put user message into session | ||
109 | user_message="$(cat <<EOF | ||
110 | {"role": "user", "content": $(<<<"$content" jq -sR .)} | ||
111 | EOF | ||
112 | )" | ||
113 | session+=("$user_message") | ||
87 | 114 | ||
88 | # Read content from terminal | 115 | # Create request body |
89 | [ -z "$content" ] && read -e -r -p "Let's Chat: " content </dev/tty | 116 | # Consider quotes, back slashes, use jq to ensure content texts are OK to put in JSON |
90 | [ -z "$content" ] && { echo -e "No message is given\n"; _print_helper_message; exit 1; } | 117 | body="$(cat <<EOF |
91 | [ ! -t 0 ] && data="$(cat)" | ||
92 | [ -n "$data" ] && content="$(printf "%s\\n\\n%s" "$content" "$data")" | ||
93 | |||
94 | # Create request body | ||
95 | body="$(cat <<EOF | ||
96 | { | 118 | { |
97 | "model": "$model", | 119 | "model": "$model", |
98 | "messages": [ | 120 | "messages": [ |
99 | {"role": "system", "content": "$behavior"}, | 121 | {"role": "system", "content": $(echo $behavior | jq -sR .)}, |
100 | {"role": "user", "content": $(echo $content | jq -R .)} | 122 | `IFS=',\n'; echo "${session[*]}"` |
101 | ], | 123 | ], |
102 | "temperature": $temperature, | 124 | "temperature": $temperature, |
103 | "n": $n | 125 | "n": $n, |
126 | "max_tokens": 50 | ||
104 | } | 127 | } |
105 | EOF | 128 | EOF |
106 | )" | 129 | )" |
107 | 130 | # Append request body into cache | |
108 | # Add an empty line between prompt and response | 131 | echo "$body" >>$cache |
109 | echo | 132 | |
110 | 133 | # Add an empty line between prompt and response | |
111 | # API call | 134 | echo -e '\n------\n' |
112 | curl https://api.openai.com/$ROUTE \ | 135 | |
113 | --silent \ | 136 | # API call |
114 | -H "Content-Type: application/json" \ | 137 | # Save original response into cache file |
115 | -H "Authorization: Bearer $OPENAI_API_KEY" \ | 138 | # And only print content of message |
116 | -d "$body" | \ | 139 | response="` |
117 | jq . | tee .gpt | \ | 140 | curl https://api.openai.com/$ROUTE \ |
118 | jq -r .choices[0].message.content | 141 | --silent \ |
142 | -H "Content-Type: application/json" \ | ||
143 | -H "Authorization: Bearer $OPENAI_API_KEY" \ | ||
144 | -d "$body" | \ | ||
145 | jq . | tee -a $cache | \ | ||
146 | jq -r .choices[0].message.content | ||
147 | `" | ||
148 | echo -e "${response}\n\n------\n" | ||
149 | |||
150 | # Append newest message into session | ||
151 | assistant_message="$(cat <<EOF | ||
152 | {"role": "assistant", "content": $(<<<"$response" jq -sR .)} | ||
153 | EOF | ||
154 | )" | ||
155 | session+=("$assistant_message") | ||
156 | |||
157 | (( count+=1 )) | ||
158 | done | ||