Skip to content

Instantly share code, notes, and snippets.

@dctremblay
Last active May 21, 2024 17:05
Show Gist options
  • Save dctremblay/bfdf7dc98c63ed9fe109922134a6e79f to your computer and use it in GitHub Desktop.
Save dctremblay/bfdf7dc98c63ed9fe109922134a6e79f to your computer and use it in GitHub Desktop.
BashGPT : Use ChatGPT with Bash and Vim. Conversations are stored and can be continued, markdown is stored as well.
#!/bin/bash
# Title: BashGPT
# Version: 0.1
# Date: 2024-05-21
# License: MIT
# Author: dctremblay@dasio.ca
[ $OPENAI_API_KEY ] || { echo "OPENAI_API_KEY env var must be set" >&2; exit 1; }
gptModel="gpt-4o" #gpt-3.5-turbo
gptNick=${NICK:-"BotMarley"}
gptRole="You are $gptNick, ${ROLE:-'the super cool omniscient AI'}"
youNick=$(whoami)
youRole="I am $youNick, ${ME:-'programmer with 10 years of experience'}"
chatsDir="$HOME/AiChats"
chatsJsonDir="$chatsDir/.json"
chatsMarkdownDir="$chatsDir"
function answer() {
vim '+normal G$' +startinsert -c 'set nonumber' "$1" 2> /dev/null
}
promptLabel="Enter a prompt (:x to submit or :q! to exit)"
function formatMarkdownMsg() {
cat <<-EOF
-----------
**$1** on $(date "+%Y-%m-%d %H:%M:%S")
$2
EOF
}
########################################################
set -e
mkdir -p "$chatsJsonDir" "$chatsMarkdownDir"
chatId=$1
isNew=$([ $chatId ]; echo $?)
(( $isNew )) && chatId=$(uuidgen)
chatJson="$chatsJsonDir/$chatId.json"
chatMarkdown="$chatsMarkdownDir/$chatId.md"
(( $isNew )) || [[ -f $chatJson ]] || {
echo "specified chatId doesn't exist" >&2; exit 1;
}
######
function esc() { sed 's/"/\\"/g' <<< "$1"; }
function cleanup { rm -rf "$buf"; }
trap cleanup EXIT
trap cleanup SIGINT
buffer=$(mktemp --suffix .md)
query() {
curl -s https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d "$(cat <<-EOF
{
"model": "$gptModel",
"messages": $1
}
EOF
)"
}
######
promptSeparatorChar='-'
sep=$(printf "%${#promptLabel}s" | tr " " "$promptSeparatorChar")
if (( $isNew )); then
echo "[{\"role\":\"system\", \"content\": \"$(esc "$gptRole"). $(esc "$youRole")\"}]" > "$chatJson"
else
cat "$chatMarkdown" > "$buffer"
fi
while true; do
echo -e "$sep\n$promptLabel\n\n" >> "$buffer"
ts0=$(stat -c%y "$buffer")
answer "$buffer"
ts1=$(stat -c%y "$buffer")
[[ $ts0 != $ts1 ]] || break
echo -n " Please wait .."$'\r';
prompt=$(sed "0,/$sep/d" < "$buffer" | tail -n+3)
formatMarkdownMsg "$youNick" "$prompt" >> "$chatMarkdown"
conv=$(jq ". += [{\"role\":\"user\", \"content\": \"$(esc "$prompt")\"}]" "$chatJson")
jsonAnswer=$(query "${conv}" | jq .choices[0].message)
answer=$(jq -j .content <<< "$jsonAnswer")
formatMarkdownMsg "$gptNick" "$answer" >> "$chatMarkdown"
jq ". += [$jsonAnswer]" <<< "$conv" > "$chatJson"
cat "$chatMarkdown" > "$buffer"
done
echo $chatId
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment