Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ninjaneural
GitHub Repository: ninjaneural/webui
Path: blob/master/misc/direct/v1.4.1/launch_utils.py
3275 views
1
# this scripts installs necessary requirements and launches main program in webui.py
2
import subprocess
3
import os
4
import sys
5
import importlib.util
6
import platform
7
import json
8
from functools import lru_cache
9
10
from modules import cmd_args, errors
11
from modules.paths_internal import script_path, extensions_dir
12
13
args, _ = cmd_args.parser.parse_known_args()
14
15
python = sys.executable
16
git = os.environ.get('GIT', "git")
17
index_url = os.environ.get('INDEX_URL', "")
18
dir_repos = "repositories"
19
20
# Whether to default to printing command output
21
default_command_live = (os.environ.get('WEBUI_LAUNCH_LIVE_OUTPUT') == "1")
22
23
if 'GRADIO_ANALYTICS_ENABLED' not in os.environ:
24
os.environ['GRADIO_ANALYTICS_ENABLED'] = 'False'
25
26
27
def check_python_version():
28
is_windows = platform.system() == "Windows"
29
major = sys.version_info.major
30
minor = sys.version_info.minor
31
micro = sys.version_info.micro
32
33
if is_windows:
34
supported_minors = [10]
35
else:
36
supported_minors = [7, 8, 9, 10, 11]
37
38
if not (major == 3 and minor in supported_minors):
39
import modules.errors
40
41
modules.errors.print_error_explanation(f"""
42
INCOMPATIBLE PYTHON VERSION
43
44
This program is tested with 3.10.6 Python, but you have {major}.{minor}.{micro}.
45
If you encounter an error with "RuntimeError: Couldn't install torch." message,
46
or any other error regarding unsuccessful package (library) installation,
47
please downgrade (or upgrade) to the latest version of 3.10 Python
48
and delete current Python and "venv" folder in WebUI's directory.
49
50
You can download 3.10 Python from here: https://www.python.org/downloads/release/python-3106/
51
52
{"Alternatively, use a binary release of WebUI: https://github.com/AUTOMATIC1111/stable-diffusion-webui/releases" if is_windows else ""}
53
54
Use --skip-python-version-check to suppress this warning.
55
""")
56
57
58
@lru_cache()
59
def commit_hash():
60
try:
61
return subprocess.check_output([git, "rev-parse", "HEAD"], shell=False, encoding='utf8').strip()
62
except Exception:
63
return "<none>"
64
65
66
@lru_cache()
67
def git_tag():
68
try:
69
return subprocess.check_output([git, "describe", "--tags"], shell=False, encoding='utf8').strip()
70
except Exception:
71
try:
72
from pathlib import Path
73
changelog_md = Path(__file__).parent.parent / "CHANGELOG.md"
74
with changelog_md.open(encoding="utf-8") as file:
75
return next((line.strip() for line in file if line.strip()), "<none>")
76
except Exception:
77
return "<none>"
78
79
80
def run(command, desc=None, errdesc=None, custom_env=None, live: bool = default_command_live) -> str:
81
if desc is not None:
82
print(desc)
83
84
run_kwargs = {
85
"args": command,
86
"shell": True,
87
"env": os.environ if custom_env is None else custom_env,
88
"encoding": 'utf8',
89
"errors": 'ignore',
90
}
91
92
if not live:
93
run_kwargs["stdout"] = run_kwargs["stderr"] = subprocess.PIPE
94
95
result = subprocess.run(**run_kwargs)
96
97
if result.returncode != 0:
98
error_bits = [
99
f"{errdesc or 'Error running command'}.",
100
f"Command: {command}",
101
f"Error code: {result.returncode}",
102
]
103
if result.stdout:
104
error_bits.append(f"stdout: {result.stdout}")
105
if result.stderr:
106
error_bits.append(f"stderr: {result.stderr}")
107
raise RuntimeError("\n".join(error_bits))
108
109
return (result.stdout or "")
110
111
112
def is_installed(package):
113
try:
114
spec = importlib.util.find_spec(package)
115
except ModuleNotFoundError:
116
return False
117
118
return spec is not None
119
120
121
def repo_dir(name):
122
return os.path.join(script_path, dir_repos, name)
123
124
125
def run_pip(command, desc=None, live=default_command_live):
126
if args.skip_install:
127
return
128
129
index_url_line = f' --index-url {index_url}' if index_url != '' else ''
130
return run(f'"{python}" -m pip {command} --prefer-binary{index_url_line}', desc=f"Installing {desc}", errdesc=f"Couldn't install {desc}", live=live)
131
132
133
def check_run_python(code: str) -> bool:
134
result = subprocess.run([python, "-c", code], capture_output=True, shell=False)
135
return result.returncode == 0
136
137
138
def git_clone(url, dir, name, commithash=None):
139
# TODO clone into temporary dir and move if successful
140
141
if os.path.exists(dir):
142
if commithash is None:
143
return
144
145
current_hash = run(f'"{git}" -C "{dir}" rev-parse HEAD', None, f"Couldn't determine {name}'s hash: {commithash}").strip()
146
if current_hash == commithash:
147
return
148
149
run(f'"{git}" -C "{dir}" fetch', f"Fetching updates for {name}...", f"Couldn't fetch {name}")
150
run(f'"{git}" -C "{dir}" reset --hard {commithash}', f"Checking out commit for {name} with hash: {commithash}...", f"Couldn't checkout commit {commithash} for {name}")
151
return
152
153
run(f'"{git}" clone "{url}" "{dir}"', f"Cloning {name} into {dir}...", f"Couldn't clone {name}")
154
155
if commithash is not None:
156
run(f'"{git}" -C "{dir}" reset --hard {commithash}', None, "Couldn't checkout {name}'s hash: {commithash}")
157
158
159
def git_pull_recursive(dir):
160
for subdir, _, _ in os.walk(dir):
161
if os.path.exists(os.path.join(subdir, '.git')):
162
try:
163
output = subprocess.check_output([git, '-C', subdir, 'pull', '--autostash'])
164
print(f"Pulled changes for repository in '{subdir}':\n{output.decode('utf-8').strip()}\n")
165
except subprocess.CalledProcessError as e:
166
print(f"Couldn't perform 'git pull' on repository in '{subdir}':\n{e.output.decode('utf-8').strip()}\n")
167
168
169
def version_check(commit):
170
try:
171
import requests
172
commits = requests.get('https://api.github.com/repos/AUTOMATIC1111/stable-diffusion-webui/branches/master').json()
173
if commit != "<none>" and commits['commit']['sha'] != commit:
174
print("--------------------------------------------------------")
175
print("| You are not up to date with the most recent release. |")
176
print("| Consider running `git pull` to update. |")
177
print("--------------------------------------------------------")
178
elif commits['commit']['sha'] == commit:
179
print("You are up to date with the most recent release.")
180
else:
181
print("Not a git clone, can't perform version check.")
182
except Exception as e:
183
print("version check failed", e)
184
185
186
def run_extension_installer(extension_dir):
187
path_installer = os.path.join(extension_dir, "install.py")
188
if not os.path.isfile(path_installer):
189
return
190
191
try:
192
env = os.environ.copy()
193
env['PYTHONPATH'] = os.path.abspath(".")
194
195
print(run(f'"{python}" "{path_installer}"', errdesc=f"Error running install.py for extension {extension_dir}", custom_env=env))
196
except Exception as e:
197
errors.report(str(e))
198
199
200
def list_extensions(settings_file):
201
settings = {}
202
203
try:
204
if os.path.isfile(settings_file):
205
with open(settings_file, "r", encoding="utf8") as file:
206
settings = json.load(file)
207
except Exception:
208
errors.report("Could not load settings", exc_info=True)
209
210
disabled_extensions = set(settings.get('disabled_extensions', []))
211
disable_all_extensions = settings.get('disable_all_extensions', 'none')
212
213
if disable_all_extensions != 'none':
214
return []
215
216
return [x for x in os.listdir(extensions_dir) if x not in disabled_extensions]
217
218
219
def run_extensions_installers(settings_file):
220
if not os.path.isdir(extensions_dir):
221
return
222
223
for dirname_extension in list_extensions(settings_file):
224
run_extension_installer(os.path.join(extensions_dir, dirname_extension))
225
226
227
def prepare_environment():
228
torch_index_url = os.environ.get('TORCH_INDEX_URL', "https://download.pytorch.org/whl/cu118")
229
torch_command = os.environ.get('TORCH_COMMAND', f"pip install torch==2.0.1 torchvision==0.15.2 --extra-index-url {torch_index_url}")
230
requirements_file = os.environ.get('REQS_FILE', "requirements_versions.txt")
231
232
xformers_package = os.environ.get('XFORMERS_PACKAGE', 'xformers==0.0.20')
233
gfpgan_package = os.environ.get('GFPGAN_PACKAGE', "https://github.com/TencentARC/GFPGAN/archive/8d2447a2d918f8eba5a4a01463fd48e45126a379.zip")
234
clip_package = os.environ.get('CLIP_PACKAGE', "https://github.com/openai/CLIP/archive/d50d76daa670286dd6cacf3bcd80b5e4823fc8e1.zip")
235
openclip_package = os.environ.get('OPENCLIP_PACKAGE', "https://github.com/mlfoundations/open_clip/archive/bb6e834e9c70d9c27d0dc3ecedeebeaeb1ffad6b.zip")
236
237
stable_diffusion_repo = os.environ.get('STABLE_DIFFUSION_REPO', "https://github.com/Stability-AI/stablediffusion.git")
238
k_diffusion_repo = os.environ.get('K_DIFFUSION_REPO', 'https://github.com/crowsonkb/k-diffusion.git')
239
codeformer_repo = os.environ.get('CODEFORMER_REPO', 'https://github.com/sczhou/CodeFormer.git')
240
blip_repo = os.environ.get('BLIP_REPO', 'https://github.com/salesforce/BLIP.git')
241
242
stable_diffusion_commit_hash = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "cf1d67a6fd5ea1aa600c4df58e5b47da45f6bdbf")
243
k_diffusion_commit_hash = os.environ.get('K_DIFFUSION_COMMIT_HASH', "c9fe758757e022f05ca5a53fa8fac28889e4f1cf")
244
codeformer_commit_hash = os.environ.get('CODEFORMER_COMMIT_HASH', "c5b4593074ba6214284d6acd5f1719b6c5d739af")
245
blip_commit_hash = os.environ.get('BLIP_COMMIT_HASH', "48211a1594f1321b00f14c9f7a5b4813144b2fb9")
246
247
try:
248
# the existance of this file is a signal to webui.sh/bat that webui needs to be restarted when it stops execution
249
os.remove(os.path.join(script_path, "tmp", "restart"))
250
os.environ.setdefault('SD_WEBUI_RESTARTING ', '1')
251
except OSError:
252
pass
253
254
if not args.skip_python_version_check:
255
check_python_version()
256
257
commit = commit_hash()
258
tag = git_tag()
259
260
print(f"Python {sys.version}")
261
print(f"Version: {tag}")
262
print(f"Commit hash: {commit}")
263
264
if args.reinstall_torch or not is_installed("torch") or not is_installed("torchvision"):
265
run(f'"{python}" -m {torch_command}', "Installing torch and torchvision", "Couldn't install torch", live=True)
266
267
if not args.skip_torch_cuda_test and not check_run_python("import torch; assert torch.cuda.is_available()"):
268
raise RuntimeError(
269
'Torch is not able to use GPU; '
270
'add --skip-torch-cuda-test to COMMANDLINE_ARGS variable to disable this check'
271
)
272
273
if not is_installed("gfpgan"):
274
run_pip(f"install {gfpgan_package}", "gfpgan")
275
276
if not is_installed("clip"):
277
run_pip(f"install {clip_package}", "clip")
278
279
if not is_installed("open_clip"):
280
run_pip(f"install {openclip_package}", "open_clip")
281
282
if (not is_installed("xformers") or args.reinstall_xformers) and args.xformers:
283
if platform.system() == "Windows":
284
if platform.python_version().startswith("3.10"):
285
run_pip(f"install -U -I --no-deps {xformers_package}", "xformers", live=True)
286
else:
287
print("Installation of xformers is not supported in this version of Python.")
288
print("You can also check this and build manually: https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Xformers#building-xformers-on-windows-by-duckness")
289
if not is_installed("xformers"):
290
exit(0)
291
elif platform.system() == "Linux":
292
run_pip(f"install -U -I --no-deps {xformers_package}", "xformers")
293
294
if not is_installed("ngrok") and args.ngrok:
295
run_pip("install ngrok", "ngrok")
296
297
os.makedirs(os.path.join(script_path, dir_repos), exist_ok=True)
298
299
git_clone(stable_diffusion_repo, repo_dir('stable-diffusion-stability-ai'), "Stable Diffusion", stable_diffusion_commit_hash)
300
git_clone(k_diffusion_repo, repo_dir('k-diffusion'), "K-diffusion", k_diffusion_commit_hash)
301
git_clone(codeformer_repo, repo_dir('CodeFormer'), "CodeFormer", codeformer_commit_hash)
302
git_clone(blip_repo, repo_dir('BLIP'), "BLIP", blip_commit_hash)
303
304
if not is_installed("lpips"):
305
run_pip(f"install -r \"{os.path.join(repo_dir('CodeFormer'), 'requirements.txt')}\"", "requirements for CodeFormer")
306
307
if not os.path.isfile(requirements_file):
308
requirements_file = os.path.join(script_path, requirements_file)
309
run_pip(f"install -r \"{requirements_file}\"", "requirements")
310
311
run_extensions_installers(settings_file=args.ui_settings_file)
312
313
if args.update_check:
314
version_check(commit)
315
316
if args.update_all_extensions:
317
git_pull_recursive(extensions_dir)
318
319
if "--exit" in sys.argv:
320
print("Exiting because of --exit argument")
321
exit(0)
322
323
324
def configure_for_tests():
325
if "--api" not in sys.argv:
326
sys.argv.append("--api")
327
if "--ckpt" not in sys.argv:
328
sys.argv.append("--ckpt")
329
sys.argv.append(os.path.join(script_path, "test/test_files/empty.pt"))
330
if "--skip-torch-cuda-test" not in sys.argv:
331
sys.argv.append("--skip-torch-cuda-test")
332
if "--disable-nan-check" not in sys.argv:
333
sys.argv.append("--disable-nan-check")
334
335
os.environ['COMMANDLINE_ARGS'] = ""
336
337
338
def start():
339
print(f"Launching {'API server' if '--nowebui' in sys.argv else 'Web UI'} with arguments: {' '.join(sys.argv[1:])}")
340
import webui
341
if '--nowebui' in sys.argv:
342
webui.api_only()
343
else:
344
webui.webui()
345
346