Upload 2 files
Browse files- config.py +176 -0
- sdwui_install.py +764 -0
config.py
ADDED
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'''
|
2 |
+
文件路径说明:
|
3 |
+
|
4 |
+
- []内的是下载文件的目标目录,可以是相对目录也可以是觉得路径
|
5 |
+
- []的下一行就是文件列表,可以是下载地址、git仓库、文件路径、文件夹路径,且支持通配符
|
6 |
+
- 如果需要对下载的文件重命名,可以在下载链接前面写上文件名后加一个:分开文件名和下载地址
|
7 |
+
- 如果需要下载到其他目录,可以使用同样的格式写其他目录
|
8 |
+
'''
|
9 |
+
|
10 |
+
# 这个列表仅加载一次 且会等待加载完成再开始安装sd
|
11 |
+
before_downloading = '''
|
12 |
+
[extensions] # 插件
|
13 |
+
https://github.com/dtlnor/stable-diffusion-webui-localization-zh_CN.git
|
14 |
+
https://github.com/AlUlkesh/stable-diffusion-webui-images-browser.git
|
15 |
+
https://github.com/DominikDoom/a1111-sd-webui-tagcomplete.git
|
16 |
+
https://github.com/Mikubill/sd-webui-controlnet.git
|
17 |
+
https://github.com/LianZiZhou/sd-webui-pixink-console.git
|
18 |
+
https://github.com/ilian6806/stable-diffusion-webui-state.git
|
19 |
+
https://github.com/pkuliyi2015/multidiffusion-upscaler-for-automatic1111.git
|
20 |
+
https://github.com/Bing-su/adetailer.git
|
21 |
+
https://github.com/civitai/sd_civitai_extension.git
|
22 |
+
https://github.com/zanllp/sd-webui-infinite-image-browsing.git
|
23 |
+
https://github.com/viyiviyi/stable-diffusion-webui-zoomimage.git
|
24 |
+
|
25 |
+
# 如果你有模型文件需要在启动前加载,可以写在这个下面对应位置
|
26 |
+
|
27 |
+
[models/Stable-diffusion] # 大模型列表
|
28 |
+
|
29 |
+
[models/hypernetworks] # hypernetworks文件列表
|
30 |
+
|
31 |
+
[models/embeddings] # embeddings文件列表
|
32 |
+
|
33 |
+
[models/Lora] # Lora文件列表
|
34 |
+
|
35 |
+
[models/VAE] # VAE文件列表
|
36 |
+
|
37 |
+
[extensions/sd-webui-controlnet/models] # controlnet插件的模型列表
|
38 |
+
|
39 |
+
'''
|
40 |
+
|
41 |
+
# 这个列表仅加载一次 且不会等待加载完成
|
42 |
+
async_downloading='''
|
43 |
+
[extensions] # 插件 如果你没有使用ngrok或者frpc,请不要把插件放在这里加载,因为这里的文件可能在webui启动后才加载完成
|
44 |
+
|
45 |
+
[models/Stable-diffusion] # 大模型列表
|
46 |
+
https://huggingface.co/viyi/testing_models/resolve/main/mg-LBG.safetensors
|
47 |
+
容华_国风_SDXL.safetensors:https://civitai.com/api/download/models/151978
|
48 |
+
|
49 |
+
[models/hypernetworks] # hypernetworks文件列表
|
50 |
+
|
51 |
+
[models/embeddings] # embeddings文件列表
|
52 |
+
|
53 |
+
[models/Lora] # Lora文件列表
|
54 |
+
Genshin_Impact_all-in-one.safetensors:https://civitai.com/api/download/models/116970
|
55 |
+
https://civitai.com/api/download/models/117151 # Clothing +/- Adjuster 衣物增/减 LoRA
|
56 |
+
https://civitai.com/api/download/models/62833 # Detail Tweaker LoRA (细节调整LoRA)
|
57 |
+
|
58 |
+
[models/VAE] # VAE文件列表
|
59 |
+
{input_path}/vae-ft-ema-prunedsafetensors/vae-ft-ema-560000-ema-pruned.safetensors
|
60 |
+
{input_path}/vae-ft-ema-prunedsafetensors/vae-ft-mse-840000-ema-pruned.safetensors
|
61 |
+
https://huggingface.co/stabilityai/sd-vae-ft-ema-original/resolve/main/vae-ft-ema-560000-ema-pruned.safetensors
|
62 |
+
https://huggingface.co/WarriorMama777/OrangeMixs/resolve/main/VAEs/orangemix.vae.pt
|
63 |
+
sdxl_vae.safetensors:https://civitai.com/api/download/models/130720?type=VAE # sdxl模型需要sdxl的vae
|
64 |
+
|
65 |
+
[extensions/sd-webui-controlnet/models] # controlnet插件的模型列表
|
66 |
+
https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11e_sd15_ip2p_fp16.safetensors
|
67 |
+
https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11e_sd15_shuffle_fp16.safetensors
|
68 |
+
https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11f1e_sd15_tile_fp16.safetensors
|
69 |
+
https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11f1p_sd15_depth_fp16.safetensors
|
70 |
+
https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_canny_fp16.safetensors
|
71 |
+
https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_inpaint_fp16.safetensors
|
72 |
+
https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_lineart_fp16.safetensors
|
73 |
+
https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_mlsd_fp16.safetensors
|
74 |
+
https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_normalbae_fp16.safetensors
|
75 |
+
https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_openpose_fp16.safetensors
|
76 |
+
https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_scribble_fp16.safetensors
|
77 |
+
https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_seg_fp16.safetensors
|
78 |
+
https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15_softedge_fp16.safetensors
|
79 |
+
https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11p_sd15s2_lineart_anime_fp16.safetensors
|
80 |
+
https://huggingface.co/comfyanonymous/ControlNet-v1-1_fp16_safetensors/resolve/main/control_v11u_sd15_tile_fp16.safetensors
|
81 |
+
'''
|
82 |
+
|
83 |
+
# 这个列表每次 启动都会加载一次,且一定按照顺序加载
|
84 |
+
before_start_sync_downloading = '''
|
85 |
+
|
86 |
+
# 如果你需要每次启动都加载一下文件,可以写在这。(比如测试路径是否正确的时候)
|
87 |
+
|
88 |
+
[models/Stable-diffusion] # 大模型列表
|
89 |
+
|
90 |
+
[models/hypernetworks] # hypernetworks文件列表
|
91 |
+
|
92 |
+
[models/embeddings] # embeddings文件列表
|
93 |
+
|
94 |
+
[models/Lora] # Lora文件列表
|
95 |
+
|
96 |
+
[models/VAE] # VAE文件列表
|
97 |
+
|
98 |
+
[extensions/sd-webui-controlnet/models] # controlnet插件的模型列表
|
99 |
+
|
100 |
+
'''
|
101 |
+
|
102 |
+
# sd启动参数
|
103 |
+
sd_start_args='''
|
104 |
+
# --ckpt=mg-Tender.safetensors # 默认模型名称,路径不能包含空格
|
105 |
+
--disable-safe-unpickle
|
106 |
+
--deepdanbooru
|
107 |
+
--no-hashing
|
108 |
+
--no-download-sd-model
|
109 |
+
--administrator
|
110 |
+
--skip-torch-cuda-test
|
111 |
+
--skip-version-check
|
112 |
+
--disable-nan-check
|
113 |
+
# --opt-sdp-attention
|
114 |
+
--opt-sdp-no-mem-attention
|
115 |
+
--xformers-flash-attention
|
116 |
+
--xformers
|
117 |
+
--api
|
118 |
+
--listen
|
119 |
+
--lowram
|
120 |
+
--no-gradio-queue
|
121 |
+
--share
|
122 |
+
--disable-console-progressbars
|
123 |
+
--no-half-vae
|
124 |
+
# --no-half #关闭半精度
|
125 |
+
# --enable-console-prompts
|
126 |
+
# --nowebui
|
127 |
+
# --api-auth=2333:6666 # api密码
|
128 |
+
# --gradio-auth=2333:6666 # webui密码
|
129 |
+
'''
|
130 |
+
|
131 |
+
useGooglrDrive = True # 连接到谷歌云盘 在google colab环境才会生效
|
132 |
+
# 启用Ngrok 如果没有配置文件即使开启也无效
|
133 |
+
useNgrok=True
|
134 |
+
# 启用frp 如果没有配置文件即使开启也无效
|
135 |
+
useFrpc=True
|
136 |
+
|
137 |
+
#文件或直接填配置
|
138 |
+
ngrok_config_or_file = '''
|
139 |
+
{input_path}/configs/ngrok_token.txt
|
140 |
+
'''
|
141 |
+
frp_config_or_file = '''
|
142 |
+
{input_path}/configs/frpc_litechat.ini
|
143 |
+
'''
|
144 |
+
frp_ssl_dir = '''
|
145 |
+
{input_path}/configs/litechat_nginx
|
146 |
+
'''
|
147 |
+
|
148 |
+
# 配置启动参数
|
149 |
+
server_port=7860 # webui 默认端口
|
150 |
+
|
151 |
+
# 仓库地址 这是修改过界面布局顺序的webui,不定期同步到官方版本
|
152 |
+
# 如果要使用官方版本,改成这个: https://github.com/AUTOMATIC1111/stable-diffusion-webui
|
153 |
+
sd_git_repo='https://github.com/viyiviyi/stable-diffusion-webui.git -b local'
|
154 |
+
# 配置文件,包括webui的设置和UI默认值,如果要自定义,fork这个仓库后修改并把地址替换这个地址
|
155 |
+
sd_config_git_repu = 'https://github.com/viyiviyi/sd-configs.git'
|
156 |
+
# 设置文件保存路径 当使用谷歌云盘时非常有用
|
157 |
+
setting_file = '{output_path}/configs/config.json'
|
158 |
+
ui_config_file = '{output_path}/configs/ui-config.json'
|
159 |
+
|
160 |
+
git_proxy="https://ghproxy.com/"
|
161 |
+
|
162 |
+
link_instead_of_copy = True # 下载或加载Input的文件时是使用链接还是复制的方式加载到目标目录
|
163 |
+
hidden_console_info = False # 是否隐藏大部分的控制台内容
|
164 |
+
|
165 |
+
reLoad = True
|
166 |
+
# 如果需要重新安装,请注释下面这一行
|
167 |
+
reLoad = False
|
168 |
+
|
169 |
+
skip_start = False
|
170 |
+
|
171 |
+
# 输出目录 如果要指定在执行目录外的目录,请写绝对路径
|
172 |
+
# 如果需要将输出的图片指定到其他目录,可以设置这里的值
|
173 |
+
output_path = '/root/autodl-fs/sd_output'
|
174 |
+
|
175 |
+
input_path = '/root/autodl-fs/sd_input'
|
176 |
+
# 安装路径说明,会安装在运行 sdwui_install 时的目录
|
sdwui_install.py
ADDED
@@ -0,0 +1,764 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python
|
2 |
+
# coding: utf-8
|
3 |
+
|
4 |
+
from pathlib import Path
|
5 |
+
import os
|
6 |
+
import time
|
7 |
+
import re
|
8 |
+
import subprocess
|
9 |
+
import threading
|
10 |
+
import sys
|
11 |
+
import socket
|
12 |
+
from typing import List
|
13 |
+
import config
|
14 |
+
|
15 |
+
def mkdirs(path, exist_ok=True):
|
16 |
+
if path and not Path(path).exists():
|
17 |
+
os.makedirs(path,exist_ok=exist_ok)
|
18 |
+
|
19 |
+
# 内置参数默认值,当上下文有参数时可覆盖默认值
|
20 |
+
|
21 |
+
_useFrpc = False
|
22 |
+
if 'useFrpc' in locals() or 'useFrpc' in globals():
|
23 |
+
_useFrpc = config.useFrpc
|
24 |
+
|
25 |
+
_useNgrok = False
|
26 |
+
if 'useNgrok' in locals() or 'useNgrok' in globals():
|
27 |
+
_useNgrok = config.useNgrok
|
28 |
+
|
29 |
+
_reLoad = False
|
30 |
+
if 'reLoad' in locals() or 'reLoad' in globals():
|
31 |
+
_reLoad = config.reLoad
|
32 |
+
|
33 |
+
_before_downloading = ''
|
34 |
+
if 'before_downloading' in locals() or 'before_downloading' in globals():
|
35 |
+
_before_downloading = config.before_downloading
|
36 |
+
|
37 |
+
_async_downloading = ''
|
38 |
+
if 'async_downloading' in locals() or 'async_downloading' in globals():
|
39 |
+
_async_downloading = config.async_downloading
|
40 |
+
|
41 |
+
_before_start_sync_downloading = ''
|
42 |
+
if 'before_start_sync_downloading' in locals() or 'before_start_sync_downloading' in globals():
|
43 |
+
_before_start_sync_downloading = config.before_start_sync_downloading
|
44 |
+
|
45 |
+
_server_port = 7860
|
46 |
+
if 'server_port' in locals() or 'server_port' in globals():
|
47 |
+
_server_port = config.server_port
|
48 |
+
|
49 |
+
_sd_git_repo ='https://github.com/viyiviyi/stable-diffusion-webui.git -b local'
|
50 |
+
if 'sd_git_repo' in locals() or 'sd_git_repo' in globals():
|
51 |
+
_sd_git_repo = config.sd_git_repo\
|
52 |
+
.replace('{sdwui}','stable-diffusion-webui')\
|
53 |
+
.replace('{wui}',"webui")
|
54 |
+
|
55 |
+
_sd_config_git_repu = 'https://github.com/viyiviyi/sd-configs.git'
|
56 |
+
if 'sd_config_git_repu' in locals() or 'sd_config_git_repu' in globals():
|
57 |
+
_sd_config_git_repu = config.sd_config_git_repu\
|
58 |
+
.replace('{sdwui}','stable-diffusion-webui')\
|
59 |
+
.replace('{wui}',"webui")
|
60 |
+
|
61 |
+
_link_instead_of_copy = True
|
62 |
+
if 'link_instead_of_copy' in locals() or 'link_instead_of_copy' in globals():
|
63 |
+
_link_instead_of_copy = config.link_instead_of_copy
|
64 |
+
|
65 |
+
show_shell_info = False
|
66 |
+
if 'hidden_console_info' in locals() or 'hidden_console_info' in globals():
|
67 |
+
show_shell_info = not config.hidden_console_info
|
68 |
+
|
69 |
+
_skip_start = False
|
70 |
+
if 'skip_start' in locals() or 'skip_start' in globals():
|
71 |
+
_skip_start = config.skip_start
|
72 |
+
|
73 |
+
run_by_none_device = False
|
74 |
+
|
75 |
+
|
76 |
+
def run(command, cwd=None, desc=None, errdesc=None, custom_env=None,try_error:bool=True) -> str:
|
77 |
+
global show_shell_info
|
78 |
+
if desc is not None:
|
79 |
+
print(desc)
|
80 |
+
|
81 |
+
run_kwargs = {
|
82 |
+
"args": command,
|
83 |
+
"shell": True,
|
84 |
+
"cwd": cwd,
|
85 |
+
"env": os.environ if custom_env is None else custom_env,
|
86 |
+
"encoding": 'utf8',
|
87 |
+
"errors": 'ignore',
|
88 |
+
}
|
89 |
+
|
90 |
+
if not show_shell_info:
|
91 |
+
run_kwargs["stdout"] = run_kwargs["stderr"] = subprocess.PIPE
|
92 |
+
|
93 |
+
result = subprocess.run(**run_kwargs)
|
94 |
+
|
95 |
+
if result.returncode != 0:
|
96 |
+
error_bits = [
|
97 |
+
f"{errdesc or 'Error running command'}.",
|
98 |
+
f"Command: {command}",
|
99 |
+
f"Error code: {result.returncode}",
|
100 |
+
]
|
101 |
+
if result.stdout:
|
102 |
+
error_bits.append(f"stdout: {result.stdout}")
|
103 |
+
if result.stderr:
|
104 |
+
error_bits.append(f"stderr: {result.stderr}")
|
105 |
+
if try_error:
|
106 |
+
print(RuntimeError("\n".join(error_bits)))
|
107 |
+
else:
|
108 |
+
raise RuntimeError("\n".join(error_bits))
|
109 |
+
|
110 |
+
if show_shell_info:
|
111 |
+
print(result.stdout or "")
|
112 |
+
return (result.stdout or "")
|
113 |
+
|
114 |
+
|
115 |
+
install_path=f"{os.getcwd()}/sdwui" # 安装目录
|
116 |
+
output_path= os.path.join(os.getcwd(), config.output_path or 'sdwui/Output')
|
117 |
+
input_path = config.input_path or f'{os.getcwd()}/sdwui/Input'
|
118 |
+
|
119 |
+
mkdirs(install_path,True)
|
120 |
+
mkdirs(output_path,True)
|
121 |
+
|
122 |
+
os.environ['install_path'] = install_path
|
123 |
+
os.environ['output_path'] = output_path
|
124 |
+
os.environ['input_path'] = input_path
|
125 |
+
|
126 |
+
def replace_path(input_str:str):
|
127 |
+
return input_str.replace('$install_path',install_path)\
|
128 |
+
.replace('{install_path}',install_path)\
|
129 |
+
.replace('$input_path',input_path)\
|
130 |
+
.replace('{input_path}',input_path)\
|
131 |
+
.replace('$output_path',output_path)\
|
132 |
+
.replace('{output_path}',output_path)\
|
133 |
+
.replace('{sdwui}','stable-diffusion-webui')\
|
134 |
+
.replace('{wui}',"webui")
|
135 |
+
|
136 |
+
space_string = ' \n\r\t\'\",'
|
137 |
+
|
138 |
+
def config_reader(conf:str):
|
139 |
+
args = [replace_path(item.split('#')[0].strip(space_string)) for item in conf.split('\n') if item.strip(space_string)]
|
140 |
+
return [item.strip() for item in args if item.strip()]
|
141 |
+
|
142 |
+
|
143 |
+
ngrokTokenFile = os.path.join(input_path,'configs/ngrok_token.txt') # 非必填 存放ngrokToken的文件的路径
|
144 |
+
frpcConfigFile = os.path.join(input_path,'configs/frpc_koishi.ini') # 非必填 frp 配置文件
|
145 |
+
# ss证书目录 下载nginx的版本,把pem格式改成crt格式
|
146 |
+
frpcSSLFFlies =[os.path.join(input_path,'configs/koishi_ssl')]
|
147 |
+
if 'frp_ssl_dir' in locals() or 'frp_ssl_dir' in globals():
|
148 |
+
frpcSSLFFlies = frpcSSLFFlies + config_reader(config.frp_ssl_dir)
|
149 |
+
# frpc 文件目录 如果目录不存在,会自动下载,也可以在数据集搜索 viyiviyi/utils 添加
|
150 |
+
frpcExePath = os.path.join(input_path,'utils-tools/frpc')
|
151 |
+
# 其他需要加载的webui启动参数 写到【参数列表】这个配置去
|
152 |
+
otherArgs = '--xformers'
|
153 |
+
if 'sd_start_args' in locals() or 'sd_start_args' in globals():
|
154 |
+
otherArgs = ' '.join([item for item in config_reader(config.sd_start_args) if item != '--no-gradio-queue'])
|
155 |
+
venvPath = os.path.join(input_path,'sd-webui-venv/venv.tar.bak') # 安装好的python环境 sd-webui-venv是一个公开是数据集 可以搜索添加
|
156 |
+
|
157 |
+
# 用于使用kaggle api的token文件 参考 https://www.kaggle.com/docs/api
|
158 |
+
# 此文件用于自动上传koishi的相关配置 也可以用于保存重要的输出文件
|
159 |
+
kaggleApiTokenFile = os.path.join(input_path,'configs/kaggle.json')
|
160 |
+
|
161 |
+
requirements = []
|
162 |
+
|
163 |
+
frpcStartArg = ''
|
164 |
+
|
165 |
+
_setting_file = ''
|
166 |
+
if 'setting_file' in locals() or 'setting_file' in globals():
|
167 |
+
_setting_file = replace_path(config.setting_file)
|
168 |
+
_ui_config_file = ''
|
169 |
+
if 'ui_config_file' in locals() or 'ui_config_file' in globals():
|
170 |
+
_ui_config_file = replace_path(config.ui_config_file)
|
171 |
+
|
172 |
+
mkdirs(f'{install_path}/configFiles',True)
|
173 |
+
if 'frp_config_or_file' in locals() or 'frp_config_or_file' in globals():
|
174 |
+
_frp_config_or_file = replace_path(config.frp_config_or_file)
|
175 |
+
if Path(_frp_config_or_file.strip()).exists():
|
176 |
+
frpcConfigFile = _frp_config_or_file.strip()
|
177 |
+
if not Path(frpcConfigFile).exists():
|
178 |
+
if _frp_config_or_file.strip().startswith('-f'):
|
179 |
+
frpcStartArg = _frp_config_or_file.strip()
|
180 |
+
else:
|
181 |
+
print('没有frpcp配置')
|
182 |
+
_useFrpc = False
|
183 |
+
else:
|
184 |
+
run(f'''cp -f {frpcConfigFile} {install_path}/configFiles/frpc_webui.ini''')
|
185 |
+
frpcConfigFile = f'{install_path}/configFiles/frpc_webui.ini'
|
186 |
+
run(f'''sed -i "s/local_port = .*/local_port = {_server_port}/g" {frpcConfigFile}''')
|
187 |
+
frpcStartArg = f' -c {frpcConfigFile}'
|
188 |
+
|
189 |
+
ngrokToken=''
|
190 |
+
if 'ngrok_config_or_file' in locals() or 'ngrok_config_or_file' in globals():
|
191 |
+
_ngrok_config_or_file = replace_path(config.ngrok_config_or_file)
|
192 |
+
if Path(_ngrok_config_or_file.strip()).exists():
|
193 |
+
ngrokTokenFile = _ngrok_config_or_file.strip()
|
194 |
+
if Path(ngrokTokenFile).exists():
|
195 |
+
with open(ngrokTokenFile,encoding = "utf-8") as nkfile:
|
196 |
+
ngrokToken = nkfile.readline()
|
197 |
+
elif not _ngrok_config_or_file.strip().startswith('/'):
|
198 |
+
ngrokToken=_ngrok_config_or_file.strip()
|
199 |
+
|
200 |
+
if not Path(venvPath).exists():
|
201 |
+
venvPath = os.path.join(input_path,'sd-webui-venv/venv.zip')
|
202 |
+
|
203 |
+
|
204 |
+
import concurrent.futures
|
205 |
+
import importlib
|
206 |
+
import os
|
207 |
+
import pprint
|
208 |
+
import re
|
209 |
+
from pathlib import Path
|
210 |
+
from typing import List
|
211 |
+
|
212 |
+
import requests
|
213 |
+
|
214 |
+
show_shell_info = False
|
215 |
+
|
216 |
+
|
217 |
+
def is_installed(package):
|
218 |
+
try:
|
219 |
+
spec = importlib.util.find_spec(package)
|
220 |
+
except ModuleNotFoundError:
|
221 |
+
return False
|
222 |
+
|
223 |
+
return spec is not None
|
224 |
+
|
225 |
+
def download_file(url:str, filename:str, dist_path:str, cache_path = '',_link_instead_of_copy:bool=True):
|
226 |
+
# 获取文件的真实文件名
|
227 |
+
if not filename:
|
228 |
+
with requests.get(url, stream=True) as r:
|
229 |
+
if 'Content-Disposition' in r.headers:
|
230 |
+
filename = r.headers['Content-Disposition'].split('filename=')[1].strip('"')
|
231 |
+
r.close()
|
232 |
+
if not filename and re.search(r'/[^/]+\.[^/]+$',url):
|
233 |
+
filename = url.split('/')[-1]
|
234 |
+
|
235 |
+
filename = re.sub(r'[\\/:*?"<>|;]', '', filename)
|
236 |
+
filename = re.sub(r'[\s\t]+', '_', filename)
|
237 |
+
|
238 |
+
if show_shell_info:
|
239 |
+
print(f'下载 {filename} url: {url} --> {dist_path}')
|
240 |
+
|
241 |
+
# 创建目录
|
242 |
+
if cache_path and not Path(cache_path).exists():
|
243 |
+
mkdirs(cache_path,exist_ok=True)
|
244 |
+
if dist_path and not Path(dist_path).exists():
|
245 |
+
mkdirs(dist_path,exist_ok=True)
|
246 |
+
|
247 |
+
# 拼接文件的完整路径
|
248 |
+
filepath = os.path.join(dist_path, filename)
|
249 |
+
|
250 |
+
if cache_path:
|
251 |
+
cache_path = os.path.join(cache_path, filename)
|
252 |
+
|
253 |
+
# 判断文件是否已存在
|
254 |
+
if Path(filepath).exists():
|
255 |
+
print(f'文件 {filename} 已存在 {dist_path}')
|
256 |
+
return
|
257 |
+
|
258 |
+
if cache_path and Path(cache_path).exists():
|
259 |
+
run(f'cp -n -r -f {"-s" if _link_instead_of_copy else ""} {cache_path} {dist_path}')
|
260 |
+
if show_shell_info:
|
261 |
+
print(f'文件缓存 {cache_path} --> {dist_path}')
|
262 |
+
return
|
263 |
+
# 下载文件
|
264 |
+
with requests.get(url, stream=True) as r:
|
265 |
+
r.raise_for_status()
|
266 |
+
with open(cache_path or filepath, 'wb') as f:
|
267 |
+
for chunk in r.iter_content(chunk_size=8192):
|
268 |
+
if chunk:
|
269 |
+
f.write(chunk)
|
270 |
+
# 如果使用了缓存目录 需要复制或链接文件到目标目录
|
271 |
+
if cache_path:
|
272 |
+
run(f'cp -n -r -f {"-s" if _link_instead_of_copy else ""} {cache_path} {dist_path}')
|
273 |
+
if show_shell_info:
|
274 |
+
print(f'下载完成 {filename} --> {dist_path}')
|
275 |
+
|
276 |
+
def download_git(url, dist_path, cache_path = '',_link_instead_of_copy:bool=True):
|
277 |
+
if not Path(dist_path).exists():
|
278 |
+
mkdirs(dist_path,exist_ok=True)
|
279 |
+
if show_shell_info:
|
280 |
+
print(f'git 下载 {url} --> {dist_path}')
|
281 |
+
if cache_path and not Path(cache_path).exists():
|
282 |
+
mkdirs(cache_path,exist_ok=True)
|
283 |
+
run(f'git clone {config.git_proxy}{url}',cwd = cache_path)
|
284 |
+
if cache_path:
|
285 |
+
run(f'cp -n -r -f {cache_path}/* {dist_path}')
|
286 |
+
else:
|
287 |
+
run(f'git clone {config.git_proxy}{url}',cwd = dist_path)
|
288 |
+
if show_shell_info:
|
289 |
+
print(f'git 下载完成 {url} --> {dist_path}')
|
290 |
+
|
291 |
+
|
292 |
+
|
293 |
+
# 加入文件到下载列表
|
294 |
+
def pause_url(url:str,dist_path:str):
|
295 |
+
file_name = ''
|
296 |
+
if re.match(r'^[^:]+:(https?|ftps?)://', url, flags=0):
|
297 |
+
file_name = re.findall(r'^[^:]+:',url)[0][:-1]
|
298 |
+
url = url[len(file_name)+1:]
|
299 |
+
if not re.match(r'^(https?|ftps?)://',url):
|
300 |
+
return
|
301 |
+
file_name = re.sub(r'\s+','_',file_name or '')
|
302 |
+
path_hash = str(hash(url)).replace('-','')
|
303 |
+
|
304 |
+
return {'file_name':file_name,'path_hash':path_hash,'url':url,'dist_path':dist_path}
|
305 |
+
|
306 |
+
def download_urls(download_list:List[dict],sync:bool=False,thread_num:int=5,
|
307 |
+
cache_path:str=os.path.join(os.getcwd(),'.cache','download_util'),
|
308 |
+
_link_instead_of_copy:bool=True,is_await:bool=False):
|
309 |
+
if sync:
|
310 |
+
for conf in download_list:
|
311 |
+
cache_dir = os.path.join(cache_path,conf['path_hash'])
|
312 |
+
if conf['url'].startswith('https://github.com'):
|
313 |
+
download_git(conf['url'],conf['dist_path'],cache_path=cache_dir,_link_instead_of_copy=_link_instead_of_copy)
|
314 |
+
continue
|
315 |
+
download_file(conf['url'],conf['file_name'],conf['dist_path'],cache_path=cache_dir,_link_instead_of_copy=_link_instead_of_copy)
|
316 |
+
else:
|
317 |
+
executor = concurrent.futures.ThreadPoolExecutor(max_workers=thread_num)
|
318 |
+
futures = []
|
319 |
+
for conf in download_list:
|
320 |
+
cache_dir = os.path.join(cache_path,conf['path_hash'])
|
321 |
+
if conf['url'].startswith('https://github.com'):
|
322 |
+
futures.append(executor.submit(download_git, conf['url'],conf['dist_path'],
|
323 |
+
cache_path=cache_dir,_link_instead_of_copy=_link_instead_of_copy))
|
324 |
+
continue
|
325 |
+
futures.append(executor.submit(download_file, conf['url'],conf['file_name'],conf['dist_path'],
|
326 |
+
cache_path=cache_dir,_link_instead_of_copy=_link_instead_of_copy))
|
327 |
+
if is_await:
|
328 |
+
concurrent.futures.wait(futures)
|
329 |
+
|
330 |
+
|
331 |
+
def parse_config(config:str):
|
332 |
+
space_string = ' \n\r\t\'\",'
|
333 |
+
other_flie_list = [item.split('#')[0].strip(space_string) for item in config.split('\n') if item.strip(space_string)]
|
334 |
+
other_flie_list = [item.strip() for item in other_flie_list if item.strip()]
|
335 |
+
other_flie_list_store = {}
|
336 |
+
other_flie_list_store_name='default'
|
337 |
+
other_flie_list_store_list_cache=[]
|
338 |
+
|
339 |
+
for item in other_flie_list:
|
340 |
+
if item.startswith('[') and item.endswith(']'):
|
341 |
+
if not other_flie_list_store_name == 'default':
|
342 |
+
other_flie_list_store[other_flie_list_store_name]=other_flie_list_store_list_cache
|
343 |
+
other_flie_list_store_list_cache = []
|
344 |
+
other_flie_list_store_name = item[1:-1]
|
345 |
+
else:
|
346 |
+
other_flie_list_store_list_cache.append(item)
|
347 |
+
other_flie_list_store[other_flie_list_store_name]=other_flie_list_store_list_cache
|
348 |
+
|
349 |
+
return other_flie_list_store
|
350 |
+
|
351 |
+
|
352 |
+
def link_or_download_flie(config:str, skip_url:bool=False, _link_instead_of_copy:bool=True, base_path:str = '',
|
353 |
+
sync:bool=False,thread_num:int=None, is_await:bool=False):
|
354 |
+
store:dict[str,List[str]] = parse_config(config)
|
355 |
+
download_list = []
|
356 |
+
for dist_dir in store.keys():
|
357 |
+
dist_path = os.path.join(base_path,dist_dir)
|
358 |
+
mkdirs(dist_path,exist_ok=True)
|
359 |
+
for path in store[dist_dir]:
|
360 |
+
if 'https://' in path or 'http://' in path:
|
361 |
+
if skip_url:
|
362 |
+
continue
|
363 |
+
if sync:
|
364 |
+
download_urls([pause_url(path,dist_path)],_link_instead_of_copy = _link_instead_of_copy, sync=sync)
|
365 |
+
continue
|
366 |
+
download_list.append(pause_url(path,dist_path))
|
367 |
+
else:
|
368 |
+
run(f'cp -n -r -f {"-s" if _link_instead_of_copy else ""} {path} {dist_path}')
|
369 |
+
if show_shell_info:
|
370 |
+
print(f'{"链接" if _link_instead_of_copy else "复制"} {path} --> {dist_path}')
|
371 |
+
run(f'rm -f {dist_path}/\*.* ')
|
372 |
+
if not skip_url:
|
373 |
+
if show_shell_info:
|
374 |
+
pprint.pprint(download_list)
|
375 |
+
download_urls(download_list,_link_instead_of_copy = _link_instead_of_copy, sync=sync, thread_num=thread_num or 2,is_await=is_await)
|
376 |
+
|
377 |
+
|
378 |
+
def echoToFile(content:str,path:str):
|
379 |
+
if path.find('/') >= 0:
|
380 |
+
_path = '/'.join(path.split('/')[:-1])
|
381 |
+
mkdirs(f'{_path}',True)
|
382 |
+
with open(path,'w') as sh:
|
383 |
+
sh.write(content)
|
384 |
+
|
385 |
+
def zipPath(path:str,zipName:str,format='tar'):
|
386 |
+
if path.startswith('$install_path'):
|
387 |
+
path = path.replace('$install_path',install_path)
|
388 |
+
if path.startswith('$output_path'):
|
389 |
+
path = path.replace('$install_path',output_path)
|
390 |
+
if not path.startswith('/'):
|
391 |
+
path = f'{install_path}/sd_main_dir/{path}'
|
392 |
+
if Path(path).exists():
|
393 |
+
if 'tar' == format:
|
394 |
+
run(f'tar -cf {output_path}/'+ zipName +'.tar -C '+ path +' . ')
|
395 |
+
elif 'gz' == format:
|
396 |
+
run(f'tar -czf {output_path}/'+ zipName +'.tar.gz -C '+ path +' . ')
|
397 |
+
return
|
398 |
+
print('指定的目录不存在:'+path)
|
399 |
+
|
400 |
+
# 检查网络
|
401 |
+
def check_service(host, port):
|
402 |
+
try:
|
403 |
+
socket.create_connection((host, port), timeout=5)
|
404 |
+
return True
|
405 |
+
except socket.error:
|
406 |
+
return False
|
407 |
+
|
408 |
+
# ngrok
|
409 |
+
def startNgrok(ngrokToken:str,ngrokLocalPort:int):
|
410 |
+
if not is_installed('pyngrok'):
|
411 |
+
run(f'pip install pyngrok')
|
412 |
+
from pyngrok import conf, ngrok
|
413 |
+
try:
|
414 |
+
conf.get_default().auth_token = ngrokToken
|
415 |
+
conf.get_default().monitor_thread = False
|
416 |
+
ssh_tunnels = ngrok.get_tunnels(conf.get_default())
|
417 |
+
if len(ssh_tunnels) == 0:
|
418 |
+
ssh_tunnel = ngrok.connect(ngrokLocalPort)
|
419 |
+
print('ngrok 访问地址:'+ssh_tunnel.public_url)
|
420 |
+
else:
|
421 |
+
print('ngrok 访问地址:'+ssh_tunnels[0].public_url)
|
422 |
+
except:
|
423 |
+
print('启动ngrok出错')
|
424 |
+
|
425 |
+
def startFrpc(name,configFile):
|
426 |
+
echoToFile(f'''
|
427 |
+
cd {install_path}/frpc/
|
428 |
+
{install_path}/frpc/frpc {configFile}
|
429 |
+
''',f'{install_path}/frpc/start.sh')
|
430 |
+
os.system(f'''bash {install_path}/frpc/start.sh''')
|
431 |
+
|
432 |
+
def installProxyExe():
|
433 |
+
if _useFrpc:
|
434 |
+
print('安装frpc')
|
435 |
+
mkdirs(f'{install_path}/frpc',True)
|
436 |
+
if Path(frpcExePath).exists():
|
437 |
+
run(f'cp -f -n {frpcExePath} {install_path}/frpc/frpc')
|
438 |
+
else:
|
439 |
+
run(f'wget "https://huggingface.co/datasets/ACCA225/Frp/resolve/main/frpc" -O {install_path}/frpc/frpc')
|
440 |
+
|
441 |
+
for ssl in frpcSSLFFlies:
|
442 |
+
if Path(ssl).exists():
|
443 |
+
run(f'cp -f -n {ssl}/* {install_path}/frpc/')
|
444 |
+
run(f'chmod +x {install_path}/frpc/frpc')
|
445 |
+
run(f'{install_path}/frpc/frpc -v')
|
446 |
+
if _useNgrok and not is_installed('pyngrok'):
|
447 |
+
run('pip install pyngrok')
|
448 |
+
|
449 |
+
def startProxy():
|
450 |
+
if _useNgrok:
|
451 |
+
startNgrok(ngrokToken,_server_port)
|
452 |
+
if _useFrpc:
|
453 |
+
startFrpc('frpc_proxy',frpcStartArg)
|
454 |
+
|
455 |
+
|
456 |
+
# nginx 反向代理配置文件
|
457 |
+
def localProxy():
|
458 |
+
conf = '''
|
459 |
+
server
|
460 |
+
{
|
461 |
+
listen '''+str(_server_port)+''';
|
462 |
+
listen [::]:'''+str(_server_port)+''';
|
463 |
+
server_name 127.0.0.1 localhost 0.0.0.0 "";
|
464 |
+
|
465 |
+
if ($request_method = OPTIONS) {
|
466 |
+
return 200;
|
467 |
+
}
|
468 |
+
fastcgi_send_timeout 10m;
|
469 |
+
fastcgi_read_timeout 10m;
|
470 |
+
fastcgi_connect_timeout 10m;
|
471 |
+
location /1/
|
472 |
+
{
|
473 |
+
proxy_pass http://127.0.0.1:'''+str(_server_port+2)+'''/;
|
474 |
+
# add_header Set-Cookie "subpath=1; expires=0; Path=/";
|
475 |
+
# proxy_set_header Set-Cookie "subpath=1; expires=0; Path=/";
|
476 |
+
proxy_set_header Host $host;
|
477 |
+
proxy_set_header X-Real-IP $remote_addr;
|
478 |
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
479 |
+
proxy_set_header REMOTE-HOST $remote_addr;
|
480 |
+
proxy_set_header Upgrade $http_upgrade;
|
481 |
+
proxy_set_header Connection upgrade;
|
482 |
+
proxy_http_version 1.1;
|
483 |
+
proxy_connect_timeout 10m;
|
484 |
+
proxy_read_timeout 10m;
|
485 |
+
}
|
486 |
+
location /
|
487 |
+
{
|
488 |
+
set $proxy_url http://127.0.0.1:'''+str(_server_port+1)+''';
|
489 |
+
# if ($cookie_subpath = "1") {
|
490 |
+
# set $proxy_url http://127.0.0.1:'''+str(_server_port+2)+''';
|
491 |
+
# }
|
492 |
+
proxy_pass $proxy_url;
|
493 |
+
proxy_set_header Host $host;
|
494 |
+
proxy_set_header X-Real-IP $remote_addr;
|
495 |
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
496 |
+
proxy_set_header REMOTE-HOST $remote_addr;
|
497 |
+
proxy_set_header Upgrade $http_upgrade;
|
498 |
+
proxy_set_header Connection upgrade;
|
499 |
+
proxy_http_version 1.1;
|
500 |
+
proxy_connect_timeout 10m;
|
501 |
+
proxy_read_timeout 10m;
|
502 |
+
}
|
503 |
+
}
|
504 |
+
'''
|
505 |
+
echoToFile(conf,'/etc/nginx/conf.d/proxy_nginx.conf')
|
506 |
+
if not check_service('localhost',_server_port):
|
507 |
+
run(f'''nginx -c /etc/nginx/nginx.conf''')
|
508 |
+
os.system(f'''nginx -s reload''')
|
509 |
+
|
510 |
+
|
511 |
+
import inspect
|
512 |
+
import ctypes
|
513 |
+
|
514 |
+
def _async_raise(tid, exctype):
|
515 |
+
"""raises the exception, performs cleanup if needed"""
|
516 |
+
tid = ctypes.c_long(tid)
|
517 |
+
if not inspect.isclass(exctype):
|
518 |
+
exctype = type(exctype)
|
519 |
+
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
|
520 |
+
if res == 0:
|
521 |
+
raise ValueError("invalid thread id")
|
522 |
+
elif res != 1:
|
523 |
+
# """if it returns a number greater than one, you're in trouble,
|
524 |
+
# and you should call it again with exc=NULL to revert the effect"""
|
525 |
+
ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
|
526 |
+
raise SystemError("PyThreadState_SetAsyncExc failed")
|
527 |
+
|
528 |
+
def stop_thread(thread):
|
529 |
+
_async_raise(thread.ident, SystemExit)
|
530 |
+
|
531 |
+
def stop_solo_threads():
|
532 |
+
# 获取当前所有活动的线程
|
533 |
+
threads = threading.enumerate()
|
534 |
+
# 关闭之前创建的子线程
|
535 |
+
for thread in threads:
|
536 |
+
if thread.name.startswith('solo_'):
|
537 |
+
print(f'结束线程:{thread.name}')
|
538 |
+
try:
|
539 |
+
stop_thread(thread)
|
540 |
+
except socket.error:
|
541 |
+
print(f'结束线程:{thread.name} 执行失败')
|
542 |
+
|
543 |
+
|
544 |
+
envInstalled=False
|
545 |
+
quickStart = True
|
546 |
+
#安装
|
547 |
+
def install():
|
548 |
+
print('安装')
|
549 |
+
os.chdir(f'''{install_path}''')
|
550 |
+
run(f'''git lfs install''')
|
551 |
+
run(f'''git config --global credential.helper store''')
|
552 |
+
for requirement in requirements:
|
553 |
+
run(f'pip install {requirement}')
|
554 |
+
if _reLoad:
|
555 |
+
run(f'''rm -rf sd_main_dir''')
|
556 |
+
if Path("sd_main_dir").exists():
|
557 |
+
os.chdir(f'''{install_path}/sd_main_dir/''')
|
558 |
+
run(f'''git checkout .''')
|
559 |
+
run(f'''git pull''')
|
560 |
+
else:
|
561 |
+
run(f'''git clone {config.git_proxy}{_sd_git_repo} sd_main_dir''')
|
562 |
+
os.chdir(f'''{install_path}/sd_main_dir''')
|
563 |
+
print('安装 完成')
|
564 |
+
|
565 |
+
# 链接输出目录
|
566 |
+
def link_dir():
|
567 |
+
print('链接输出目录')
|
568 |
+
# 链接图片输出目录
|
569 |
+
mkdirs(f'{output_path}/outputs',True)
|
570 |
+
run(f'''rm -rf {install_path}/sd_main_dir/outputs''')
|
571 |
+
run(f'''ln -s -r {output_path}/outputs {install_path}/sd_main_dir/''')
|
572 |
+
# 输出收藏目录
|
573 |
+
mkdirs(f'{output_path}/log',True)
|
574 |
+
run(f'''rm -rf {install_path}/sd_main_dir/log''')
|
575 |
+
run(f'''ln -s -r {output_path}/log {install_path}/sd_main_dir/''')
|
576 |
+
# 链接训练输出目录 文件夹链接会导致功能不能用
|
577 |
+
run(f'''rm -rf {install_path}/sd_main_dir/textual_inversion''')
|
578 |
+
mkdirs(f'{output_path}/textual_inversion/',True)
|
579 |
+
run(f'''ln -s -r {output_path}/textual_inversion {install_path}/sd_main_dir/''')
|
580 |
+
print('链接输出目录 完成')
|
581 |
+
|
582 |
+
def install_optimizing():
|
583 |
+
run('sudo apt install nginx -y')
|
584 |
+
run('env TF_CPP_MIN_LOG_LEVEL=1')
|
585 |
+
run('sudo apt -y update -qq')
|
586 |
+
run('wget http://launchpadlibrarian.net/367274644/libgoogle-perftools-dev_2.5-2.2ubuntu3_amd64.deb')
|
587 |
+
run('wget https://launchpad.net/ubuntu/+source/google-perftools/2.5-2.2ubuntu3/+build/14795286/+files/google-perftools_2.5-2.2ubuntu3_all.deb')
|
588 |
+
run('wget https://launchpad.net/ubuntu/+source/google-perftools/2.5-2.2ubuntu3/+build/14795286/+files/libtcmalloc-minimal4_2.5-2.2ubuntu3_amd64.deb')
|
589 |
+
run('wget https://launchpad.net/ubuntu/+source/google-perftools/2.5-2.2ubuntu3/+build/14795286/+files/libgoogle-perftools4_2.5-2.2ubuntu3_amd64.deb')
|
590 |
+
run('sudo apt -y install -qq libunwind8-dev')
|
591 |
+
run('dpkg -i *.deb')
|
592 |
+
run('env LD_P_reLoad=libtcmalloc.so')
|
593 |
+
run('rm *.deb')
|
594 |
+
|
595 |
+
#安装依赖
|
596 |
+
def install_dependencies():
|
597 |
+
print('安装需要的python环境')
|
598 |
+
global envInstalled
|
599 |
+
global venvPath
|
600 |
+
run(f'''rm -rf {install_path}/sd_main_dir/venv''')
|
601 |
+
mkdirs(f'{install_path}/sd_main_dir/venv',True)
|
602 |
+
if str(sys.version).startswith('3.10'):
|
603 |
+
try:
|
604 |
+
run('python3 -m venv venv' ,cwd=f'{install_path}/sd_main_dir',try_error=False)
|
605 |
+
except:
|
606 |
+
run('sudo apt install python3.10-venv -y')
|
607 |
+
run('python3 -m venv venv' ,cwd=f'{install_path}/sd_main_dir')
|
608 |
+
else:
|
609 |
+
run('add-apt-repository ppa:deadsnakes/ppa -y')
|
610 |
+
run('sudo apt update')
|
611 |
+
run('sudo apt install python3.10 -y')
|
612 |
+
run('python3.10 -m venv venv',cwd=f'{install_path}/sd_main_dir')
|
613 |
+
|
614 |
+
if quickStart:
|
615 |
+
if not Path(venvPath).exists():
|
616 |
+
mkdirs(f'{install_path}/venv_cache',True)
|
617 |
+
if not Path(f'{install_path}/venv_cache/venv.tar.bak').exists():
|
618 |
+
download_file('https://huggingface.co/viyi/sdwui/resolve/main/venv.zip','venv.zip',f'{install_path}/venv_cache')
|
619 |
+
run(f'''unzip {install_path}/venv_cache/venv.zip -d {install_path}/venv_cache''')
|
620 |
+
venvPath = f'{install_path}/venv_cache/venv.tar.bak'
|
621 |
+
run(f'''rm -rf {install_path}/venv_cache/venv.zip''')
|
622 |
+
elif venvPath.endswith('.zip'):
|
623 |
+
mkdirs(f'{install_path}/venv_cache',True)
|
624 |
+
run(f'''unzip {venvPath} -d {install_path}/venv_cache''')
|
625 |
+
venvPath = f'{install_path}/venv_cache/venv.tar.bak'
|
626 |
+
print('解压环境')
|
627 |
+
run(f'tar -xf {venvPath} -C ./venv',cwd=f'{install_path}/sd_main_dir')
|
628 |
+
run(f'rm -rf {install_path}/sd_main_dir/venv.lib')
|
629 |
+
if not Path(f'{install_path}/sd_main_dir/venv/bin/pip').exists():
|
630 |
+
run('curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py')
|
631 |
+
run(f'{install_path}/sd_main_dir/venv/bin/python3 get-pip.py')
|
632 |
+
|
633 |
+
os.system(f'''{install_path}/sd_main_dir/venv/bin/python3 -V''')
|
634 |
+
os.system(f'''{install_path}/sd_main_dir/venv/bin/python3 -m pip -V''')
|
635 |
+
|
636 |
+
envInstalled = True
|
637 |
+
print('安装需要的python环境 完成')
|
638 |
+
|
639 |
+
# 个性化配置
|
640 |
+
def use_config():
|
641 |
+
print('使用自定义配置 包括tag翻译 \n')
|
642 |
+
mkdirs(f'{install_path}/temp',True)
|
643 |
+
run(f'git clone {config.git_proxy}{_sd_config_git_repu} sd-configs',cwd=f'{install_path}/temp')
|
644 |
+
run(f'cp -r -f -n {install_path}/temp/sd-configs/dist/* {install_path}/sd_main_dir')
|
645 |
+
if not Path(_ui_config_file).exists(): # ui配置文件
|
646 |
+
mkdirs(f"{_ui_config_file[:_ui_config_file.rfind('/')]}",True)
|
647 |
+
run(f'cp -f -n {install_path}/sd_main_dir/ui-config.json {_ui_config_file}')
|
648 |
+
if not Path(_setting_file).exists(): # 设置配置文件
|
649 |
+
mkdirs(f"{_setting_file[:_setting_file.rfind('/')]}",True)
|
650 |
+
run(f'cp -f -n {install_path}/sd_main_dir/config.json {_setting_file}')
|
651 |
+
|
652 |
+
def copy_last_log_to_images():
|
653 |
+
print('复制编号最大的一张收藏图到输出目录,用于保持编号,否则会出现收藏的图片被覆盖的情况')
|
654 |
+
img_list = os.listdir(f'{install_path}/sd_main_dir/log/images')
|
655 |
+
last_img_path = ''
|
656 |
+
last_img_num = 0
|
657 |
+
for img in img_list:
|
658 |
+
if re.findall(r'^\d+-',str(img)):
|
659 |
+
num = int(re.findall(r'^\d+-',str(img))[0][:-1])
|
660 |
+
if num > last_img_num:
|
661 |
+
last_img_path = img
|
662 |
+
last_img_num = num
|
663 |
+
print(f'{install_path}/sd_main_dir/log/images/{last_img_path} {install_path}/sd_main_dir/outputs/txt2img-images')
|
664 |
+
mkdirs(f"{install_path}/sd_main_dir/outputs/txt2img-images",True)
|
665 |
+
run(f'''cp -f {install_path}/sd_main_dir/log/images/{last_img_path} {install_path}/sd_main_dir/outputs/txt2img-images/''')
|
666 |
+
|
667 |
+
print(f'{install_path}/sd_main_dir/log/images/{last_img_path} {install_path}/sd_main_dir/outputs/img2img-images')
|
668 |
+
mkdirs(f"{install_path}/sd_main_dir/outputs/img2img-images",True)
|
669 |
+
run(f'''cp -f {install_path}/sd_main_dir/log/images/{last_img_path} {install_path}/sd_main_dir/outputs/img2img-images/''')
|
670 |
+
|
671 |
+
def start_webui(i):
|
672 |
+
# 只要不爆内存,其他方式关闭后会再次重启 访问地址会发生变化
|
673 |
+
print(i,'--port',str(_server_port+1+i))
|
674 |
+
if i>0:
|
675 |
+
print(f'使用第{i+1}张显卡启动第{i+1}个服务,通过frpc或nrgok地址后加/{i}/进行访问(不能使用同一个浏览器)')
|
676 |
+
if _useFrpc:
|
677 |
+
restart_times = 0
|
678 |
+
last_restart_time = time.time()
|
679 |
+
while True:
|
680 |
+
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'}''')
|
681 |
+
print('5秒后重启服务')
|
682 |
+
if time.time() - last_restart_time < 30:
|
683 |
+
restart_times = restart_times + 1
|
684 |
+
else:
|
685 |
+
restart_times = 0
|
686 |
+
last_restart_time = time.time()
|
687 |
+
if restart_times >3 :
|
688 |
+
# 如果90秒内重启了3此,将不再自动重启
|
689 |
+
break
|
690 |
+
time.sleep(5)
|
691 |
+
else:
|
692 |
+
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'}''')
|
693 |
+
|
694 |
+
# 启动
|
695 |
+
def start():
|
696 |
+
print('启动')
|
697 |
+
os.chdir(f'''{install_path}/sd_main_dir''')
|
698 |
+
args = ''
|
699 |
+
if _ui_config_file is not None and _ui_config_file != '' and Path(_ui_config_file).exists(): # ui配置文件
|
700 |
+
args += ' --ui-config-file=' + _ui_config_file
|
701 |
+
if _setting_file is not None and _setting_file != '' and Path(_setting_file).exists(): # 设置配置文件
|
702 |
+
args += ' --ui-settings-file=' + _setting_file
|
703 |
+
args += ' ' + otherArgs
|
704 |
+
os.environ['COMMANDLINE_ARGS']=args
|
705 |
+
run(f'''echo COMMANDLINE_ARGS=$COMMANDLINE_ARGS''')
|
706 |
+
os.environ['REQS_FILE']='requirements.txt'
|
707 |
+
start_webui()
|
708 |
+
|
709 |
+
|
710 |
+
# 启动非webui相关的的内容,加快启动速度
|
711 |
+
def main():
|
712 |
+
global envInstalled
|
713 |
+
global huggingface_is_init
|
714 |
+
startTicks = time.time()
|
715 |
+
stop_solo_threads()
|
716 |
+
isInstall = True if os.getenv('IsInstall','False') == 'True' else False
|
717 |
+
if Path(f'{install_path}/sd_main_dir').exists():
|
718 |
+
isInstall = True
|
719 |
+
if isInstall is False or _reLoad:
|
720 |
+
print('启动 安装和运行环境')
|
721 |
+
install()
|
722 |
+
link_dir()
|
723 |
+
threading.Thread(target = install_dependencies,daemon=True,name='solo_install_dependencies').start()
|
724 |
+
threading.Thread(target = install_optimizing,daemon=True,name='solo_install_optimizing').start()
|
725 |
+
threading.Thread(target = installProxyExe,daemon=True).start()
|
726 |
+
link_or_download_flie(replace_path(_async_downloading), _link_instead_of_copy=_link_instead_of_copy,
|
727 |
+
base_path=f'{install_path}/sd_main_dir')
|
728 |
+
|
729 |
+
link_or_download_flie(replace_path(_before_downloading), _link_instead_of_copy=_link_instead_of_copy,
|
730 |
+
base_path=f'{install_path}/sd_main_dir',is_await=True)
|
731 |
+
t = 0
|
732 |
+
while not envInstalled:
|
733 |
+
if t%10==0:
|
734 |
+
print('等待python环境安装...')
|
735 |
+
t = t+1
|
736 |
+
time.sleep(1)
|
737 |
+
use_config()
|
738 |
+
localProxy()
|
739 |
+
os.environ['IsInstall'] = 'True'
|
740 |
+
else:
|
741 |
+
envInstalled = True
|
742 |
+
link_or_download_flie(replace_path(_before_start_sync_downloading), _link_instead_of_copy=_link_instead_of_copy,
|
743 |
+
base_path=f'{install_path}/sd_main_dir',sync=True)
|
744 |
+
threading.Thread(target = startProxy, daemon=True, name='solo_startProxy').start()
|
745 |
+
ticks = time.time()
|
746 |
+
print("安装耗时:",(ticks - startTicks),"秒")
|
747 |
+
start()
|
748 |
+
|
749 |
+
|
750 |
+
if _skip_start:
|
751 |
+
print('已跳过自动启动,可手动执行 main() 进行启动。')
|
752 |
+
print('''推荐的启动代码:
|
753 |
+
try:
|
754 |
+
check_gpu() # 检查是否存在gpu
|
755 |
+
main()
|
756 |
+
except KeyboardInterrupt:
|
757 |
+
stop_solo_threads() # 中断后自动停止后台线程 (有部分功能在后台线程中运行)
|
758 |
+
''')
|
759 |
+
else:
|
760 |
+
try:
|
761 |
+
main()
|
762 |
+
except KeyboardInterrupt:
|
763 |
+
stop_solo_threads()
|
764 |
+
|