#!/bin/bash
#
# SillyTavern Launcher
# Created by: Deffcolony
#
# Description:
# This script runs SillyTavern and/or Extras on your Linux system.
#
# Usage:
# chmod +x launcher.sh && ./launcher.sh
#
# In automated environments, you may want to run as root.
# If using curl, we recommend using the -fsSL flags.
#
# This script is intended for use on Linux systems. Please
# report any issues or bugs on the GitHub repository.
#
# App Github: https://github.com/SillyTavern/SillyTavern.git
#
# GitHub: https://github.com/SillyTavern/SillyTavern-Launcher
# Issues: https://github.com/SillyTavern/SillyTavern-Launcher/issues
# ----------------------------------------------------------
# Note: Modify the script as needed to fit your requirements.
# ----------------------------------------------------------
echo -e "\033]0;STL\007"
# ANSI Escape Code for Colors
reset="\033[0m"
white_fg_strong="\033[90m"
red_fg_strong="\033[91m"
green_fg_strong="\033[92m"
yellow_fg_strong="\033[93m"
blue_fg_strong="\033[94m"
magenta_fg_strong="\033[95m"
cyan_fg_strong="\033[96m"
# Normal Background Colors
red_bg="\033[41m"
blue_bg="\033[44m"
yellow_bg="\033[43m"
# Environment Variables (FFmpeg)
ffmpeg_download_url="https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-full.7z"
ffmpeg_download_path="$(dirname "$0")/bin/ffmpeg.7z"
ffmpeg_install_path="/opt/ffmpeg"
ffmpeg_path_bin="$ffmpeg_install_path/bin"
# Define variables to track module status (EXTRAS)
export extras_modules_path="$(dirname "$0")/bin/settings/modules-extras.txt"
export cuda_trigger="false"
export rvc_trigger="false"
export talkinghead_trigger="false"
export caption_trigger="false"
export summarize_trigger="false"
export listen_trigger="false"
export whisper_trigger="false"
export edge_tts_trigger="false"
export websearch_trigger="false"
if [ -f "$extras_modules_path" ]; then
while IFS='=' read -r key value; do
export "$key"="$value"
done < "$extras_modules_path"
fi
# Define variables to track module status (XTTS)
export xtts_modules_path="$(dirname "$0")/bin/settings/modules-xtts.txt"
export xtts_cuda_trigger="false"
export xtts_hs_trigger="false"
export xtts_deepspeed_trigger="false"
export xtts_cache_trigger="false"
export xtts_listen_trigger="false"
export xtts_model_trigger="false"
if [ -f "$xtts_modules_path" ]; then
while IFS='=' read -r key value; do
export "$key"="$value"
done < "$xtts_modules_path"
fi
# Define variables to track module status (STABLE DIFFUSION WEBUI)
export sdwebui_modules_path="$(dirname "$0")/bin/settings/modules-sdwebui.txt"
export sdwebui_autolaunch_trigger="false"
export sdwebui_api_trigger="false"
export sdwebui_listen_trigger="false"
export sdwebui_port_trigger="false"
export sdwebui_optsdpattention_trigger="false"
export sdwebui_themedark_trigger="false"
export sdwebui_skiptorchcudatest_trigger="false"
export sdwebui_lowvram_trigger="false"
export sdwebui_medvram_trigger="false"
if [ -f "$sdwebui_modules_path" ]; then
while IFS='=' read -r key value; do
export "$key"="$value"
done < "$sdwebui_modules_path"
fi
# Define variables to track module status (STABLE DIFFUSION WEBUI FORGE)
export sdwebuiforge_modules_path="$(dirname "$0")/bin/settings/modules-sdwebuiforge.txt"
export sdwebuiforge_autolaunch_trigger="false"
export sdwebuiforge_api_trigger="false"
export sdwebuiforge_listen_trigger="false"
export sdwebuiforge_port_trigger="false"
export sdwebuiforge_optsdpattention_trigger="false"
export sdwebuiforge_themedark_trigger="false"
export sdwebuiforge_skiptorchcudatest_trigger="false"
export sdwebuiforge_lowvram_trigger="false"
export sdwebuiforge_medvram_trigger="false"
if [ -f "$sdwebuiforge_modules_path" ]; then
while IFS='=' read -r key value; do
export "$key"="$value"
done < "$sdwebuiforge_modules_path"
fi
# Define variables to track module status (TEXT GENERATION WEBUI OOBABOOGA)
export ooba_modules_path="$(dirname "$0")/bin/settings/modules-ooba.txt"
export ooba_autolaunch_trigger="false"
export ooba_extopenai_trigger="false"
export ooba_listen_trigger="false"
export ooba_listenport_trigger="false"
export ooba_apiport_trigger="false"
export ooba_verbose_trigger="false"
if [ -f "$ooba_modules_path" ]; then
while IFS='=' read -r key value; do
export "$key"="$value"
done < "$ooba_modules_path"
fi
# Define variables to track module status (TABBYAPI)
export tabbyapi_modules_path="$(dirname "$0")/bin/settings/modules-tabbyapi.txt"
export tabbyapi_selectedmodelname_trigger="false"
export selected_tabbyapi_model_folder=""
export tabbyapi_ignoreupdate_trigger="false"
export tabbyapi_port_trigger="false"
export tabbyapi_port=""
export tabbyapi_host_trigger="false"
export tabbyapi_maxseqlen_trigger="false"
export tabbyapi_maxseqlen=""
export tabbyapi_ropealpha_trigger=""
export tabbyapi_ropealpha=""
export ttabbyapi_cachemode_trigger=""
export tabbyapi_cachemode=""
export ttabbyapi_updatedeps_trigger=""
if [ -f "$tabbyapi_modules_path" ]; then
while IFS='=' read -r key value; do
export "$key"="$value"
done < "$tabbyapi_modules_path"
fi
# Define variables for install locations (Core Utilities)
stl_root="$(dirname "$(realpath "$0")")"
st_install_path="$stl_root/SillyTavern"
st_package_json_path="$st_install_path/package.json"
extras_install_path="$stl_root/SillyTavern-extras"
st_backup_path="$stl_root/SillyTavern-backups"
NODE_ENV="production"
# Define variables for install locations (Image Generation)
image_generation_dir="$stl_root/image-generation"
sdwebui_install_path="$image_generation_dir/stable-diffusion-webui"
sdwebuiforge_install_path="$image_generation_dir/stable-diffusion-webui-forge"
comfyui_install_path="$image_generation_dir/ComfyUI"
fooocus_install_path="$image_generation_dir/Fooocus"
invokeai_install_path="$image_generation_dir/InvokeAI"
ostrisaitoolkit_install_path="$image_generation_dir/ai-toolkit"
# Define variables for install locations (Text Completion)
text_completion_dir="$stl_root/text-completion"
ooba_install_path="$text_completion_dir/text-generation-webui"
koboldcpp_install_path="$text_completion_dir/dev-koboldcpp"
llamacpp_install_path="$text_completion_dir/dev-llamacpp"
tabbyapi_install_path="$text_completion_dir/tabbyAPI"
# Define variables for install locations (Voice Generation)
voice_generation_dir="$stl_root/voice-generation"
alltalk_install_path="$voice_generation_dir/alltalk_tts"
alltalk_v2_install_path="$voice_generation_dir/alltalk_tts"
xtts_install_path="$voice_generation_dir/xtts"
rvc_install_path="$voice_generation_dir/Retrieval-based-Voice-Conversion-WebUI"
# Define variables for the core directories
bin_dir="$stl_root/bin"
log_dir="$bin_dir/logs"
functions_dir="$bin_dir/functions_linux"
# Define variables for the directories for Toolbox
toolbox_dir="$functions_dir/Toolbox"
troubleshooting_dir="$toolbox_dir/Troubleshooting"
backup_dir="$toolbox_dir/Backup"
# Define variables for the directories for App Installer
app_installer_image_generation_dir="$functions_dir/Toolbox/App_Installer/Image_Generation"
app_installer_text_completion_dir="$functions_dir/Toolbox/App_Installer/Text_Completion"
app_installer_voice_generation_dir="$functions_dir/Toolbox/App_Installer/Voice_Generation"
app_installer_core_utilities_dir="$functions_dir/Toolbox/App_Installer/Core_Utilities"
# Define variables for the directories for App Uninstaller
app_uninstaller_image_generation_dir="$functions_dir/Toolbox/App_Uninstaller/Image_Generation"
app_uninstaller_text_completion_dir="$functions_dir/Toolbox/App_Uninstaller/Text_Completion"
app_uninstaller_voice_generation_dir="$functions_dir/Toolbox/App_Uninstaller/Voice_Generation"
app_uninstaller_core_utilities_dir="$functions_dir/Toolbox/App_Uninstaller/Core_Utilities"
# Define variables for the directories for App Launcher
app_launcher_image_generation_dir="$functions_dir/Toolbox/App_Launcher/Image_Generation"
app_launcher_text_completion_dir="$functions_dir/Toolbox/App_Launcher/Text_Completion"
app_launcher_voice_generation_dir="$functions_dir/Toolbox/App_Launcher/Voice_Generation"
app_launcher_core_utilities_dir="$functions_dir/Toolbox/App_Launcher/Core_Utilities"
# Define variables for the directories for Editor
editor_image_generation_dir="$functions_dir/Toolbox/Editor/Image_Generation"
editor_text_completion_dir="$functions_dir/Toolbox/Editor/Text_Completion"
editor_voice_generation_dir="$functions_dir/Toolbox/Editor/Voice_Generation"
editor_core_utilities_dir="$functions_dir/Toolbox/Editor/Core_Utilities"
# Define variables for logging
st_auto_repair="$log_dir/autorepair-setting.txt"
logs_stl_console_path="$log_dir/stl.log"
logs_st_console_path="$log_dir/st_console_output.log"
# Function to log messages with timestamps and colors
log_message() {
# This is only time
current_time=$(date +'%H:%M:%S')
# This is with date and time
# current_time=$(date +'%Y-%m-%d %H:%M:%S')
case "$1" in
"INFO")
echo -e "${blue_bg}[$current_time]${reset} ${blue_fg_strong}[INFO]${reset} $2"
;;
"WARN")
echo -e "${yellow_bg}[$current_time]${reset} ${yellow_fg_strong}[WARN]${reset} $2"
;;
"ERROR")
echo -e "${red_bg}[$current_time]${reset} ${red_fg_strong}[ERROR]${reset} $2"
;;
*)
echo -e "${blue_bg}[$current_time]${reset} ${blue_fg_strong}[DEBUG]${reset} $2"
;;
esac
}
# Log your messages test window
#log_message "INFO" "Something has been launched."
#log_message "WARN" "${yellow_fg_strong}Something is not installed on this system.${reset}"
#log_message "ERROR" "${red_fg_strong}An error occurred during the process.${reset}"
#log_message "DEBUG" "This is a debug message."
#read -p "Press Enter to continue..."
# Function to find Miniconda installation directory
find_conda() {
local paths=(
"$HOME/miniconda3"
"$HOME/miniconda"
"/opt/miniconda3"
"/opt/miniconda"
"/usr/local/miniconda3"
"/usr/local/miniconda"
"/usr/miniconda3"
"/usr/miniconda"
"$HOME/anaconda3"
"$HOME/anaconda"
"/opt/anaconda3"
"/opt/anaconda"
"/usr/local/anaconda3"
"/usr/local/anaconda"
"/usr/anaconda3"
"/usr/anaconda"
)
for path in "${paths[@]}"; do
if [ -d "$path" ]; then
echo "$path"
return 0
fi
done
return 1
}
# Function to install Git
install_git() {
if ! command -v git &> /dev/null; then
log_message "WARN" "${yellow_fg_strong}Git is not installed on this system${reset}"
case "$(uname -s)" in
Linux)
package_manager=$(detect_package_manager)
case "$package_manager" in
apt)
log_message "INFO" "Detected apt (Debian/Ubuntu). Installing Git..."
sudo apt update && sudo apt install -y git
;;
dnf|yum)
log_message "INFO" "Detected dnf/yum (Red Hat/Fedora). Installing Git..."
sudo $package_manager install -y git
;;
apk)
log_message "INFO" "Detected apk (Alpine). Installing Git..."
sudo apk add git
;;
pacman)
log_message "INFO" "Detected pacman (Arch). Installing Git..."
sudo pacman -Sy --noconfirm git
;;
emerge)
log_message "INFO" "Detected emerge (Gentoo). Installing Git..."
sudo emerge --ask dev-vcs/git
;;
zypper)
log_message "INFO" "Detected zypper (openSUSE). Installing Git..."
sudo zypper install -y git
;;
xbps)
log_message "INFO" "Detected xbps (Void). Installing Git..."
sudo xbps-install -y git
;;
nix)
log_message "INFO" "Detected nix (NixOS). Installing Git..."
nix-env -iA nixpkgs.git
;;
guix)
log_message "INFO" "Detected guix (Guix). Installing Git..."
guix package -i git
;;
pkg)
log_message "INFO" "Detected pkg (Termux). Installing Git..."
pkg install git
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported package manager or distribution.${reset}"
exit 1
;;
esac
;;
Darwin)
log_message "INFO" "Detected macOS. Installing Git via Homebrew..."
if ! command -v brew &> /dev/null; then
log_message "ERROR" "${red_fg_strong}Homebrew not installed. Install it first: https://brew.sh/${reset}"
exit 1
fi
brew install git
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported operating system.${reset}"
exit 1
;;
esac
log_message "INFO" "${green_fg_strong}Git is installed.${reset}"
else
log_message "INFO" "${blue_fg_strong}Git is already installed.${reset}"
fi
}
# Function to check if Node.js is installed
check_nodejs() {
node --version > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo -e "${red_fg_strong}[ERROR] node command not found in PATH${reset}"
echo -e "${red_bg}Please make sure Node.js is installed and added to your PATH.${reset}"
echo -e "${blue_bg}To install Node.js, go to Toolbox${reset}"
read -p "Press Enter to continue..."
home
fi
}
# Function to start SillyTavern with Extras
start_extras() {
check_nodejs
if [ "$LAUNCH_NEW_WIN" = "0" ]; then
local main_pid=$!
log_message "INFO" "Extras launched under pid $main_pid"
{
#has to be after the first one, so we are 1 directory up
cd "SillyTavern-extras" || {
log_message "ERROR" "SillyTavern-extras directory not found. Please make sure you have installed SillyTavern-extras."
kill $main_pid
exit 1
}
log_message "INFO" "Working dir: $(pwd)"
./start.sh
} &
local extras_pid=$!
log_message "INFO" "Extras launched under pid $extras_pid"
wait $main_pid
kill $extras_pid
else
cd "SillyTavern-extras"
log_message "INFO" "Extras launched in a new window."
# Find a suitable terminal
local detected_terminal
detected_terminal=$(find_terminal)
log_message "INFO" "Found terminal: $detected_terminal"
# Enable read p command for troubleshooting
# read -p "Press Enter to continue..."
# Start SillyTavern in the detected terminal
if [ "$(uname)" == "Darwin" ]; then
log_message "INFO" "Detected macOS. Opening new Terminal window."
open -a Terminal --args --title="SillyTavern Extras" --working-directory="SillyTavern-extras" --command "python server.py --listen --rvc-save-file --max-content-length=1000 --enable-modules=rvc,caption; exec bash"
else
exec "$detected_terminal" -e "python server.py --listen --rvc-save-file --max-content-length=1000 --enable-modules=rvc,caption; bash"
fi
fi
home
}
# Function to start xtts
start_xtts() {
check_nodejs
if [ "$LAUNCH_NEW_WIN" = "0" ]; then
local main_pid=$!
log_message "INFO" "xtts launched under pid $main_pid"
# Move to xtts directory
cd "xtts" || {
log_message "ERROR" "xtts directory not found. Please make sure you have installed xtts"
kill "$main_pid"
exit 1
}
log_message "INFO" "Working dir: $(pwd)"
./start.sh &
local xtts_pid=$!
log_message "INFO" "xtts launched under pid $xtts_pid"
wait "$main_pid"
kill "$xtts_pid"
else
cd "xtts"
log_message "INFO" "xtts launched in a new window."
# Find a suitable terminal
local detected_terminal
detected_terminal=$(find_terminal)
log_message "INFO" "Found terminal: $detected_terminal"
# Enable read p command for troubleshooting
# read -p "Press Enter to continue..."
# Start XTTS in the detected terminal
if [ "$(uname)" == "Darwin" ]; then
log_message "INFO" "Detected macOS. Opening new Terminal window."
open -a Terminal --args --title="XTTSv2 API Server" --working-directory="xtts" --command "conda activate xtts; python -m xtts_api_server; exec bash"
else
exec "$detected_terminal" -e "conda activate xtts && python -m xtts_api_server; bash"
fi
fi
home
}
# Function to update
update() {
echo -e "\033]0;STL [UPDATE]\007"
log_message "INFO" "Updating SillyTavern-Launcher..."
git pull --rebase --autostash
# Update SillyTavern if directory exists
if [ -d "SillyTavern" ]; then
log_message "INFO" "Updating SillyTavern..."
cd "SillyTavern"
git pull --rebase --autostash
cd ..
log_message "INFO" "SillyTavern updated successfully."
else
log_message "WARN" "SillyTavern directory not found. Skipping SillyTavern update."
fi
# Update Extras if directory exists
if [ -d "SillyTavern-extras" ]; then
log_message "INFO" "Updating SillyTavern-extras..."
cd "SillyTavern-extras"
git pull --rebase --autostash
cd ..
log_message "INFO" "SillyTavern-extras updated successfully."
else
log_message "WARN" "SillyTavern-extras directory not found. Skipping SillyTavern-extras update."
fi
# Update XTTS if directory exists
if [ -d "xtts" ]; then
log_message "INFO" "Updating XTTS..."
cd "xtts"
source activate xtts
pip install --upgrade xtts-api-server
conda deactivate
cd ..
log_message "INFO" "XTTS updated successfully."
else
log_message "WARN" "xtts directory not found. Skipping XTTS update."
fi
read -p "Press Enter to continue..."
home
}
create_backup() {
echo -e "\033]0;STL [CREATE BACKUP]\007"
clear
echo -e "${blue_fg_strong}| > / Home / Toolbox / Backup / Create Backup |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
# Scan for user folders
user_folders=()
for dir in "$st_install_path/data"/*; do
if [ -d "$dir" ]; then
folder_name=$(basename "$dir")
if [[ "$folder_name" != "_storage" && "$folder_name" != "_uploads" ]]; then
user_folders+=("$folder_name")
fi
fi
done
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Detected Accounts |${reset}"
for ((i = 0; i < ${#user_folders[@]}; i++)); do
echo -e " $((i + 1)). ${yellow_fg_strong}${user_folders[$i]}${reset}"
done
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Cancel"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
# If only one user folder is found, skip the selection
if [ ${#user_folders[@]} -eq 1 ]; then
selected_user_folder="${user_folders[0]}"
else
echo
read -p "Select a folder to backup: " user_choice
# Check if the user wants to exit
if [ "$user_choice" -eq 0 ]; then
backup
fi
# Validate user input
if [[ "$user_choice" -lt 1 || "$user_choice" -gt ${#user_folders[@]} ]]; then
echo -e "${red_fg_strong}[ERROR] Invalid selection. Please enter a number between 1 and ${#user_folders[@]}, or press 0 to cancel.${reset}"
read -p "Press Enter to continue..."
create_backup
return
fi
selected_user_folder="${user_folders[$((user_choice - 1))]}"
fi
# Prompt user for custom name
read -p " Give backup file a custom name? (Default is st_backup_DATE_TIME.7z) [Y/N]: " rename_choice
rename_choice=$(echo "$rename_choice" | tr '[:upper:]' '[:lower:]')
# Check if the user wants to exit
if [[ "$rename_choice" == "0" ]]; then
backup
fi
if [[ "$rename_choice" == "y" ]]; then
read -p "Enter custom name for backup file (without extension): " custom_name
backup_filename="st_backup_${custom_name}.7z"
else
# Get current date and time
formatted_date=$(date +"%Y-%m-%d_%H-%M")
backup_filename="st_backup_${formatted_date}.7z"
fi
# Create a backup using 7zip
if ! command -v 7z &> /dev/null; then
echo -e "${red_fg_strong}[ERROR] 7z is not installed. Please install it to create backups.${reset}"
read -p "Press Enter to continue..."
backup
fi
7z a "$st_backup_path/$backup_filename" "$st_install_path/data/$selected_user_folder/*" > /dev/null
if [ $? -eq 0 ]; then
echo -e "${blue_bg}[$(date +%T)]${reset} ${blue_fg_strong}[INFO]${reset} ${green_fg_strong}Backup created at $st_backup_path/$backup_filename${reset}"
else
echo -e "${red_fg_strong}[ERROR] Backup creation failed.${reset}"
fi
read -p "Press Enter to continue..."
backup
}
restore_backup() {
echo -e "\033]0;STL [RESTORE BACKUP]\007"
clear
echo -e "${blue_fg_strong}| > / Home / Toolbox / Backup / Restore Backup |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Available Backups |${reset}"
backup_files=()
backup_count=0
for file in "$st_backup_path"/st_backup_*.7z; do
if [ -f "$file" ]; then
backup_count=$((backup_count + 1))
backup_files+=("$(basename "$file" .7z)")
echo -e " $backup_count. ${yellow_fg_strong}$(basename "$file" .7z)${reset}"
fi
done
if [ "$backup_count" -eq 0 ]; then
echo -e " ${red_fg_strong}No backups found.${reset}"
fi
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Cancel"
echo
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
# Prompt user to select a backup
read -p " Select backup to restore: " restore_choice
# Check if the user wants to cancel
if [[ "$restore_choice" == "0" ]]; then
backup
fi
# Validate user input
if [[ "$restore_choice" -lt 1 || "$restore_choice" -gt "$backup_count" ]]; then
echo -e "${red_fg_strong}[ERROR] Invalid selection. Please enter a number between 1 and $backup_count, or press 0 to cancel.${reset}"
read -p "Press Enter to continue..."
restore_backup
return
fi
# Get the selected backup file
selected_backup="${backup_files[$((restore_choice - 1))]}"
# Restore the backup
echo "Restoring backup $selected_backup..."
# Create a temporary directory for extraction
temp_dir=$(mktemp -d)
# Extract the backup to the temporary directory
if ! command -v 7z &> /dev/null; then
echo -e "${red_fg_strong}[ERROR] 7z is not installed. Please install it to restore backups.${reset}"
read -p "Press Enter to continue..."
backup
fi
7z x "$st_backup_path/$selected_backup.7z" -o"$temp_dir" -aoa > /dev/null
if [ $? -ne 0 ]; then
echo -e "${red_fg_strong}[ERROR] Failed to extract backup.${reset}"
rm -rf "$temp_dir"
read -p "Press Enter to continue..."
backup
fi
# Copy the extracted data to the SillyTavern data directory
if [ -d "$temp_dir/data" ]; then
cp -r "$temp_dir/data/"* "$st_install_path/data/"
else
echo -e "${red_fg_strong}[ERROR] Backup does not contain a valid data directory.${reset}"
rm -rf "$temp_dir"
read -p "Press Enter to continue..."
backup
fi
# Clean up the temporary directory
rm -rf "$temp_dir"
echo -e "${blue_bg}[$(date +%T)]${reset} ${blue_fg_strong}[INFO]${reset} ${green_fg_strong}$selected_backup restored successfully.${reset}"
read -p "Press Enter to continue..."
backup
}
############################################################
################# BACKUP - FRONTEND ########################
############################################################
backup() {
echo -e "\033]0;STL [BACKUP]\007"
clear
echo -e "${blue_fg_strong}| > / Home / Toolbox / Backup |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| What would you like to do? |${reset}"
echo " 1. Create Backup"
echo " 2. Restore Backup"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Back"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " backup_choice
################# BACKUP - BACKEND ########################
case $backup_choice in
1) create_backup ;;
2) restore_backup ;;
0) toolbox ;;
*) echo -e "${yellow_fg_strong}WARNING: Invalid number. Please insert a valid number.${reset}"
read -p "Press Enter to continue..."
backup ;;
esac
}
########################################################################################
########################################################################################
####################### EDITOR FUNCTIONS ##############################################
########################################################################################
########################################################################################
# Function to print module options with color based on their status
printModule() {
if [ "$2" == "true" ]; then
echo -e "\e[32;1m$1 [Enabled]\e[0m"
else
echo -e "\e[31;1m$1 [Disabled]\e[0m"
fi
}
# Function to edit extras modules
edit_extras_modules() {
echo -e "\033]0;STL [EDIT-MODULES]\007"
clear
echo -e "${blue_fg_strong}/ Home / Toolbox / Editor / Edit Extras Modules${reset}"
echo "-------------------------------------"
echo "Choose extras modules to enable or disable (e.g., \"1 2 4\" to enable Cuda, RVC, and Caption)"
# Display module options with colors based on their status
printModule "1. Cuda (--gpu 0 --cuda --cuda-device=0)" "$cuda_trigger"
printModule "2. RVC (--enable-modules=rvc --rvc-save-file --max-content-length=1000)" "$rvc_trigger"
printModule "3. talkinghead (--enable-modules=talkinghead)" "$talkinghead_trigger"
printModule "4. caption (--enable-modules=caption)" "$caption_trigger"
printModule "5. summarize (--enable-modules=summarize)" "$summarize_trigger"
printModule "6. listen (--listen)" "$listen_trigger"
printModule "7. Edge TTS (--enable-modules=edge-tts)" "$edge_tts_trigger"
echo "0. Back to Toolbox"
set "python_command="
read -p "Choose modules to enable/disable (1-6): " module_choices
# Handle the user's module choices and construct the Python command
for i in $module_choices; do
case $i in
1) [ "$cuda_trigger" == "true" ] && cuda_trigger=false || cuda_trigger=true ;;
2) [ "$rvc_trigger" == "true" ] && rvc_trigger=false || rvc_trigger=true ;;
3) [ "$talkinghead_trigger" == "true" ] && talkinghead_trigger=false || talkinghead_trigger=true ;;
4) [ "$caption_trigger" == "true" ] && caption_trigger=false || caption_trigger=true ;;
5) [ "$summarize_trigger" == "true" ] && summarize_trigger=false || summarize_trigger=true ;;
6) [ "$listen_trigger" == "true" ] && listen_trigger=false || listen_trigger=true ;;
7) [ "$edge_tts_trigger" == "true" ] && edge_tts_trigger=false || edge_tts_trigger=true ;;
0) toolbox ;;
esac
done
# Save the module flags to modules.txt
modules_file="$(dirname "$0")/modules.txt"
echo "cuda_trigger=$cuda_trigger" > "$modules_file"
echo "rvc_trigger=$rvc_trigger" >> "$modules_file"
echo "talkinghead_trigger=$talkinghead_trigger" >> "$modules_file"
echo "caption_trigger=$caption_trigger" >> "$modules_file"
echo "summarize_trigger=$summarize_trigger" >> "$modules_file"
echo "listen_trigger=$listen_trigger" >> "$modules_file"
echo "edge_tts_trigger=$edge_tts_trigger" >> "$modules_file"
# Compile the Python command
python_command="python server.py"
[ "$listen_trigger" == "true" ] && python_command+=" --listen"
[ "$cuda_trigger" == "true" ] && python_command+=" --gpu 0 --cuda --cuda-device=0 "
[ "$rvc_trigger" == "true" ] && python_command+=" --rvc-save-file --max-content-length=1000"
modules_enable=""
[ "$talkinghead_trigger" == "true" ] && modules_enable+="talkinghead,"
[ "$caption_trigger" == "true" ] && modules_enable+="caption,"
[ "$summarize_trigger" == "true" ] && modules_enable+="summarize,"
[ "$edge_tts_trigger" == "true" ] && modules_enable+="edge-tts,"
# Remove the last comma from modules_enable
modules_enable="${modules_enable%,}"
# Save the constructed Python command to modules.txt for testing
echo "start_command=$python_command --enable-modules=$modules_enable" >> "$modules_file"
edit_extras_modules
}
# Function to edit XTTS modules
edit_xtts_modules() {
echo -e "\033]0;STL [EDIT-XTTS-MODULES]\007"
clear
echo -e "${blue_fg_strong}/ Home / Toolbox / Editor / Edit XTTS Modules${reset}"
echo "-------------------------------------"
echo "Choose XTTS modules to enable or disable (e.g., "1 2 4" to enable Cuda, hs, and cache)"
# Display module options with colors based on their status
printModule "1. cuda (--device cuda)" "$xtts_cuda_trigger"
printModule "2. hs (-hs 0.0.0.0)" "$xtts_hs_trigger"
printModule "3. deepspeed (--deepspeed)" "$xtts_deepspeed_trigger"
printModule "4. cache (--use-cache)" "$xtts_cache_trigger"
printModule "5. listen (--listen)" "$xtts_listen_trigger"
printModule "6. model (--model-source local)" "$xtts_model_trigger"
echo "0. Back to Editor"s
set "python_command="
read -p "Choose modules to enable/disable (1-6): " module_choices
# Handle the user's module choices and construct the Python command
for i in $module_choices; do
case $i in
1) [ "$xtts_cuda_trigger" == "true" ] && xtts_cuda_trigger=false || xtts_cuda_trigger=true ;;
2) [ "$xtts_hs_trigger" == "true" ] && xtts_hs_trigger=false || xtts_hs_trigger=true ;;
3) [ "$xtts_deepspeed_trigger" == "true" ] && xtts_deepspeed_trigger=false || xtts_deepspeed_trigger=true ;;
4) [ "$xtts_cache_trigger" == "true" ] && xtts_cache_trigger=false || xtts_cache_trigger=true ;;
5) [ "$xtts_listen_trigger" == "true" ] && xtts_listen_trigger=false || xtts_listen_trigger=true ;;
6) [ "$xtts_model_trigger" == "true" ] && xtts_model_trigger=false || xtts_model_trigger=true ;;
0) editor ;;
esac
done
# Save the module flags to modules-xtts.txt
modules_file="$(dirname "$0")/modules-xtts.txt"
echo "xtts_cuda_trigger=$xtts_cuda_trigger" > "$modules_file"
echo "xtts_hs_trigger=$xtts_hs_trigger" >> "$modules_file"
echo "xtts_deepspeed_trigger=$xtts_deepspeed_trigger" >> "$modules_file"
echo "xtts_cache_trigger=$xtts_cache_trigger" >> "$modules_file"
echo "xtts_listen_trigger=$xtts_listen_trigger" >> "$modules_file"
echo "xtts_model_trigger=$xtts_model_trigger" >> "$modules_file"
# Compile the Python command
python_command="python server.py"
[ "$xtts_cuda_trigger" == "true" ] && python_command+=" --device cuda"
[ "$xtts_hs_trigger" == "true" ] && python_command+=" -hs 0.0.0.0"
[ "$xtts_deepspeed_trigger" == "true" ] && python_command+=" --deepspeed"
[ "$xtts_cache_trigger" == "true" ] && python_command+=" --use-cache"
[ "$xtts_listen_trigger" == "true" ] && python_command+=" --listen"
[ "$xtts_model_trigger" == "true" ] && python_command+=" --model-source local"
# Save the constructed Python command to modules.txt for testing
echo "start_command=$python_command" >> "$modules_file"
edit_xtts_modules
}
# Function to edit environment variables
edit_env_var() {
# Open the environment variables file for editing
if [ -f ~/.bashrc ]; then
# Use your preferred text editor (e.g., nano, vim, or gedit)
nano ~/.bashrc
else
echo "Environment file not found. Create or specify the correct file path."
fi
# Optionally, ask the user to reload the environment
read -p "Would you like to reload the environment? [Y/N]: " reload
if [ "$reload" = "Y" ] || [ "$reload" = "y" ]; then
source ~/.bashrc # Reload the environment (may vary based on your shell)
echo "Environment reloaded."
fi
editor_core_utilities
}
edit_st_config() {
# Check if nano is available
if ! command -v nano &>/dev/null; then
echo "Error: Nano is not installed. Please install Nano to edit config.yaml"
editor_core_utilities
fi
# Open config.yaml file in nano
nano "$st_install_path/config.yaml"
editor_core_utilities
}
editor_text_completion() {
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
editor
}
editor_voice_generation() {
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
editor
}
editor_image_generation() {
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
editor
}
edit_extras_modules() {
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
editor_core_utilities
}
create_st_ssl() {
# Check if a specific argument is passed to detect if called by another script
local pause_required=true
local silent_mode=false
if [ -n "$1" ]; then
silent_mode=true
fi
# Redirect output to /dev/null if in silent mode
if [ "$silent_mode" = true ]; then
local output_redirection=">/dev/null 2>&1"
else
local output_redirection=""
fi
# Set the SSL certificate directory and files
local CERT_DIR="$st_install_path/certs"
local CERT_FILE="$CERT_DIR/cert.pem"
local KEY_FILE="$CERT_DIR/privkey.pem"
local CERT_INFO_FILE="$CERT_DIR/SillyTavernSSLInfo.txt"
local ERROR_LOG="$CERT_DIR/error_log.txt"
# Check if the SillyTavern directory exists
if [ ! -d "$st_install_path" ]; then
echo "Please install SillyTavern first."
if [ "$pause_required" = true ]; then
read -p "Press Enter to continue..."
fi
editor_core_utilities
fi
# Create the SSL certificate directory if it doesn't exist
if [ ! -d "$CERT_DIR" ]; then
mkdir -p "$CERT_DIR"
eval "echo Created directory $CERT_DIR $output_redirection"
else
eval "echo Directory $CERT_DIR already exists. $output_redirection"
fi
# Check if the certificate already exists and delete it if it does
if [ -f "$CERT_FILE" ]; then
rm "$CERT_FILE"
eval "echo Existing certificate deleted. $output_redirection"
fi
if [ -f "$KEY_FILE" ]; then
rm "$KEY_FILE"
eval "echo Existing key deleted. $output_redirection"
fi
# Find the OpenSSL binary
local openssl_path=$(which openssl)
if [ -z "$openssl_path" ]; then
echo "OpenSSL is not installed. Please install it first."
if [ "$pause_required" = true ]; then
read -p "Press Enter to continue..."
fi
editor_core_utilities
fi
eval "echo OpenSSL is located at: $openssl_path $output_redirection"
# Generate the self-signed certificate in PEM format
eval "echo Generating self-signed certificate... $output_redirection"
eval "$openssl_path req -x509 -newkey rsa:4096 -keyout \"$KEY_FILE\" -out \"$CERT_FILE\" -days 825 -nodes -subj \"/CN=127.0.0.1\" $output_redirection"
if [ $? -ne 0 ]; then
echo "An error occurred. Please check the console output for details."
echo "[$(date)] An error occurred during certificate generation." >> "$ERROR_LOG"
if [ "$pause_required" = true ]; then
read -p "Press Enter to continue..."
fi
editor_core_utilities
fi
eval "echo Certificate generation complete. $output_redirection"
# Calculate the expiration date (today + 825 days) and format as YYYY-MM-DD
local exp_date=$(date -d "+825 days" +"%Y-%m-%d")
# Store the certificate and key path, and expiration date in the text file
{
echo "$CERT_FILE"
echo "$KEY_FILE"
echo "SSL Expiration Date (YYYY-MM-DD): $exp_date"
} > "$CERT_INFO_FILE"
eval "echo Certificate and key paths and expiration date stored in $CERT_INFO_FILE. $output_redirection"
echo "Done."
if [ "$pause_required" = true ]; then
read -p "Press Enter to continue..."
fi
editor_core_utilities
}
delete_st_ssl() {
CERTS_DIR="$st_install_path/certs"
if [ -d "$CERTS_DIR" ]; then
log_message "INFO" "Removing $CERTS_DIR..."
rm -rf "$CERTS_DIR"
if [ $? -eq 0 ]; then
echo -e "${green_fg_strong}certs directory successfully deleted.${reset}"
else
log_message "ERROR" "Failed to delete certs directory. Please check permissions."
fi
else
log_message "INFO" "No SSL certificates found. Nothing to delete."
fi
read -p "Press Enter to continue..."
editor_core_utilities
}
config_tailscale() {
echo -e "\033]0;STL [TAILSCALE CONFIGURATION]\007"
clear
echo -e "${blue_fg_strong}| > / Home / Toolbox / App Installer / Core Utilities / Tailscale${reset}"
echo -e "${blue_fg_strong} ============================================================================================${reset}"
echo -e "${cyan_fg_strong}____________________________________________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| What would you like to do? |${reset}"
# Calculate the path to the logs folder based on the current script location
log_dir="$(dirname "$(readlink -f "$0")")/../../../logs"
log_file="$log_dir/tailscale_status.txt"
# Check if the log file exists before attempting to clear it
if [ -f "$log_file" ]; then
echo -e "${blue_bg}[$(date '+%H:%M:%S')]${reset} ${blue_fg_strong}[INFO]${reset} Clearing existing log file..."
> "$log_file"
else
echo -e "${blue_bg}[$(date '+%H:%M:%S')]${reset} ${blue_fg_strong}[INFO]${reset} Log file does not exist, no need to clear."
fi
echo -e "${blue_bg}[$(date '+%H:%M:%S')]${reset} ${blue_fg_strong}[INFO]${reset} Configuring Tailscale..."
echo -e "${blue_bg}[$(date '+%H:%M:%S')]${reset} ${blue_fg_strong}[INFO]${reset} Running Tailscale login..."
tailscale up
if [ $? -eq 0 ]; then
echo -e "${blue_bg}[$(date '+%H:%M:%S')]${reset} ${blue_fg_strong}[INFO]${reset} Tailscale configuration successful."
echo -e "${cyan_fg_strong}____________________________________________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 1. Find Tailscale SillyTavern Remote URLs"
echo " 0. Back"
echo -e "${cyan_fg_strong}____________________________________________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " choice
case $choice in
1)
echo
echo -e "${blue_bg}[$(date '+%H:%M:%S')]${reset} ${blue_fg_strong}[INFO]${reset} Fetching Tailscale status..."
# Fetch Tailscale status and write to log file
tailscale status --json | jq -r '.Self | .TailscaleIPs[0], .HostName, .DNSName' > "$log_file"
# Read values from the log file
mapfile -t tailscale_info < "$log_file"
ip4="${tailscale_info[0]}"
hostName="${tailscale_info[1]}"
dnsName="${tailscale_info[2]}"
# Remove trailing period from dnsName if it exists
dnsName="${dnsName%.}"
echo -e "${blue_fg_strong}____________________________________________________________________________________________${reset}"
echo -e "${blue_bg}[$(date '+%H:%M:%S')]${reset} ${blue_fg_strong}[INFO]${reset} Tailscale Remote SillyTavern URLs (if you changed your SillyTavern Port # change 8000 to that new port):"
echo -e "${cyan_fg_strong}IP4:${reset} http://$ip4:8000"
echo -e "${cyan_fg_strong}Machine Name:${reset} http://$hostName:8000"
echo -e "${cyan_fg_strong}MagicDNS Name:${reset} http://$dnsName:8000"
echo -e "${blue_fg_strong}____________________________________________________________________________________________${reset}"
# Prompt the user to open the additional config instructions page
read -p "Do you want to open the additional configuration instructions page (Y/N)? " userChoice
if [[ "$userChoice" =~ ^[Yy]$ ]]; then
url="https://sillytavernai.com/tailscale-config/?HostName=$hostName&DNSName=$dnsName&IP4=$ip4#STL"
xdg-open "$url"
else
echo -e "${blue_bg}[$(date '+%H:%M:%S')]${reset} ${blue_fg_strong}[INFO]${reset} Skipping additional configuration instructions."
fi
;;
0)
echo -e "${blue_bg}[$(date '+%H:%M:%S')]${reset} ${blue_fg_strong}[INFO]${reset} Returning to Home..."
editor_core_utilities
;;
*)
echo -e "${yellow_fg_strong}WARNING: Invalid number. Please insert a valid number.${reset}"
read -p "Press Enter to continue..."
config_tailscale
;;
esac
else
echo -e "${red_bg}[$(date +%T)]${reset} ${red_fg_strong}[ERROR] Tailscale configuration failed.${reset}"
read -p "Press Enter to continue..."
editor_core_utilities
fi
read -p "Press Enter to continue..."
config_tailscale
}
editor_core_utilities() {
echo -e "\033]0;STL [EDITOR CORE UTILITIES]\007"
clear
SSL_INFO_FILE="$st_install_path/certs/SillyTavernSSLInfo.txt"
sslOption="2. Generate & Use Self-Signed SSL for SillyTavern"
sslDeleteOption="" # Initialize delete option as empty
# Check if SSL exists and populate options
if [ -f "$SSL_INFO_FILE" ]; then
expDate=$(sed -n '3p' "$SSL_INFO_FILE")
sslOption="2. Regenerate SillyTavern SSL - $expDate"
sslDeleteOption="222. Delete Generated SSL"
fi
echo -e "${blue_fg_strong}| > / Home / Toolbox / Editor / Core Utilities |${reset}"
echo -e "${blue_fg_strong} ============================================================================================${reset}"
echo -e "${cyan_fg_strong}____________________________________________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| What would you like to do? |${reset}"
echo " 1. Edit SillyTavern config.yaml"
echo " 3. Edit Extras"
echo " 4. Edit Environment Variables"
echo " 5. View Tailscale configuration"
echo -e "${cyan_fg_strong}____________________________________________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| SSL Options |${reset}"
echo -e " $sslOption"
[ -n "$sslDeleteOption" ] && echo -e ${yellow_fg_strong}" $sslDeleteOption${reset}" # Show delete option only if SSL exists
echo -e " 223. Open SSL documentation"
echo -e "${cyan_fg_strong}____________________________________________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Back"
echo -e "${cyan_fg_strong}____________________________________________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " editor_core_utilities_choice
case $editor_core_utilities_choice in
1) edit_st_config ;;
2) create_st_ssl ;;
3) edit_extras_modules ;;
4) edit_env_var ;;
5) config_tailscale ;;
222) delete_st_ssl ;;
223) xdg-open "https://sillytavernai.com/launcher-ssl" ; editor_core_utilities ;;
0) editor ;;
*) echo -e "${yellow_fg_strong}WARNING: Invalid number. Please insert a valid number.${reset}"
read -p "Press Enter to continue..."
editor_core_utilities ;;
esac
}
############################################################
############## EDITOR - FRONTEND ###########################
############################################################
editor() {
echo -e "\033]0;STL [EDITOR]\007"
clear
echo -e "${blue_fg_strong}| > / Home / Toolbox / Editor |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| What would you like to do? |${reset}"
echo " 1. Text Completion"
echo " 2. Voice Generation"
echo " 3. Image Generation"
echo " 4. Core Utilities"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Back"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " editor_choice
################# EDITOR - BACKEND ################
case $editor_choice in
1) editor_text_completion ;;
2) editor_voice_generation ;;
3) editor_image_generation ;;
4) editor_core_utilities ;;
0) toolbox ;;
*) echo -e "${yellow_fg_strong}WARNING: Invalid number. Please insert a valid number.${reset}"
read -p "Press Enter to continue..."
editor ;;
esac
}
########################################################################################
########################################################################################
####################### TROUBLESHOOTING FUNCTIONS #####################################
########################################################################################
########################################################################################
remove_node_modules() {
log_message "INFO" "Removing node_modules folder..."
rm -rf "$st_install_path/node_modules"
log_message "INFO" "node_modules successfully removed."
read -p "Press Enter to continue..."
troubleshooting
}
remove_npm_cache() {
log_message "INFO" "Clearing npm cache..."
npm cache clean --force
log_message "INFO" "npm cache cleared successfully."
read -p "Press Enter to continue..."
troubleshooting
}
remove_pip_cache() {
log_message "INFO" "Clearing pip cache..."
pip cache purge
log_message "INFO" "pip cache cleared successfully."
read -p "Press Enter to continue..."
troubleshooting
}
fix_github_conflicts() {
log_message "INFO" "Trying to resolve unresolved conflicts in the working directory or unmerged files..."
git -C "$st_install_path" merge --abort
git -C "$st_install_path" reset --hard
git -C "$st_install_path" pull --rebase --autostash
read -p "Press Enter to continue..."
troubleshooting
}
export_system_info() {
log_message "INFO" "Exporting system information..."
lshw > "$(dirname "$0")/system_info.txt"
log_message "INFO" "You can find the system_info.txt at: $(dirname "$0")/system_info.txt"
read -p "Press Enter to continue..."
troubleshooting
}
find_app_port() {
echo -e "\033]0;STL [FIND APP PORT]\007"
clear
echo -e "${blue_fg_strong}| > / Home / Troubleshooting & Support / Find App Port |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Cancel"
# Prompt for port number if not provided
if [ -z "$1" ]; then
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Insert port number: " port_choice
else
port_choice="$1"
fi
# Check if the user wants to cancel
if [[ "$port_choice" == "0" ]]; then
troubleshooting
fi
# Validate input: Check if it's a number
if ! [[ "$port_choice" =~ ^[0-9]+$ ]]; then
echo -e "${red_bg}[$(date +%T)]${reset} ${red_fg_strong}[ERROR] Invalid input: Not a number.${reset}"
read -p "Press Enter to continue..."
troubleshooting
return
fi
# Validate port range
if [ "$port_choice" -gt 65535 ]; then
echo -e "${red_bg}[$(date +%T)]${reset} ${red_fg_strong}[ERROR] Port out of range. There are only 65,535 possible port numbers.${reset}"
echo "[0-1023]: These ports are reserved for system services or commonly used protocols."
echo "[1024-49151]: These ports can be used by user processes or applications."
echo "[49152-65535]: These ports are available for use by any application or service on the system."
read -p "Press Enter to continue..."
troubleshooting
return
fi
echo -e "${blue_bg}[$(date +%T)]${reset} ${blue_fg_strong}[INFO]${reset} Searching for application using port: $port_choice..."
# Find the PID of the process using the port
pid=$(lsof -i :"$port_choice" -t)
if [ -n "$pid" ]; then
app_name=$(ps -p "$pid" -o comm=)
echo -e "Application Name: ${cyan_fg_strong}$app_name${reset}"
echo -e "PID of Port $port_choice: ${cyan_fg_strong}$pid${reset}"
# Fetch the page title for the specified port
fetch_page_title "$port_choice"
if [ -n "$PAGE_TITLE" ]; then
echo -e "Title of Application: ${cyan_fg_strong}$PAGE_TITLE${reset}"
else
echo -e "${yellow_bg}[$(date +%T)]${reset} ${yellow_fg_strong}[WARN]${reset} Could not retrieve page title."
fi
else
echo -e "${yellow_bg}[$(date +%T)]${reset} ${yellow_fg_strong}[WARN]${reset} Port: $port_choice not found."
fi
read -p "Press Enter to continue..."
find_app_port
}
# Function to fetch the page title for a given port
fetch_page_title() {
local port="$1"
local url="http://localhost:$port"
# Use curl to fetch the page title
PAGE_TITLE=$(curl -s "$url" | grep -oP '(?<=
).*?(?=)')
}
onboarding_flow() {
read -p "Enter new value for Onboarding Flow (true/false): " onboarding_flow_value
if [[ "$onboarding_flow_value" != "true" && "$onboarding_flow_value" != "false" ]]; then
log_message "WARN" "Invalid input. Please enter 'true' or 'false'."
read -p "Press Enter to continue..."
onboarding_flow
fi
sed -i "s/\"firstRun\": .*/\"firstRun\": $onboarding_flow_value,/" "$st_install_path/public/settings.json"
log_message "INFO" "Value of 'firstRun' in settings.json has been updated to $onboarding_flow_value."
read -p "Press Enter to continue..."
troubleshooting
}
discord_servers_menu() {
echo -e "\033]0;STL [DISCORD SERVERS]\007"
clear
echo -e "${blue_fg_strong}| > / Home / Troubleshooting & Support / Discord Servers |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo " 1. Join SillyTavern"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Discord - LLM Backends: |${reset}"
echo " 2. Join TabbyAPI"
echo " 3. Join KoboldAI"
echo " 4. Join Text Generation WEBUI ooba"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Discord - Cloud API: |${reset}"
echo " 5. Join Mancer"
echo " 6. Join OpenRouter"
echo " 7. Join AI Horde"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Discord - Model Devs & Research: |${reset}"
echo " 8. Join TheBloke"
echo " 9. Join PygmalionAI"
echo " 10. Join Nous Research"
echo " 11. Join RWKV"
echo " 12. Join EleutherAI"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Back"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " discord_servers_choice
################ DISCORD SERVERS - BACKEND ################
case $discord_servers_choice in
1) discord_sillytavern ;;
2) discord_tabbyapi ;;
3) discord_koboldai ;;
4) discord_textgenwebuiooba ;;
5) discord_mancer ;;
6) discord_openrouter ;;
7) discord_aihorde ;;
8) discord_thebloke ;;
9) discord_pygmalionai ;;
10) discord_nousresearch ;;
11) discord_rwkv ;;
12) discord_eleutherai ;;
0) troubleshooting ;;
*)
echo -e "${red_fg_strong}[ERROR] Invalid input. Please enter a valid number.${reset}"
read -p "Press Enter to continue..."
discord_servers_menu
;;
esac
}
# Discord server functions
discord_sillytavern() {
xdg-open "https://discord.gg/sillytavern"
discord_servers_menu
}
discord_tabbyapi() {
xdg-open "https://discord.gg/sYQxnuD7Fj"
discord_servers_menu
}
discord_koboldai() {
xdg-open "https://discord.gg/UCyXV7NssH"
discord_servers_menu
}
discord_textgenwebuiooba() {
xdg-open "https://discord.gg/jwZCF2dPQN"
discord_servers_menu
}
discord_mancer() {
xdg-open "https://discord.gg/6DZaU9Gv9F"
discord_servers_menu
}
discord_openrouter() {
xdg-open "https://discord.gg/H9tjZYgauh"
discord_servers_menu
}
discord_aihorde() {
xdg-open "https://discord.gg/3DxrhksKzn"
discord_servers_menu
}
discord_thebloke() {
xdg-open "https://discord.gg/Jq4vkcDakD"
discord_servers_menu
}
discord_pygmalionai() {
xdg-open "https://discord.gg/pygmalionai"
discord_servers_menu
}
discord_nousresearch() {
xdg-open "https://discord.gg/jqVphNsB4H"
discord_servers_menu
}
discord_rwkv() {
xdg-open "https://discord.gg/bDSBUMeFpc"
discord_servers_menu
}
discord_eleutherai() {
xdg-open "https://discord.gg/zBGx3azzUn"
discord_servers_menu
}
############################################################
############## TROUBLESHOOTING - FRONTEND ##################
############################################################
troubleshooting() {
echo -e "\033]0;STL [TROUBLESHOOTING SUPPORT]\007"
clear
echo -e "${blue_fg_strong}| > / Home / Troubleshooting & Support |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Troubleshooting & Repair Options |${reset}"
echo " 1. Remove node_modules folder"
echo " 2. Clear npm cache"
echo " 3. Clear pip cache"
echo " 4. Fix unresolved conflicts or unmerged files [SillyTavern]"
echo " 5. Export system info"
echo " 6. Find what app is using port"
echo " 7. Set Onboarding Flow"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Support Options: |${reset}"
echo " 8. Report an Issue"
echo " 9. SillyTavern Documentation"
echo " 10. Discord servers"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Back"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " troubleshooting_choice
################# TROUBLESHOOTING - BACKEND ################
case $troubleshooting_choice in
1) remove_node_modules ;;
2) remove_npm_cache ;;
3) remove_pip_cache ;;
4) fix_github_conflicts ;;
5) export_system_info ;;
6) find_app_port ;;
7) onboarding_flow ;;
8) issue_report ;;
9) documentation ;;
10) discord_servers_menu ;;
0) home ;;
*) echo -e "${yellow_fg_strong}WARNING: Invalid number. Please insert a valid number.${reset}"
read -p "Press Enter to continue..."
troubleshooting ;;
esac
}
########################################################################################
########################################################################################
####################### SUPPORT FUNCTIONS #############################################
########################################################################################
########################################################################################
issue_report() {
if [ "$EUID" -eq 0 ]; then
log_message "ERROR" "${red_fg_strong}Cannot run xdg-open as root. Please run the script without root permission.${reset}"
else
if [ "$(uname -s)" == "Darwin" ]; then
open https://github.com/SillyTavern/SillyTavern-Launcher/issues/new/choose
else
xdg-open https://github.com/SillyTavern/SillyTavern-Launcher/issues/new/choose
fi
fi
read -p "Press Enter to continue..."
troubleshooting
}
documentation() {
if [ "$EUID" -eq 0 ]; then
log_message "ERROR" "${red_fg_strong}Cannot run xdg-open as root. Please run the script without root permission.${reset}"
else
if [ "$(uname -s)" == "Darwin" ]; then
open https://docs.sillytavern.app/
else
xdg-open https://docs.sillytavern.app/
fi
fi
read -p "Press Enter to continue..."
troubleshooting
}
########################################################################################
########################################################################################
####################### TOOLBOX MENU FUNCTIONS ########################################
########################################################################################
########################################################################################
# Function to switch to the Release branch in SillyTavern
switch_release_st() {
log_message "INFO" "Switching to release branch..."
git -C "$st_install_path" switch release
read -p "Press Enter to continue..."
switch_branch
}
# Function to switch to the Staging branch in SillyTavern
switch_staging_st() {
log_message "INFO" "Switching to staging branch..."
git -C "$st_install_path" switch staging
read -p "Press Enter to continue..."
switch_branch
}
############################################################
############## SWITCH BRANCE - FRONTEND ####################
############################################################
switch_branch() {
echo -e "\033]0;STL [SWITCH BRANCH]\007"
clear
echo -e "${blue_fg_strong}| > / Home / Toolbox / Switch Branch |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo -e "${yellow_fg_strong} ______________________________________________________________${reset}"
echo -e "${yellow_fg_strong}| Version Status |${reset}"
current_st_branch=$(git -C "$st_install_path" branch --show-current)
echo -e " SillyTavern branch: ${cyan_fg_strong}$current_st_branch${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| What would you like to do? |${reset}"
echo " 1. Switch to Release - SillyTavern"
echo " 2. Switch to Staging - SillyTavern"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Back"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " branch_choice
################# SWITCH BRANCE - BACKEND ########################
case $branch_choice in
1) switch_release_st ;;
2) switch_staging_st ;;
0) toolbox ;;
*) echo -e "${yellow_fg_strong}WARNING: Invalid number. Please insert a valid number.${reset}"
read -p "Press Enter to continue..."
switch_branch ;;
esac
}
reset_custom_shortcut() {
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
toolbox
}
app_launcher() {
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
toolbox
}
########################################################################################
########################################################################################
####################### APP INSTALLER MENU FUNCTIONS ##################################
########################################################################################
########################################################################################
# Function to install p7zip (7-Zip)
install_p7zip() {
if ! command -v 7z &> /dev/null; then
log_message "WARN" "${yellow_fg_strong}p7zip (7-Zip) is not installed on this system${reset}"
case "$(grep -E '^ID=' /etc/os-release | cut -d= -f2)" in
debian|ubuntu)
# Debian/Ubuntu-based system
log_message "INFO" "Installing p7zip (7-Zip) using apt..."
sudo apt-get update
sudo apt-get install -y p7zip-full
;;
fedora|centos|rhel)
# Red Hat/Fedora-based system
log_message "INFO" "Installing p7zip (7-Zip) using yum..."
sudo yum install -y p7zip p7zip-plugins
;;
alpine)
# Alpine Linux-based system
log_message "INFO" "Installing p7zip (7-Zip) using apk..."
sudo apk add p7zip
;;
arch|manjaro)
# Arch Linux-based system
log_message "INFO" "Installing p7zip (7-Zip) using pacman..."
sudo pacman -Sy --noconfirm p7zip
;;
gentoo)
# Gentoo Linux-based system
log_message "INFO" "Installing p7zip (7-Zip) using emerge..."
sudo emerge --ask app-arch/p7zip
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported Linux distribution.${reset}"
exit 1
;;
esac
log_message "INFO" "${green_fg_strong}p7zip (7-Zip) is installed.${reset}"
else
log_message "INFO" "${blue_fg_strong}p7zip (7-Zip) is already installed.${reset}"
fi
}
# Function to install FFmpeg
install_ffmpeg() {
if ! command -v ffmpeg &> /dev/null; then
log_message "WARN" "${yellow_fg_strong}FFmpeg is not installed on this system${reset}"
case "$(grep -E '^ID=' /etc/os-release | cut -d= -f2)" in
debian|ubuntu)
# Debian/Ubuntu-based system
log_message "INFO" "Installing FFmpeg using apt..."
sudo apt-get update
sudo apt-get install -y ffmpeg
;;
fedora|centos|rhel)
# Red Hat/Fedora-based system
log_message "INFO" "Installing FFmpeg using yum..."
sudo yum install -y ffmpeg
;;
alpine)
# Alpine Linux-based system
log_message "INFO" "Installing FFmpeg using apk..."
sudo apk add ffmpeg
;;
arch|manjaro)
# Arch Linux-based system
log_message "INFO" "Installing FFmpeg using pacman..."
sudo pacman -Sy --noconfirm ffmpeg
;;
gentoo)
# Gentoo Linux-based system
log_message "INFO" "Installing FFmpeg using emerge..."
sudo emerge --ask media-video/ffmpeg
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported Linux distribution.${reset}"
exit 1
;;
esac
log_message "INFO" "${green_fg_strong}FFmpeg is installed.${reset}"
else
log_message "INFO" "${blue_fg_strong}FFmpeg is already installed.${reset}"
fi
}
install_nodejs() {
if ! command -v node &> /dev/null; then
log_message "WARN" "${yellow_fg_strong}Node.js is not installed on this system${reset}"
case "$(uname -s)" in
Linux)
package_manager=$(detect_package_manager)
case "$package_manager" in
apt)
log_message "INFO" "Detected apt (Debian/Ubuntu). Installing Node.js..."
sudo apt update && sudo apt install -y nodejs npm
;;
dnf|yum)
log_message "INFO" "Detected dnf/yum (Red Hat/Fedora). Installing Node.js..."
sudo $package_manager install -y nodejs npm
;;
apk)
log_message "INFO" "Detected apk (Alpine). Installing Node.js..."
sudo apk add nodejs npm
;;
pacman)
log_message "INFO" "Detected pacman (Arch). Installing Node.js..."
sudo pacman -Sy --noconfirm nodejs npm
;;
emerge)
log_message "INFO" "Detected emerge (Gentoo). Installing Node.js..."
sudo emerge --ask nodejs npm
;;
zypper)
log_message "INFO" "Detected zypper (openSUSE). Installing Node.js..."
sudo zypper install -y nodejs npm
;;
xbps)
log_message "INFO" "Detected xbps (Void). Installing Node.js..."
sudo xbps-install -y nodejs npm
;;
nix)
log_message "INFO" "Detected nix (NixOS). Installing Node.js..."
nix-env -iA nixpkgs.nodejs
;;
guix)
log_message "INFO" "Detected guix (Guix). Installing Node.js..."
guix package -i node
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported package manager or distribution.${reset}"
exit 1
;;
esac
;;
Darwin)
log_message "INFO" "Detected macOS. Installing Node.js via Homebrew..."
if ! command -v brew &> /dev/null; then
log_message "ERROR" "${red_fg_strong}Homebrew not installed. Install it first: https://brew.sh/${reset}"
exit 1
fi
brew install node
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported operating system.${reset}"
exit 1
;;
esac
log_message "INFO" "${green_fg_strong}Node.js is installed.${reset}"
else
log_message "INFO" "${blue_fg_strong}Node.js is already installed.${reset}"
fi
}
install_yq() {
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_installer_core_utilities
}
install_vs_buildtools() {
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_installer_core_utilities
}
install_cuda_toolkit() {
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_installer_core_utilities
}
install_tailscale() {
if ! command -v tailscale &> /dev/null; then
log_message "WARN" "${yellow_fg_strong}Tailscale is not installed on this system${reset}"
# Ask the user if they have a Tailscale account
read -p "Do you have a Tailscale account? [Y/N]: " has_account
if [[ "$has_account" =~ ^[Nn]$ ]]; then
echo -e "${blue_fg_strong}Please create a Tailscale account at https://login.tailscale.com/start${reset}"
xdg-open "https://login.tailscale.com/start"
read -p "Press Enter after you have created an account to continue..."
fi
# Detect the package manager and install Tailscale
case "$(uname -s)" in
Linux)
package_manager=$(detect_package_manager)
case "$package_manager" in
apt)
log_message "INFO" "Detected apt (Debian/Ubuntu). Installing Tailscale..."
curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/$(lsb_release -cs).noarmor.gpg | sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null
curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/$(lsb_release -cs).tailscale-keyring.list | sudo tee /etc/apt/sources.list.d/tailscale.list
sudo apt update && sudo apt install -y tailscale
;;
dnf|yum)
log_message "INFO" "Detected dnf/yum (Red Hat/Fedora). Installing Tailscale..."
sudo dnf config-manager --add-repo https://pkgs.tailscale.com/stable/fedora/tailscale.repo
sudo dnf install -y tailscale
;;
apk)
log_message "INFO" "Detected apk (Alpine). Installing Tailscale..."
sudo apk add tailscale
;;
pacman)
log_message "INFO" "Detected pacman (Arch). Installing Tailscale..."
sudo pacman -Sy --noconfirm tailscale
;;
emerge)
log_message "INFO" "Detected emerge (Gentoo). Installing Tailscale..."
sudo emerge --ask net-vpn/tailscale
;;
zypper)
log_message "INFO" "Detected zypper (openSUSE). Installing Tailscale..."
sudo zypper addrepo https://pkgs.tailscale.com/stable/opensuse/tailscale.repo
sudo zypper refresh
sudo zypper install -y tailscale
;;
xbps)
log_message "INFO" "Detected xbps (Void). Installing Tailscale..."
sudo xbps-install -y tailscale
;;
nix)
log_message "INFO" "Detected nix (NixOS). Installing Tailscale..."
nix-env -iA nixpkgs.tailscale
;;
guix)
log_message "INFO" "Detected guix (Guix). Installing Tailscale..."
guix package -i tailscale
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported package manager or distribution.${reset}"
app_installer_core_utilities
;;
esac
;;
Darwin)
log_message "INFO" "Detected macOS. Installing Tailscale via Homebrew..."
if ! command -v brew &> /dev/null; then
log_message "ERROR" "${red_fg_strong}Homebrew not installed. Install it first: https://brew.sh/${reset}"
app_installer_core_utilities
fi
brew install tailscale
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported operating system.${reset}"
app_installer_core_utilities
;;
esac
# Start and enable Tailscale
if command -v tailscale &> /dev/null; then
log_message "INFO" "${green_fg_strong}Tailscale is installed. Starting Tailscale...${reset}"
sudo tailscale up
if [ $? -eq 0 ]; then
log_message "INFO" "${green_fg_strong}Tailscale is now running.${reset}"
else
log_message "ERROR" "${red_fg_strong}Failed to start Tailscale.${reset}"
fi
else
log_message "ERROR" "${red_fg_strong}Tailscale installation failed.${reset}"
fi
else
log_message "INFO" "${blue_fg_strong}Tailscale is already installed.${reset}"
fi
read -p "Press Enter to continue..."
app_installer_core_utilities
}
install_ngrok() {
if ! command -v ngrok &> /dev/null; then
log_message "WARN" "${yellow_fg_strong}ngrok is not installed on this system${reset}"
# Detect the operating system and architecture
case "$(uname -s)" in
Linux)
case "$(uname -m)" in
x86_64)
arch="amd64"
;;
armv7l|armv8l|aarch64)
arch="arm64"
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported architecture.${reset}"
exit 1
;;
esac
os="linux"
;;
Darwin)
case "$(uname -m)" in
x86_64)
arch="amd64"
;;
arm64)
arch="arm64"
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported architecture.${reset}"
app_installer_core_utilities
;;
esac
os="darwin"
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported operating system.${reset}"
app_installer_core_utilities
;;
esac
# Download and install ngrok
log_message "INFO" "Downloading ngrok for ${os}-${arch}..."
download_url="https://bin.equinox.io/c/bNyj1mQVY4c/ngrok-v3-stable-${os}-${arch}.tgz"
temp_dir=$(mktemp -d)
curl -fsSL "$download_url" -o "$temp_dir/ngrok.tgz"
if [ $? -ne 0 ]; then
log_message "ERROR" "${red_fg_strong}Failed to download ngrok.${reset}"
rm -rf "$temp_dir"
read -p "Press Enter to continue..."
app_installer_core_utilities
fi
log_message "INFO" "Installing ngrok..."
tar -xzf "$temp_dir/ngrok.tgz" -C "$temp_dir"
sudo mv "$temp_dir/ngrok" /usr/local/bin/ngrok
rm -rf "$temp_dir"
if command -v ngrok &> /dev/null; then
log_message "INFO" "${green_fg_strong}ngrok is installed.${reset}"
else
log_message "ERROR" "${red_fg_strong}Failed to install ngrok.${reset}"
read -p "Press Enter to continue..."
app_installer_core_utilities
fi
else
log_message "INFO" "${blue_fg_strong}ngrok is already installed.${reset}"
fi
# Authenticate ngrok if not already authenticated
if [ ! -f "$HOME/.config/ngrok/ngrok.yml" ]; then
log_message "INFO" "Authenticating ngrok..."
echo -e "${blue_fg_strong}Please visit https://dashboard.ngrok.com/signup to create an account if you don't have one.${reset}"
echo -e "${blue_fg_strong}After signing up, go to https://dashboard.ngrok.com/get-started/your-authtoken to get your authtoken.${reset}"
read -p "Enter your ngrok authtoken: " authtoken
ngrok config add-authtoken "$authtoken"
if [ $? -eq 0 ]; then
log_message "INFO" "${green_fg_strong}ngrok authenticated successfully.${reset}"
else
log_message "ERROR" "${red_fg_strong}Failed to authenticate ngrok.${reset}"
read -p "Press Enter to continue..."
app_installer_core_utilities
fi
else
log_message "INFO" "${blue_fg_strong}ngrok is already authenticated.${reset}"
fi
read -p "Press Enter to continue..."
app_installer_core_utilities
}
install_tabbyapi_menu() {
# Check if the tabbyapi folder exists and deactivate Conda environment if necessary
if [[ -d "$tabbyapi_install_path" ]]; then
log_message "INFO" "Deactivating Conda environment: tabbyapi"
conda deactivate
fi
clear
echo -e "${blue_fg_strong}| > / Home / Toolbox / App Installer / Text Completion / TabbyAPI |${reset}"
echo -e "${blue_fg_strong} =================================================================${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| What would you like to do? |${reset}"
echo " 1. Install TabbyAPI"
echo " 2. Install ST-tabbyAPI-loader Extension"
echo " 3. Models [Install Options]"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Back"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " app_installer_tabbyapi_choice
echo
# Handle user input
case "$app_installer_tabbyapi_choice" in
1)
if [[ -f "$app_installer_text_completion_dir/install_tabbyapi.sh" ]]; then
bash "$app_installer_text_completion_dir/install_tabbyapi.sh"
install_tabbyapi_menu
else
log_message "ERROR" "install_tabbyapi.sh not found in: $app_installer_text_completion_dir"
read -p "Press Enter to continue..."
install_tabbyapi_menu
fi
;;
2)
if [[ -f "$app_installer_text_completion_dir/install_tabbyapi_st_ext.sh" ]]; then
bash "$app_installer_text_completion_dir/install_tabbyapi_st_ext.sh"
install_tabbyapi_menu
else
log_message "ERROR" "install_tabbyapi_st_ext.sh not found in: $app_installer_text_completion_dir"
read -p "Press Enter to continue..."
install_tabbyapi_menu
fi
;;
3)
bash "$app_installer_text_completion_dir/install_tabbyapi_model_menu.sh"
install_tabbyapi_menu
;;
0)
app_installer_text_completion
;;
*)
log_message "ERROR" "Invalid input"
read -p "Press Enter to continue..."
install_tabbyapi_menu
;;
esac
}
app_installer_text_completion() {
echo -e "\033]0;STL [APP INSTALLER TEXT COMPLETION]\007"
clear
echo -e "${blue_fg_strong}| > / Home / Toolbox / App Installer / Text Completion |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| What would you like to do? |${reset}"
echo " 1. Install Text generation web UI oobabooga"
echo " 2. koboldcpp [Install options]"
echo " 3. TabbyAPI [Install options]"
echo " 4. Install llamacpp"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Back"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " app_installer_text_completion_choice
case "$app_installer_text_completion_choice" in
1)
if [[ -f "$app_installer_text_completion_dir/install_ooba.sh" ]]; then
bash "$app_installer_text_completion_dir/install_ooba.sh"
app_installer_text_completion
else
log_message "ERROR" "install_ooba.sh not found in: $app_installer_text_completion_dir"
read -p "Press Enter to continue..."
app_installer_text_completion
fi
;;
2)
install_koboldcpp_menu
;;
3)
install_tabbyapi_menu
;;
4)
if [[ -f "$app_installer_text_completion_dir/install_llamacpp.sh" ]]; then
bash "$app_installer_text_completion_dir/install_llamacpp.sh"
app_installer_text_completion
else
log_message "ERROR" "install_llamacpp.sh not found in: $app_installer_text_completion_dir"
read -p "Press Enter to continue..."
app_installer_text_completion
fi
;;
0)
app_installer
;;
*)
log_message "ERROR" "Invalid input"
read -p "Press Enter to continue..."
app_installer_text_completion
;;
esac
}
app_installer_voice_generation() {
echo -e "\033]0;STL [APP INSTALLER VOICE GENERATION]\007"
clear
echo -e "${blue_fg_strong}| > / Home / Toolbox / App Installer / Voice Generation |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| What would you like to do? |${reset}"
echo " 1. Install AllTalk V2"
echo " 2. Install AllTalk"
echo " 3. Install XTTS"
echo " 4. Install RVC"
echo " 5. Install RVC-Python"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Back"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " app_installer_voice_generation_choice
case "$app_installer_voice_generation_choice" in
1)
if [[ -f "$app_installer_voice_generation_dir/install_alltalk_v2.sh" ]]; then
bash "$app_installer_voice_generation_dir/install_alltalk_v2.sh"
app_installer_voice_generation
else
log_message "ERROR" "install_alltalk_v2.sh not found in: $app_installer_voice_generation_dir"
read -p "Press Enter to continue..."
app_installer_voice_generation
fi
;;
2)
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_installer_voice_generation
;;
3)
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_installer_voice_generation
;;
4)
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_installer_voice_generation
;;
5)
if [[ -f "$app_installer_voice_generation_dir/install_rvc_python.sh" ]]; then
bash "$app_installer_voice_generation_dir/install_rvc_python.sh"
app_installer_voice_generation
else
log_message "ERROR" "install_rvc_python.sh not found in: $app_installer_voice_generation_dir"
read -p "Press Enter to continue..."
app_installer_voice_generation
fi
;;
0)
app_installer
;;
*)
log_message "ERROR" "Invalid input"
read -p "Press Enter to continue..."
app_installer_voice_generation
;;
esac
}
app_installer_image_generation() {
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_installer
}
app_installer_core_utilities() {
echo -e "\033]0;STL [APP INSTALLER CORE UTILITIES]\007"
clear
echo -e "${blue_fg_strong}| > / Home / Toolbox / App Installer / Core Utilities |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| What would you like to do? |${reset}"
echo " 1. Install 7-Zip"
echo " 2. Install FFmpeg"
echo " 3. Install Node.js"
echo " 4. Install yq"
echo " 5. Install Visual Studio BuildTools"
echo " 6. Install CUDA Toolkit"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Remote Access & Tunneling |${reset}"
echo " 7. Install Tailscale"
echo " 8. Install ngrok"
echo " 9. Install Cloudflare Tunnel"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Back"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " app_installer_choice
case $app_installer_choice in
1) install_p7zip ;;
2) install_ffmpeg ;;
3) install_nodejs ;;
4) install_yq ;;
5) install_vs_buildtools ;;
6) install_cuda_toolkit ;;
7) install_tailscale ;;
8) install_ngrok ;;
9) start_st_remotelink ;;
0) app_installer ;;
*) echo -e "${yellow_fg_strong}WARNING: Invalid number. Please insert a valid number.${reset}"
read -p "Press Enter to continue..."
app_installer_core_utilities ;;
esac
}
############################################################
############## APP INSTALLER - FRONTEND ####################
############################################################
app_installer() {
echo -e "\033]0;STL [APP INSTALLER]\007"
clear
echo -e "${blue_fg_strong}| > / Home / Toolbox / App Installer |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| What would you like to do? |${reset}"
echo " 1. Text Completion"
echo " 2. Voice Generation"
echo " 3. Image Generation"
echo " 4. Core Utilities"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Back"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " app_installer_choice
################# APP INSTALLER - BACKEND ################
case $app_installer_choice in
1) app_installer_text_completion ;;
2) app_installer_voice_generation ;;
3) app_installer_image_generation ;;
4) app_installer_core_utilities ;;
0) toolbox ;;
*) echo -e "${yellow_fg_strong}WARNING: Invalid number. Please insert a valid number.${reset}"
read -p "Press Enter to continue..."
app_installer ;;
esac
}
########################################################################################
########################################################################################
####################### APP UNINSTALLER MENU FUNCTIONS ################################
########################################################################################
########################################################################################
# Function to uninstall Extras
uninstall_extras() {
echo
echo -e "${red_bg}╔════ DANGER ZONE ═══════════════════════════════════════════════════════════════════╗${reset}"
echo -e "${red_bg}║ WARNING: This will delete all data in Extras ║${reset}"
echo -e "${red_bg}║ If you want to keep any data, make sure to create a backup before proceeding. ║${reset}"
echo -e "${red_bg}╚════════════════════════════════════════════════════════════════════════════════════╝${reset}"
echo
echo -n "Are you sure you want to proceed? [Y/N]: "
read confirmation
if [ "$confirmation" = "Y" ] || [ "$confirmation" = "y" ]; then
log_message "INFO" "Removing the SillyTavern-extras directory..."
rm -rf SillyTavern-extras
log_message "INFO" "Removing the Conda environment: extras"
conda remove --name extras --all -y
log_message "INFO" "${green_fg_strong}Extras uninstalled successfully.${reset}"
else
echo "Uninstall canceled."
fi
pause
app_uninstaller
}
# Function to uninstall XTTS
uninstall_xtts() {
echo
echo -e "${red_bg}╔════ DANGER ZONE ═══════════════════════════════════════════════════════════════════╗${reset}"
echo -e "${red_bg}║ WARNING: This will delete all data in XTTS ║${reset}"
echo -e "${red_bg}║ If you want to keep any data, make sure to create a backup before proceeding. ║${reset}"
echo -e "${red_bg}╚════════════════════════════════════════════════════════════════════════════════════╝${reset}"
echo
echo -n "Are you sure you want to proceed? [Y/N]: "
read confirmation
if [ "$confirmation" = "Y" ] || [ "$confirmation" = "y" ]; then
log_message "INFO" "Removing the xtts directory..."
rm -rf xtts
log_message "INFO" "Removing the Conda environment: xtts"
conda remove --name xtts --all -y
log_message "INFO" "${green_fg_strong}XTTS uninstalled successfully.${reset}"
else
echo "Uninstall canceled."
fi
pause
app_uninstaller
}
# Function to uninstall SillyTavern
uninstall_st() {
echo
echo -e "${red_bg}╔════ DANGER ZONE ═══════════════════════════════════════════════════════════════════╗${reset}"
echo -e "${red_bg}║ WARNING: This will delete all data in SillyTavern ║${reset}"
echo -e "${red_bg}║ If you want to keep any data, make sure to create a backup before proceeding. ║${reset}"
echo -e "${red_bg}╚════════════════════════════════════════════════════════════════════════════════════╝${reset}"
echo
echo -n "Are you sure you want to proceed? [Y/N]: "
read confirmation
if [ "$confirmation" = "Y" ] || [ "$confirmation" = "y" ]; then
log_message "INFO" "Removing the SillyTavern directory..."
rm -rf "$st_install_path"
log_message "INFO" "${green_fg_strong}SillyTavern uninstalled successfully.${reset}"
else
echo "Uninstall canceled."
fi
read -p "Press Enter to continue..."
app_uninstaller_core_utilities
}
uninstall_p7zip() {
if command -v 7z &> /dev/null; then
log_message "INFO" "${blue_fg_strong}Uninstalling p7zip (7-Zip)...${reset}"
case "$(uname -s)" in
Linux)
package_manager=$(detect_package_manager)
case "$package_manager" in
apt)
sudo apt remove -y p7zip p7zip-full
;;
dnf|yum)
sudo $package_manager remove -y p7zip p7zip-plugins
;;
apk)
sudo apk del p7zip
;;
pacman)
sudo pacman -Rns --noconfirm p7zip
;;
emerge)
sudo emerge --unmerge p7zip
;;
zypper)
sudo zypper remove -y p7zip
;;
xbps)
sudo xbps-remove -y p7zip
;;
nix)
nix-env -e p7zip
;;
guix)
guix package -r p7zip
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported package manager or distribution.${reset}"
app_uninstaller_core_utilities
;;
esac
;;
Darwin)
if command -v brew &> /dev/null; then
brew uninstall p7zip
else
log_message "ERROR" "${red_fg_strong}Homebrew not installed.${reset}"
app_uninstaller_core_utilities
fi
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported operating system.${reset}"
app_uninstaller_core_utilities
;;
esac
if ! command -v 7z &> /dev/null; then
log_message "INFO" "${green_fg_strong}p7zip (7-Zip) has been successfully uninstalled.${reset}"
else
log_message "ERROR" "${red_fg_strong}Failed to uninstall p7zip (7-Zip).${reset}"
app_uninstaller_core_utilities
fi
else
log_message "INFO" "${blue_fg_strong}p7zip (7-Zip) is not installed.${reset}"
fi
read -p "Press Enter to continue..."
app_uninstaller_core_utilities
}
uninstall_ffmpeg() {
if command -v ffmpeg &> /dev/null; then
log_message "INFO" "${blue_fg_strong}Uninstalling FFmpeg...${reset}"
case "$(uname -s)" in
Linux)
package_manager=$(detect_package_manager)
case "$package_manager" in
apt)
sudo apt remove -y ffmpeg
;;
dnf|yum)
sudo $package_manager remove -y ffmpeg
;;
apk)
sudo apk del ffmpeg
;;
pacman)
sudo pacman -Rns --noconfirm ffmpeg
;;
emerge)
sudo emerge --unmerge ffmpeg
;;
zypper)
sudo zypper remove -y ffmpeg
;;
xbps)
sudo xbps-remove -y ffmpeg
;;
nix)
nix-env -e ffmpeg
;;
guix)
guix package -r ffmpeg
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported package manager or distribution.${reset}"
app_uninstaller_core_utilities
;;
esac
;;
Darwin)
if command -v brew &> /dev/null; then
brew uninstall ffmpeg
else
log_message "ERROR" "${red_fg_strong}Homebrew not installed.${reset}"
app_uninstaller_core_utilities
fi
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported operating system.${reset}"
app_uninstaller_core_utilities
;;
esac
if ! command -v ffmpeg &> /dev/null; then
log_message "INFO" "${green_fg_strong}FFmpeg has been successfully uninstalled.${reset}"
else
log_message "ERROR" "${red_fg_strong}Failed to uninstall FFmpeg.${reset}"
app_uninstaller_core_utilities
fi
else
log_message "INFO" "${blue_fg_strong}FFmpeg is not installed.${reset}"
fi
read -p "Press Enter to continue..."
app_uninstaller_core_utilities
}
uninstall_nodejs() {
echo -e "\033]0;STL [UNINSTALL NODEJS]\007"
if command -v node &> /dev/null; then
log_message "INFO" "${blue_fg_strong}Uninstalling Node.js...${reset}"
rm -rf /usr/local/bin/npm
rm -rf /usr/local/share/man/man1/node*
rm -rf /usr/local/lib/dtrace/node.d
rm -rf ~/.npm
rm -rf ~/.node-gyp
rm -rf /opt/local/bin/node
rm -rf /opt/local/include/node
rm -rf /opt/local/lib/node_modules
rm -rf /usr/local/lib/node*
rm -rf /usr/local/include/node*
rm -rf /usr/local/bin/node*
case "$(uname -s)" in
Linux)
package_manager=$(detect_package_manager)
case "$package_manager" in
apt)
sudo apt remove -y nodejs npm
;;
dnf|yum)
sudo $package_manager remove -y nodejs npm
;;
apk)
sudo apk del nodejs npm
;;
pacman)
sudo pacman -Rns --noconfirm nodejs npm
;;
emerge)
sudo emerge --unmerge nodejs
;;
zypper)
sudo zypper remove -y nodejs npm
;;
xbps)
sudo xbps-remove -y nodejs npm
;;
nix)
nix-env -e nodejs
;;
guix)
guix package -r node
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported package manager or distribution.${reset}"
exit 1
;;
esac
;;
Darwin)
if command -v brew &> /dev/null; then
brew uninstall node
else
log_message "ERROR" "${red_fg_strong}Homebrew not installed.${reset}"
exit 1
fi
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported operating system.${reset}"
exit 1
;;
esac
if ! command -v node &> /dev/null; then
log_message "INFO" "${green_fg_strong}Node.js successfully uninstalled.${reset}"
fi
else
log_message "INFO" "${blue_fg_strong}Node.js is not installed.${reset}"
fi
read -p "Press Enter to continue..."
app_uninstaller_core_utilities
}
uninstall_git() {
if command -v git &> /dev/null; then
log_message "INFO" "${blue_fg_strong}Uninstalling Git...${reset}"
case "$(uname -s)" in
Linux)
package_manager=$(detect_package_manager)
case "$package_manager" in
apt)
sudo apt remove -y git
;;
dnf|yum)
sudo $package_manager remove -y git
;;
apk)
sudo apk del git
;;
pacman)
sudo pacman -Rns --noconfirm git
;;
emerge)
sudo emerge --unmerge dev-vcs/git
;;
zypper)
sudo zypper remove -y git
;;
xbps)
sudo xbps-remove -y git
;;
nix)
nix-env -e git
;;
guix)
guix package -r git
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported package manager or distribution.${reset}"
app_uninstaller_core_utilities
;;
esac
;;
Darwin)
if command -v brew &> /dev/null; then
brew uninstall git
else
log_message "ERROR" "${red_fg_strong}Homebrew not installed.${reset}"
app_uninstaller_core_utilities
fi
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported operating system.${reset}"
app_uninstaller_core_utilities
;;
esac
if ! command -v git &> /dev/null; then
log_message "INFO" "${green_fg_strong}Git has been successfully uninstalled.${reset}"
else
log_message "ERROR" "${red_fg_strong}Failed to uninstall Git.${reset}"
app_uninstaller_core_utilities
fi
else
log_message "INFO" "${blue_fg_strong}Git is not installed.${reset}"
fi
read -p "Press Enter to continue..."
app_uninstaller_core_utilities
}
uninstall_tailscale() {
if command -v tailscale &> /dev/null; then
log_message "INFO" "${blue_fg_strong}Uninstalling Tailscale...${reset}"
# Stop Tailscale service
if systemctl is-active --quiet tailscaled; then
log_message "INFO" "Stopping Tailscale service..."
sudo systemctl stop tailscaled
fi
# Disable Tailscale service
if systemctl is-enabled --quiet tailscaled; then
log_message "INFO" "Disabling Tailscale service..."
sudo systemctl disable tailscaled
fi
# Remove Tailscale binary and configuration files
case "$(uname -s)" in
Linux)
package_manager=$(detect_package_manager)
case "$package_manager" in
apt)
sudo apt remove -y tailscale
;;
dnf|yum)
sudo $package_manager remove -y tailscale
;;
apk)
sudo apk del tailscale
;;
pacman)
sudo pacman -R --noconfirm tailscale
;;
emerge)
sudo emerge --ask --depclean net-vpn/tailscale
;;
zypper)
sudo zypper remove -y tailscale
;;
xbps)
sudo xbps-remove -y tailscale
;;
nix)
nix-env -e tailscale
;;
guix)
guix package -r tailscale
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported package manager or distribution.${reset}"
app_uninstaller_core_utilities
;;
esac
;;
Darwin)
if command -v brew &> /dev/null; then
brew uninstall tailscale
else
log_message "ERROR" "${red_fg_strong}Homebrew not installed.${reset}"
app_uninstaller_core_utilities
fi
;;
*)
log_message "ERROR" "${red_fg_strong}Unsupported operating system.${reset}"
app_uninstaller_core_utilities
;;
esac
# Remove Tailscale configuration files
if [ -d "/var/lib/tailscale" ]; then
log_message "INFO" "Removing Tailscale configuration files..."
sudo rm -rf /var/lib/tailscale
fi
if ! command -v tailscale &> /dev/null; then
log_message "INFO" "${green_fg_strong}Tailscale has been successfully uninstalled.${reset}"
else
log_message "ERROR" "${red_fg_strong}Failed to uninstall Tailscale.${reset}"
app_uninstaller_core_utilities
fi
else
log_message "INFO" "${blue_fg_strong}Tailscale is not installed.${reset}"
fi
read -p "Press Enter to continue..."
app_uninstaller_core_utilities
}
uninstall_ngrok() {
if command -v ngrok &> /dev/null; then
log_message "INFO" "${blue_fg_strong}Uninstalling ngrok...${reset}"
# Remove the ngrok binary
sudo rm -f /usr/local/bin/ngrok
# Remove ngrok configuration files
if [ -d "$HOME/.config/ngrok" ]; then
log_message "INFO" "Removing ngrok configuration files..."
rm -rf "$HOME/.config/ngrok"
fi
if ! command -v ngrok &> /dev/null; then
log_message "INFO" "${green_fg_strong}ngrok has been successfully uninstalled.${reset}"
else
log_message "ERROR" "${red_fg_strong}Failed to uninstall ngrok.${reset}"
app_uninstaller_core_utilities
fi
else
log_message "INFO" "${blue_fg_strong}ngrok is not installed.${reset}"
fi
read -p "Press Enter to continue..."
app_uninstaller_core_utilities
}
app_uninstaller_text_completion() {
clear
echo -e "${blue_fg_strong}| > / Home / Toolbox / App Uninstaller / Text Completion |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| What would you like to do? |${reset}"
echo " 1. UNINSTALL Text generation web UI oobabooga"
echo " 2. UNINSTALL koboldcpp"
echo " 3. UNINSTALL TabbyAPI"
echo " 4. UNINSTALL llamacpp"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Back"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " app_uninstaller_text_completion_choice
echo
# Handle user input
case "$app_uninstaller_text_completion_choice" in
1)
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_uninstaller_text_completion
if [[ -f "$app_uninstaller_text_completion_dir/uninstall_ooba.sh" ]]; then
bash "$app_uninstaller_text_completion_dir/uninstall_ooba.sh"
app_uninstaller_text_completion
else
log_message "ERROR" "uninstall_ooba.sh not found in: $app_uninstaller_text_completion_dir"
log_message "INFO" "Running Automatic Repair..."
git pull
read -p "Press Enter to continue..."
app_uninstaller_text_completion
fi
;;
2)
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_uninstaller_text_completion
if [[ -f "$app_uninstaller_text_completion_dir/uninstall_koboldcpp.sh" ]]; then
bash "$app_uninstaller_text_completion_dir/uninstall_koboldcpp.sh"
app_uninstaller_text_completion
else
log_message "ERROR" "uninstall_koboldcpp.sh not found in: $app_uninstaller_text_completion_dir"
log_message "INFO" "Running Automatic Repair..."
git pull
read -p "Press Enter to continue..."
app_uninstaller_text_completion
fi
;;
3)
if [[ -f "$app_uninstaller_text_completion_dir/uninstall_tabbyapi.sh" ]]; then
bash "$app_uninstaller_text_completion_dir/uninstall_tabbyapi.sh"
app_uninstaller_text_completion
else
log_message "ERROR" "uninstall_tabbyapi.sh not found in: $app_uninstaller_text_completion_dir"
log_message "INFO" "Running Automatic Repair..."
git pull
read -p "Press Enter to continue..."
app_uninstaller_text_completion
fi
;;
4)
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_uninstaller_text_completion
if [[ -f "$app_uninstaller_text_completion_dir/uninstall_llamacpp.sh" ]]; then
bash "$app_uninstaller_text_completion_dir/uninstall_llamacpp.sh"
app_uninstaller_text_completion
else
log_message "ERROR" "uninstall_llamacpp.sh not found in: $app_uninstaller_text_completion_dir"
log_message "INFO" "Running Automatic Repair..."
git pull
read -p "Press Enter to continue..."
app_uninstaller_text_completion
fi
;;
0)
app_uninstaller
;;
*)
log_message "ERROR" "Invalid input"
read -p "Press Enter to continue..."
app_uninstaller_text_completion
;;
esac
}
app_uninstaller_voice_generation() {
clear
echo -e "${blue_fg_strong}| > / Home / Toolbox / App Uninstaller / Voice Generation |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| What would you like to do? |${reset}"
echo " 1. UNINSTALL AllTalk V2"
echo " 2. UNINSTALL AllTalk"
echo " 3. UNINSTALL XTTS"
echo " 4. UNINSTALL RVC"
echo " 5. UNINSTALL RVC-Python"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Back"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " app_uninstaller_voice_generation_choice
echo
# Handle user input
case "$app_uninstaller_voice_generation_choice" in
1)
if [[ -f "$app_uninstaller_voice_generation_dir/uninstall_alltalk_v2.sh" ]]; then
bash "$app_uninstaller_voice_generation_dir/uninstall_alltalk_v2.sh"
app_uninstaller_voice_generation
else
log_message "ERROR" "uninstall_alltalk_v2.sh not found in: $app_uninstaller_voice_generation_dir"
log_message "INFO" "Running Automatic Repair..."
git pull
read -p "Press Enter to continue..."
app_uninstaller_voice_generation
fi
;;
2)
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_uninstaller_voice_generation
if [[ -f "$app_uninstaller_voice_generation_dir/uninstall_alltalk.sh" ]]; then
bash "$app_uninstaller_voice_generation_dir/uninstall_alltalk.sh"
app_uninstaller_voice_generation
else
log_message "ERROR" "uninstall_alltalk.sh not found in: $app_uninstaller_voice_generation_dir"
log_message "INFO" "Running Automatic Repair..."
git pull
read -p "Press Enter to continue..."
app_uninstaller_voice_generation
fi
;;
3)
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_uninstaller_voice_generation
if [[ -f "$app_uninstaller_voice_generation_dir/uninstall_xtts.sh" ]]; then
bash "$app_uninstaller_voice_generation_dir/uninstall_xtts.sh"
app_uninstaller_voice_generation
else
log_message "ERROR" "uninstall_xtts.sh not found in: $app_uninstaller_voice_generation_dir"
log_message "INFO" "Running Automatic Repair..."
git pull
read -p "Press Enter to continue..."
app_uninstaller_voice_generation
fi
;;
4)
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_uninstaller_voice_generation
if [[ -f "$app_uninstaller_voice_generation_dir/uninstall_rvc.sh" ]]; then
bash "$app_uninstaller_voice_generation_dir/uninstall_rvc.sh"
app_uninstaller_voice_generation
else
log_message "ERROR" "uninstall_rvc.sh not found in: $app_uninstaller_voice_generation_dir"
log_message "INFO" "Running Automatic Repair..."
git pull
read -p "Press Enter to continue..."
app_uninstaller_voice_generation
fi
;;
5)
if [[ -f "$app_uninstaller_voice_generation_dir/uninstall_rvc_python.sh" ]]; then
bash "$app_uninstaller_voice_generation_dir/uninstall_rvc_python.sh"
app_uninstaller_voice_generation
else
log_message "ERROR" "uninstall_rvc_python.sh not found in: $app_uninstaller_voice_generation_dir"
log_message "INFO" "Running Automatic Repair..."
git pull
read -p "Press Enter to continue..."
app_uninstaller_voice_generation
fi
;;
0)
app_uninstaller
;;
*)
log_message "ERROR" "Invalid input"
read -p "Press Enter to continue..."
app_uninstaller_voice_generation
;;
esac
}
app_uninstaller_image_generation() {
clear
echo -e "${blue_fg_strong}| > / Home / Toolbox / App Uninstaller / Image Generation |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| What would you like to do? |${reset}"
echo " 1. UNINSTALL Stable Diffusion WebUI"
echo " 2. UNINSTALL Stable Diffusion WebUI Forge"
echo " 3. UNINSTALL ComfyUI"
echo " 4. UNINSTALL Fooocus"
echo " 5. UNINSTALL InvokeAI"
echo " 6. UNINSTALL Ostris AI Toolkit"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Back"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " app_uninstaller_image_generation_choice
echo
# Handle user input
case "$app_uninstaller_image_generation_choice" in
1)
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_uninstaller_image_generation
if [[ -f "$app_uninstaller_image_generation_dir/uninstall_sdwebui.sh" ]]; then
bash "$app_uninstaller_image_generation_dir/uninstall_sdwebui.sh"
app_uninstaller_image_generation
else
log_message "ERROR" "uninstall_sdwebui.sh not found in: $app_uninstaller_image_generation_dir"
log_message "INFO" "Running Automatic Repair..."
git pull
read -p "Press Enter to continue..."
app_uninstaller_image_generation
fi
;;
2)
if [[ -f "$app_uninstaller_image_generation_dir/uninstall_sdwebuiforge.sh" ]]; then
bash "$app_uninstaller_image_generation_dir/uninstall_sdwebuiforge.sh"
app_uninstaller_image_generation
else
log_message "ERROR" "uninstall_sdwebuiforge.sh not found in: $app_uninstaller_image_generation_dir"
log_message "INFO" "Running Automatic Repair..."
git pull
read -p "Press Enter to continue..."
app_uninstaller_image_generation
fi
;;
3)
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_uninstaller_image_generation
if [[ -f "$app_uninstaller_image_generation_dir/uninstall_comfyui.sh" ]]; then
bash "$app_uninstaller_image_generation_dir/uninstall_comfyui.sh"
app_uninstaller_image_generation
else
log_message "ERROR" "uninstall_comfyui.sh not found in: $app_uninstaller_image_generation_dir"
log_message "INFO" "Running Automatic Repair..."
git pull
read -p "Press Enter to continue..."
app_uninstaller_image_generation
fi
;;
4)
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_uninstaller_image_generation
if [[ -f "$app_uninstaller_image_generation_dir/uninstall_fooocus.sh" ]]; then
bash "$app_uninstaller_image_generation_dir/uninstall_fooocus.sh"
app_uninstaller_image_generation
else
log_message "ERROR" "uninstall_fooocus.sh not found in: $app_uninstaller_image_generation_dir"
log_message "INFO" "Running Automatic Repair..."
git pull
read -p "Press Enter to continue..."
app_uninstaller_image_generation
fi
;;
5)
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_uninstaller_image_generation
if [[ -f "$app_uninstaller_image_generation_dir/uninstall_invokeai.sh" ]]; then
bash "$app_uninstaller_image_generation_dir/uninstall_invokeai.sh"
app_uninstaller_image_generation
else
log_message "ERROR" "uninstall_invokeai.sh not found in: $app_uninstaller_image_generation_dir"
log_message "INFO" "Running Automatic Repair..."
git pull
read -p "Press Enter to continue..."
app_uninstaller_image_generation
fi
;;
6)
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
app_uninstaller_image_generation
if [[ -f "$app_uninstaller_image_generation_dir/uninstall_ostris_aitoolkit.sh" ]]; then
bash "$app_uninstaller_image_generation_dir/uninstall_ostris_aitoolkit.sh"
app_uninstaller_image_generation
else
log_message "ERROR" "uninstall_ostris_aitoolkit.sh not found in: $app_uninstaller_image_generation_dir"
log_message "INFO" "Running Automatic Repair..."
git pull
read -p "Press Enter to continue..."
app_uninstaller_image_generation
fi
;;
0)
app_uninstaller
;;
*)
log_message "ERROR" "Invalid input"
read -p "Press Enter to continue..."
app_uninstaller_image_generation
;;
esac
}
app_uninstaller_core_utilities() {
echo -e "\033]0;STL [APP UNINSTALLER CORE UTILITIES]\007"
clear
echo -e "${blue_fg_strong}| > / Home / Toolbox / App Uninstaller / Core Utilities |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| What would you like to do? |${reset}"
echo " 1. UNINSTALL Extras"
echo " 2. UNINSTALL SillyTavern"
echo " 3. UNINSTALL 7-Zip"
echo " 4. UNINSTALL FFmpeg"
echo " 5. UNINSTALL Node.js"
echo " 6. UNINSTALL yq"
echo " 7. UNINSTALL Visual Studio BuildTools"
echo " 8. UNINSTALL CUDA Toolkit"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Remote Access & Tunneling |${reset}"
echo " 9. UNINSTALL Tailscale"
echo " 10. UNINSTALL ngrok"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Back"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " app_uninstaller_choice
case $app_uninstaller_choice in
1) uninstall_extras ;;
2) uninstall_st ;;
3) uninstall_p7zip ;;
4) uninstall_ffmpeg ;;
5) uninstall_nodejs ;;
6) uninstall_yq ;;
7) uninstall_vs_buildtools ;;
8) uninstall_cuda_toolkit ;;
9) uninstall_tailscale ;;
10) uninstall_ngrok ;;
0) app_uninstaller ;;
*) echo -e "${yellow_fg_strong}WARNING: Invalid number. Please insert a valid number.${reset}"
read -p "Press Enter to continue..."
app_uninstaller_core_utilities ;;
esac
}
############################################################
############## APP UNINSTALLER - FRONTEND ##################
############################################################
app_uninstaller() {
echo -e "\033]0;STL [APP UNINSTALLER]\007"
clear
echo -e "${blue_fg_strong}| > / Home / Toolbox / App Uninstaller |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| What would you like to do? |${reset}"
echo " 1. Text Completion"
echo " 2. Voice Generation"
echo " 3. Image Generation"
echo " 4. Core Utilities"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Back"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " app_uninstaller_choice
################# APP UNINSTALLER - BACKEND ################
case $app_uninstaller_choice in
1) app_uninstaller_text_completion ;;
2) app_uninstaller_voice_generation ;;
3) app_uninstaller_image_generation ;;
4) app_uninstaller_core_utilities ;;
0) toolbox ;;
*) echo -e "${yellow_fg_strong}WARNING: Invalid number. Please insert a valid number.${reset}"
read -p "Press Enter to continue..."
app_uninstaller ;;
esac
}
############################################################
################# TOOLBOX - FRONTEND #######################
############################################################
toolbox() {
echo -e "\033]0;STL [TOOLBOX]\007"
clear
echo -e "${blue_fg_strong}| > / Home / Toolbox |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| What would you like to do? |${reset}"
echo " 1. App Launcher"
echo " 2. App Installer"
echo " 3. App Uninstaller"
echo " 4. Editor"
echo " 5. Backup"
echo " 6. Switch Branch"
echo " 7. Reset Custom Shortcut"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Back"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Choose Your Destiny: " toolbox_choice
################# TOOLBOX - BACKEND #######################
case $toolbox_choice in
1) app_launcher ;;
2) app_installer ;;
3) app_uninstaller ;;
4) editor ;;
5) backup ;;
6) switch_branch ;;
7) reset_custom_shortcut ;;
0) home ;;
*) echo -e "${yellow_fg_strong}WARNING: Invalid number. Please insert a valid number.${reset}"
read -p "Press Enter to continue..."
toolbox ;;
esac
}
########################################################################################
########################################################################################
####################### STARTUP CHECK FUNCTIONS #######################################
########################################################################################
########################################################################################
# Function to detect package manager
detect_package_manager() {
local package_manager
case "$(true; command -v apt dnf yum apk pacman emerge zypper xbps-install guix nix-env 2>/dev/null | head -n1)" in
*apt) package_manager="apt" ;;
*dnf) package_manager="dnf" ;;
*yum) package_manager="yum" ;;
*apk) package_manager="apk" ;;
*pacman) package_manager="pacman" ;;
*emerge) package_manager="emerge" ;;
*zypper) package_manager="zypper" ;;
*xbps-install) package_manager="xbps" ;;
*guix) package_manager="guix" ;;
*nix-env) package_manager="nix" ;;
*)
if [ -f /etc/os-release ]; then
os_id=$(grep -E '^ID=' /etc/os-release | cut -d= -f2 | tr -d '"')
case "$os_id" in
almalinux|centos_stream|ol|rhel|rocky|fedora|fedoraremixforwsl|nobara)
package_manager="yum" ;;
alpine|wolfi)
package_manager="apk" ;;
arch|arch32|archcraft|arcolinux|arkane|artix|aurora|bazzite|blackarch|blendos|bluefin|bodhi|cachyos|chimera|chimeraos|endeavouros|garuda|hyperbola|kaos|manjaro|manjaro-arm|rebornos|steamos|void)
package_manager="pacman" ;;
debian|devuan|elementary|kali|linuxmint|parrot|pika|pisilinux|pop|pureos|raspbian|tails|ubuntu|ubuntu_kylin|vanillaos|zorin)
package_manager="apt" ;;
opensuse-leap|opensuse-tumbleweed|sled|sles)
package_manager="zypper" ;;
gentoo|funtoo)
package_manager="emerge" ;;
nixos)
package_manager="nix" ;;
guix)
package_manager="guix" ;;
clear-linux-os|miraclelinux|photon|solus|tencentos|tinycore|trisquel|ultramarine)
package_manager="unknown" ;; # Custom handling needed
*)
package_manager="unknown" ;;
esac
else
package_manager="unknown"
fi
;;
esac
echo "$package_manager"
}
# Function to create the logs folder if it doesn't exist
create_logs_folder() {
if [ ! -d "$log_dir" ]; then
mkdir -p "$log_dir"
log_message "INFO" "Created logs directory: $log_dir"
fi
}
# Function to check if the folder path has no spaces
check_path_spaces() {
if [[ "$PWD" =~ [[:space:]] ]]; then
log_message "ERROR" "${red_fg_strong}Path cannot have spaces! Please remove them or replace with: - ${reset}"
log_message "ERROR" "Folders containing spaces make the launcher unstable."
log_message "ERROR" "Path: ${red_fg_strong}$PWD${reset}"
exit 1
fi
}
# Function to check if the folder path has no special characters
check_path_special_chars() {
if [[ "$PWD" =~ [\!\#\$\%\&\*\+\,\;\<\=\>\?\@\[\]\^\`\{\|\}\~] ]]; then
log_message "ERROR" "${red_fg_strong}Path cannot have special characters! Please remove them.${reset}"
log_message "ERROR" "Folders containing special characters make the launcher unstable."
log_message "ERROR" "Path: ${red_fg_strong}$PWD${reset}"
exit 1
fi
}
# Function to check for updates in the launcher
check_launcher_updates() {
log_message "INFO" "Checking for updates..."
git fetch origin
current_branch=$(git branch --show-current)
if [ "$(git rev-list HEAD..origin/$current_branch)" ]; then
log_message "INFO" "${cyan_fg_strong}New update for SillyTavern-Launcher is available!${reset}"
read -p "Update now? [Y/n]: " update_choice
update_choice=${update_choice:-Y}
if [[ "$update_choice" =~ ^[Yy]$ ]]; then
log_message "INFO" "Updating the repository..."
git pull
log_message "INFO" "${green_fg_strong}SillyTavern-Launcher updated successfully. Restarting launcher...${reset}"
sleep 10
exec ./launcher.sh
exit
fi
else
log_message "INFO" "${green_fg_strong}SillyTavern-Launcher is up to date.${reset}"
fi
}
# Function to create necessary directories
create_directories() {
if [ ! -d "$bin_dir" ]; then
mkdir -p "$bin_dir"
log_message "INFO" "Created folder: $bin_dir"
fi
if [ ! -d "$functions_dir" ]; then
mkdir -p "$functions_dir"
log_message "INFO" "Created folder: $functions_dir"
fi
if [ ! -d "$log_dir" ]; then
mkdir -p "$log_dir"
log_message "INFO" "Created folder: $log_dir"
fi
}
# Function to create empty module files if they don't exist
create_module_files() {
modules=("extras" "xtts" "sdwebui" "ooba" "tabbyapi")
for module in "${modules[@]}"; do
module_path="$bin_dir/settings/modules-$module.txt"
if [ ! -f "$module_path" ]; then
touch "$module_path"
log_message "INFO" "Created text file: modules-$module.txt"
fi
done
}
# Function to check if Miniconda3 is installed
check_miniconda() {
# Try to find Miniconda installation
miniconda_path=$(find_conda)
if [ $? -ne 0 ]; then
log_message "WARN" "${yellow_fg_strong}Miniconda3 is not installed on this system.${reset}"
log_message "INFO" "Please install Miniconda3 manually from https://docs.conda.io/en/latest/miniconda.html"
return 1
fi
# Source Conda initialization script
if [ -f "${miniconda_path}/etc/profile.d/conda.sh" ]; then
source "${miniconda_path}/etc/profile.d/conda.sh"
else
log_message "ERROR" "${red_fg_strong}Conda initialization script not found at ${miniconda_path}/etc/profile.d/conda.sh${reset}"
log_message "INFO" "Please ensure Miniconda3 is properly installed from https://docs.conda.io/en/latest/miniconda.html"
return 1
fi
# Check if conda command is available
if ! command -v conda &> /dev/null; then
log_message "ERROR" "${red_fg_strong}Conda command not available after initialization.${reset}"
log_message "INFO" "Please ensure Miniconda3 is properly installed from https://docs.conda.io/en/latest/miniconda.html"
return 1
fi
log_message "INFO" "${blue_fg_strong}Miniconda3 is installed at ${miniconda_path}${reset}"
return 0
}
# Function to check if SillyTavern folder exists
check_sillytavern_folder() {
if [ ! -d "$st_install_path" ]; then
log_message "ERROR" "${red_fg_strong}SillyTavern not found in: $st_install_path${reset}"
read -p "Press Enter to run the install.sh script"
./install.sh
fi
}
# Function to check for updates in SillyTavern
check_sillytavern_updates() {
cd "$st_install_path" || { log_message "ERROR" "${red_fg_strong}Failed to change directory to SillyTavern.${reset}"; exit 1; }
log_message "INFO" "Checking for SillyTavern updates..."
git fetch origin
if [ "$(git rev-list HEAD..origin/$(git branch --show-current))" ]; then
log_message "INFO" "${cyan_fg_strong}New update for SillyTavern is available!${reset}"
read -p "Update now? [Y/n]: " update_choice
update_choice=${update_choice:-Y}
if [[ "$update_choice" =~ ^[Yy]$ ]]; then
log_message "INFO" "Updating SillyTavern..."
git pull
log_message "INFO" "${green_fg_strong}SillyTavern updated successfully.${reset}"
fi
else
log_message "INFO" "${green_fg_strong}SillyTavern is up to date.${reset}"
fi
}
########################################################################################
########################################################################################
####################### DISPLAY STATUS FUNCTIONS ######################################
########################################################################################
########################################################################################
# Function to get the current Git branch
get_current_branch() {
current_st_branch=$(git -C "$st_install_path" branch --show-current)
}
# Function to manage the GPU info counter
manage_gpu_counter() {
counter_file="$log_dir/gpu_counter.txt"
if [ -f "$counter_file" ]; then
counter=$(cat "$counter_file")
counter=$((counter + 1))
else
counter=1
fi
if [ "$counter" -ge 10 ]; then
counter=0
rm -f "$log_dir/gpu_info_output.txt"
fi
echo "$counter" > "$counter_file"
}
# Function to detect GPU info
detect_gpu_info() {
if [ ! -f "$log_dir/gpu_info_output.txt" ]; then
"$troubleshooting_dir/gpu_info.sh" > "$log_dir/gpu_info_output.txt"
fi
if [ -f "$log_dir/gpu_info_output.txt" ]; then
gpuInfo=$(cat "$log_dir/gpu_info_output.txt")
else
gpuInfo="GPU Info not found"
fi
}
# Function to read Tailscale status
read_tailscale_status() {
if [ -f "$log_dir/tailscale_status.txt" ]; then
count=0
while IFS= read -r line; do
count=$((count + 1))
case $count in
1) ip4="$line" ;;
2) hostName="$line" ;;
3) dnsName="$line" ;;
esac
done < "$log_dir/tailscale_status.txt"
# Remove trailing period from dnsName if it exists
if [[ "$dnsName" == *. ]]; then
dnsName="${dnsName%.}"
fi
fi
}
# Function to get SillyTavern version from package.json
get_sillytavern_version() {
if [ -f "$st_package_json_path" ]; then
st_version=$(grep -oP '"version": "\K[^"]+' "$st_package_json_path")
else
st_version="${red_fg_strong}[ERROR] Cannot get ST version because package.json file not found in $st_install_path${reset}"
fi
}
# Function to display version and compatibility status
display_version_status() {
echo -e "${yellow_fg_strong} ______________________________________________________________${reset}"
echo -e "${yellow_fg_strong}| Version & Compatibility Status: |${reset}"
echo -e " SillyTavern - Branch: ${cyan_fg_strong}$current_st_branch ${reset}| Status: ${cyan_fg_strong}$update_status_st${reset}"
echo -e " SillyTavern: ${cyan_fg_strong}$st_version${reset}"
echo -e " STL: ${cyan_fg_strong}$stl_version${reset}"
echo -e " Node.js: ${cyan_fg_strong}$node_version${reset}"
if [ -n "$ip4" ]; then
echo -e " Tailscale URL - IP4: ${cyan_fg_strong}http://$ip4:8000${reset}"
fi
if [ -n "$hostName" ]; then
echo -e " Tailscale URL - Machine Name: ${cyan_fg_strong}http://$hostName:8000${reset}"
fi
if [ -n "$dnsName" ]; then
echo -e " Tailscale URL - MagicDNS Name: ${cyan_fg_strong}http://$dnsName:8000${reset}"
fi
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
}
########################################################################################
########################################################################################
####################### HOME MENU FUNCTIONS ##########################################
########################################################################################
########################################################################################
# Exit Function
exit_program() {
clear
echo "Bye!"
exit 0
}
# Function to find a suitable terminal emulator with proper fallbacks
find_terminal() {
# List of common terminal emulators in priority order
local terminals=(
"gnome-terminal" # GNOME
"konsole" # KDE
"xfce4-terminal" # XFCE
"mate-terminal" # MATE
"lxterminal" # LXDE
"kitty" # Kitty
"alacritty" # Alacritty
"tilix" # Tilix
"terminator" # Terminator
"urxvt" # RXVT
"xterm" # XTerm
"x-terminal-emulator" # Debian/Ubuntu fallback
)
# First check the $TERMINAL environment variable
if [ -n "$TERMINAL" ] && command -v "$TERMINAL" >/dev/null 2>&1; then
echo "$TERMINAL"
return 0
fi
# Check the list of known terminals
for term in "${terminals[@]}"; do
if command -v "$term" >/dev/null 2>&1; then
echo "$term"
return 0
fi
done
# Final fallback to x-terminal-emulator
if command -v "x-terminal-emulator" >/dev/null 2>&1; then
echo "x-terminal-emulator"
return 0
fi
# If no terminal found, return error
return 1
}
start_st() {
check_nodejs
local start_script_path="$st_install_path/start.sh"
local detected_terminal
if [ "$LAUNCH_NEW_WIN" = "0" ]; then
log_message "INFO" "SillyTavern launched"
(cd "$st_install_path" && exec "./start.sh")
else
log_message "INFO" "SillyTavern launched in a new window."
detected_terminal=$(find_terminal)
if [ $? -ne 0 ]; then
log_message "ERROR" "No terminal emulator found! Falling back to current shell"
(cd "$st_install_path" && exec "./start.sh")
return
fi
log_message "INFO" "Found terminal: $detected_terminal"
# macOS handling
if [ "$(uname)" = "Darwin" ]; then
log_message "INFO" "Detected macOS. Opening new Terminal window."
osascript < / Home / SillyTavern Remote Link |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
# Warning and confirmation prompt
echo
echo -e "${blue_bg}${bold}╔═══════════════ CLOUDFLARE TUNNEL ═══════════════════════════════════════════════════╗${reset}"
echo -e "${blue_bg}${bold}║ WARNING: This script downloads and runs the latest cloudflared from Cloudflare to ║${reset}"
echo -e "${blue_bg}${bold}║ set up an HTTPS tunnel to your SillyTavern. ║${reset}"
echo -e "${blue_bg}${bold}║ ║${reset}"
echo -e "${blue_bg}${bold}║ Using the randomly generated temporary tunnel URL, anyone can access your ║${reset}"
echo -e "${blue_bg}${bold}║ SillyTavern over the Internet while the tunnel is active. ║${reset}"
echo -e "${blue_bg}${bold}║ ║${reset}"
echo -e "${blue_bg}${bold}║ Keep the URL safe and secure your SillyTavern installation by setting a username ║${reset}"
echo -e "${blue_bg}${bold}║ and password in config.yaml. ║${reset}"
echo -e "${blue_bg}${bold}║ ║${reset}"
echo -e "${blue_bg}${bold}║ See https://docs.sillytavern.app/usage/remoteconnections/ for more details about ║${reset}"
echo -e "${blue_bg}${bold}║ how to secure your SillyTavern install. ║${reset}"
echo -e "${blue_bg}${bold}║ ║${reset}"
echo -e "${blue_bg}${bold}║ By continuing you confirm that you're aware of the potential dangers of having a ║${reset}"
echo -e "${blue_bg}${bold}║ tunnel open and take all responsibility to properly use and secure it. ║${reset}"
echo -e "${blue_bg}${bold}╚═════════════════════════════════════════════════════════════════════════════════════╝${reset}"
echo
echo -n -e "${yellow_fg_strong}Are you sure you want to continue? [Y/N]: ${reset}"
read -r confirm
case "$confirm" in
[Yy]*)
# Check if cloudflared is already downloaded, if not, download it
if [ ! -f cloudflared ]; then
echo "Downloading cloudflared..."
curl -Lo cloudflared https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64
chmod +x cloudflared
fi
# Run cloudflared tunnel
./cloudflared tunnel --url localhost:8000
start_st
;;
[Nn]*)
home
;;
*)
log_message "ERROR" "Invalid input. Please enter Y or N."
read -p "Press Enter to try again..."
start_st_remotelink
;;
esac
}
launch_custom_shortcut() {
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
home
}
update_manager() {
log_message "INFO" "coming soon"
read -p "Press Enter to continue..."
home
}
info_vram() {
# Clear the screen
clear
# Get GPU information using lspci and filter for VGA compatible controllers
gpu_info=$(lspci | grep -i vga)
if [ -z "$gpu_info" ]; then
gpu_info="GPU information not found"
fi
# Get VRAM size using nvidia-smi (for NVIDIA GPUs) or fallback to other methods
if command -v nvidia-smi &> /dev/null; then
UVRAM=$(nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits | awk '{print $1/1024}')
else
UVRAM=0
echo "DEBUG: VRAM could not be detected. Defaulting to 0."
fi
# Handle undefined or invalid UVRAM
if [ -z "$UVRAM" ] || [ "$UVRAM" = "Property not found" ]; then
UVRAM=0
echo "DEBUG: VRAM could not be detected. Defaulting to 0."
fi
# Display header
echo -e "${blue_fg_strong}| > / Home / VRAM & LLM Info |${reset}"
echo -e "${blue_fg_strong} ======================================================================================================${reset}"
# Display GPU information
echo -e "${cyan_fg_strong}GPU: $gpu_info${reset}"
echo -e "${cyan_fg_strong}GPU VRAM: $UVRAM GB${reset}"
# Recommendations based on VRAM size
if (( $(echo "$UVRAM < 8" | bc -l) )); then
echo "It's recommended to stick with APIs like OpenAI, Claude, or OpenRouter for LLM usage."
echo "Local models will result in memory errors or perform very slowly."
elif (( $(echo "$UVRAM < 12" | bc -l) )); then
echo "Great for 7B and 8B models. Check info below for BPW (Bits Per Weight)."
display_bpw_table
elif (( $(echo "$UVRAM < 22" | bc -l) )); then
echo "Great for 7B, 8B, and 13B models. Check info below for BPW (Bits Per Weight)."
display_bpw_table
elif (( $(echo "$UVRAM < 25" | bc -l) )); then
echo "Great for 7B, 8B, 13B, and 30B models. Check info below for BPW (Bits Per Weight)."
display_bpw_table
elif (( $(echo "$UVRAM >= 25" | bc -l) )); then
echo "Great for 7B, 8B, 13B, 30B, and 70B models. Check info below for BPW (Bits Per Weight)."
display_bpw_table
else
echo "An unexpected amount of VRAM detected or unable to detect VRAM. Check your system specifications."
fi
# Ask if the user wants to check the VRAM calculator website
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| |${reset}"
read -p " Check for compatible models on VRAM calculator website? [Y/N]: " info_vram_choice
info_vram_choice=$(echo "$info_vram_choice" | tr '[:upper:]' '[:lower:]')
if [ "$info_vram_choice" = "y" ]; then
xdg-open "https://sillytavernai.com/llm-model-vram-calculator/?vram=$UVRAM"
fi
# Return to the home menu
home
}
# Function to display the BPW (Bits Per Weight) table
display_bpw_table() {
echo
echo "╔══ EXL2 - RECOMMENDED BPW [Bits Per Weight] ═════════════════════════════════════════════════════════════════════════════════╗"
echo "║ Branch ║ Bits ║ lm_head bits ║ VRAM - 4k ║ VRAM - 8k ║ VRAM - 16k ║ VRAM - 32k ║ Description ║"
echo "║═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════║"
echo "║ 8.0 ║ 8.0 ║ 8.0 ║ 10.1 GB ║ 10.5 GB ║ 11.5 GB ║ 13.6 GB ║ Maximum quality that ExLlamaV2 ║"
echo "║ ║ ║ ║ ║ ║ ║ ║ can produce, near unquantized performance. ║"
echo "║═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════║"
echo "║ 6.5 ║ 6.5 ║ 8.0 ║ 8.9 GB ║ 9.3 GB ║ 10.3 GB ║ 12.4 GB ║ Similar to 8.0, good tradeoff of ║"
echo "║ ║ ║ ║ ║ ║ ║ ║ size vs performance, RECOMMENDED. ║"
echo "║═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════║"
echo "║ 5.0 ║ 5.0 ║ 6.0 ║ 7.7 GB ║ 8.1 GB ║ 9.1 GB ║ 11.2 GB ║ Slightly lower quality vs 6.5, ║"
echo "║ ║ ║ ║ ║ ║ ║ ║ but usable on 8GB cards. ║"
echo "║═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════║"
echo "║ 4.25 ║ 4.25 ║ 6.0 ║ 7.0 GB ║ 7.4 GB ║ 8.4 GB ║ 10.5 GB ║ GPTQ equivalent bits per weight, ║"
echo "║ ║ ║ ║ ║ ║ ║ ║ slightly higher quality. ║"
echo "║═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════║"
echo "║ 3.5 ║ 3.5 ║ 6.0 ║ 6.4 GB ║ 6.8 GB ║ 7.8 GB ║ 9.9 GB ║ Lower quality, only use if you have to. ║"
echo "╚═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝"
echo
}
############################################################
################## HOME - FRONTEND #########################
############################################################
home() {
echo -e "\033]0;STL [HOME]\007"
clear
echo -e "${blue_fg_strong}| > / Home |${reset}"
echo -e "${blue_fg_strong} ==============================================================${reset}"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| What would you like to do? |${reset}"
echo " 1. Update & Start SillyTavern"
echo " 2. Start SillyTavern"
echo " 3. Start SillyTavern With Remote Link"
echo " 4. Create Custom App Shortcut"
echo " 5. Update Manager"
echo " 6. Toolbox"
echo " 7. Troubleshooting & Support"
echo " 8. More info about LLM models your GPU can run."
# DEBUG CURRENT PATH
#echo -e "$(pwd)"
#echo -e "$stl_root"
#echo "$(dirname "$(realpath "$0")")"
echo -e "${cyan_fg_strong} ______________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo " 0. Exit"
# Display version and compatibility status
display_version_status
read -p " Choose Your Destiny: " home_choice
# Default to choice 1 if no input is provided
if [ -z "$home_choice" ]; then
home_choice=1
fi
################## HOME - BACKEND #########################
case $home_choice in
1) update_start_st ;;
2) start_st ;;
3) start_st_remotelink ;;
4) launch_custom_shortcut ;;
5) update_manager ;;
6) toolbox ;;
7) troubleshooting ;;
8) info_vram ;;
0) exit_program ;;
*) echo -e "${yellow_fg_strong}WARNING: Invalid number. Please insert a valid number.${reset}"
read -p "Press Enter to continue..."
home ;;
esac
}
# Startup functions
startup() {
create_logs_folder
check_path_spaces
check_path_special_chars
install_git
check_launcher_updates
create_directories
create_module_files
install_nodejs
check_miniconda
check_sillytavern_folder
check_sillytavern_updates
# Functions related for displaying status
cd "$stl_root"
get_current_branch
manage_gpu_counter
detect_gpu_info
read_tailscale_status
get_sillytavern_version
node_version=$(node -v)
stl_version="25.1.0.0"
update_status_st="Up to date"
}
# Run startup functions
startup
# Display the main menu
home