Path: blob/master/misc/direct/v1.7.0/launch_utils_org.py
3275 views
# this scripts installs necessary requirements and launches main program in webui.py1import logging2import re3import subprocess4import os5import shutil6import sys7import importlib.util8import importlib.metadata9import platform10import json11from functools import lru_cache1213from modules import cmd_args, errors14from modules.paths_internal import script_path, extensions_dir15from modules.timer import startup_timer16from modules import logging_config1718args, _ = cmd_args.parser.parse_known_args()19logging_config.setup_logging(args.loglevel)2021python = sys.executable22git = os.environ.get('GIT', "git")23index_url = os.environ.get('INDEX_URL', "")24dir_repos = "repositories"2526# Whether to default to printing command output27default_command_live = (os.environ.get('WEBUI_LAUNCH_LIVE_OUTPUT') == "1")2829if 'GRADIO_ANALYTICS_ENABLED' not in os.environ:30os.environ['GRADIO_ANALYTICS_ENABLED'] = 'False'313233def check_python_version():34is_windows = platform.system() == "Windows"35major = sys.version_info.major36minor = sys.version_info.minor37micro = sys.version_info.micro3839if is_windows:40supported_minors = [10]41else:42supported_minors = [7, 8, 9, 10, 11]4344if not (major == 3 and minor in supported_minors):45import modules.errors4647modules.errors.print_error_explanation(f"""48INCOMPATIBLE PYTHON VERSION4950This program is tested with 3.10.6 Python, but you have {major}.{minor}.{micro}.51If you encounter an error with "RuntimeError: Couldn't install torch." message,52or any other error regarding unsuccessful package (library) installation,53please downgrade (or upgrade) to the latest version of 3.10 Python54and delete current Python and "venv" folder in WebUI's directory.5556You can download 3.10 Python from here: https://www.python.org/downloads/release/python-3106/5758{"Alternatively, use a binary release of WebUI: https://github.com/AUTOMATIC1111/stable-diffusion-webui/releases" if is_windows else ""}5960Use --skip-python-version-check to suppress this warning.61""")626364@lru_cache()65def commit_hash():66try:67return subprocess.check_output([git, "-C", script_path, "rev-parse", "HEAD"], shell=False, encoding='utf8').strip()68except Exception:69return "<none>"707172@lru_cache()73def git_tag():74try:75return subprocess.check_output([git, "-C", script_path, "describe", "--tags"], shell=False, encoding='utf8').strip()76except Exception:77try:7879changelog_md = os.path.join(os.path.dirname(os.path.dirname(__file__)), "CHANGELOG.md")80with open(changelog_md, "r", encoding="utf-8") as file:81line = next((line.strip() for line in file if line.strip()), "<none>")82line = line.replace("## ", "")83return line84except Exception:85return "<none>"868788def run(command, desc=None, errdesc=None, custom_env=None, live: bool = default_command_live) -> str:89if desc is not None:90print(desc)9192run_kwargs = {93"args": command,94"shell": True,95"env": os.environ if custom_env is None else custom_env,96"encoding": 'utf8',97"errors": 'ignore',98}99100if not live:101run_kwargs["stdout"] = run_kwargs["stderr"] = subprocess.PIPE102103result = subprocess.run(**run_kwargs)104105if result.returncode != 0:106error_bits = [107f"{errdesc or 'Error running command'}.",108f"Command: {command}",109f"Error code: {result.returncode}",110]111if result.stdout:112error_bits.append(f"stdout: {result.stdout}")113if result.stderr:114error_bits.append(f"stderr: {result.stderr}")115raise RuntimeError("\n".join(error_bits))116117return (result.stdout or "")118119120def is_installed(package):121try:122dist = importlib.metadata.distribution(package)123except importlib.metadata.PackageNotFoundError:124try:125spec = importlib.util.find_spec(package)126except ModuleNotFoundError:127return False128129return spec is not None130131return dist is not None132133134def repo_dir(name):135return os.path.join(script_path, dir_repos, name)136137138def run_pip(command, desc=None, live=default_command_live):139if args.skip_install:140return141142index_url_line = f' --index-url {index_url}' if index_url != '' else ''143return run(f'"{python}" -m pip {command} --prefer-binary{index_url_line}', desc=f"Installing {desc}", errdesc=f"Couldn't install {desc}", live=live)144145146def check_run_python(code: str) -> bool:147result = subprocess.run([python, "-c", code], capture_output=True, shell=False)148return result.returncode == 0149150151def git_fix_workspace(dir, name):152run(f'"{git}" -C "{dir}" fetch --refetch --no-auto-gc', f"Fetching all contents for {name}", f"Couldn't fetch {name}", live=True)153run(f'"{git}" -C "{dir}" gc --aggressive --prune=now', f"Pruning {name}", f"Couldn't prune {name}", live=True)154return155156157def run_git(dir, name, command, desc=None, errdesc=None, custom_env=None, live: bool = default_command_live, autofix=True):158try:159return run(f'"{git}" -C "{dir}" {command}', desc=desc, errdesc=errdesc, custom_env=custom_env, live=live)160except RuntimeError:161if not autofix:162raise163164print(f"{errdesc}, attempting autofix...")165git_fix_workspace(dir, name)166167return run(f'"{git}" -C "{dir}" {command}', desc=desc, errdesc=errdesc, custom_env=custom_env, live=live)168169170def git_clone(url, dir, name, commithash=None):171# TODO clone into temporary dir and move if successful172173if os.path.exists(dir):174if commithash is None:175return176177current_hash = run_git(dir, name, 'rev-parse HEAD', None, f"Couldn't determine {name}'s hash: {commithash}", live=False).strip()178if current_hash == commithash:179return180181if run_git(dir, name, 'config --get remote.origin.url', None, f"Couldn't determine {name}'s origin URL", live=False).strip() != url:182run_git(dir, name, f'remote set-url origin "{url}"', None, f"Failed to set {name}'s origin URL", live=False)183184run_git(dir, name, 'fetch', f"Fetching updates for {name}...", f"Couldn't fetch {name}", autofix=False)185186run_git(dir, name, f'checkout {commithash}', f"Checking out commit for {name} with hash: {commithash}...", f"Couldn't checkout commit {commithash} for {name}", live=True)187188return189190try:191run(f'"{git}" clone "{url}" "{dir}"', f"Cloning {name} into {dir}...", f"Couldn't clone {name}", live=True)192except RuntimeError:193shutil.rmtree(dir, ignore_errors=True)194raise195196if commithash is not None:197run(f'"{git}" -C "{dir}" checkout {commithash}', None, "Couldn't checkout {name}'s hash: {commithash}")198199200def git_pull_recursive(dir):201for subdir, _, _ in os.walk(dir):202if os.path.exists(os.path.join(subdir, '.git')):203try:204output = subprocess.check_output([git, '-C', subdir, 'pull', '--autostash'])205print(f"Pulled changes for repository in '{subdir}':\n{output.decode('utf-8').strip()}\n")206except subprocess.CalledProcessError as e:207print(f"Couldn't perform 'git pull' on repository in '{subdir}':\n{e.output.decode('utf-8').strip()}\n")208209210def version_check(commit):211try:212import requests213commits = requests.get('https://api.github.com/repos/AUTOMATIC1111/stable-diffusion-webui/branches/master').json()214if commit != "<none>" and commits['commit']['sha'] != commit:215print("--------------------------------------------------------")216print("| You are not up to date with the most recent release. |")217print("| Consider running `git pull` to update. |")218print("--------------------------------------------------------")219elif commits['commit']['sha'] == commit:220print("You are up to date with the most recent release.")221else:222print("Not a git clone, can't perform version check.")223except Exception as e:224print("version check failed", e)225226227def run_extension_installer(extension_dir):228path_installer = os.path.join(extension_dir, "install.py")229if not os.path.isfile(path_installer):230return231232try:233env = os.environ.copy()234env['PYTHONPATH'] = f"{os.path.abspath('.')}{os.pathsep}{env.get('PYTHONPATH', '')}"235236stdout = run(f'"{python}" "{path_installer}"', errdesc=f"Error running install.py for extension {extension_dir}", custom_env=env).strip()237if stdout:238print(stdout)239except Exception as e:240errors.report(str(e))241242243def list_extensions(settings_file):244settings = {}245246try:247if os.path.isfile(settings_file):248with open(settings_file, "r", encoding="utf8") as file:249settings = json.load(file)250except Exception:251errors.report("Could not load settings", exc_info=True)252253disabled_extensions = set(settings.get('disabled_extensions', []))254disable_all_extensions = settings.get('disable_all_extensions', 'none')255256if disable_all_extensions != 'none' or args.disable_extra_extensions or args.disable_all_extensions or not os.path.isdir(extensions_dir):257return []258259return [x for x in os.listdir(extensions_dir) if x not in disabled_extensions]260261262def run_extensions_installers(settings_file):263if not os.path.isdir(extensions_dir):264return265266with startup_timer.subcategory("run extensions installers"):267for dirname_extension in list_extensions(settings_file):268logging.debug(f"Installing {dirname_extension}")269270path = os.path.join(extensions_dir, dirname_extension)271272if os.path.isdir(path):273run_extension_installer(path)274startup_timer.record(dirname_extension)275276277re_requirement = re.compile(r"\s*([-_a-zA-Z0-9]+)\s*(?:==\s*([-+_.a-zA-Z0-9]+))?\s*")278279280def requirements_met(requirements_file):281"""282Does a simple parse of a requirements.txt file to determine if all rerqirements in it283are already installed. Returns True if so, False if not installed or parsing fails.284"""285286import importlib.metadata287import packaging.version288289with open(requirements_file, "r", encoding="utf8") as file:290for line in file:291if line.strip() == "":292continue293294m = re.match(re_requirement, line)295if m is None:296return False297298package = m.group(1).strip()299version_required = (m.group(2) or "").strip()300301if version_required == "":302continue303304try:305version_installed = importlib.metadata.version(package)306except Exception:307return False308309if packaging.version.parse(version_required) != packaging.version.parse(version_installed):310return False311312return True313314315def prepare_environment():316torch_index_url = os.environ.get('TORCH_INDEX_URL', "https://download.pytorch.org/whl/cu118")317torch_command = os.environ.get('TORCH_COMMAND', f"pip install torch==2.0.1 torchvision==0.15.2 --extra-index-url {torch_index_url}")318if args.use_ipex:319if platform.system() == "Windows":320# The "Nuullll/intel-extension-for-pytorch" wheels were built from IPEX source for Intel Arc GPU: https://github.com/intel/intel-extension-for-pytorch/tree/xpu-main321# This is NOT an Intel official release so please use it at your own risk!!322# See https://github.com/Nuullll/intel-extension-for-pytorch/releases/tag/v2.0.110%2Bxpu-master%2Bdll-bundle for details.323#324# Strengths (over official IPEX 2.0.110 windows release):325# - AOT build (for Arc GPU only) to eliminate JIT compilation overhead: https://github.com/intel/intel-extension-for-pytorch/issues/399326# - Bundles minimal oneAPI 2023.2 dependencies into the python wheels, so users don't need to install oneAPI for the whole system.327# - Provides a compatible torchvision wheel: https://github.com/intel/intel-extension-for-pytorch/issues/465328# Limitation:329# - Only works for python 3.10330url_prefix = "https://github.com/Nuullll/intel-extension-for-pytorch/releases/download/v2.0.110%2Bxpu-master%2Bdll-bundle"331torch_command = os.environ.get('TORCH_COMMAND', f"pip install {url_prefix}/torch-2.0.0a0+gite9ebda2-cp310-cp310-win_amd64.whl {url_prefix}/torchvision-0.15.2a0+fa99a53-cp310-cp310-win_amd64.whl {url_prefix}/intel_extension_for_pytorch-2.0.110+gitc6ea20b-cp310-cp310-win_amd64.whl")332else:333# Using official IPEX release for linux since it's already an AOT build.334# However, users still have to install oneAPI toolkit and activate oneAPI environment manually.335# See https://intel.github.io/intel-extension-for-pytorch/index.html#installation for details.336torch_index_url = os.environ.get('TORCH_INDEX_URL', "https://pytorch-extension.intel.com/release-whl/stable/xpu/us/")337torch_command = os.environ.get('TORCH_COMMAND', f"pip install torch==2.0.0a0 intel-extension-for-pytorch==2.0.110+gitba7f6c1 --extra-index-url {torch_index_url}")338requirements_file = os.environ.get('REQS_FILE', "requirements_versions.txt")339340xformers_package = os.environ.get('XFORMERS_PACKAGE', 'xformers==0.0.20')341clip_package = os.environ.get('CLIP_PACKAGE', "https://github.com/openai/CLIP/archive/d50d76daa670286dd6cacf3bcd80b5e4823fc8e1.zip")342openclip_package = os.environ.get('OPENCLIP_PACKAGE', "https://github.com/mlfoundations/open_clip/archive/bb6e834e9c70d9c27d0dc3ecedeebeaeb1ffad6b.zip")343344stable_diffusion_repo = os.environ.get('STABLE_DIFFUSION_REPO', "https://github.com/Stability-AI/stablediffusion.git")345stable_diffusion_xl_repo = os.environ.get('STABLE_DIFFUSION_XL_REPO', "https://github.com/Stability-AI/generative-models.git")346k_diffusion_repo = os.environ.get('K_DIFFUSION_REPO', 'https://github.com/crowsonkb/k-diffusion.git')347codeformer_repo = os.environ.get('CODEFORMER_REPO', 'https://github.com/sczhou/CodeFormer.git')348blip_repo = os.environ.get('BLIP_REPO', 'https://github.com/salesforce/BLIP.git')349350stable_diffusion_commit_hash = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "cf1d67a6fd5ea1aa600c4df58e5b47da45f6bdbf")351stable_diffusion_xl_commit_hash = os.environ.get('STABLE_DIFFUSION_XL_COMMIT_HASH', "45c443b316737a4ab6e40413d7794a7f5657c19f")352k_diffusion_commit_hash = os.environ.get('K_DIFFUSION_COMMIT_HASH', "ab527a9a6d347f364e3d185ba6d714e22d80cb3c")353codeformer_commit_hash = os.environ.get('CODEFORMER_COMMIT_HASH', "c5b4593074ba6214284d6acd5f1719b6c5d739af")354blip_commit_hash = os.environ.get('BLIP_COMMIT_HASH', "48211a1594f1321b00f14c9f7a5b4813144b2fb9")355356try:357# the existence of this file is a signal to webui.sh/bat that webui needs to be restarted when it stops execution358os.remove(os.path.join(script_path, "tmp", "restart"))359os.environ.setdefault('SD_WEBUI_RESTARTING', '1')360except OSError:361pass362363if not args.skip_python_version_check:364check_python_version()365366startup_timer.record("checks")367368commit = commit_hash()369tag = git_tag()370startup_timer.record("git version info")371372print(f"Python {sys.version}")373print(f"Version: {tag}")374print(f"Commit hash: {commit}")375376if args.reinstall_torch or not is_installed("torch") or not is_installed("torchvision"):377run(f'"{python}" -m {torch_command}', "Installing torch and torchvision", "Couldn't install torch", live=True)378startup_timer.record("install torch")379380if args.use_ipex:381args.skip_torch_cuda_test = True382if not args.skip_torch_cuda_test and not check_run_python("import torch; assert torch.cuda.is_available()"):383raise RuntimeError(384'Torch is not able to use GPU; '385'add --skip-torch-cuda-test to COMMANDLINE_ARGS variable to disable this check'386)387startup_timer.record("torch GPU test")388389if not is_installed("clip"):390run_pip(f"install {clip_package}", "clip")391startup_timer.record("install clip")392393if not is_installed("open_clip"):394run_pip(f"install {openclip_package}", "open_clip")395startup_timer.record("install open_clip")396397if (not is_installed("xformers") or args.reinstall_xformers) and args.xformers:398run_pip(f"install -U -I --no-deps {xformers_package}", "xformers")399startup_timer.record("install xformers")400401if not is_installed("ngrok") and args.ngrok:402run_pip("install ngrok", "ngrok")403startup_timer.record("install ngrok")404405os.makedirs(os.path.join(script_path, dir_repos), exist_ok=True)406407git_clone(stable_diffusion_repo, repo_dir('stable-diffusion-stability-ai'), "Stable Diffusion", stable_diffusion_commit_hash)408git_clone(stable_diffusion_xl_repo, repo_dir('generative-models'), "Stable Diffusion XL", stable_diffusion_xl_commit_hash)409git_clone(k_diffusion_repo, repo_dir('k-diffusion'), "K-diffusion", k_diffusion_commit_hash)410git_clone(codeformer_repo, repo_dir('CodeFormer'), "CodeFormer", codeformer_commit_hash)411git_clone(blip_repo, repo_dir('BLIP'), "BLIP", blip_commit_hash)412413startup_timer.record("clone repositores")414415if not is_installed("lpips"):416run_pip(f"install -r \"{os.path.join(repo_dir('CodeFormer'), 'requirements.txt')}\"", "requirements for CodeFormer")417startup_timer.record("install CodeFormer requirements")418419if not os.path.isfile(requirements_file):420requirements_file = os.path.join(script_path, requirements_file)421422if not requirements_met(requirements_file):423run_pip(f"install -r \"{requirements_file}\"", "requirements")424startup_timer.record("install requirements")425426if not args.skip_install:427run_extensions_installers(settings_file=args.ui_settings_file)428429if args.update_check:430version_check(commit)431startup_timer.record("check version")432433if args.update_all_extensions:434git_pull_recursive(extensions_dir)435startup_timer.record("update extensions")436437if "--exit" in sys.argv:438print("Exiting because of --exit argument")439exit(0)440441442443def configure_for_tests():444if "--api" not in sys.argv:445sys.argv.append("--api")446if "--ckpt" not in sys.argv:447sys.argv.append("--ckpt")448sys.argv.append(os.path.join(script_path, "test/test_files/empty.pt"))449if "--skip-torch-cuda-test" not in sys.argv:450sys.argv.append("--skip-torch-cuda-test")451if "--disable-nan-check" not in sys.argv:452sys.argv.append("--disable-nan-check")453454os.environ['COMMANDLINE_ARGS'] = ""455456457def start():458print(f"Launching {'API server' if '--nowebui' in sys.argv else 'Web UI'} with arguments: {' '.join(sys.argv[1:])}")459import webui460if '--nowebui' in sys.argv:461webui.api_only()462else:463webui.webui()464465466def dump_sysinfo():467from modules import sysinfo468import datetime469470text = sysinfo.get()471filename = f"sysinfo-{datetime.datetime.utcnow().strftime('%Y-%m-%d-%H-%M')}.json"472473with open(filename, "w", encoding="utf8") as file:474file.write(text)475476return filename477478479