@@ 1,64 1,62 @@
#!/usr/bin/env sh
err() {
- printf 'error: %s\n' "$1" >&2
+ printf 'error: %s\n' "$1" >&2
}
has() {
- # check if a command exists
- # $1 - cmd to check
- cmd=$(command -v "$1") 2>/dev/null || return 1
- [ -x "$cmd" ] || return 1
+ # check if a command exists
+ # $1 - cmd to check
+ cmd=$(command -v "$1") 2>/dev/null || return 1
+ [ -x "$cmd" ] || return 1
}
editor() {
- # get the user's editor
- printf '%s' "${EDITOR:-nano}"
+ # get the user's editor
+ printf '%s' "${EDITOR:-nano}"
}
shell() {
- # get the user's editor
- shell=$(basename "$SHELL")
- printf '%s' "${shell:-sh}"
+ # get the user's editor
+ shell=$(basename "$SHELL")
+ printf '%s' "${shell:-sh}"
}
os() {
- # get the user's os
- printf '%s' "$(uname -or)"
+ # get the user's os
+ printf '%s' "$(uname -or)"
}
hostname() {
- # get the user's hostname
- printf '%s' "$(uname -n)"
+ # get the user's hostname
+ printf '%s' "$(uname -n)"
}
cwd() {
- # get the current working directory
- printf '%s' "${PWD:-$(pwd)}"
+ # get the current working directory
+ printf '%s' "${PWD:-$(pwd)}"
}
clear_line() {
- # clear the current line and place cursor at the beginning
- printf '\r\033[K' >&2
+ # clear the current line and place cursor at the beginning
+ printf '\r\033[K' >&2
}
spinner() {
- # display a spinner animation
- # $1 - message to display
- spinner_chars="⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏"
- while :
- do
- for char in $spinner_chars
- do
- clear_line
- printf '%s %s' "$char" "$1" >&2
- sleep 0.05
- done
- done
+ # display a spinner animation
+ # $1 - message to display
+ spinner_chars="⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏"
+ while :; do
+ for char in $spinner_chars; do
+ clear_line
+ printf '%s %s' "$char" "$1" >&2
+ sleep 0.05
+ done
+ done
}
mkprompt_shell() {
- prompt="Provide only commands or scripts for the shell \`$(shell)\`.\n\
+ prompt="Provide only commands or scripts for the shell \`$(shell)\`.\n\
Do not give any explanations or descriptions.\n\
Provide the command exactly as it should be ran, so the user can copy and paste it.\n\
Ensure the output is a valid for the user's shell.\n\
@@ 66,159 64,159 @@ Provide the most logical solution if the prompt is unclear.\n\
Try to make a one-line solution, but it is not required.\n\
The user is using the operating system $(os).\n\
The user is currently in the directory \`$(cwd)\` on a host named \`$(hostname)\`.\n"
- if [ -n "$2" ]; then
- prompt="$prompt""The user piped this in from stdin: $2\n"
- fi
- prompt="$prompt""The user request is: $1"
- printf '%s' "$prompt"
+ if [ -n "$2" ]; then
+ prompt="$prompt""The user piped this in from stdin: $2\n"
+ fi
+ prompt="$prompt""The user request is: $1"
+ printf '%s' "$prompt"
}
mkprompt_default() {
- prompt="You are a shell script called shatgpt, assisting the user with programming and system administration.\n\
+ prompt="You are a shell script called shatgpt, assisting the user with programming and system administration.\n\
The user is using the operating system $(os).\n\
The user is currently in the directory \`$(cwd)\` on a host named \`$(hostname)\`.\n"
- if [ -n "$2" ]; then
- prompt="$prompt""The user piped this in from stdin: $2\n"
- fi
- prompt="$prompt""The user request is: $1"
- printf '%s' "$prompt"
+ if [ -n "$2" ]; then
+ prompt="$prompt""The user piped this in from stdin: $2\n"
+ fi
+ prompt="$prompt""The user request is: $1"
+ printf '%s' "$prompt"
}
mkbody() {
- # make a body to send to the openai chat api
- # $1 - prompt
- printf '%s' "{\"model\": \"gpt-3.5-turbo\", \"stream\": true, \"messages\": [{\"role\": \"user\", \"content\": \""
- printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'
- printf '%s' "\"}]}"
+ # make a body to send to the openai chat api
+ # $1 - prompt
+ printf '%s' "{\"model\": \"gpt-3.5-turbo\", \"stream\": true, \"messages\": [{\"role\": \"user\", \"content\": \""
+ printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'
+ printf '%s' "\"}]}"
}
get_field() {
- # get a field from a json string
- # $1 - json string
- # $2 - field to get
- case $1 in
- *"$2"*);;
- *) return;;
- esac
-
- tmp="${1#*\"$2\":\"}"
- while [ -n "$tmp" ]; do
- rest="${tmp#?}"
- c="${tmp%"$rest"}"
- tmp="$rest"
- case $c in
- '"')
- break
- ;;
- '\')
- printf '%s' "$c"
- rest="${tmp#?}"
- c="${tmp%"$rest"}"
- tmp="$rest"
- ;;
- *);;
- esac
- printf '%s' "$c"
- done
+ # get a field from a json string
+ # $1 - json string
+ # $2 - field to get
+ case $1 in
+ *"$2"*) ;;
+ *) return ;;
+ esac
+
+ tmp="${1#*\"$2\":\"}"
+ while [ -n "$tmp" ]; do
+ rest="${tmp#?}"
+ c="${tmp%"$rest"}"
+ tmp="$rest"
+ case $c in
+ '"')
+ break
+ ;;
+ '\')
+ printf '%s' "$c"
+ rest="${tmp#?}"
+ c="${tmp%"$rest"}"
+ tmp="$rest"
+ ;;
+ *) ;;
+ esac
+ printf '%s' "$c"
+ done
}
process_event() {
- # process each streaming event
- # $1 - event
- delta=$(get_field "$1" content)
- if [ -n "$delta" ]; then
- printf '%b' "$delta"
- fi
+ # process each streaming event
+ # $1 - event
+ delta=$(get_field "$1" content)
+ if [ -n "$delta" ]; then
+ printf '%b' "$delta"
+ fi
}
stream_events() {
- # do http request from a url
- # $1 - url
- # $2 - data
- spinner "Establishing connection..." &
- spinner_pid=$!
-
- if has curl; then
- curl "$1" -d "$2" -s -N -H "Content-Type: application/json" -H "Authorization: Bearer $OPENAI_API_KEY" | while IFS= read -r event; do
- if kill $spinner_pid 2>/dev/null; then
- clear_line
- fi
- process_event "$event"
- done
- printf '\n'
- else
- cleanup
- err "curl not found"
- exit 1
- fi
+ # do http request from a url
+ # $1 - url
+ # $2 - data
+ spinner "Establishing connection..." &
+ spinner_pid=$!
+
+ if has curl; then
+ curl "$1" -d "$2" -s -N -H "Content-Type: application/json" -H "Authorization: Bearer $OPENAI_API_KEY" | while IFS= read -r event; do
+ if kill $spinner_pid 2>/dev/null; then
+ clear_line
+ fi
+ process_event "$event"
+ done
+ printf '\n'
+ else
+ cleanup
+ err "curl not found"
+ exit 1
+ fi
}
cleanup() {
- kill $spinner_pid 2>/dev/null
- clear_line
+ kill $spinner_pid 2>/dev/null
+ clear_line
}
term() {
- cleanup
- exit 0
+ cleanup
+ exit 0
}
trap term INT TERM
show_help() {
- printf '%s\n' "usage: $(basename $0) [-hes] prompt"
- printf '%s\n' "options:"
- printf '%s\n' " -h, --help show this help message and exit."
- printf '%s\n' " -e, --edit open an editor to enter the prompt interactively."
- printf '%s\n' " -s, --shell output only shell commands to the terminal."
+ printf '%s\n' "usage: $(basename $0) [-hes] prompt"
+ printf '%s\n' "options:"
+ printf '%s\n' " -h, --help show this help message and exit."
+ printf '%s\n' " -e, --edit open an editor to enter the prompt interactively."
+ printf '%s\n' " -s, --shell output only shell commands to the terminal."
}
parse_args() {
- while [ $# -gt 0 ]; do
- case $1 in
- -h|--help)
- show_help
- term
- ;;
- -e|--edit)
- editor_mode=true
- shift
- ;;
- -s|--shell)
- shell_mode=true
- shift
- ;;
- *)
- break
- ;;
- esac
- done
-
- prompt="$*"
+ while [ $# -gt 0 ]; do
+ case $1 in
+ -h | --help)
+ show_help
+ term
+ ;;
+ -e | --edit)
+ editor_mode=true
+ shift
+ ;;
+ -s | --shell)
+ shell_mode=true
+ shift
+ ;;
+ *)
+ break
+ ;;
+ esac
+ done
+
+ prompt="$*"
}
editor_mode=false
shell_mode=false
if [ -t 0 ]; then
- stdin=""
+ stdin=""
else
- stdin="$(cat)"
+ stdin="$(cat)"
fi
parse_args $*
if [ $editor_mode = true ]; then
- tmp=$(mktemp)
- printf '%s' "$prompt" > $tmp
- $(editor) "$tmp"
- prompt="$(cat $tmp)"
+ tmp=$(mktemp)
+ printf '%s' "$prompt" >$tmp
+ $(editor) "$tmp"
+ prompt="$(cat $tmp)"
fi
if [ $shell_mode = true ]; then
- prompt="$(mkprompt_shell "$prompt" "$stdin")"
+ prompt="$(mkprompt_shell "$prompt" "$stdin")"
else
- prompt="$(mkprompt_default "$prompt" "$stdin")"
+ prompt="$(mkprompt_default "$prompt" "$stdin")"
fi
request=$(mkbody "$prompt")