(installer) copy launch/update scripts to the root dir; improve launch experience on Linux/Mac

- install.sh is now a thin wrapper around the pythonized install script
- install.bat not done yet - to follow
- user messaging is tailored to the current platform (paste shortcuts, file paths, etc)
- emit invoke.sh/invoke.bat scripts to the runtime dir
- improve launch scripts (add help option, etc)
- only emit the platform-specific scripts
This commit is contained in:
Eugene Brodsky 2023-01-16 01:52:22 -05:00
parent d047e070b8
commit 71733bcfa1
4 changed files with 86 additions and 249 deletions

View File

@ -1,234 +1,9 @@
#!/usr/bin/env bash #!/bin/bash
# ensure we're in the correct folder in case user's CWD is somewhere else
scriptdir=$(dirname "$0")
cd "$scriptdir"
# This version number will be replaced by the one supplied to create_installers.sh.
# Do not change it here - change it in create_installers.sh.
INVOKEAI_VERSION="latest"
# make sure we are not already in a venv # make sure we are not already in a venv
# (don't need to check status) # (don't need to check status)
deactivate >/dev/null 2>&1 deactivate >/dev/null 2>&1
INVOKE_AI_SRC=https://github.com/invoke-ai/InvokeAI/archive/refs/tags/${INVOKEAI_VERSION}.zip
INSTRUCTIONS=https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/
TROUBLESHOOTING=https://invoke-ai.github.io/InvokeAI/installation/INSTALL_AUTOMATED/#troubleshooting
MINIMUM_PYTHON_VERSION=3.9.0
set -euo pipefail set -euo pipefail
IFS=$'\n\t'
function _err_exit { exec python3 $(dirname $0)/main.py ${@}
if test "$1" -ne 0
then
echo -e "Error code $1; Error caught was '$2'"
if [ "$OS_NAME" == "osx" ]; then
echo "Something went wrong while installing InvokeAI and/or its requirements."
echo "You may need to use the Xcode command line tools to proceed. See step number 3 of"
echo "https://invoke-ai.github.io/InvokeAI/INSTALL_SOURCE#walk_through for"
echo "installation instructions and then run this script again."
else
echo "Something went wrong while installing InvokeAI and/or its requirements."
echo "See https://invoke-ai.github.io/InvokeAI/INSTALL_SOURCE#troubleshooting for troubleshooting"
echo "tips, or visit https://invoke-ai.github.io/InvokeAI/#installation for alternative"
echo "installation methods"
fi
read -p "Press any key to exit..."
exit
fi
}
function readinput() {
local CLEAN_ARGS=""
while [[ $# -gt 0 ]]; do
local i="$1"
case "$i" in
"-i")
if read -i "default" 2>/dev/null <<< "test"; then
CLEAN_ARGS="$CLEAN_ARGS -i \"$2\""
fi
shift
shift
;;
"-p")
CLEAN_ARGS="$CLEAN_ARGS -p \"$2\""
shift
shift
;;
*)
CLEAN_ARGS="$CLEAN_ARGS $1"
shift
;;
esac
done
eval read $CLEAN_ARGS
}
function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }
echo "InvokeAI simple installer..."
echo ""
echo "Some of the installation steps take a long time to run. Please be patient."
echo "If the script appears to hang for more than 10 minutes, please interrupt with control-C and retry."
read -n 1 -s -r -p "<Press any key to start the install>"
echo ""
OS_NAME=$(uname -s)
case "${OS_NAME}" in
Linux*) OS_NAME="linux";;
Darwin*) OS_NAME="osx";;
*) echo "Unknown OS: $OS_NAME! This script runs only on Linux or Mac" && exit
esac
OS_ARCH=$(uname -m)
case "${OS_ARCH}" in
x86_64*) OS_ARCH="64";;
arm64*) OS_ARCH="arm64";;
*) echo "Unknown system architecture: $OS_ARCH! This script runs only on x86_64 or arm64" && exit
esac
echo "Installing for $OS_NAME-$OS_ARCH"
# confirm that python is installed and is up to date
PYTHON=""
for candidate in python3.10 python3.9 python3 python python3.11 ; do
if ppath=`which $candidate`; then
python_version=$($ppath -V | awk '{ print $2 }')
if [ $(version $python_version) -ge $(version "$MINIMUM_PYTHON_VERSION") ]; then
PYTHON=$ppath
echo Python $python_version found at $PYTHON
break
fi
fi
done
if [ -z "$PYTHON" ]; then
echo "A suitable Python interpreter could not be found"
echo "Please install Python 3.9 or higher before running this script. See instructions at $INSTRUCTIONS for help."
read -p "Press any key to exit"
exit -1
fi
ROOTDIR=""
while [ "$ROOTDIR" == "" ]
do
echo
readinput -e -p "Select your preferred location for the 'invokeai' directory [$HOME]: " -i $HOME input
ROOTDIR=${input:=$HOME}/invokeai
# This is surprisingly hard to do in plain Bash; easier in ZSH. Just running python in subshell is easiest.
ROOTDIR=$($PYTHON -c "from pathlib import Path; print(Path('${ROOTDIR}').expanduser().resolve())")
read -e -p "InvokeAI will be installed into $ROOTDIR. OK? [y]: " input
RESPONSE=${input:='y'}
if [ "$RESPONSE" == 'y' ]; then
if [ -e "$ROOTDIR" ]; then
echo
read -e -p "Directory "$ROOTDIR" already exists. Do you want to resume an interrupted install? [y]: " input
RESPONSE=${input:='y'}
if [ "$RESPONSE" != 'y' ]; then
ROOTDIR=""
fi
else
mkdir -p "$ROOTDIR"
if [ $? -ne 0 ]; then
echo "Could not create "$ROOTDIR". Try again with a different install location."
ROOTDIR=""
fi
fi
else
ROOTDIR=""
fi
done
#--------------------------------------------------------------------------------
echo
echo "** Creating Virtual Environment for InvokeAI **"
$PYTHON -mvenv "$ROOTDIR"/.venv
_err_exit $? "Python failed to create virtual environment "$ROOTDIR"/.venv. Please see $TROUBLESHOOTING for help."
#--------------------------------------------------------------------------------
echo
echo "** Activating Virtual Environment for InvokeAI **"
source "$ROOTDIR"/.venv/bin/activate
_err_exit $? "Failed to activate virtual evironment "$ROOTDIR"/.venv. Please see $TROUBLESHOOTING for help."
PYTHON="$ROOTDIR"/.venv/bin/python
$PYTHON -mensurepip --upgrade
$PYTHON -mpip install --upgrade pip
#--------------------------------------------------------------------------------
echo
echo "*** Installing InvokeAI Dependencies ***"
if [ "$OS_NAME" == "osx" ]; then
echo "macOS detected. Installing MPS and CPU support."
egrep -v '^-e .' environments-and-requirements/requirements-mac-mps-cpu.txt >requirements.txt
else
if (lsmod | grep amdgpu) &>/dev/null ; then
readinput -e -p "Linux system with AMD GPU driver detected. Install ROCm AMD accelerated support? (Otherwise, CUDA support will be installed) [n]: " input
RESPONSE=${input:='n'}
if [ "$RESPONSE" != "n" ]; then
echo "Installing ROCm (AMD) support"
egrep -v '^-e .' environments-and-requirements/requirements-lin-amd.txt >requirements.txt
else
echo "Installing CUDA support"
egrep -v '^-e .' environments-and-requirements/requirements-lin-cuda.txt >requirements.txt
fi
else
echo "Linux system detected. Installing CUDA and CPU support."
egrep -v '^-e .' environments-and-requirements/requirements-lin-cuda.txt >requirements.txt
fi
fi
$PYTHON -mpip install --prefer-binary -r requirements.txt
_err_exit $? "Failed to install InvokeAI's dependencies."
#--------------------------------------------------------------------------------
echo
echo "*** Installing InvokeAI Modules and Executables ***"
$PYTHON -mpip install $INVOKE_AI_SRC
_err_exit $? "Installation of InvokeAI failed."
#--------------------------------------------------------------------------------
echo " *** Setting Up Root Directory "$ROOTDIR" *** "
cp -pr templates/rootdir/* "$ROOTDIR"/
cp templates/invoke.sh.in "$ROOTDIR"/invoke.sh
chmod a+rx "$ROOTDIR"/invoke.sh
cp templates/update.sh.in "$ROOTDIR"/update.sh
chmod a+rx "$ROOTDIR"/update.sh
# This allows the updater to work!
cp -pr environments-and-requirements requirements.txt "$ROOTDIR/"
#--------------------------------------------------------------------------------
echo
echo "*** Confguring InvokeAI ***"
pushd "$ROOTDIR" >/dev/null
$PYTHON ./.venv/bin/configure_invokeai.py --root="$ROOTDIR"
_err_exit $? "Initial configuration failed. Please see above error messages and $TROUBLESHOOTING for help."
#--------------------------------------------------------------------------------
popd
cp templates/invoke.sh.in "$ROOTDIR"/invoke.sh
chmod a+rx "$ROOTDIR"/invoke.sh
cp templates/update.sh.in "$ROOTDIR"/update.sh
chmod a+rx "$ROOTDIR"/update.sh
echo "You may now run InvokeAI by entering the directory $ROOTDIR and running invoke.sh:"
echo
echo " ${ROOTDIR}/invoke.sh"
echo
read -e -p "Run InvokeAI now? [y]:" input
RESPONSE=${input:='y'}
if [ "$RESPONSE" == 'y' ]; then
exec ${ROOTDIR}/invoke.sh
fi

View File

@ -4,6 +4,7 @@ InvokeAI installer script
import os import os
import platform import platform
import shutil
import subprocess import subprocess
import sys import sys
import venv import venv
@ -160,10 +161,15 @@ class Installer:
self.instance = InvokeAiInstance(runtime=self.dest, venv=self.venv) self.instance = InvokeAiInstance(runtime=self.dest, venv=self.venv)
# create the venv, install dependencies and the application
self.instance.deploy(extra_index_url=get_torch_source()) self.instance.deploy(extra_index_url=get_torch_source())
# run the configuration flow
self.instance.configure() self.instance.configure()
# install the launch/update scritps into the runtime directory
self.instance.install_user_scripts()
class InvokeAiInstance: class InvokeAiInstance:
""" """
@ -206,7 +212,7 @@ class InvokeAiInstance:
### until we continuously build wheels ### until we continuously build wheels
import messages import messages
from plumbum import local, FG from plumbum import FG, local
# pre-installing Torch because this is the most reliable way to ensure # pre-installing Torch because this is the most reliable way to ensure
# the correct version gets installed. # the correct version gets installed.
@ -253,7 +259,7 @@ class InvokeAiInstance:
Install PyTorch Install PyTorch
""" """
from plumbum import local, FG from plumbum import FG, local
extra_index_url_arg = "--extra-index-url" if extra_index_url is not None else None extra_index_url_arg = "--extra-index-url" if extra_index_url is not None else None
@ -284,6 +290,19 @@ class InvokeAiInstance:
configure_invokeai.main() configure_invokeai.main()
def install_user_scripts(self):
"""
Copy the launch and update scripts to the runtime dir
"""
ext = 'bat' if OS == 'Windows' else 'sh'
for script in ["invoke", "update"]:
src = Path(__file__).parent / "templates" / f"{script}.{ext}.in"
dest = self.runtime / f"{script}.{ext}"
shutil.copy (src, dest)
os.chmod(dest, 0o0755)
def update(self): def update(self):
pass pass

View File

@ -1,5 +1,14 @@
#!/bin/bash #!/bin/bash
####
# This launch script assumes that:
# 1. it is located in the runtime directory,
# 2. the .venv is also located in the runtime directory and is named exactly that
#
# If both of the above are not true, this script will likely not work as intended.
# Activate the virtual environment and run `invoke.py` directly.
####
set -eu set -eu
# ensure we're in the correct folder in case user's CWD is somewhere else # ensure we're in the correct folder in case user's CWD is somewhere else
@ -23,16 +32,41 @@ if [ "$0" != "bash" ]; then
echo "4. merge models (diffusers type only)" echo "4. merge models (diffusers type only)"
echo "5. open the developer console" echo "5. open the developer console"
echo "6. re-run the configure script to download new models" echo "6. re-run the configure script to download new models"
read -p "Please enter 1, 2, 3, 4 or 5: [1] " yn echo "7. command-line help "
echo ""
read -p "Please enter 1, 2, 3, 4, 5, 6 or 7: [2] " yn
choice=${yn:='2'} choice=${yn:='2'}
case $choice in case $choice in
1 ) printf "\nStarting the InvokeAI command-line..\n"; invoke $*;; 1)
2 ) printf "\nStarting the InvokeAI browser-based UI..\n"; invoke --web $*;; echo "Starting the InvokeAI command-line..."
3 ) printf "\nStarting Textual Inversion:\n"; textual_inversion --gui $*;; exec invokeai $@
4 ) printf "\nMerging Models:\n"; merge_models --gui $*;; ;;
5 ) printf "\nDeveloper Console:\n"; file_name=$(basename "${BASH_SOURCE[0]}"); bash --init-file "$file_name";; 2)
6 ) printf "\nRunning configure_invokeai.py:\n"; configure_invokeai $*;; echo "Starting the InvokeAI browser-based UI..."
* ) echo "Invalid selection"; exit;; exec invokeai --web $@
;;
3)
echo "Starting Textual Inversion:"
exec textual_inversion --gui $@
;;
4)
echo "Merging Models:"
exec merge_models --gui $@
;;
5)
echo "Developer Console:"
file_name=$(basename "${BASH_SOURCE[0]}")
bash --init-file "$file_name"
;;
6)
exec invokeai-config --root ${INVOKEAI_ROOT}
;;
7)
exec invokeai --help
;;
*)
echo "Invalid selection"
exit;;
esac esac
else # in developer console else # in developer console
python --version python --version

View File

@ -71,23 +71,30 @@ Config_preamble = '''# This file describes the alternative machine learning mode
#-------------------------------------------- #--------------------------------------------
def postscript(errors: None): def postscript(errors: None):
if not any(errors): if not any(errors):
message=''' message=f'''
** Model Installation Successful ** ** Model Installation Successful **
You're all set! You're all set!
If you installed using one of the automated installation scripts, ---
execute 'invoke.sh' (Linux/macOS) or 'invoke.bat' (Windows) to
start InvokeAI.
If you installed manually, activate the 'invokeai' environment If you installed manually from source or with 'pip install': activate the virtual environment
(e.g. 'conda activate invokeai'), then run one of the following then run one of the following commands to start InvokeAI.
commands to start InvokeAI.
Web UI: Web UI:
python scripts/invoke.py --web # (connect to http://localhost:9090) invoke.py --web # (connect to http://localhost:9090)
invoke.py --web --host 0.0.0.0 # (connect to http://your-lan-ip:9090 from another computer on the local network)
Command-line interface: Command-line interface:
python scripts/invoke.py invoke.py
---
If you installed using an installation script, run:
{Globals.root}/invoke.{"bat" if sys.platform == "win32" else "sh"}
Add the '--help' argument to see all of the command-line switches available for use.
Have fun! Have fun!
''' '''
@ -277,7 +284,7 @@ The license terms are located here:
print(f"Login failed due to invalid token found in cache") print(f"Login failed due to invalid token found in cache")
if not (yes_to_all or token_found): if not (yes_to_all or token_found):
print(''' You may optionally enter your Huggingface token now. InvokeAI print(f''' You may optionally enter your Huggingface token now. InvokeAI
*will* work without it but you will not be able to automatically *will* work without it but you will not be able to automatically
download some of the Hugging Face style concepts. See download some of the Hugging Face style concepts. See
https://invoke-ai.github.io/InvokeAI/features/CONCEPTS/#using-a-hugging-face-concept https://invoke-ai.github.io/InvokeAI/features/CONCEPTS/#using-a-hugging-face-concept
@ -285,8 +292,10 @@ for more information.
Visit https://huggingface.co/settings/tokens to generate a token. (Sign up for an account if needed). Visit https://huggingface.co/settings/tokens to generate a token. (Sign up for an account if needed).
Paste the token below using Ctrl-V on macOS/Linux, or Ctrl-Shift-V or right-click on Windows. Paste the token below using {"Ctrl+Shift+V" if sys.platform == "linux" else "Command+V" if sys.platform == "darwin" else "Ctrl+V, right-click, or Edit>Paste"}.
Alternatively press 'Enter' to skip this step and continue.
Alternatively, press 'Enter' to skip this step and continue.
You may re-run the configuration script again in the future if you do not wish to set the token right now. You may re-run the configuration script again in the future if you do not wish to set the token right now.
''') ''')
again = True again = True