|
#!/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 |