2022-09-13 21:48:18 +08:00
# this scripts installs necessary requirements and launches main program in webui.py
import subprocess
import os
import sys
import importlib . util
import shlex
2022-10-08 21:13:26 +08:00
import platform
2022-11-27 23:48:08 +08:00
import argparse
import json
2022-09-13 21:48:18 +08:00
2022-10-09 20:22:51 +08:00
dir_repos = " repositories "
2022-11-01 19:19:24 +08:00
dir_extensions = " extensions "
2022-10-09 20:22:51 +08:00
python = sys . executable
git = os . environ . get ( ' GIT ' , " git " )
2022-10-15 15:28:20 +08:00
index_url = os . environ . get ( ' INDEX_URL ' , " " )
2023-01-05 16:57:01 +08:00
stored_commit_hash = None
2023-01-17 01:13:23 +08:00
skip_install = False
2023-01-05 16:57:01 +08:00
2023-01-26 01:07:48 +08:00
def check_python_version ( ) :
2023-01-28 15:48:08 +08:00
is_windows = platform . system ( ) == " Windows "
major = sys . version_info . major
minor = sys . version_info . minor
micro = sys . version_info . micro
if is_windows :
2023-01-28 15:21:31 +08:00
supported_minors = [ 10 ]
else :
supported_minors = [ 7 , 8 , 9 , 10 , 11 ]
2023-01-28 15:48:08 +08:00
if not ( major == 3 and minor in supported_minors ) :
2023-01-28 15:21:31 +08:00
import modules . errors
modules . errors . print_error_explanation ( f """
2023-01-28 15:48:08 +08:00
INCOMPATIBLE PYTHON VERSION
This program is tested with 3.10 .6 Python , but you have { major } . { minor } . { micro } .
2023-01-27 20:35:24 +08:00
If you encounter an error with " RuntimeError: Couldn ' t install torch. " message ,
or any other error regarding unsuccessful package ( library ) installation ,
please downgrade ( or upgrade ) to the latest version of 3.10 Python
and delete current Python and " venv " folder in WebUI ' s directory.
2023-01-28 15:48:08 +08:00
You can download 3.10 Python from here : https : / / www . python . org / downloads / release / python - 3109 /
{ " Alternatively, use a binary release of WebUI: https://github.com/AUTOMATIC1111/stable-diffusion-webui/releases " if is_windows else " " }
Use - - skip - python - version - check to suppress this warning .
2023-01-28 15:21:31 +08:00
""" )
2023-01-26 01:07:48 +08:00
2023-01-05 16:57:01 +08:00
def commit_hash ( ) :
global stored_commit_hash
if stored_commit_hash is not None :
return stored_commit_hash
try :
stored_commit_hash = run ( f " { git } rev-parse HEAD " ) . strip ( )
except Exception :
stored_commit_hash = " <none> "
return stored_commit_hash
2022-10-09 20:22:51 +08:00
2022-09-21 15:25:45 +08:00
def extract_arg ( args , name ) :
return [ x for x in args if x != name ] , name in args
2022-11-14 18:39:22 +08:00
def extract_opt ( args , name ) :
opt = None
is_present = False
if name in args :
is_present = True
idx = args . index ( name )
del args [ idx ]
if idx < len ( args ) and args [ idx ] [ 0 ] != " - " :
opt = args [ idx ]
del args [ idx ]
return args , is_present , opt
2023-01-25 02:13:05 +08:00
def run ( command , desc = None , errdesc = None , custom_env = None , live = False ) :
2022-09-13 21:48:18 +08:00
if desc is not None :
print ( desc )
2023-01-25 02:13:05 +08:00
if live :
result = subprocess . run ( command , shell = True , env = os . environ if custom_env is None else custom_env )
if result . returncode != 0 :
raise RuntimeError ( f """ { errdesc or ' Error running command ' } .
Command : { command }
Error code : { result . returncode } """ )
return " "
2022-11-01 19:48:53 +08:00
result = subprocess . run ( command , stdout = subprocess . PIPE , stderr = subprocess . PIPE , shell = True , env = os . environ if custom_env is None else custom_env )
2022-09-13 21:48:18 +08:00
if result . returncode != 0 :
message = f """ { errdesc or ' Error running command ' } .
Command : { command }
Error code : { result . returncode }
stdout : { result . stdout . decode ( encoding = " utf8 " , errors = " ignore " ) if len ( result . stdout ) > 0 else ' <empty> ' }
stderr : { result . stderr . decode ( encoding = " utf8 " , errors = " ignore " ) if len ( result . stderr ) > 0 else ' <empty> ' }
"""
raise RuntimeError ( message )
return result . stdout . decode ( encoding = " utf8 " , errors = " ignore " )
def check_run ( command ) :
result = subprocess . run ( command , stdout = subprocess . PIPE , stderr = subprocess . PIPE , shell = True )
return result . returncode == 0
def is_installed ( package ) :
try :
spec = importlib . util . find_spec ( package )
except ModuleNotFoundError :
return False
return spec is not None
2022-10-09 20:22:51 +08:00
def repo_dir ( name ) :
return os . path . join ( dir_repos , name )
def run_python ( code , desc = None , errdesc = None ) :
return run ( f ' " { python } " -c " { code } " ' , desc , errdesc )
def run_pip ( args , desc = None ) :
2023-01-17 01:13:23 +08:00
if skip_install :
return
2022-10-15 15:28:20 +08:00
index_url_line = f ' --index-url { index_url } ' if index_url != ' ' else ' '
return run ( f ' " { python } " -m pip { args } --prefer-binary { index_url_line } ' , desc = f " Installing { desc } " , errdesc = f " Couldn ' t install { desc } " )
2022-10-09 20:22:51 +08:00
def check_run_python ( code ) :
return check_run ( f ' " { python } " -c " { code } " ' )
def git_clone ( url , dir , name , commithash = None ) :
# TODO clone into temporary dir and move if successful
if os . path . exists ( dir ) :
if commithash is None :
return
2023-01-25 01:22:19 +08:00
current_hash = run ( f ' " { git } " -C " { dir } " rev-parse HEAD ' , None , f " Couldn ' t determine { name } ' s hash: { commithash } " ) . strip ( )
2022-10-09 20:22:51 +08:00
if current_hash == commithash :
return
2023-01-25 01:22:19 +08:00
run ( f ' " { git } " -C " { dir } " fetch ' , f " Fetching updates for { name } ... " , f " Couldn ' t fetch { name } " )
run ( f ' " { git } " -C " { dir } " checkout { commithash } ' , f " Checking out commit for { name } with hash: { commithash } ... " , f " Couldn ' t checkout commit { commithash } for { name } " )
2022-10-09 20:22:51 +08:00
return
2022-09-13 21:48:18 +08:00
2022-10-09 20:22:51 +08:00
run ( f ' " { git } " clone " { url } " " { dir } " ' , f " Cloning { name } into { dir } ... " , f " Couldn ' t clone { name } " )
if commithash is not None :
2023-01-25 01:22:19 +08:00
run ( f ' " { git } " -C " { dir } " checkout { commithash } ' , None , " Couldn ' t checkout {name} ' s hash: {commithash} " )
2022-10-09 20:22:51 +08:00
2023-03-11 17:21:53 +08:00
2023-03-09 22:25:18 +08:00
def git_pull_recursive ( dir ) :
for subdir , _ , _ in os . walk ( dir ) :
if os . path . exists ( os . path . join ( subdir , ' .git ' ) ) :
try :
2023-03-11 17:21:53 +08:00
output = subprocess . check_output ( [ git , ' -C ' , subdir , ' pull ' , ' --autostash ' ] )
2023-03-09 22:25:18 +08:00
print ( f " Pulled changes for repository in ' { subdir } ' : \n { output . decode ( ' utf-8 ' ) . strip ( ) } \n " )
except subprocess . CalledProcessError as e :
print ( f " Couldn ' t perform ' git pull ' on repository in ' { subdir } ' : \n { e . output . decode ( ' utf-8 ' ) . strip ( ) } \n " )
2023-03-11 17:21:53 +08:00
2022-10-17 00:04:09 +08:00
def version_check ( commit ) :
try :
import requests
commits = requests . get ( ' https://api.github.com/repos/AUTOMATIC1111/stable-diffusion-webui/branches/master ' ) . json ( )
if commit != " <none> " and commits [ ' commit ' ] [ ' sha ' ] != commit :
print ( " -------------------------------------------------------- " )
print ( " | You are not up to date with the most recent release. | " )
print ( " | Consider running `git pull` to update. | " )
print ( " -------------------------------------------------------- " )
elif commits [ ' commit ' ] [ ' sha ' ] == commit :
print ( " You are up to date with the most recent release. " )
else :
print ( " Not a git clone, can ' t perform version check. " )
except Exception as e :
2022-11-01 19:19:24 +08:00
print ( " version check failed " , e )
2022-11-12 16:11:47 +08:00
def run_extension_installer ( extension_dir ) :
path_installer = os . path . join ( extension_dir , " install.py " )
if not os . path . isfile ( path_installer ) :
return
try :
env = os . environ . copy ( )
env [ ' PYTHONPATH ' ] = os . path . abspath ( " . " )
print ( run ( f ' " { python } " " { path_installer } " ' , errdesc = f " Error running install.py for extension { extension_dir } " , custom_env = env ) )
except Exception as e :
print ( e , file = sys . stderr )
2022-11-27 23:48:08 +08:00
def list_extensions ( settings_file ) :
settings = { }
try :
if os . path . isfile ( settings_file ) :
with open ( settings_file , " r " , encoding = " utf8 " ) as file :
settings = json . load ( file )
except Exception as e :
print ( e , file = sys . stderr )
disabled_extensions = set ( settings . get ( ' disabled_extensions ' , [ ] ) )
return [ x for x in os . listdir ( dir_extensions ) if x not in disabled_extensions ]
def run_extensions_installers ( settings_file ) :
2022-11-01 19:19:24 +08:00
if not os . path . isdir ( dir_extensions ) :
return
2022-11-27 23:48:08 +08:00
for dirname_extension in list_extensions ( settings_file ) :
2022-11-12 16:11:47 +08:00
run_extension_installer ( os . path . join ( dir_extensions , dirname_extension ) )
2022-11-01 19:19:24 +08:00
2022-10-09 20:22:51 +08:00
2022-12-03 17:35:17 +08:00
def prepare_environment ( ) :
2023-01-17 01:13:23 +08:00
global skip_install
2022-12-23 06:28:10 +08:00
torch_command = os . environ . get ( ' TORCH_COMMAND ' , " pip install torch==1.13.1+cu117 torchvision==0.14.1+cu117 --extra-index-url https://download.pytorch.org/whl/cu117 " )
2022-10-09 19:44:13 +08:00
requirements_file = os . environ . get ( ' REQS_FILE ' , " requirements_versions.txt " )
commandline_args = os . environ . get ( ' COMMANDLINE_ARGS ' , " " )
2022-10-06 17:08:06 +08:00
2023-01-30 14:12:43 +08:00
xformers_package = os . environ . get ( ' XFORMERS_PACKAGE ' , ' xformers==0.0.16rc425 ' )
2022-10-09 19:44:13 +08:00
gfpgan_package = os . environ . get ( ' GFPGAN_PACKAGE ' , " git+https://github.com/TencentARC/GFPGAN.git@8d2447a2d918f8eba5a4a01463fd48e45126a379 " )
clip_package = os . environ . get ( ' CLIP_PACKAGE ' , " git+https://github.com/openai/CLIP.git@d50d76daa670286dd6cacf3bcd80b5e4823fc8e1 " )
2022-11-26 21:10:46 +08:00
openclip_package = os . environ . get ( ' OPENCLIP_PACKAGE ' , " git+https://github.com/mlfoundations/open_clip.git@bb6e834e9c70d9c27d0dc3ecedeebeaeb1ffad6b " )
2022-10-16 15:13:18 +08:00
2022-11-26 21:10:46 +08:00
stable_diffusion_repo = os . environ . get ( ' STABLE_DIFFUSION_REPO ' , " https://github.com/Stability-AI/stablediffusion.git " )
2022-11-13 11:41:22 +08:00
taming_transformers_repo = os . environ . get ( ' TAMING_TRANSFORMERS_REPO ' , " https://github.com/CompVis/taming-transformers.git " )
2022-10-16 15:13:18 +08:00
k_diffusion_repo = os . environ . get ( ' K_DIFFUSION_REPO ' , ' https://github.com/crowsonkb/k-diffusion.git ' )
2022-11-13 11:41:22 +08:00
codeformer_repo = os . environ . get ( ' CODEFORMER_REPO ' , ' https://github.com/sczhou/CodeFormer.git ' )
2022-10-16 15:13:18 +08:00
blip_repo = os . environ . get ( ' BLIP_REPO ' , ' https://github.com/salesforce/BLIP.git ' )
2022-10-09 19:44:13 +08:00
2022-11-26 21:10:46 +08:00
stable_diffusion_commit_hash = os . environ . get ( ' STABLE_DIFFUSION_COMMIT_HASH ' , " 47b6b607fdd31875c9279cd2f4f16b92e4ea958e " )
2022-10-09 19:44:13 +08:00
taming_transformers_commit_hash = os . environ . get ( ' TAMING_TRANSFORMERS_COMMIT_HASH ' , " 24268930bf1dce879235a7fddd0b2355b84d7ea6 " )
2022-11-26 21:10:46 +08:00
k_diffusion_commit_hash = os . environ . get ( ' K_DIFFUSION_COMMIT_HASH ' , " 5b3af030dd83e0297272d861c19477735d0317ec " )
2022-10-09 19:44:13 +08:00
codeformer_commit_hash = os . environ . get ( ' CODEFORMER_COMMIT_HASH ' , " c5b4593074ba6214284d6acd5f1719b6c5d739af " )
blip_commit_hash = os . environ . get ( ' BLIP_COMMIT_HASH ' , " 48211a1594f1321b00f14c9f7a5b4813144b2fb9 " )
2022-10-18 20:18:02 +08:00
sys . argv + = shlex . split ( commandline_args )
2022-10-09 19:44:13 +08:00
2023-02-04 22:23:20 +08:00
parser = argparse . ArgumentParser ( add_help = False )
2022-11-27 23:48:08 +08:00
parser . add_argument ( " --ui-settings-file " , type = str , help = " filename to use for ui settings " , default = ' config.json ' )
args , _ = parser . parse_known_args ( sys . argv )
2022-12-01 17:04:14 +08:00
sys . argv , _ = extract_arg ( sys . argv , ' -f ' )
2023-03-09 22:25:18 +08:00
sys . argv , update_all_extensions = extract_arg ( sys . argv , ' --update-all-extensions ' )
2022-10-18 20:18:02 +08:00
sys . argv , skip_torch_cuda_test = extract_arg ( sys . argv , ' --skip-torch-cuda-test ' )
2023-01-28 15:48:08 +08:00
sys . argv , skip_python_version_check = extract_arg ( sys . argv , ' --skip-python-version-check ' )
2022-10-18 20:18:02 +08:00
sys . argv , reinstall_xformers = extract_arg ( sys . argv , ' --reinstall-xformers ' )
2023-01-23 22:17:31 +08:00
sys . argv , reinstall_torch = extract_arg ( sys . argv , ' --reinstall-torch ' )
2022-10-18 20:18:02 +08:00
sys . argv , update_check = extract_arg ( sys . argv , ' --update-check ' )
2022-11-14 18:39:22 +08:00
sys . argv , run_tests , test_dir = extract_opt ( sys . argv , ' --tests ' )
2023-01-17 01:13:23 +08:00
sys . argv , skip_install = extract_arg ( sys . argv , ' --skip-install ' )
2022-10-18 20:18:02 +08:00
xformers = ' --xformers ' in sys . argv
ngrok = ' --ngrok ' in sys . argv
2022-10-09 19:44:13 +08:00
2023-01-28 15:48:08 +08:00
if not skip_python_version_check :
check_python_version ( )
2023-01-05 16:57:01 +08:00
commit = commit_hash ( )
2022-09-21 20:03:15 +08:00
2022-10-09 19:44:13 +08:00
print ( f " Python { sys . version } " )
print ( f " Commit hash: { commit } " )
2023-01-25 02:13:05 +08:00
2023-01-23 22:17:31 +08:00
if reinstall_torch or not is_installed ( " torch " ) or not is_installed ( " torchvision " ) :
2023-01-25 02:13:05 +08:00
run ( f ' " { python } " -m { torch_command } ' , " Installing torch and torchvision " , " Couldn ' t install torch " , live = True )
2022-09-13 21:48:18 +08:00
2022-12-03 15:28:53 +08:00
if not skip_torch_cuda_test :
2022-10-09 19:44:13 +08:00
run_python ( " import torch; assert torch.cuda.is_available(), ' Torch is not able to use GPU; add --skip-torch-cuda-test to COMMANDLINE_ARGS variable to disable this check ' " )
2022-09-13 21:48:18 +08:00
2022-10-09 19:44:13 +08:00
if not is_installed ( " gfpgan " ) :
2022-10-15 10:02:18 +08:00
run_pip ( f " install { gfpgan_package } " , " gfpgan " )
2022-10-02 23:21:56 +08:00
2022-10-09 19:44:13 +08:00
if not is_installed ( " clip " ) :
2022-10-15 10:02:18 +08:00
run_pip ( f " install { clip_package } " , " clip " )
2022-10-08 19:42:34 +08:00
2022-11-26 21:10:46 +08:00
if not is_installed ( " open_clip " ) :
run_pip ( f " install { openclip_package } " , " open_clip " )
2022-10-20 02:16:22 +08:00
if ( not is_installed ( " xformers " ) or reinstall_xformers ) and xformers :
2022-10-09 19:44:13 +08:00
if platform . system ( ) == " Windows " :
2022-10-20 02:16:22 +08:00
if platform . python_version ( ) . startswith ( " 3.10 " ) :
2023-01-30 14:12:43 +08:00
run_pip ( f " install -U -I --no-deps { xformers_package } " , " xformers " )
2022-10-20 02:16:22 +08:00
else :
print ( " Installation of xformers is not supported in this version of Python. " )
print ( " You can also check this and build manually: https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Xformers#building-xformers-on-windows-by-duckness " )
if not is_installed ( " xformers " ) :
exit ( 0 )
2022-10-09 19:44:13 +08:00
elif platform . system ( ) == " Linux " :
2023-01-30 23:48:10 +08:00
run_pip ( f " install { xformers_package } " , " xformers " )
2022-10-09 00:02:56 +08:00
2022-10-11 17:38:03 +08:00
if not is_installed ( " pyngrok " ) and ngrok :
2022-10-15 10:02:18 +08:00
run_pip ( " install pyngrok " , " ngrok " )
2022-10-11 17:38:03 +08:00
2022-10-09 19:44:13 +08:00
os . makedirs ( dir_repos , exist_ok = True )
2022-09-30 16:42:40 +08:00
2022-11-26 21:10:46 +08:00
git_clone ( stable_diffusion_repo , repo_dir ( ' stable-diffusion-stability-ai ' ) , " Stable Diffusion " , stable_diffusion_commit_hash )
2022-10-16 15:13:18 +08:00
git_clone ( taming_transformers_repo , repo_dir ( ' taming-transformers ' ) , " Taming Transformers " , taming_transformers_commit_hash )
git_clone ( k_diffusion_repo , repo_dir ( ' k-diffusion ' ) , " K-diffusion " , k_diffusion_commit_hash )
git_clone ( codeformer_repo , repo_dir ( ' CodeFormer ' ) , " CodeFormer " , codeformer_commit_hash )
git_clone ( blip_repo , repo_dir ( ' BLIP ' ) , " BLIP " , blip_commit_hash )
2022-09-13 21:48:18 +08:00
2022-10-09 19:44:13 +08:00
if not is_installed ( " lpips " ) :
2022-10-15 10:02:18 +08:00
run_pip ( f " install -r { os . path . join ( repo_dir ( ' CodeFormer ' ) , ' requirements.txt ' ) } " , " requirements for CodeFormer " )
2022-09-13 21:48:18 +08:00
2022-10-15 10:02:18 +08:00
run_pip ( f " install -r { requirements_file } " , " requirements for Web UI " )
2022-10-09 19:44:13 +08:00
2022-11-27 23:48:08 +08:00
run_extensions_installers ( settings_file = args . ui_settings_file )
2022-11-01 19:19:24 +08:00
2022-10-18 20:18:02 +08:00
if update_check :
2022-10-17 00:04:09 +08:00
version_check ( commit )
2023-03-09 22:25:18 +08:00
if update_all_extensions :
git_pull_recursive ( dir_extensions )
2022-10-16 17:54:09 +08:00
2022-10-18 20:18:02 +08:00
if " --exit " in sys . argv :
2022-10-09 19:44:13 +08:00
print ( " Exiting because of --exit argument " )
exit ( 0 )
2022-09-13 21:48:18 +08:00
2022-10-30 13:22:44 +08:00
if run_tests :
2022-11-14 19:36:07 +08:00
exitcode = tests ( test_dir )
exit ( exitcode )
2022-10-30 13:22:44 +08:00
2022-11-14 18:39:22 +08:00
def tests ( test_dir ) :
if " --api " not in sys . argv :
sys . argv . append ( " --api " )
if " --ckpt " not in sys . argv :
sys . argv . append ( " --ckpt " )
sys . argv . append ( " ./test/test_files/empty.pt " )
2022-11-14 23:40:15 +08:00
if " --skip-torch-cuda-test " not in sys . argv :
sys . argv . append ( " --skip-torch-cuda-test " )
2023-01-17 16:04:56 +08:00
if " --disable-nan-check " not in sys . argv :
sys . argv . append ( " --disable-nan-check " )
2022-10-30 13:28:36 +08:00
2022-11-14 18:39:22 +08:00
print ( f " Launching Web UI in another process for testing with arguments: { ' ' . join ( sys . argv [ 1 : ] ) } " )
2022-10-30 13:22:44 +08:00
2023-01-10 17:46:35 +08:00
os . environ [ ' COMMANDLINE_ARGS ' ] = " "
2022-10-30 13:22:44 +08:00
with open ( ' test/stdout.txt ' , " w " , encoding = " utf8 " ) as stdout , open ( ' test/stderr.txt ' , " w " , encoding = " utf8 " ) as stderr :
2022-11-14 18:39:22 +08:00
proc = subprocess . Popen ( [ sys . executable , * sys . argv ] , stdout = stdout , stderr = stderr )
2022-10-30 13:22:44 +08:00
import test . server_poll
2022-11-14 19:36:07 +08:00
exitcode = test . server_poll . run_tests ( proc , test_dir )
2022-10-30 13:22:44 +08:00
print ( f " Stopping Web UI process with id { proc . pid } " )
proc . kill ( )
2022-11-14 19:36:07 +08:00
return exitcode
2022-10-30 13:22:44 +08:00
2022-09-13 21:48:18 +08:00
2022-11-03 13:08:11 +08:00
def start ( ) :
print ( f " Launching { ' API server ' if ' --nowebui ' in sys . argv else ' Web UI ' } with arguments: { ' ' . join ( sys . argv [ 1 : ] ) } " )
2022-09-13 21:48:18 +08:00
import webui
2022-11-03 13:08:11 +08:00
if ' --nowebui ' in sys . argv :
webui . api_only ( )
else :
webui . webui ( )
2022-09-13 21:48:18 +08:00
2022-10-09 19:44:13 +08:00
2022-09-20 19:56:07 +08:00
if __name__ == " __main__ " :
2022-12-03 17:35:17 +08:00
prepare_environment ( )
2022-11-03 13:08:11 +08:00
start ( )