sdwui / sdwui_install.py
viyi's picture
Upload sdwui_install.py
c8aff2a
raw
history blame
29.1 kB
#!/usr/bin/env python
# coding: utf-8
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') # 非必填 存放ngrokToken的文件的路径
frpcConfigFile = os.path.join(input_path,'configs/frpc_koishi.ini') # 非必填 frp 配置文件
# ss证书目录 下载nginx的版本,把pem格式改成crt格式
frpcSSLFFlies = [os.path.join(input_path,'configs/koishi_ssl')] + config_reader(config.frp_ssl_dir)
# frpc 文件目录 如果目录不存在,会自动下载,也可以在数据集搜索 viyiviyi/utils 添加
frpcExePath = os.path.join(input_path,'utils-tools/frpc')
# 其他需要加载的webui启动参数 写到【参数列表】这个配置去
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') # 安装好的python环境 sd-webui-venv是一个公开是数据集 可以搜索添加
# 用于使用kaggle api的token文件 参考 https://www.kaggle.com/docs/api
# 此文件用于自动上传koishi的相关配置 也可以用于保存重要的输出文件
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
# ngrok
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)
# nginx 反向代理配置文件
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:
# """if it returns a number greater than one, you're in trouble,
# and you should call it again with exc=NULL to revert the effect"""
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(): # ui配置文件
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 :
# 如果90秒内重启了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(): # ui配置文件
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)
# 启动非webui相关的的内容,加快启动速度
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()