Skip to content

Instantly share code, notes, and snippets.

@MinecraftPublisher
Last active July 19, 2023 06:34
Show Gist options
  • Select an option

  • Save MinecraftPublisher/7b7f30c28a4cb9360231a3f172481655 to your computer and use it in GitHub Desktop.

Select an option

Save MinecraftPublisher/7b7f30c28a4cb9360231a3f172481655 to your computer and use it in GitHub Desktop.
PocketBot

πŸ€– PocketBot

Tiny chatbot living in a text file.

PocketBot is a simple self-modifying bash script that uses levenshtein distancing to intelligently respond to queries.

The central database containing its input/output pairs is contained in a variable named brain at line 133 (as of now).

Each element of this variable contains an input/output pair that are separated by a chinese doll emoji. (chosen due to low usage frequency and issues with the current string split bash implementation)

WARNING:

Sharing your pocketbot script that you have trained with someone will expose the entirety of the content you have taught it, So be careful with this due to a lack of and inability to implement a content filtering system for it due to the way it is implemented.

Release Notes

0.2.1:

  • You can now use the ..revert command to rollback the last I/O operation performed on PocketBot. And you can also revert a revert, If the result is not desired by you.

0.2:

  • You can now update your local PocketBot installation by running ./pocketbot.sh update in your terminal or ..update inside PocketBot itself.
  • The published version is now shipped with an empty brain...

0.1:

  • Initial release

Installation

Depends on your platform and wether your OS supports bash or not.

Windows

  1. Download Git Bash (Git for Windows)
  2. Download the file pocketbot.sh below (click on raw, then press Ctrl+S, save the name as pocketbot.sh)
  3. Open Git Bash
  4. Run this: curl -fsSL https://gist.github.com/MinecraftPublisher/7b7f30c28a4cb9360231a3f172481655/raw/pocketbot.sh > ./pocketbot.sh && chmod +x ./pocketbot.sh && echo Successfully downloaded PocketBot!
  5. Pocketbot will be downloaded and saved as ./pocketbot.sh in your current directory.
  6. Viola!

Linux/Unix/MacOS (any os with bash support)

  1. Run this: curl -fsSL https://gist.github.com/MinecraftPublisher/7b7f30c28a4cb9360231a3f172481655/raw/pocketbot.sh > ./pocketbot.sh && chmod +x ./pocketbot.sh && echo Successfully downloaded PocketBot!
  2. Pocketbot will be downloaded and saved as ./pocketbot.sh in your current directory.

Any other operating system

Figure out a way to run bash on it and then run the steps from the linux/unix/macos download section

Commands

Commands in pocketbot are detected by two periods at the start of them. (..command)

Current commands:

  • .. -> Clear console
  • ..clear -> Clear console
  • ..teach -> Teach PocketBot a new input/output pair
  • ..forget -> Delete entries you don't want (supplement a prefix for better search)
  • ..exit -> Close PocketBot
#!/bin/bash
: '
PocketBot
Tiny chatbot living in a text file.
Running in fullscreen is recommended.
Created by @MinecraftPublisher on GitHub.
'
bracks="===================="
version="0.2"
function whopper() {
echo -e "${IBlack}${bracks}"
echo -e "${BIPurple}PocketBot ${IBlack}- ${BIGreen}v${version}"
echo -e "${BIBlue}Tiny chatbot living in a text file"
echo -e "${IBlack}Running in fullscreen is recommended."
}
file=$BASH_SOURCE
pocketbot="$(cat $file)"
# Reset
Reset='\033[0m' # Text Reset
# Regular Colors
Black='\033[0;30m' # Black
Red='\033[0;31m' # Red
Green='\033[0;32m' # Green
Yellow='\033[0;33m' # Yellow
Blue='\033[0;34m' # Blue
Purple='\033[0;35m' # Purple
Cyan='\033[0;36m' # Cyan
White='\033[0;37m' # White
# Bold
BBlack='\033[1;30m' # Black
BRed='\033[1;31m' # Red
BGreen='\033[1;32m' # Green
BYellow='\033[1;33m' # Yellow
BBlue='\033[1;34m' # Blue
BPurple='\033[1;35m' # Purple
BCyan='\033[1;36m' # Cyan
BWhite='\033[1;37m' # White
# Underline
UBlack='\033[4;30m' # Black
URed='\033[4;31m' # Red
UGreen='\033[4;32m' # Green
UYellow='\033[4;33m' # Yellow
UBlue='\033[4;34m' # Blue
UPurple='\033[4;35m' # Purple
UCyan='\033[4;36m' # Cyan
UWhite='\033[4;37m' # White
# Background
On_Black='\033[40m' # Black
On_Red='\033[41m' # Red
On_Green='\033[42m' # Green
On_Yellow='\033[43m' # Yellow
On_Blue='\033[44m' # Blue
On_Purple='\033[45m' # Purple
On_Cyan='\033[46m' # Cyan
On_White='\033[47m' # White
# High Intensity
IBlack='\033[0;90m' # Black
IRed='\033[0;91m' # Red
IGreen='\033[0;92m' # Green
IYellow='\033[0;93m' # Yellow
IBlue='\033[0;94m' # Blue
IPurple='\033[0;95m' # Purple
ICyan='\033[0;96m' # Cyan
IWhite='\033[0;97m' # White
# Bold High Intensity
BIBlack='\033[1;90m' # Black
BIRed='\033[1;91m' # Red
BIGreen='\033[1;92m' # Green
BIYellow='\033[1;93m' # Yellow
BIBlue='\033[1;94m' # Blue
BIPurple='\033[1;95m' # Purple
BICyan='\033[1;96m' # Cyan
BIWhite='\033[1;97m' # White
# High Intensity backgrounds
On_IBlack='\033[0;100m' # Black
On_IRed='\033[0;101m' # Red
On_IGreen='\033[0;102m' # Green
On_IYellow='\033[0;103m' # Yellow
On_IBlue='\033[0;104m' # Blue
On_IPurple='\033[0;105m' # Purple
On_ICyan='\033[0;106m' # Cyan
On_IWhite='\033[0;107m' # White
levenshtein_distance() {
# Get the lengths of the input strings
local str1=$1
local str2=$2
local len1=${#str1}
local len2=${#str2}
# Create a 2D array to store the distances
declare -A distances
# Initialize the first row and column of the array
for ((i = 0; i <= len1; i++)); do
distances[$i, 0]=$i
done
for ((j = 0; j <= len2; j++)); do
distances[0, $j]=$j
done
# Calculate the distances
for ((i = 1; i <= len1; i++)); do
for ((j = 1; j <= len2; j++)); do
if [[ ${str1:i-1:1} == ${str2:j-1:1} ]]; then
distances[$i, $j]=${distances[$((i - 1)), $((j - 1))]}
else
local deletion=$((distances[$((i - 1)), $j] + 1))
local insertion=$((distances[$i, $((j - 1))] + 1))
local substitution=$((distances[$((i - 1)), $((j - 1))] + 1))
distances[$i, $j]=$(($(($(($deletion < $insertion ? $deletion : $insertion)) < $substitution ? $(($deletion < $insertion ? $deletion : $insertion)) : $substitution))))
fi
done
done
# Return the final distance
echo ${distances[$len1, $len2]}
}
brain=(
#__NEXT__ (modifying this line will remove the bot's ability to learn.)
)
function save() {
echo "$(cat $file)" >/tmp/pocketbot-backup.sh
echo "${pocketbot}" >$file
if [[ $1 == "notice" ]]; then
echo "Saved instance. (Backup can be found at /tmp/pocketbot-backup.sh)"
fi
}
function respond() {
q="$(echo "$1" | tr -cd '[a-zA-Z] ')"
declare -a results=()
for line in "${brain[@]}"; do
IFS="🎎" read -ra _splits <<<${line}
_key="${_splits[0]}"
_value="${_splits[@]:1}"
key=$(echo "${_key}" | tr -cd '[a-zA-Z] ')
distance=$(levenshtein_distance "${key,,}" "${q,,}")
if [[ distance -le 3 ]]; then
results+=("${_value}")
fi
done
offset=$((${#results[@]}))
if [[ offset -ne 0 ]]; then
index=$(($RANDOM % $offset))
echo -e "${BBlack}[πŸ€–] PocketBot${Reset}:${BICyan}
${results["$index"]}"
else
echo -e "${BBlack}[πŸ€–] PocketBot${Reset}:${BICyan}
I don't know that yet! Could you teach me a response?"
echo -e "${BBlack}[πŸ‘Ύ] You (as PocketBot)${Reset}:${BICyan}"
read -re ans
if [[ -z "$ans" ]]; then
echo -e "${BIYellow}Warning${Reset}: ${BIBlack}Teaching cancelled"
return 0
fi
pocketbot="${pocketbot/"#__NEXT__"/"\"$q🎎$ans\"
#__NEXT__"}"
save $2
bash $BASH_SOURCE "ignore" "$1"
exit
fi
}
function cond() {
c="$1"
args="$2"
if [[ -z "$c" ]]; then
clear
whopper
return
elif [[ $c == "exit" ]]; then
exit
elif [[ $c == "revert" ]]; then
cp $BASH_SOURCE /tmp/pocketbot-backup-backup.sh
cp /tmp/pocketbot-backup.sh $BASH_SOURCE
mv /tmp/pocketbot-backup-backup.sh /tmp/pocketbot-backup.sh
chmod +x $BASH_SOURCE
elif [[ $c == "version" ]]; then
echo "PocketBot version: ${BIGreen}v${version}"
return
elif [[ $c == "update" ]]; then
update
elif [[ $c == "forget" ]]; then
echo -e "${BIRed}[❌] ${BIYellow}Prefix for deletion${Reset}:${BICyan}"
read -re hint
filtered=()
echo -e "${BIYellow}I found these:"
declare -i i
i+=1
for line in "${brain[@]}"; do
if [[ "${line}" == "$hint"* ]]; then
echo -e "${BIPurple}${i}. ${BIBlack}${line/"🎎"/"${BICyan} -> ${BIBlack}"}"
i+=1
filtered+=("${line}")
fi
done
echo -e "${BIRed}[❌] ${BIYellow}Which one(s) should I delete${Reset}? (${BIBlack}separate with spaces${Reset})${BIRed}"
read -re choice
IFS=" " read -ra choices <<<${choice}
for choice in "${choice[@]}"; do
if [[ -n choice ]]; then
choice=$((choice - 1))
option="${brain[$choice]}"
echo "Deleted: '${option}' (${choice})"
pocketbot="${pocketbot/"\"${option}\"
"/""}"
fi
done
# pocketbot="${pocketbot/"${s}\n"/""}"
echo -e "${Reset}"
save "notice"
elif [[ $c == "clear" ]]; then
clear
whopper
return
elif [[ $c == "teach" ]]; then
echo -e "${BBlack}[πŸ‘Ύ] You (as You)${Reset}:${BICyan}"
read -re q
q="$(echo "$q" | tr -cd '[a-zA-Z] ')"
if [[ -z "$q" ]]; then
echo -e "${BIYellow}Warning${Reset}: ${BIBlack}Teaching cancelled"
return 0
fi
echo -e "${BBlack}[πŸ‘Ύ] You (as PocketBot)${Reset}:${BICyan}"
read -re ans
if [[ -z "$ans" ]]; then
echo -e "${BIYellow}Warning${Reset}: ${BIBlack}Teaching cancelled"
return 0
fi
pocketbot="${pocketbot/"#__NEXT__"/"\"$q🎎$ans\"
#__NEXT__"}"
save $1
return
else
echo -e "${BIRed}Error${Reset}: ${BIBlack}Unknown command '${c}'"
return
fi
}
function chat() {
echo -e "${IBlack}${bracks}
${bracks}${Reset}"
echo -e "${BBlack}[πŸ™‚] You${Reset}:${BICyan}"
read -re ans
if [[ ${ans:0:2} == ".." ]]; then
IFS=" " read -ra splits <<<${ans#..}
c=${splits[0]}
args=${splits[@]:1}
cond "$c" "$args"
bash $BASH_SOURCE "ignore" "$1"
exit
else
respond "$ans" $1
bash $BASH_SOURCE "ignore" "$1"
exit
fi
}
function update() {
echo "Updating..."
# prepare the current brain data
cur_brain="brain=("
for line in "${brain[@]}"; do
cur_brain="${cur_brain}
\"${line}\""
done
echo "Downloading new version from the official source..."
# download the new pocketbot script from the official source
pocketbot=$(curl -fsSL https://gist.github.com/MinecraftPublisher/7b7f30c28a4cb9360231a3f172481655/raw/pocketbot.sh?v=$RANDOM)
echo "Patching installation..."
pocketbot="${pocketbot/"brain=("/"${cur_brain}"}"
save notice
bash $BASH_SOURCE "ignore"
exit
}
if [[ $1 != "ignore" ]]; then
whopper
fi
if [[ $1 == "update" ]]; then
update
bash $BASH_SOURCE "ignore" "$1"
else
chat "$2"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment