|
|
|
|
|
|
|
from pathlib import Path |
|
import os |
|
import time |
|
import re |
|
import subprocess |
|
import threading |
|
import sys |
|
import socket |
|
from typing import List |
|
import config |
|
|
|
def mkdirs(path, exist_ok=True): |
|
if path and not Path(path).exists(): |
|
os.makedirs(path,exist_ok=exist_ok) |
|
|
|
|
|
|
|
_useFrpc = config.useFrpc |
|
|
|
_useNgrok = config.useNgrok |
|
|
|
_reLoad = config.reLoad |
|
|
|
_before_downloading = config.before_downloading |
|
|
|
_async_downloading = config.async_downloading |
|
|
|
_before_start_sync_downloading = config.before_start_sync_downloading |
|
|
|
_server_port = config.server_port or 7860 |
|
|
|
_sd_git_repo = config.sd_git_repo\ |
|
.replace('{sdwui}','stable-diffusion-webui')\ |
|
.replace('{wui}',"webui") or 'https://github.com/viyiviyi/stable-diffusion-webui.git -b local' |
|
|
|
_sd_config_git_repu = config.sd_config_git_repu\ |
|
.replace('{sdwui}','stable-diffusion-webui')\ |
|
.replace('{wui}',"webui") or 'https://github.com/viyiviyi/sd-configs.git' |
|
|
|
_link_instead_of_copy = config.link_instead_of_copy |
|
|
|
show_shell_info = not config.hidden_console_info |
|
|
|
_skip_start = config.skip_start |
|
|
|
run_by_none_device = False |
|
|
|
|
|
def run(command, cwd=None, desc=None, errdesc=None, custom_env=None,try_error:bool=True) -> str: |
|
global show_shell_info |
|
if desc is not None: |
|
print(desc) |
|
|
|
run_kwargs = { |
|
"args": command, |
|
"shell": True, |
|
"cwd": cwd, |
|
"env": os.environ if custom_env is None else custom_env, |
|
"encoding": 'utf8', |
|
"errors": 'ignore', |
|
} |
|
|
|
if not show_shell_info: |
|
run_kwargs["stdout"] = run_kwargs["stderr"] = subprocess.PIPE |
|
|
|
result = subprocess.run(**run_kwargs) |
|
|
|
if result.returncode != 0: |
|
error_bits = [ |
|
f"{errdesc or 'Error running command'}.", |
|
f"Command: {command}", |
|
f"Error code: {result.returncode}", |
|
] |
|
if result.stdout: |
|
error_bits.append(f"stdout: {result.stdout}") |
|
if result.stderr: |
|
error_bits.append(f"stderr: {result.stderr}") |
|
if try_error: |
|
print(RuntimeError("\n".join(error_bits))) |
|
else: |
|
raise RuntimeError("\n".join(error_bits)) |
|
|
|
if show_shell_info: |
|
print(result.stdout or "") |
|
return (result.stdout or "") |
|
|
|
|
|
install_path=f"{os.getcwd()}/sdwui" |
|
output_path= os.path.join(os.getcwd(), config.output_path or 'sdwui/Output') |
|
input_path = config.input_path or f'{os.getcwd()}/sdwui/Input' |
|
|
|
mkdirs(install_path,True) |
|
mkdirs(output_path,True) |
|
|
|
os.environ['install_path'] = install_path |
|
os.environ['output_path'] = output_path |
|
os.environ['input_path'] = input_path |
|
|
|
def replace_path(input_str:str): |
|
return input_str.replace('$install_path',install_path)\ |
|
.replace('{install_path}',install_path)\ |
|
.replace('$input_path',input_path)\ |
|
.replace('{input_path}',input_path)\ |
|
.replace('$output_path',output_path)\ |
|
.replace('{output_path}',output_path)\ |
|
.replace('{sdwui}','stable-diffusion-webui')\ |
|
.replace('{wui}',"webui") |
|
|
|
space_string = ' \n\r\t\'\",' |
|
|
|
def config_reader(conf:str): |
|
args = [replace_path(item.split('#')[0].strip(space_string)) for item in conf.split('\n') if item.strip(space_string)] |
|
return [item.strip() for item in args if item.strip()] |
|
|
|
|
|
ngrokTokenFile = os.path.join(input_path,'configs/ngrok_token.txt') |
|
frpcConfigFile = os.path.join(input_path,'configs/frpc_koishi.ini') |
|
|
|
frpcSSLFFlies = [os.path.join(input_path,'configs/koishi_ssl')] + config_reader(config.frp_ssl_dir) |
|
|
|
|
|
frpcExePath = os.path.join(input_path,'utils-tools/frpc') |
|
|
|
otherArgs = ' '.join([item for item in config_reader(config.sd_start_args) if item != '--no-gradio-queue']) or '--xformers' |
|
|
|
venvPath = os.path.join(input_path,'sd-webui-venv/venv.tar.bak') |
|
|
|
|
|
|
|
kaggleApiTokenFile = os.path.join(input_path,'configs/kaggle.json') |
|
|
|
requirements = [] |
|
|
|
frpcStartArg = '' |
|
|
|
_setting_file = replace_path(config.setting_file) |
|
|
|
_ui_config_file = replace_path(config.ui_config_file) |
|
|
|
mkdirs(f'{install_path}/configFiles',True) |
|
|
|
_frp_config_or_file = replace_path(config.frp_config_or_file) |
|
if Path(_frp_config_or_file.strip()).exists(): |
|
frpcConfigFile = _frp_config_or_file.strip() |
|
if not Path(frpcConfigFile).exists(): |
|
if _frp_config_or_file.strip().startswith('-f'): |
|
frpcStartArg = _frp_config_or_file.strip() |
|
else: |
|
print('没有frpcp配置') |
|
_useFrpc = False |
|
else: |
|
run(f'''cp -f {frpcConfigFile} {install_path}/configFiles/frpc_webui.ini''') |
|
frpcConfigFile = f'{install_path}/configFiles/frpc_webui.ini' |
|
run(f'''sed -i "s/local_port = .*/local_port = {_server_port}/g" {frpcConfigFile}''') |
|
frpcStartArg = f' -c {frpcConfigFile}' |
|
|
|
|
|
ngrokToken='' |
|
_ngrok_config_or_file = replace_path(config.ngrok_config_or_file) |
|
if Path(_ngrok_config_or_file.strip()).exists(): |
|
ngrokTokenFile = _ngrok_config_or_file.strip() |
|
if Path(ngrokTokenFile).exists(): |
|
with open(ngrokTokenFile,encoding = "utf-8") as nkfile: |
|
ngrokToken = nkfile.readline() |
|
elif not _ngrok_config_or_file.strip().startswith('/'): |
|
ngrokToken=_ngrok_config_or_file.strip() |
|
|
|
if not Path(venvPath).exists(): |
|
venvPath = os.path.join(input_path,'sd-webui-venv/venv.zip') |
|
|
|
import concurrent.futures |
|
import importlib |
|
import os |
|
import pprint |
|
import re |
|
from pathlib import Path |
|
from typing import List |
|
|
|
import requests |
|
|
|
show_shell_info = False |
|
|
|
|
|
def is_installed(package): |
|
try: |
|
spec = importlib.util.find_spec(package) |
|
except ModuleNotFoundError: |
|
return False |
|
|
|
return spec is not None |
|
|
|
def download_file(url:str, filename:str, dist_path:str, cache_path = '',_link_instead_of_copy:bool=True): |
|
|
|
if not filename: |
|
with requests.get(url, stream=True) as r: |
|
if 'Content-Disposition' in r.headers: |
|
filename = r.headers['Content-Disposition'].split('filename=')[1].strip('"') |
|
r.close() |
|
if not filename and re.search(r'/[^/]+\.[^/]+$',url): |
|
filename = url.split('/')[-1] |
|
|
|
filename = re.sub(r'[\\/:*?"<>|;]', '', filename) |
|
filename = re.sub(r'[\s\t]+', '_', filename) |
|
|
|
if show_shell_info: |
|
print(f'下载 {filename} url: {url} --> {dist_path}') |
|
|
|
|
|
if cache_path and not Path(cache_path).exists(): |
|
mkdirs(cache_path,exist_ok=True) |
|
if dist_path and not Path(dist_path).exists(): |
|
mkdirs(dist_path,exist_ok=True) |
|
|
|
|
|
filepath = os.path.join(dist_path, filename) |
|
|
|
if cache_path: |
|
cache_path = os.path.join(cache_path, filename) |
|
|
|
|
|
if Path(filepath).exists(): |
|
print(f'文件 {filename} 已存在 {dist_path}') |
|
return |
|
|
|
if cache_path and Path(cache_path).exists(): |
|
run(f'cp -n -r -f {"-s" if _link_instead_of_copy else ""} {cache_path} {dist_path}') |
|
if show_shell_info: |
|
print(f'文件缓存 {cache_path} --> {dist_path}') |
|
return |
|
|
|
with requests.get(url, stream=True) as r: |
|
r.raise_for_status() |
|
with open(cache_path or filepath, 'wb') as f: |
|
for chunk in r.iter_content(chunk_size=8192): |
|
if chunk: |
|
f.write(chunk) |
|
|
|
if cache_path: |
|
run(f'cp -n -r -f {"-s" if _link_instead_of_copy else ""} {cache_path} {dist_path}') |
|
if show_shell_info: |
|
print(f'下载完成 {filename} --> {dist_path}') |
|
|
|
def download_git(url, dist_path, cache_path = '',_link_instead_of_copy:bool=True): |
|
if not Path(dist_path).exists(): |
|
mkdirs(dist_path,exist_ok=True) |
|
if show_shell_info: |
|
print(f'git 下载 {url} --> {dist_path}') |
|
if cache_path and not Path(cache_path).exists(): |
|
mkdirs(cache_path,exist_ok=True) |
|
run(f'git clone {config.git_proxy}{url}',cwd = cache_path) |
|
if cache_path: |
|
run(f'cp -n -r -f {cache_path}/* {dist_path}') |
|
else: |
|
run(f'git clone {config.git_proxy}{url}',cwd = dist_path) |
|
if show_shell_info: |
|
print(f'git 下载完成 {url} --> {dist_path}') |
|
|
|
|
|
|
|
|
|
def pause_url(url:str,dist_path:str): |
|
file_name = '' |
|
if re.match(r'^[^:]+:(https?|ftps?)://', url, flags=0): |
|
file_name = re.findall(r'^[^:]+:',url)[0][:-1] |
|
url = url[len(file_name)+1:] |
|
if not re.match(r'^(https?|ftps?)://',url): |
|
return |
|
file_name = re.sub(r'\s+','_',file_name or '') |
|
path_hash = str(hash(url)).replace('-','') |
|
|
|
return {'file_name':file_name,'path_hash':path_hash,'url':url,'dist_path':dist_path} |
|
|
|
def download_urls(download_list:List[dict],sync:bool=False,thread_num:int=5, |
|
cache_path:str=os.path.join(os.getcwd(),'.cache','download_util'), |
|
_link_instead_of_copy:bool=True,is_await:bool=False): |
|
if sync: |
|
for conf in download_list: |
|
cache_dir = os.path.join(cache_path,conf['path_hash']) |
|
if conf['url'].startswith('https://github.com'): |
|
download_git(conf['url'],conf['dist_path'],cache_path=cache_dir,_link_instead_of_copy=_link_instead_of_copy) |
|
continue |
|
download_file(conf['url'],conf['file_name'],conf['dist_path'],cache_path=cache_dir,_link_instead_of_copy=_link_instead_of_copy) |
|
else: |
|
executor = concurrent.futures.ThreadPoolExecutor(max_workers=thread_num) |
|
futures = [] |
|
for conf in download_list: |
|
cache_dir = os.path.join(cache_path,conf['path_hash']) |
|
if conf['url'].startswith('https://github.com'): |
|
futures.append(executor.submit(download_git, conf['url'],conf['dist_path'], |
|
cache_path=cache_dir,_link_instead_of_copy=_link_instead_of_copy)) |
|
continue |
|
futures.append(executor.submit(download_file, conf['url'],conf['file_name'],conf['dist_path'], |
|
cache_path=cache_dir,_link_instead_of_copy=_link_instead_of_copy)) |
|
if is_await: |
|
concurrent.futures.wait(futures) |
|
|
|
|
|
def parse_config(config:str): |
|
space_string = ' \n\r\t\'\",' |
|
other_flie_list = [item.split('#')[0].strip(space_string) for item in config.split('\n') if item.strip(space_string)] |
|
other_flie_list = [item.strip() for item in other_flie_list if item.strip()] |
|
other_flie_list_store = {} |
|
other_flie_list_store_name='default' |
|
other_flie_list_store_list_cache=[] |
|
|
|
for item in other_flie_list: |
|
if item.startswith('[') and item.endswith(']'): |
|
if not other_flie_list_store_name == 'default': |
|
other_flie_list_store[other_flie_list_store_name]=other_flie_list_store_list_cache |
|
other_flie_list_store_list_cache = [] |
|
other_flie_list_store_name = item[1:-1] |
|
else: |
|
other_flie_list_store_list_cache.append(item) |
|
other_flie_list_store[other_flie_list_store_name]=other_flie_list_store_list_cache |
|
|
|
return other_flie_list_store |
|
|
|
|
|
def link_or_download_flie(config:str, skip_url:bool=False, _link_instead_of_copy:bool=True, base_path:str = '', |
|
sync:bool=False,thread_num:int=None, is_await:bool=False): |
|
store:dict[str,List[str]] = parse_config(config) |
|
download_list = [] |
|
for dist_dir in store.keys(): |
|
dist_path = os.path.join(base_path,dist_dir) |
|
mkdirs(dist_path,exist_ok=True) |
|
for path in store[dist_dir]: |
|
if 'https://' in path or 'http://' in path: |
|
if skip_url: |
|
continue |
|
if sync: |
|
download_urls([pause_url(path,dist_path)],_link_instead_of_copy = _link_instead_of_copy, sync=sync) |
|
continue |
|
download_list.append(pause_url(path,dist_path)) |
|
else: |
|
run(f'cp -n -r -f {"-s" if _link_instead_of_copy else ""} {path} {dist_path}') |
|
if show_shell_info: |
|
print(f'{"链接" if _link_instead_of_copy else "复制"} {path} --> {dist_path}') |
|
run(f'rm -f {dist_path}/\*.* ') |
|
if not skip_url: |
|
if show_shell_info: |
|
pprint.pprint(download_list) |
|
download_urls(download_list,_link_instead_of_copy = _link_instead_of_copy, sync=sync, thread_num=thread_num or 2,is_await=is_await) |
|
|
|
|
|
def echoToFile(content:str,path:str): |
|
if path.find('/') >= 0: |
|
_path = '/'.join(path.split('/')[:-1]) |
|
mkdirs(f'{_path}',True) |
|
with open(path,'w') as sh: |
|
sh.write(content) |
|
|
|
def zipPath(path:str,zipName:str,format='tar'): |
|
if path.startswith('$install_path'): |
|
path = path.replace('$install_path',install_path) |
|
if path.startswith('$output_path'): |
|
path = path.replace('$install_path',output_path) |
|
if not path.startswith('/'): |
|
path = f'{install_path}/sd_main_dir/{path}' |
|
if Path(path).exists(): |
|
if 'tar' == format: |
|
run(f'tar -cf {output_path}/'+ zipName +'.tar -C '+ path +' . ') |
|
elif 'gz' == format: |
|
run(f'tar -czf {output_path}/'+ zipName +'.tar.gz -C '+ path +' . ') |
|
return |
|
print('指定的目录不存在:'+path) |
|
|
|
|
|
def check_service(host, port): |
|
try: |
|
socket.create_connection((host, port), timeout=5) |
|
return True |
|
except socket.error: |
|
return False |
|
|
|
|
|
def startNgrok(ngrokToken:str,ngrokLocalPort:int): |
|
if not is_installed('pyngrok'): |
|
run(f'pip install pyngrok') |
|
from pyngrok import conf, ngrok |
|
try: |
|
conf.get_default().auth_token = ngrokToken |
|
conf.get_default().monitor_thread = False |
|
ssh_tunnels = ngrok.get_tunnels(conf.get_default()) |
|
if len(ssh_tunnels) == 0: |
|
ssh_tunnel = ngrok.connect(ngrokLocalPort) |
|
print('ngrok 访问地址:'+ssh_tunnel.public_url) |
|
else: |
|
print('ngrok 访问地址:'+ssh_tunnels[0].public_url) |
|
except: |
|
print('启动ngrok出错') |
|
|
|
def startFrpc(name,configFile): |
|
echoToFile(f''' |
|
cd {install_path}/frpc/ |
|
{install_path}/frpc/frpc {configFile} |
|
''',f'{install_path}/frpc/start.sh') |
|
os.system(f'''bash {install_path}/frpc/start.sh''') |
|
|
|
def installProxyExe(): |
|
if _useFrpc: |
|
print('安装frpc') |
|
mkdirs(f'{install_path}/frpc',True) |
|
if Path(frpcExePath).exists(): |
|
run(f'cp -f -n {frpcExePath} {install_path}/frpc/frpc') |
|
else: |
|
run(f'wget "https://huggingface.co/datasets/ACCA225/Frp/resolve/main/frpc" -O {install_path}/frpc/frpc') |
|
|
|
for ssl in frpcSSLFFlies: |
|
if Path(ssl).exists(): |
|
run(f'cp -f -n {ssl}/* {install_path}/frpc/') |
|
run(f'chmod +x {install_path}/frpc/frpc') |
|
run(f'{install_path}/frpc/frpc -v') |
|
if _useNgrok and not is_installed('pyngrok'): |
|
run('pip install pyngrok') |
|
|
|
def startProxy(): |
|
if _useNgrok: |
|
startNgrok(ngrokToken,_server_port) |
|
if _useFrpc: |
|
startFrpc('frpc_proxy',frpcStartArg) |
|
|
|
|
|
|
|
def localProxy(): |
|
conf = ''' |
|
server |
|
{ |
|
listen '''+str(_server_port)+'''; |
|
listen [::]:'''+str(_server_port)+'''; |
|
server_name 127.0.0.1 localhost 0.0.0.0 ""; |
|
|
|
if ($request_method = OPTIONS) { |
|
return 200; |
|
} |
|
fastcgi_send_timeout 10m; |
|
fastcgi_read_timeout 10m; |
|
fastcgi_connect_timeout 10m; |
|
location /1/ |
|
{ |
|
proxy_pass http://127.0.0.1:'''+str(_server_port+2)+'''/; |
|
# add_header Set-Cookie "subpath=1; expires=0; Path=/"; |
|
# proxy_set_header Set-Cookie "subpath=1; expires=0; Path=/"; |
|
proxy_set_header Host $host; |
|
proxy_set_header X-Real-IP $remote_addr; |
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
|
proxy_set_header REMOTE-HOST $remote_addr; |
|
proxy_set_header Upgrade $http_upgrade; |
|
proxy_set_header Connection upgrade; |
|
proxy_http_version 1.1; |
|
proxy_connect_timeout 10m; |
|
proxy_read_timeout 10m; |
|
} |
|
location / |
|
{ |
|
set $proxy_url http://127.0.0.1:'''+str(_server_port+1)+'''; |
|
# if ($cookie_subpath = "1") { |
|
# set $proxy_url http://127.0.0.1:'''+str(_server_port+2)+'''; |
|
# } |
|
proxy_pass $proxy_url; |
|
proxy_set_header Host $host; |
|
proxy_set_header X-Real-IP $remote_addr; |
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
|
proxy_set_header REMOTE-HOST $remote_addr; |
|
proxy_set_header Upgrade $http_upgrade; |
|
proxy_set_header Connection upgrade; |
|
proxy_http_version 1.1; |
|
proxy_connect_timeout 10m; |
|
proxy_read_timeout 10m; |
|
} |
|
} |
|
''' |
|
echoToFile(conf,'/etc/nginx/conf.d/proxy_nginx.conf') |
|
if not check_service('localhost',_server_port): |
|
run(f'''nginx -c /etc/nginx/nginx.conf''') |
|
os.system(f'''nginx -s reload''') |
|
|
|
|
|
import inspect |
|
import ctypes |
|
|
|
def _async_raise(tid, exctype): |
|
"""raises the exception, performs cleanup if needed""" |
|
tid = ctypes.c_long(tid) |
|
if not inspect.isclass(exctype): |
|
exctype = type(exctype) |
|
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)) |
|
if res == 0: |
|
raise ValueError("invalid thread id") |
|
elif res != 1: |
|
|
|
|
|
ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None) |
|
raise SystemError("PyThreadState_SetAsyncExc failed") |
|
|
|
def stop_thread(thread): |
|
_async_raise(thread.ident, SystemExit) |
|
|
|
def stop_solo_threads(): |
|
|
|
threads = threading.enumerate() |
|
|
|
for thread in threads: |
|
if thread.name.startswith('solo_'): |
|
print(f'结束线程:{thread.name}') |
|
try: |
|
stop_thread(thread) |
|
except socket.error: |
|
print(f'结束线程:{thread.name} 执行失败') |
|
|
|
|
|
envInstalled=False |
|
quickStart = True |
|
|
|
def install(): |
|
print('安装') |
|
os.chdir(f'''{install_path}''') |
|
run(f'''git lfs install''') |
|
run(f'''git config --global credential.helper store''') |
|
for requirement in requirements: |
|
run(f'pip install {requirement}') |
|
if _reLoad: |
|
run(f'''rm -rf sd_main_dir''') |
|
if Path("sd_main_dir").exists(): |
|
os.chdir(f'''{install_path}/sd_main_dir/''') |
|
run(f'''git checkout .''') |
|
run(f'''git pull''') |
|
else: |
|
run(f'''git clone {config.git_proxy}{_sd_git_repo} sd_main_dir''') |
|
os.chdir(f'''{install_path}/sd_main_dir''') |
|
print('安装 完成') |
|
|
|
|
|
def link_dir(): |
|
print('链接输出目录') |
|
|
|
mkdirs(f'{output_path}/outputs',True) |
|
run(f'''rm -rf {install_path}/sd_main_dir/outputs''') |
|
run(f'''ln -s -r {output_path}/outputs {install_path}/sd_main_dir/''') |
|
|
|
mkdirs(f'{output_path}/log',True) |
|
run(f'''rm -rf {install_path}/sd_main_dir/log''') |
|
run(f'''ln -s -r {output_path}/log {install_path}/sd_main_dir/''') |
|
|
|
run(f'''rm -rf {install_path}/sd_main_dir/textual_inversion''') |
|
mkdirs(f'{output_path}/textual_inversion/',True) |
|
run(f'''ln -s -r {output_path}/textual_inversion {install_path}/sd_main_dir/''') |
|
print('链接输出目录 完成') |
|
|
|
def install_optimizing(): |
|
run('sudo apt install nginx -y') |
|
run('env TF_CPP_MIN_LOG_LEVEL=1') |
|
run('sudo apt -y update -qq') |
|
run('wget http://launchpadlibrarian.net/367274644/libgoogle-perftools-dev_2.5-2.2ubuntu3_amd64.deb') |
|
run('wget https://launchpad.net/ubuntu/+source/google-perftools/2.5-2.2ubuntu3/+build/14795286/+files/google-perftools_2.5-2.2ubuntu3_all.deb') |
|
run('wget https://launchpad.net/ubuntu/+source/google-perftools/2.5-2.2ubuntu3/+build/14795286/+files/libtcmalloc-minimal4_2.5-2.2ubuntu3_amd64.deb') |
|
run('wget https://launchpad.net/ubuntu/+source/google-perftools/2.5-2.2ubuntu3/+build/14795286/+files/libgoogle-perftools4_2.5-2.2ubuntu3_amd64.deb') |
|
run('sudo apt -y install -qq libunwind8-dev') |
|
run('dpkg -i *.deb') |
|
run('env LD_P_reLoad=libtcmalloc.so') |
|
run('rm *.deb') |
|
|
|
|
|
def install_dependencies(): |
|
print('安装需要的python环境') |
|
global envInstalled |
|
global venvPath |
|
run(f'''rm -rf {install_path}/sd_main_dir/venv''') |
|
mkdirs(f'{install_path}/sd_main_dir/venv',True) |
|
if str(sys.version).startswith('3.10'): |
|
try: |
|
run('python3 -m venv venv' ,cwd=f'{install_path}/sd_main_dir',try_error=False) |
|
except: |
|
run('sudo apt install python3.10-venv -y') |
|
run('python3 -m venv venv' ,cwd=f'{install_path}/sd_main_dir') |
|
else: |
|
run('add-apt-repository ppa:deadsnakes/ppa -y') |
|
run('sudo apt update') |
|
run('sudo apt install python3.10 -y') |
|
run('python3.10 -m venv venv',cwd=f'{install_path}/sd_main_dir') |
|
|
|
if quickStart: |
|
if not Path(venvPath).exists(): |
|
mkdirs(f'{install_path}/venv_cache',True) |
|
if not Path(f'{install_path}/venv_cache/venv.tar.bak').exists(): |
|
download_file('https://huggingface.co/viyi/sdwui/resolve/main/venv.zip','venv.zip',f'{install_path}/venv_cache') |
|
run(f'''unzip {install_path}/venv_cache/venv.zip -d {install_path}/venv_cache''') |
|
venvPath = f'{install_path}/venv_cache/venv.tar.bak' |
|
run(f'''rm -rf {install_path}/venv_cache/venv.zip''') |
|
elif venvPath.endswith('.zip'): |
|
mkdirs(f'{install_path}/venv_cache',True) |
|
run(f'''unzip {venvPath} -d {install_path}/venv_cache''') |
|
venvPath = f'{install_path}/venv_cache/venv.tar.bak' |
|
print('解压环境') |
|
run(f'tar -xf {venvPath} -C ./venv',cwd=f'{install_path}/sd_main_dir') |
|
run(f'rm -rf {install_path}/sd_main_dir/venv.lib') |
|
if not Path(f'{install_path}/sd_main_dir/venv/bin/pip').exists(): |
|
run('curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py') |
|
run(f'{install_path}/sd_main_dir/venv/bin/python3 get-pip.py') |
|
|
|
os.system(f'''{install_path}/sd_main_dir/venv/bin/python3 -V''') |
|
os.system(f'''{install_path}/sd_main_dir/venv/bin/python3 -m pip -V''') |
|
|
|
envInstalled = True |
|
print('安装需要的python环境 完成') |
|
|
|
|
|
def use_config(): |
|
print('使用自定义配置 包括tag翻译 \n') |
|
mkdirs(f'{install_path}/temp',True) |
|
run(f'git clone {config.git_proxy}{_sd_config_git_repu} sd-configs',cwd=f'{install_path}/temp') |
|
run(f'cp -r -f -n {install_path}/temp/sd-configs/dist/* {install_path}/sd_main_dir') |
|
if not Path(_ui_config_file).exists(): |
|
mkdirs(f"{_ui_config_file[:_ui_config_file.rfind('/')]}",True) |
|
run(f'cp -f -n {install_path}/sd_main_dir/ui-config.json {_ui_config_file}') |
|
if not Path(_setting_file).exists(): |
|
mkdirs(f"{_setting_file[:_setting_file.rfind('/')]}",True) |
|
run(f'cp -f -n {install_path}/sd_main_dir/config.json {_setting_file}') |
|
|
|
def copy_last_log_to_images(): |
|
print('复制编号最大的一张收藏图到输出目录,用于保持编号,否则会出现收藏的图片被覆盖的情况') |
|
img_list = os.listdir(f'{install_path}/sd_main_dir/log/images') |
|
last_img_path = '' |
|
last_img_num = 0 |
|
for img in img_list: |
|
if re.findall(r'^\d+-',str(img)): |
|
num = int(re.findall(r'^\d+-',str(img))[0][:-1]) |
|
if num > last_img_num: |
|
last_img_path = img |
|
last_img_num = num |
|
print(f'{install_path}/sd_main_dir/log/images/{last_img_path} {install_path}/sd_main_dir/outputs/txt2img-images') |
|
mkdirs(f"{install_path}/sd_main_dir/outputs/txt2img-images",True) |
|
run(f'''cp -f {install_path}/sd_main_dir/log/images/{last_img_path} {install_path}/sd_main_dir/outputs/txt2img-images/''') |
|
|
|
print(f'{install_path}/sd_main_dir/log/images/{last_img_path} {install_path}/sd_main_dir/outputs/img2img-images') |
|
mkdirs(f"{install_path}/sd_main_dir/outputs/img2img-images",True) |
|
run(f'''cp -f {install_path}/sd_main_dir/log/images/{last_img_path} {install_path}/sd_main_dir/outputs/img2img-images/''') |
|
|
|
def start_webui(i): |
|
|
|
print(i,'--port',str(_server_port+1+i)) |
|
if i>0: |
|
print(f'使用第{i+1}张显卡启动第{i+1}个服务,通过frpc或nrgok地址后加/{i}/进行访问(不能使用同一个浏览器)') |
|
if _useFrpc: |
|
restart_times = 0 |
|
last_restart_time = time.time() |
|
while True: |
|
os.system(f'''{install_path}/sd_main_dir/venv/bin/python3 launch.py --device-id={i} --port {str(_server_port+1+i)} {'' if i ==0 else '--nowebui'}''') |
|
print('5秒后重启服务') |
|
if time.time() - last_restart_time < 30: |
|
restart_times = restart_times + 1 |
|
else: |
|
restart_times = 0 |
|
last_restart_time = time.time() |
|
if restart_times >3 : |
|
|
|
break |
|
time.sleep(5) |
|
else: |
|
os.system(f'''{install_path}/sd_main_dir/venv/bin/python3 launch.py --device-id={i} --port {str(_server_port+1+i)} {'' if i ==0 else '--nowebui'}''') |
|
|
|
|
|
def start(): |
|
print('启动') |
|
os.chdir(f'''{install_path}/sd_main_dir''') |
|
args = '' |
|
if _ui_config_file is not None and _ui_config_file != '' and Path(_ui_config_file).exists(): |
|
args += ' --ui-config-file=' + _ui_config_file |
|
if _setting_file is not None and _setting_file != '' and Path(_setting_file).exists(): |
|
args += ' --ui-settings-file=' + _setting_file |
|
args += ' ' + otherArgs |
|
os.environ['COMMANDLINE_ARGS']=args |
|
run(f'''echo COMMANDLINE_ARGS=$COMMANDLINE_ARGS''') |
|
os.environ['REQS_FILE']='requirements.txt' |
|
start_webui(0) |
|
|
|
|
|
|
|
def main(): |
|
global envInstalled |
|
global huggingface_is_init |
|
startTicks = time.time() |
|
stop_solo_threads() |
|
isInstall = True if os.getenv('IsInstall','False') == 'True' else False |
|
if Path(f'{install_path}/sd_main_dir').exists(): |
|
isInstall = True |
|
if isInstall is False or _reLoad: |
|
print('启动 安装和运行环境') |
|
install() |
|
link_dir() |
|
threading.Thread(target = install_dependencies,daemon=True,name='solo_install_dependencies').start() |
|
threading.Thread(target = install_optimizing,daemon=True,name='solo_install_optimizing').start() |
|
threading.Thread(target = installProxyExe,daemon=True).start() |
|
link_or_download_flie(replace_path(_async_downloading), _link_instead_of_copy=_link_instead_of_copy, |
|
base_path=f'{install_path}/sd_main_dir') |
|
|
|
link_or_download_flie(replace_path(_before_downloading), _link_instead_of_copy=_link_instead_of_copy, |
|
base_path=f'{install_path}/sd_main_dir',is_await=True) |
|
t = 0 |
|
while not envInstalled: |
|
if t%10==0: |
|
print('等待python环境安装...') |
|
t = t+1 |
|
time.sleep(1) |
|
use_config() |
|
localProxy() |
|
os.environ['IsInstall'] = 'True' |
|
else: |
|
envInstalled = True |
|
link_or_download_flie(replace_path(_before_start_sync_downloading), _link_instead_of_copy=_link_instead_of_copy, |
|
base_path=f'{install_path}/sd_main_dir',sync=True) |
|
threading.Thread(target = startProxy, daemon=True, name='solo_startProxy').start() |
|
ticks = time.time() |
|
print("安装耗时:",(ticks - startTicks),"秒") |
|
start() |
|
|
|
|
|
if _skip_start: |
|
print('已跳过自动启动,可手动执行 main() 进行启动。') |
|
print('''推荐的启动代码: |
|
try: |
|
check_gpu() # 检查是否存在gpu |
|
main() |
|
except KeyboardInterrupt: |
|
stop_solo_threads() # 中断后自动停止后台线程 (有部分功能在后台线程中运行) |
|
''') |
|
else: |
|
try: |
|
main() |
|
except KeyboardInterrupt: |
|
stop_solo_threads() |
|
|
|
|