(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
# 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"
#!/bin/bash
# make sure we are not already in a venv
# (don't need to check status)
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
IFS=$'\n\t'
function _err_exit {
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
exec python3 $(dirname $0)/main.py ${@}

View File

@ -4,6 +4,7 @@ InvokeAI installer script
import os
import platform
import shutil
import subprocess
import sys
import venv
@ -160,10 +161,15 @@ class Installer:
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())
# run the configuration flow
self.instance.configure()
# install the launch/update scritps into the runtime directory
self.instance.install_user_scripts()
class InvokeAiInstance:
"""
@ -206,7 +212,7 @@ class InvokeAiInstance:
### until we continuously build wheels
import messages
from plumbum import local, FG
from plumbum import FG, local
# pre-installing Torch because this is the most reliable way to ensure
# the correct version gets installed.
@ -253,7 +259,7 @@ class InvokeAiInstance:
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
@ -284,6 +290,19 @@ class InvokeAiInstance:
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):
pass

View File

@ -1,5 +1,14 @@
#!/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
# 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 "5. open the developer console"
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'}
case $choice in
1 ) printf "\nStarting the InvokeAI command-line..\n"; invoke $*;;
2 ) printf "\nStarting the InvokeAI browser-based UI..\n"; invoke --web $*;;
3 ) printf "\nStarting Textual Inversion:\n"; textual_inversion --gui $*;;
4 ) printf "\nMerging Models:\n"; merge_models --gui $*;;
5 ) printf "\nDeveloper Console:\n"; file_name=$(basename "${BASH_SOURCE[0]}"); bash --init-file "$file_name";;
6 ) printf "\nRunning configure_invokeai.py:\n"; configure_invokeai $*;;
* ) echo "Invalid selection"; exit;;
1)
echo "Starting the InvokeAI command-line..."
exec invokeai $@
;;
2)
echo "Starting the InvokeAI browser-based UI..."
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
else # in developer console
python --version

View File

@ -71,23 +71,30 @@ Config_preamble = '''# This file describes the alternative machine learning mode
#--------------------------------------------
def postscript(errors: None):
if not any(errors):
message='''
message=f'''
** Model Installation Successful **
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
(e.g. 'conda activate invokeai'), then run one of the following
commands to start InvokeAI.
If you installed manually from source or with 'pip install': activate the virtual environment
then run one of the following commands to start InvokeAI.
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:
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!
'''
@ -277,7 +284,7 @@ The license terms are located here:
print(f"Login failed due to invalid token found in cache")
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
download some of the Hugging Face style concepts. See
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).
Paste the token below using Ctrl-V on macOS/Linux, or Ctrl-Shift-V or right-click on Windows.
Alternatively press 'Enter' to skip this step and continue.
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.
You may re-run the configuration script again in the future if you do not wish to set the token right now.
''')
again = True