-
Notifications
You must be signed in to change notification settings - Fork 12
/
zsh-ask.zsh
executable file
·271 lines (251 loc) · 8.99 KB
/
zsh-ask.zsh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# A lightweight Zsh plugin serves as a ChatGPT API frontend, enabling you to interact with ChatGPT directly from the Zsh.
# https://github.com/Licheam/zsh-ask
# Copyright (c) 2023-2024 Leachim
#--------------------------------------------------------------------#
# Global Configuration Variables #
#--------------------------------------------------------------------#
0=${(%):-%N}
typeset -g ZSH_ASK_PREFIX=${0:A:h}
(( ! ${+ZSH_ASK_REPO} )) &&
typeset -g ZSH_ASK_REPO="https://github.com/Licheam/zsh-ask"
# Get the corresponding endpoint for your desired model.
(( ! ${+ZSH_ASK_API_URL} )) &&
typeset -g ZSH_ASK_API_URL="https://api.openai.com/v1/chat/completions"
# Fill up your OpenAI api key here.
(( ! ${+ZSH_ASK_API_KEY} )) &&
typeset -g ZSH_ASK_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# Default configurations
(( ! ${+ZSH_ASK_MODEL} )) &&
typeset -g ZSH_ASK_MODEL="gpt-3.5-turbo"
(( ! ${+ZSH_ASK_CONVERSATION} )) &&
typeset -g ZSH_ASK_CONVERSATION=false
(( ! ${+ZSH_ASK_INHERITS} )) &&
typeset -g ZSH_ASK_INHERITS=false
(( ! ${+ZSH_ASK_MARKDOWN} )) &&
typeset -g ZSH_ASK_MARKDOWN=false
(( ! ${+ZSH_ASK_STREAM} )) &&
typeset -g ZSH_ASK_STREAM=false
(( ! ${+ZSH_ASK_TOKENS} )) &&
typeset -g ZSH_ASK_TOKENS=800
(( ! ${+ZSH_ASK_HISTORY} )) &&
typeset -g ZSH_ASK_HISTORY=""
(( ! ${+ZSH_ASK_INITIALROLE} )) &&
typeset -g ZSH_ASK_INITIALROLE="system"
(( ! ${+ZSH_ASK_INITIALPROMPT} )) &&
typeset -g ZSH_ASK_INITIALPROMPT="You are a large language model trained by OpenAI. Answer as concisely as possible.\nKnowledge cutoff: {knowledge_cutoff} Current date: {current_date}"
function _zsh_ask_show_help() {
echo "A lightweight Zsh plugin serves as a ChatGPT API frontend, enabling you to interact with ChatGPT directly from the Zsh."
echo "Usage: ask [options...]"
echo " ask [options...] '<your-question>'"
echo "Options:"
echo " -h Display this help message."
echo " -v Display the version number."
echo " -i Inherits conversation from ZSH_ASK_HISTORY."
echo " -c Enable conversation."
echo " -f <path_to_file> Enable file as query suffix (testing feature)."
echo " -m Enable markdown rendering (glow required)."
echo " -M <openai_model> Set OpenAI model to <openai_model>, default sets to gpt-3.5-turbo."
echo " Models can be found at https://platform.openai.com/docs/models."
echo " -s Enable streaming (Doesn't work with -m yet)."
echo " -t <max_tokens> Set max tokens to <max_tokens>, default sets to 800."
echo " -u Upgrade this plugin."
echo " -r Print raw output."
echo " -d Print debug information."
}
function _zsh_ask_upgrade() {
git -C $ZSH_ASK_PREFIX remote set-url origin $ZSH_ASK_REPO
if git -C $ZSH_ASK_PREFIX pull; then
source $ZSH_ASK_PREFIX/zsh-ask.zsh
return 0
else
echo "Failed to upgrade."
return 1
fi
}
function _zsh_ask_show_version() {
cat "$ZSH_ASK_PREFIX/VERSION"
}
function ask() {
local api_url=$ZSH_ASK_API_URL
local api_key=$ZSH_ASK_API_KEY
local conversation=$ZSH_ASK_CONVERSATION
local markdown=$ZSH_ASK_MARKDOWN
local stream=$ZSH_ASK_STREAM
local tokens=$ZSH_ASK_TOKENS
local inherits=$ZSH_ASK_INHERITS
local model=$ZSH_ASK_MODEL
local history=""
local usefile=false
local filepath=""
local requirements=("curl" "jq")
local debug=false
local raw=false
local satisfied=true
local input=""
local assistant="assistant"
while getopts ":hvcdmsiurM:f:t:" opt; do
case $opt in
h)
_zsh_ask_show_help
return 0
;;
v)
_zsh_ask_show_version
return 0
;;
u)
if ! which "git" > /dev/null; then
echo "git is required for upgrade."
return 1
fi
if _zsh_ask_upgrade; then
return 0
else
return 1
fi
;;
c)
conversation=true
;;
d)
debug=true
;;
i)
inherits=true
;;
t)
if ! [[ $OPTARG =~ ^[0-9]+$ ]]; then
echo "Max tokens has to be an valid numbers."
return 1
else
tokens=$OPTARG
fi
;;
f)
usefile=true
if ! [ -f $OPTARG ]; then
echo "$OPTARG does not exist."
return 1
else
if ! which "xargs" > /dev/null; then
echo "xargs is required for file."
satisfied=false
fi
filepath=$OPTARG
fi
;;
M)
model=$OPTARG
;;
m)
markdown=true
if ! which "glow" > /dev/null; then
echo "glow is required for markdown rendering."
satisfied=false
fi
;;
s)
stream=true
;;
r)
raw=true
;;
:)
echo "-$OPTARG needs a parameter"
return 1
;;
esac
done
for i in "${requirements[@]}"
do
if ! which $i > /dev/null; then
echo "zsh-ask \033[0;31merror:\033[0m $i is required."
return 1
fi
done
if $inherits; then
history=$ZSH_ASK_HISTORY
fi
if [ "$history" = "" ]; then
history='{"role":"'$ZSH_ASK_INITIALROLE'", "content":"'$ZSH_ASK_INITIALPROMPT'"}, '
fi
shift $((OPTIND-1))
input=$*
if $usefile; then
input="$input$(cat "$filepath")"
elif ! $raw && [ "$input" = "" ]; then
echo -n "\033[32muser: \033[0m"
read -r input
fi
while true; do
history=$history' {"role":"user", "content":"'"$input"'"}'
if $debug; then
echo -E "$history"
fi
local data='{"messages":['$history'], "model":"'$model'", "stream":'$stream', "max_tokens":'$tokens'}'
local message=""
local generated_text=""
if $stream; then
local begin=true
local token=""
curl -s -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $api_key" -d $data $api_url | while read -r token; do
if [ "$token" = "" ]; then
continue
fi
if $debug || $raw; then
echo -E $token
fi
if ! $raw; then
token=${token:6}
if ! $raw && delta_text=$(echo -E $token | jq -re '.choices[].delta.role'); then
assistant=$(echo -E $token | jq -je '.choices[].delta.role')
echo -n "\033[0;36m$assistant: \033[0m"
fi
local delta_text=""
if delta_text=$(echo -E $token | jq -re '.choices[].delta.content'); then
begin=false
echo -E $token | jq -je '.choices[].delta.content'
generated_text=$generated_text$delta_text
fi
if (echo -E $token | jq -re '.choices[].finish_reason' > /dev/null); then
echo ""
break
fi
fi
done
message='{"role":"'"$assistant"'", "content":"'"$generated_text"'"}'
else
local response=$(curl -s -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $api_key" -d $data $api_url)
if $debug || $raw; then
echo -E "$response"
fi
if ! $raw; then
echo -n "\033[0;36m$assistant: \033[0m"
if echo -E $response | jq -e '.error' > /dev/null; then
echo "zsh-ask \033[0;31merror:\033[0m"
echo -E $response | jq -r '.error'
return 1
fi
fi
assistant=$(echo -E $response | jq -r '.choices[].role')
message=$(echo -E $response | jq -r '.choices[].message')
generated_text=$(echo -E $message | jq -r '.content')
if ! $raw; then
if $markdown; then
echo -E $generated_text | glow
else
echo -E $generated_text
fi
fi
fi
history=$history', '$message', '
ZSH_ASK_HISTORY=$history
if ! $conversation; then
break
fi
echo -n "\033[0;32muser: \033[0m"
if ! read -r input; then
break
fi
done
}